From 687245abd92f11db0f6fdff405c77f708344eb07 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 5 Jan 2012 22:04:05 +0400 Subject: [PATCH] Allow setting job item materials. --- library/include/MiscUtils.h | 27 +++++++ library/include/modules/Materials.h | 13 ++++ library/modules/Materials.cpp | 111 ++++++++++++++++++++++++++++ library/xml | 2 +- plugins/jobutils.cpp | 77 ++++++++++++++++--- 5 files changed, 218 insertions(+), 12 deletions(-) diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index 961904e5c..5897994e3 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -70,6 +70,24 @@ void print_bits ( T val, DFHack::Console& out ) * Binary search in vectors. */ +template +int linear_index(const std::vector &vec, FT key) +{ + for (unsigned i = 0; i < vec.size(); i++) + if (vec[i] == key) + return i; + return -1; +} + +template +int linear_index(const std::vector &vec, const FT &key) +{ + for (unsigned i = 0; i < vec.size(); i++) + if (vec[i] && *vec[i] == key) + return i; + return -1; +} + template int binsearch_index(const std::vector &vec, FT key, bool exact = true) { @@ -91,6 +109,15 @@ int binsearch_index(const std::vector &vec, FT key, bool exact = true) } } +template +int linear_index(const std::vector &vec, FT CT::*field, FT key) +{ + for (unsigned i = 0; i < vec.size(); i++) + if (vec[i]->*field == key) + return i; + return -1; +} + template int binsearch_index(const std::vector &vec, FT CT::*field, FT key, bool exact = true) { diff --git a/library/include/modules/Materials.h b/library/include/modules/Materials.h index c5f54cd91..25becc400 100644 --- a/library/include/modules/Materials.h +++ b/library/include/modules/Materials.h @@ -48,7 +48,12 @@ namespace df struct creature_raw; struct historical_figure; struct material_vec_ref; + struct job_item; + union job_material_category; + union job_item_flags1; + union job_item_flags2; + union job_item_flags3; } namespace DFHack @@ -104,8 +109,16 @@ namespace DFHack std::string toString(uint16_t temp = 10015, bool named = true); + bool isAnyCloth(); + + void getMatchBits(df::job_item_flags1 &ok, df::job_item_flags1 &mask); + void getMatchBits(df::job_item_flags2 &ok, df::job_item_flags2 &mask); + void getMatchBits(df::job_item_flags3 &ok, df::job_item_flags3 &mask); + df::craft_material_class getCraftClass(); + bool matches(const df::job_material_category &cat); + bool matches(const df::job_item &item); }; inline bool operator== (const MaterialInfo &a, const MaterialInfo &b) { diff --git a/library/modules/Materials.cpp b/library/modules/Materials.cpp index 0faf26030..8e9d30cc1 100644 --- a/library/modules/Materials.cpp +++ b/library/modules/Materials.cpp @@ -43,12 +43,15 @@ using namespace std; #include "MiscUtils.h" #include "df/world.h" +#include "df/ui.h" #include "df/item.h" #include "df/inorganic_raw.h" #include "df/plant_raw.h" +#include "df/plant_raw_flags.h" #include "df/creature_raw.h" #include "df/historical_figure.h" +#include "df/job_item.h" #include "df/job_material_category.h" #include "df/matter_state.h" #include "df/material_vec_ref.h" @@ -259,6 +262,17 @@ df::craft_material_class MaterialInfo::getCraftClass() return craft_material_class::None; } +bool MaterialInfo::isAnyCloth() +{ + using namespace df::enums::material_flags; + + return material && ( + material->flags.is_set(THREAD_PLANT) || + material->flags.is_set(SILK) || + material->flags.is_set(YARN) + ); +} + bool MaterialInfo::matches(const df::job_material_category &cat) { if (!material) @@ -283,6 +297,103 @@ bool MaterialInfo::matches(const df::job_material_category &cat) return false; } +bool MaterialInfo::matches(const df::job_item &item) +{ + if (!isValid()) return false; + + df::job_item_flags1 ok1, mask1; + getMatchBits(ok1, mask1); + + df::job_item_flags2 ok2, mask2; + getMatchBits(ok2, mask2); + + df::job_item_flags3 ok3, mask3; + getMatchBits(ok3, mask3); + + return ((item.flags1.whole & mask1.whole) == (item.flags1.whole & ok1.whole)) && + ((item.flags2.whole & mask2.whole) == (item.flags2.whole & ok2.whole)) && + ((item.flags3.whole & mask3.whole) == (item.flags3.whole & ok3.whole)); +} + +void MaterialInfo::getMatchBits(df::job_item_flags1 &ok, df::job_item_flags1 &mask) +{ + ok.whole = mask.whole = 0; + if (!isValid()) return; + +#define MAT_FLAG(name) material->flags.is_set(df::enums::material_flags::name) +#define FLAG(field, name) (field && field->flags.is_set(name)) +#define TEST(bit, check) \ + mask.bits.bit = true; ok.bits.bit = !!(check); + + bool structural = MAT_FLAG(STRUCTURAL_PLANT_MAT); + + TEST(millable, structural && FLAG(plant, plant_raw_flags::MILL)); + TEST(sharpenable, MAT_FLAG(IS_STONE)); + TEST(distillable, structural && FLAG(plant, plant_raw_flags::DRINK)); + TEST(processable, structural && FLAG(plant, plant_raw_flags::THREAD)); + TEST(bag, isAnyCloth()); + TEST(cookable, MAT_FLAG(EDIBLE_COOKED)); + TEST(extract_bearing_plant, structural && FLAG(plant, plant_raw_flags::EXTRACT_STILL_VIAL)); + TEST(extract_bearing_fish, false); + TEST(extract_bearing_vermin, false); + TEST(processable_to_vial, structural && FLAG(plant, plant_raw_flags::EXTRACT_VIAL)); + TEST(processable_to_bag, structural && FLAG(plant, plant_raw_flags::LEAVES)); + TEST(processable_to_barrel, structural && FLAG(plant, plant_raw_flags::EXTRACT_BARREL)); + TEST(solid, !(MAT_FLAG(ALCOHOL_PLANT) || + MAT_FLAG(ALCOHOL_CREATURE) || + MAT_FLAG(LIQUID_MISC_PLANT) || + MAT_FLAG(LIQUID_MISC_CREATURE) || + MAT_FLAG(LIQUID_MISC_OTHER))); + TEST(tameable_vermin, false); + TEST(sharpenable, MAT_FLAG(IS_GLASS)); + TEST(milk, linear_index(material->reaction_product.id, std::string("CHEESE_MAT")) >= 0); + //04000000 - "milkable" - vtable[107],1,1 +} + +void MaterialInfo::getMatchBits(df::job_item_flags2 &ok, df::job_item_flags2 &mask) +{ + ok.whole = mask.whole = 0; + if (!isValid()) return; + + bool is_cloth = isAnyCloth(); + + TEST(dye, MAT_FLAG(IS_DYE)); + TEST(dyeable, is_cloth); + TEST(dyed, is_cloth); + TEST(sewn_imageless, is_cloth); + TEST(glass_making, MAT_FLAG(CRYSTAL_GLASSABLE)); + + TEST(fire_safe, material->heat.melting_point > 11000); + TEST(magma_safe, material->heat.melting_point > 12000); + TEST(deep_material, FLAG(inorganic, df::enums::inorganic_flags::DEEP_ANY)); + TEST(non_economic, inorganic && !(df::global::ui && df::global::ui->economic_stone[index])); + + TEST(plant, plant); + TEST(silk, MAT_FLAG(SILK)); + TEST(leather, MAT_FLAG(LEATHER)); + TEST(bone, MAT_FLAG(BONE)); + TEST(shell, MAT_FLAG(SHELL)); + TEST(totemable, false); + TEST(horn, MAT_FLAG(HORN)); + TEST(pearl, MAT_FLAG(PEARL)); + TEST(soap, MAT_FLAG(SOAP)); + TEST(ivory_tooth, MAT_FLAG(TOOTH)); + //TEST(hair_wool, MAT_FLAG(YARN)); + TEST(yarn, MAT_FLAG(YARN)); +} + +void MaterialInfo::getMatchBits(df::job_item_flags3 &ok, df::job_item_flags3 &mask) +{ + ok.whole = mask.whole = 0; + if (!isValid()) return; + + TEST(hard, MAT_FLAG(ITEMS_HARD)); +} + +#undef MAT_FLAG +#undef FLAG +#undef TEST + Module* DFHack::createMaterials() { return new Materials(); diff --git a/library/xml b/library/xml index e61e696e2..f20758b0a 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit e61e696e2a2bb6b24a86c9c01a26f3133509585e +Subproject commit f20758b0a3ef5aebcbf5896cbb7a824cbdf7b218 diff --git a/plugins/jobutils.cpp b/plugins/jobutils.cpp index c89ca2f40..66ed00024 100644 --- a/plugins/jobutils.cpp +++ b/plugins/jobutils.cpp @@ -60,8 +60,12 @@ DFhackCExport command_result plugin_init (Core *c, std::vector & PluginCommand( "job", "General job query and manipulation.", job_cmd, false, - " job query - Print details of the current job.\n" - " job list - Print details of all jobs in the workshop.\n" + " job query\n" + " Print details of the current job.\n" + " job list\n" + " Print details of all jobs in the workshop.\n" + " job item-material [submaterial]\n" + " Replace the exact material id in the job item.\n" ) ); @@ -382,9 +386,9 @@ static command_result job_duplicate(Core * c, vector & parameters) /* Main job command implementation */ -static void print_job_item_details(Core *c, df::job *job, df::job_item *item) +static void print_job_item_details(Core *c, df::job *job, unsigned idx, df::job_item *item) { - c->con << " Input Item: " << ENUM_KEY_STR(item_type,item->item_type); + c->con << " Input Item " << (idx+1) << ": " << ENUM_KEY_STR(item_type,item->item_type); if (item->item_subtype != -1) c->con << " [" << item->item_subtype << "]"; if (item->quantity != 1) @@ -443,7 +447,17 @@ static void print_job_details(Core *c, df::job *job) c->con << " reaction: " << job->reaction_name << endl; for (unsigned i = 0; i < job->job_items.size(); i++) - print_job_item_details(c, job, job->job_items[i]); + print_job_item_details(c, job, i, job->job_items[i]); +} + +static df::job *getWorkshopJobSafe(Core *c) +{ + if (!workshop_job_hotkey(c, c->getTopViewscreen())) { + c->con.printerr("No job is highlighted.\n"); + return NULL; + } + + return getWorkshopJob(c); } static command_result job_cmd(Core * c, vector & parameters) @@ -456,15 +470,11 @@ static command_result job_cmd(Core * c, vector & parameters) std::string cmd = parameters[0]; if (cmd == "query" || cmd == "list") { - if (!workshop_job_hotkey(c, c->getTopViewscreen())) { - c->con.printerr("No job is highlighted.\n"); + df::job *job = getWorkshopJobSafe(c); + if (!job) return CR_WRONG_USAGE; - } if (cmd == "query") { - df::job *job = getWorkshopJob(c); - if (!job) - return CR_FAILURE; print_job_details(c, job); } else { df::building *selected = world->selected_building; @@ -472,6 +482,51 @@ static command_result job_cmd(Core * c, vector & parameters) print_job_details(c, selected->jobs[i]); } } + else if (cmd == "item-material") + { + if (parameters.size() < 1+1+1) + return CR_WRONG_USAGE; + + df::job *job = getWorkshopJobSafe(c); + if (!job) + return CR_WRONG_USAGE; + + int v = atoi(parameters[1].c_str()); + if (v < 1 || v > job->job_items.size()) { + c->con.printerr("Invalid item index.\n"); + return CR_WRONG_USAGE; + } + + df::job_item *item = job->job_items[v-1]; + + std::string subtoken = (parameters.size()>3 ? parameters[3] : ""); + MaterialInfo info; + if (!info.find(parameters[2], subtoken)) { + c->con.printerr("Could not find the specified material.\n"); + return CR_FAILURE; + } + + if (!info.matches(*item)) { + c->con.printerr("Material does not match the requirements.\n"); + print_job_details(c, job); + return CR_FAILURE; + } + + if (job->mat_type != -1 && + job->mat_type == item->mat_type && + job->mat_index == item->mat_index) + { + job->mat_type = info.type; + job->mat_index = info.index; + } + + item->mat_type = info.type; + item->mat_index = info.index; + + c->con << "Job item " << v << " updated." << endl; + print_job_details(c, job); + return CR_OK; + } else return CR_WRONG_USAGE;