|
|
|
@ -7,6 +7,7 @@
|
|
|
|
|
#include "MiscUtils.h"
|
|
|
|
|
|
|
|
|
|
#include "modules/Maps.h"
|
|
|
|
|
#include "modules/MapCache.h"
|
|
|
|
|
#include "modules/Gui.h"
|
|
|
|
|
#include "modules/Items.h"
|
|
|
|
|
#include "modules/Materials.h"
|
|
|
|
@ -22,6 +23,7 @@
|
|
|
|
|
#include "df/creature_raw.h"
|
|
|
|
|
#include "df/caste_raw.h"
|
|
|
|
|
#include "df/reaction_reagent.h"
|
|
|
|
|
#include "df/reaction_reagent_itemst.h"
|
|
|
|
|
#include "df/reaction_product_itemst.h"
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
@ -33,18 +35,27 @@ using df::global::gametype;
|
|
|
|
|
|
|
|
|
|
DFHACK_PLUGIN("createitem");
|
|
|
|
|
|
|
|
|
|
int dest_container = -1, dest_building = -1;
|
|
|
|
|
|
|
|
|
|
command_result df_createitem (color_ostream &out, vector <string> & parameters);
|
|
|
|
|
|
|
|
|
|
DFhackCExport command_result plugin_init (color_ostream &out, std::vector<PluginCommand> &commands)
|
|
|
|
|
{
|
|
|
|
|
commands.push_back(PluginCommand("createitem", "Create arbitrary item at the selected unit's feet.", df_createitem, false,
|
|
|
|
|
commands.push_back(PluginCommand("createitem", "Create arbitrary items.", df_createitem, false,
|
|
|
|
|
"Syntax: createitem <item> <material> [count]\n"
|
|
|
|
|
" <item> - Item token for what you wish to create, as specified in custom\n"
|
|
|
|
|
" reactions. If the item has no subtype, omit the :NONE.\n"
|
|
|
|
|
" <material> - The material you want the item to be made of, as specified\n"
|
|
|
|
|
" in custom reactions. For REMAINS, FISH, FISH_RAW, VERMIN,\n"
|
|
|
|
|
" PET, and EGG, replace this with a creature ID and caste.\n"
|
|
|
|
|
" [count] - How many of the item you wish to create.\n"));
|
|
|
|
|
" [count] - How many of the item you wish to create.\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"By default, items are created at the feet of the selected unit.\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"Syntax: createitem <destination>\n"
|
|
|
|
|
" <destination> - Where to put subsequently created items.\n"
|
|
|
|
|
" Valid values are 'floor', 'item', and 'building'.\n"
|
|
|
|
|
));
|
|
|
|
|
return CR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -61,6 +72,14 @@ bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool second_it
|
|
|
|
|
bool is_gloves = (prod->item_type == df::item_type::GLOVES);
|
|
|
|
|
bool is_shoes = (prod->item_type == df::item_type::SHOES);
|
|
|
|
|
|
|
|
|
|
df::item *container = NULL;
|
|
|
|
|
df::building *building = NULL;
|
|
|
|
|
df::reaction_reagent_itemst *reagent = NULL;
|
|
|
|
|
if (dest_container != -1)
|
|
|
|
|
container = df::item::find(dest_container);
|
|
|
|
|
if (dest_building != -1)
|
|
|
|
|
building = df::building::find(dest_building);
|
|
|
|
|
|
|
|
|
|
prod->produce(unit, &out_items, &in_reag, &in_items, 1, df::job_skill::NONE,
|
|
|
|
|
df::historical_entity::find(unit->civ_id),
|
|
|
|
|
((*gametype == df::game_type::DWARF_MAIN) || (*gametype == df::game_type::DWARF_RECLAIM)) ? df::world_site::find(ui->site_id) : NULL);
|
|
|
|
@ -70,9 +89,28 @@ bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool second_it
|
|
|
|
|
// otherwise, make a second set because shoes are normally made in pairs
|
|
|
|
|
if (is_shoes && out_items.size() == prod->count * 2)
|
|
|
|
|
is_shoes = false;
|
|
|
|
|
|
|
|
|
|
MapExtras::MapCache mc;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < out_items.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
out_items[i]->moveToGround(unit->pos.x, unit->pos.y, unit->pos.z);
|
|
|
|
|
bool on_ground = true;
|
|
|
|
|
if (container)
|
|
|
|
|
{
|
|
|
|
|
on_ground = false;
|
|
|
|
|
out_items[i]->flags.bits.removed = 1;
|
|
|
|
|
if (!Items::moveToContainer(mc, out_items[i], container))
|
|
|
|
|
out_items[i]->moveToGround(container->pos.x, container->pos.y, container->pos.z);
|
|
|
|
|
}
|
|
|
|
|
if (building)
|
|
|
|
|
{
|
|
|
|
|
on_ground = false;
|
|
|
|
|
out_items[i]->flags.bits.removed = 1;
|
|
|
|
|
if (!Items::moveToBuilding(mc, out_items[i], (df::building_actual *)building, 0))
|
|
|
|
|
out_items[i]->moveToGround(building->centerx, building->centery, building->z);
|
|
|
|
|
}
|
|
|
|
|
if (on_ground)
|
|
|
|
|
out_items[i]->moveToGround(unit->pos.x, unit->pos.y, unit->pos.z);
|
|
|
|
|
if (is_gloves)
|
|
|
|
|
{
|
|
|
|
|
// if the reaction creates gloves without handedness, then create 2 sets (left and right)
|
|
|
|
@ -97,8 +135,104 @@ command_result df_createitem (color_ostream &out, vector <string> & parameters)
|
|
|
|
|
int32_t mat_index = -1;
|
|
|
|
|
int count = 1;
|
|
|
|
|
|
|
|
|
|
if (parameters.size() == 1)
|
|
|
|
|
{
|
|
|
|
|
if (parameters[0] == "floor")
|
|
|
|
|
{
|
|
|
|
|
dest_container = -1;
|
|
|
|
|
dest_building = -1;
|
|
|
|
|
out.print("Items created will be placed on the floor.\n");
|
|
|
|
|
return CR_OK;
|
|
|
|
|
}
|
|
|
|
|
else if (parameters[0] == "item")
|
|
|
|
|
{
|
|
|
|
|
dest_building = -1;
|
|
|
|
|
df::item *item = Gui::getSelectedItem(out);
|
|
|
|
|
if (!item)
|
|
|
|
|
{
|
|
|
|
|
out.printerr("You must select a container!\n");
|
|
|
|
|
return CR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
switch (item->getType())
|
|
|
|
|
{
|
|
|
|
|
case df::item_type::FLASK:
|
|
|
|
|
case df::item_type::BARREL:
|
|
|
|
|
case df::item_type::BUCKET:
|
|
|
|
|
case df::item_type::ANIMALTRAP:
|
|
|
|
|
case df::item_type::BOX:
|
|
|
|
|
case df::item_type::BIN:
|
|
|
|
|
case df::item_type::BACKPACK:
|
|
|
|
|
case df::item_type::QUIVER:
|
|
|
|
|
break;
|
|
|
|
|
case df::item_type::TOOL:
|
|
|
|
|
if (item->hasToolUse(df::tool_uses::LIQUID_CONTAINER))
|
|
|
|
|
break;
|
|
|
|
|
if (item->hasToolUse(df::tool_uses::FOOD_STORAGE))
|
|
|
|
|
break;
|
|
|
|
|
if (item->hasToolUse(df::tool_uses::SMALL_OBJECT_STORAGE))
|
|
|
|
|
break;
|
|
|
|
|
if (item->hasToolUse(df::tool_uses::TRACK_CART))
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
out.printerr("The selected item cannot be used for item storage!\n");
|
|
|
|
|
return CR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
dest_container = item->id;
|
|
|
|
|
string name;
|
|
|
|
|
item->getItemDescription(&name, 0);
|
|
|
|
|
out.print("Items created will be placed inside %s.\n", name.c_str());
|
|
|
|
|
return CR_OK;
|
|
|
|
|
}
|
|
|
|
|
else if (parameters[0] == "building")
|
|
|
|
|
{
|
|
|
|
|
dest_container = -1;
|
|
|
|
|
df::building *building = Gui::getSelectedBuilding(out);
|
|
|
|
|
if (!building)
|
|
|
|
|
{
|
|
|
|
|
out.printerr("You must select a building!\n");
|
|
|
|
|
return CR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
switch (building->getType())
|
|
|
|
|
{
|
|
|
|
|
case df::building_type::Coffin:
|
|
|
|
|
case df::building_type::Furnace:
|
|
|
|
|
case df::building_type::TradeDepot:
|
|
|
|
|
case df::building_type::Shop:
|
|
|
|
|
case df::building_type::Box:
|
|
|
|
|
case df::building_type::Weaponrack:
|
|
|
|
|
case df::building_type::Armorstand:
|
|
|
|
|
case df::building_type::Workshop:
|
|
|
|
|
case df::building_type::Cabinet:
|
|
|
|
|
case df::building_type::SiegeEngine:
|
|
|
|
|
case df::building_type::Trap:
|
|
|
|
|
case df::building_type::AnimalTrap:
|
|
|
|
|
case df::building_type::Cage:
|
|
|
|
|
case df::building_type::Wagon:
|
|
|
|
|
case df::building_type::NestBox:
|
|
|
|
|
case df::building_type::Hive:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
out.printerr("The selected building cannot be used for item storage!\n");
|
|
|
|
|
return CR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
if (building->getBuildStage() != building->getMaxBuildStage())
|
|
|
|
|
{
|
|
|
|
|
out.printerr("The selected building has not yet been fully constructed!\n");
|
|
|
|
|
return CR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
dest_building = building->id;
|
|
|
|
|
string name;
|
|
|
|
|
building->getName(&name);
|
|
|
|
|
out.print("Items created will be placed inside %s.\n", name.c_str());
|
|
|
|
|
return CR_OK;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return CR_WRONG_USAGE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((parameters.size() < 2) || (parameters.size() > 3))
|
|
|
|
|
return CR_WRONG_USAGE;
|
|
|
|
|
|
|
|
|
|
item_str = parameters[0];
|
|
|
|
|
material_str = parameters[1];
|
|
|
|
|
|
|
|
|
@ -250,6 +384,17 @@ command_result df_createitem (color_ostream &out, vector <string> & parameters)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((dest_container != -1) && !df::item::find(dest_container))
|
|
|
|
|
{
|
|
|
|
|
dest_container = -1;
|
|
|
|
|
out.printerr("Previously selected container no longer exists - item will be placed on the floor.\n");
|
|
|
|
|
}
|
|
|
|
|
if ((dest_building != -1) && !df::building::find(dest_building))
|
|
|
|
|
{
|
|
|
|
|
dest_building = -1;
|
|
|
|
|
out.printerr("Previously selected building no longer exists - item will be placed on the floor.\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool result = makeItem(prod, unit);
|
|
|
|
|
delete prod;
|
|
|
|
|
if (!result)
|
|
|
|
|