From f5e121a1963da0fc923b04db3ca99fdbd4328ad6 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 7 Jan 2012 19:21:07 +0400 Subject: [PATCH] Move a bunch of stuff from the jobutils plugin into the core. --- library/CMakeLists.txt | 2 + library/include/DataDefs.h | 12 ++ library/include/modules/Gui.h | 12 ++ library/include/modules/Job.h | 54 +++++++++ library/modules/Gui.cpp | 97 +++++++++++++++ library/modules/Job.cpp | 201 +++++++++++++++++++++++++++++++ library/xml | 2 +- plugins/jobutils.cpp | 220 +++++----------------------------- 8 files changed, 409 insertions(+), 191 deletions(-) create mode 100644 library/include/modules/Job.h create mode 100644 library/modules/Job.cpp diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 808c13a18..e940264b7 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -48,6 +48,7 @@ include/modules/Units.h include/modules/Engravings.h include/modules/Gui.h include/modules/Items.h +include/modules/Job.h include/modules/kitchen.h include/modules/Maps.h include/modules/MapCache.h @@ -88,6 +89,7 @@ modules/Units.cpp modules/Engravings.cpp modules/Gui.cpp modules/Items.cpp +modules/Job.cpp modules/kitchen.cpp modules/Maps.cpp modules/Materials.cpp diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index 5d942c46a..a7fb956ed 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -188,6 +188,18 @@ namespace df } }; + template + inline bool operator== (enum_field a, enum_field b) + { + return EnumType(a) == EnumType(b); + } + + template + inline bool operator!= (enum_field a, enum_field b) + { + return EnumType(a) != EnumType(b); + } + namespace enums {} } diff --git a/library/include/modules/Gui.h b/library/include/modules/Gui.h index 3d3fe81c7..2da6cdbe7 100644 --- a/library/include/modules/Gui.h +++ b/library/include/modules/Gui.h @@ -32,6 +32,11 @@ distribution. #include "BitArray.h" #include +namespace df { + struct viewscreen; + struct job; +}; + /** * \defgroup grp_gui query DF's GUI state * @ingroup grp_modules @@ -39,6 +44,13 @@ distribution. namespace DFHack { + class Core; + + bool workshop_job_hotkey(Core *c, df::viewscreen *top); + bool build_selector_hotkey(Core *c, df::viewscreen *top); + + df::job *getSelectedWorkshopJob(Core *c, bool quiet = false); + class DFContextShared; /** * A GUI screen diff --git a/library/include/modules/Job.h b/library/include/modules/Job.h new file mode 100644 index 000000000..7136971ce --- /dev/null +++ b/library/include/modules/Job.h @@ -0,0 +1,54 @@ +/* +https://github.com/peterix/dfhack +Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#pragma once +#ifndef CL_MOD_JOB +#define CL_MOD_JOB + +#include "Export.h" +#include "Module.h" +#include + +namespace df +{ + struct job; + struct job_item; + struct job_item_filter; +} + +namespace DFHack +{ + // Duplicate the job structure. It is not linked into any DF lists. + df::job *cloneJobStruct(df::job *job); + + // Delete a cloned structure. + void deleteJobStruct(df::job *job); + + bool operator== (const df::job_item &a, const df::job_item &b); + bool operator== (const df::job &a, const df::job &b); + + void printJobDetails(Core *c, df::job *job); +} +#endif + diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 1a970deeb..04f23ccba 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -41,8 +41,16 @@ using namespace std; using namespace DFHack; #include "DataDefs.h" +#include "df/world.h" #include "df/cursor.h" #include "df/viewscreen_dwarfmodest.h" +#include "df/ui.h" +#include "df/job.h" +#include "df/ui_build_selector.h" +#include "df/building_workshopst.h" +#include "df/building_furnacest.h" + +using namespace df::enums; // Predefined common guard functions @@ -73,6 +81,95 @@ bool DFHack::cursor_hotkey(Core *c, df::viewscreen *top) return true; } +bool DFHack::workshop_job_hotkey(Core *c, df::viewscreen *top) +{ + using namespace ui_sidebar_mode; + using df::global::ui; + using df::global::world; + using df::global::ui_workshop_in_add; + using df::global::ui_workshop_job_cursor; + + if (!dwarfmode_hotkey(c,top)) + return false; + + switch (ui->main.mode) { + case QueryBuilding: + { + if (!ui_workshop_job_cursor) // allow missing + return false; + + df::building *selected = world->selected_building; + if (!virtual_cast(selected) && + !virtual_cast(selected)) + return false; + + // No jobs? + if (selected->jobs.empty() || + selected->jobs[0]->job_type == job_type::DestroyBuilding) + return false; + + // Add job gui activated? + if (ui_workshop_in_add && *ui_workshop_in_add) + return false; + + return true; + }; + default: + return false; + } +} + +bool DFHack::build_selector_hotkey(Core *c, df::viewscreen *top) +{ + using namespace ui_sidebar_mode; + using df::global::ui; + using df::global::ui_build_selector; + + if (!dwarfmode_hotkey(c,top)) + return false; + + switch (ui->main.mode) { + case Build: + { + if (!ui_build_selector) // allow missing + return false; + + // Not selecting, or no choices? + if (ui_build_selector->building_type < 0 || + ui_build_selector->stage != 2 || + ui_build_selector->choices.empty()) + return false; + + return true; + }; + default: + return false; + } +} + +df::job *DFHack::getSelectedWorkshopJob(Core *c, bool quiet) +{ + using df::global::world; + using df::global::ui_workshop_job_cursor; + + if (!workshop_job_hotkey(c, c->getTopViewscreen())) { + if (!quiet) + c->con.printerr("Not in a workshop, or no job is highlighted.\n"); + return NULL; + } + + df::building *selected = world->selected_building; + int idx = *ui_workshop_job_cursor; + + if (idx < 0 || idx >= selected->jobs.size()) + { + c->con.printerr("Invalid job cursor index: %d\n", idx); + return NULL; + } + + return selected->jobs[idx]; +} + // Module* DFHack::createGui() diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp new file mode 100644 index 000000000..a91146c98 --- /dev/null +++ b/library/modules/Job.cpp @@ -0,0 +1,201 @@ +/* +https://github.com/peterix/dfhack +Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + + +#include "Internal.h" + +#include +#include +#include +#include +using namespace std; + +#include "Core.h" +#include "PluginManager.h" + +#include "modules/Job.h" +#include "modules/Materials.h" + +#include "DataDefs.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace DFHack; +using namespace df::enums; + +df::job *DFHack::cloneJobStruct(df::job *job) +{ + df::job *pnew = new df::job(*job); + + // Clean out transient fields + pnew->flags.whole = 0; + pnew->flags.bits.repeat = job->flags.bits.repeat; + pnew->flags.bits.suspend = job->flags.bits.suspend; + + pnew->list_link = NULL; + pnew->completion_timer = -1; + pnew->items.clear(); + pnew->misc_links.clear(); + + // Clone refs + for (int i = pnew->references.size()-1; i >= 0; i--) + { + df::general_ref *ref = pnew->references[i]; + + if (virtual_cast(ref)) + pnew->references.erase(pnew->references.begin()+i); + else + pnew->references[i] = ref->clone(); + } + + // Clone items + for (int i = pnew->job_items.size()-1; i >= 0; i--) + pnew->job_items[i] = new df::job_item(*pnew->job_items[i]); + + return pnew; +} + +void DFHack::deleteJobStruct(df::job *job) +{ + if (!job) + return; + + // Only allow free-floating job structs + assert(!job->list_link && job->items.empty() && job->misc_links.empty()); + + for (int i = job->references.size()-1; i >= 0; i--) + delete job->references[i]; + + for (int i = job->job_items.size()-1; i >= 0; i--) + delete job->job_items[i]; + + delete job; +} + +#define CMP(field) (a.field == b.field) + +bool DFHack::operator== (const df::job_item &a, const df::job_item &b) +{ + if (!(CMP(item_type) && CMP(item_subtype) && + CMP(mat_type) && CMP(mat_index) && + CMP(flags1.whole) && CMP(quantity) && CMP(vector_id) && + CMP(flags2.whole) && CMP(flags3.whole) && + CMP(metal_ore) && CMP(reaction_class) && + CMP(has_material_reaction_product) && + CMP(min_dimension) && CMP(reagent_index) && + CMP(reaction_id) && CMP(has_tool_use) && + CMP(contains.size()))) + return false; + + for (int i = a.contains.size()-1; i >= 0; i--) + if (a.contains[i] != b.contains[i]) + return false; + + return true; +} + +bool DFHack::operator== (const df::job &a, const df::job &b) +{ + if (!(CMP(job_type) && CMP(unk2) && + CMP(mat_type) && CMP(mat_index) && + CMP(item_subtype) && CMP(item_category.whole) && + CMP(hist_figure_id) && CMP(material_category.whole) && + CMP(reaction_name) && CMP(job_items.size()))) + return false; + + for (int i = a.job_items.size()-1; i >= 0; i--) + if (!(*a.job_items[i] == *b.job_items[i])) + return false; + + return true; +} + +static void print_job_item_details(Core *c, df::job *job, unsigned idx, df::job_item *item) +{ + 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) + c->con << "; quantity=" << item->quantity; + if (item->min_dimension >= 0) + c->con << "; min_dimension=" << item->min_dimension; + c->con << endl; + + MaterialInfo mat(item); + if (mat.isValid() || item->metal_ore >= 0) { + c->con << " material: " << mat.toString(); + if (item->metal_ore >= 0) + c->con << "; ore of " << MaterialInfo(0,item->metal_ore).toString(); + c->con << endl; + } + + if (item->flags1.whole) + c->con << " flags1: " << bitfieldToString(item->flags1) << endl; + if (item->flags2.whole) + c->con << " flags2: " << bitfieldToString(item->flags2) << endl; + if (item->flags3.whole) + c->con << " flags3: " << bitfieldToString(item->flags3) << endl; + + if (!item->reaction_class.empty()) + c->con << " reaction class: " << item->reaction_class << endl; + if (!item->has_material_reaction_product.empty()) + c->con << " reaction product: " << item->has_material_reaction_product << endl; + if (item->has_tool_use >= 0) + c->con << " tool use: " << ENUM_KEY_STR(tool_uses, item->has_tool_use) << endl; +} + +void DFHack::printJobDetails(Core *c, df::job *job) +{ + c->con << "Job " << job->id << ": " << ENUM_KEY_STR(job_type,job->job_type); + if (job->flags.whole) + c->con << " (" << bitfieldToString(job->flags) << ")"; + c->con << endl; + + MaterialInfo mat(job); + if (mat.isValid() || job->material_category.whole) + { + c->con << " material: " << mat.toString(); + if (job->material_category.whole) + c->con << " (" << bitfieldToString(job->material_category) << ")"; + c->con << endl; + } + + if (job->item_subtype >= 0 || job->item_category.whole) + c->con << " item: " << job->item_subtype + << " (" << bitfieldToString(job->item_category) << ")" << endl; + + if (job->hist_figure_id >= 0) + c->con << " figure: " << job->hist_figure_id << endl; + + if (!job->reaction_name.empty()) + c->con << " reaction: " << job->reaction_name << endl; + + for (unsigned i = 0; i < job->job_items.size(); i++) + print_job_item_details(c, job, i, job->job_items[i]); +} diff --git a/library/xml b/library/xml index e5713a6ad..30d6b3330 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit e5713a6add0c21477d3bfa5e228ecdb4b3a2c33d +Subproject commit 30d6b333037b2f5d968aad738b67d5bed42993d3 diff --git a/plugins/jobutils.cpp b/plugins/jobutils.cpp index 66ed00024..a89fa99cd 100644 --- a/plugins/jobutils.cpp +++ b/plugins/jobutils.cpp @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include @@ -37,8 +39,6 @@ using df::global::job_next_id; /* Plugin registration */ -static bool workshop_job_hotkey(Core *c, df::viewscreen *top); -static bool build_selector_hotkey(Core *c, df::viewscreen *top); static bool job_material_hotkey(Core *c, df::viewscreen *top); static command_result job_material(Core *c, vector & parameters); @@ -106,67 +106,6 @@ DFhackCExport command_result plugin_shutdown ( Core * c ) /* UI state guards */ -static bool workshop_job_hotkey(Core *c, df::viewscreen *top) -{ - using namespace ui_sidebar_mode; - - if (!dwarfmode_hotkey(c,top)) - return false; - - switch (ui->main.mode) { - case QueryBuilding: - { - if (!ui_workshop_job_cursor) // allow missing - return false; - - df::building *selected = world->selected_building; - if (!virtual_cast(selected) && - !virtual_cast(selected)) - return false; - - // No jobs? - if (selected->jobs.empty() || - selected->jobs[0]->job_type == job_type::DestroyBuilding) - return false; - - // Add job gui activated? - if (df::global::ui_workshop_in_add && // allow missing - *df::global::ui_workshop_in_add) - return false; - - return true; - }; - default: - return false; - } -} - -static bool build_selector_hotkey(Core *c, df::viewscreen *top) -{ - using namespace ui_sidebar_mode; - - if (!dwarfmode_hotkey(c,top)) - return false; - - switch (ui->main.mode) { - case Build: - { - if (!ui_build_selector) // allow missing - return false; - - // Not selecting, or no choices? - if (ui_build_selector->building_type < 0 || - ui_build_selector->stage != 2 || - ui_build_selector->choices.empty()) - return false; - - return true; - }; - default: - return false; - } -} - static bool job_material_hotkey(Core *c, df::viewscreen *top) { return workshop_job_hotkey(c, top) || @@ -175,23 +114,9 @@ static bool job_material_hotkey(Core *c, df::viewscreen *top) /* job-material implementation */ -static df::job *getWorkshopJob(Core *c) -{ - df::building *selected = world->selected_building; - int idx = *ui_workshop_job_cursor; - - if (idx < 0 || idx >= selected->jobs.size()) - { - c->con.printerr("Invalid job cursor index: %d\n", idx); - return NULL; - } - - return selected->jobs[idx]; -} - static command_result job_material_in_job(Core *c, MaterialInfo &new_mat) { - df::job *job = getWorkshopJob(c); + df::job *job = getSelectedWorkshopJob(c); if (!job) return CR_FAILURE; @@ -248,13 +173,13 @@ static command_result job_material_in_job(Core *c, MaterialInfo &new_mat) } static bool build_choice_matches(df::ui_build_item_req *req, df::build_req_choicest *choice, - MaterialInfo &new_mat) + MaterialInfo &new_mat, bool ignore_select) { if (VIRTUAL_CAST_VAR(gen, df::build_req_choice_genst, choice)) { if (gen->mat_type == new_mat.type && gen->mat_index == new_mat.index && - gen->used_count < gen->candidates.size()) + (ignore_select || gen->used_count < gen->candidates.size())) { return true; } @@ -264,7 +189,7 @@ static bool build_choice_matches(df::ui_build_item_req *req, df::build_req_choic if (spec->candidate && spec->candidate->getActualMaterial() == new_mat.type && spec->candidate->getActualMaterialIndex() == new_mat.index && - !req->candidate_selected[spec->candidate_id]) + (ignore_select || !req->candidate_selected[spec->candidate_id])) { return true; } @@ -275,13 +200,22 @@ static bool build_choice_matches(df::ui_build_item_req *req, df::build_req_choic static command_result job_material_in_build(Core *c, MaterialInfo &new_mat) { - df::ui_build_item_req *req = ui_build_selector->requirements[ui_build_selector->req_index]; + df::ui_build_selector *sel = ui_build_selector; + df::ui_build_item_req *req = sel->requirements[ui_build_selector->req_index]; + + // Loop through matching choices + bool matches = build_choice_matches(req, sel->choices[sel->sel_index], new_mat, true); + + int size = sel->choices.size(); + int base = (matches ? sel->sel_index + 1 : 0); - for (unsigned i = 0; i < ui_build_selector->choices.size(); i++) + for (unsigned i = 0; i < size; i++) { - if (build_choice_matches(req, ui_build_selector->choices[i], new_mat)) + int idx = (base + i) % size; + + if (build_choice_matches(req, sel->choices[idx], new_mat, false)) { - ui_build_selector->sel_index = i; + sel->sel_index = idx; return CR_OK; } } @@ -317,39 +251,16 @@ static command_result job_material(Core * c, vector & parameters) static df::job *clone_job(df::job *job) { - df::job *pnew = new df::job(*job); + df::job *pnew = cloneJobStruct(job); pnew->id = (*job_next_id)++; - // Clean out transient fields - pnew->flags.whole = 0; - pnew->flags.bits.repeat = job->flags.bits.repeat; - - pnew->completion_timer = -1; - pnew->items.clear(); - pnew->misc_links.clear(); - // Link the job into the global list pnew->list_link = new df::job_list_link(); pnew->list_link->item = pnew; linked_list_append(&world->job_list, pnew->list_link); - // Clone refs - for (int i = pnew->references.size()-1; i >= 0; i--) - { - df::general_ref *ref = pnew->references[i]; - - if (virtual_cast(ref)) - pnew->references.erase(pnew->references.begin()+i); - else - pnew->references[i] = ref->clone(); - } - - // Clone items - for (int i = pnew->job_items.size()-1; i >= 0; i--) - pnew->job_items[i] = new df::job_item(*pnew->job_items[i]); - return pnew; } @@ -358,7 +269,7 @@ static command_result job_duplicate(Core * c, vector & parameters) if (!parameters.empty()) return CR_WRONG_USAGE; - df::job *job = getWorkshopJob(c); + df::job *job = getSelectedWorkshopJob(c); if (!job) return CR_FAILURE; @@ -386,80 +297,6 @@ static command_result job_duplicate(Core * c, vector & parameters) /* Main job command implementation */ -static void print_job_item_details(Core *c, df::job *job, unsigned idx, df::job_item *item) -{ - 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) - c->con << "; quantity=" << item->quantity; - if (item->min_dimension >= 0) - c->con << "; min_dimension=" << item->min_dimension; - c->con << endl; - - MaterialInfo mat(item); - if (mat.isValid() || item->metal_ore >= 0) { - c->con << " material: " << mat.toString(); - if (item->metal_ore >= 0) - c->con << "; ore of " << MaterialInfo(0,item->metal_ore).toString(); - c->con << endl; - } - - if (item->flags1.whole) - c->con << " flags1: " << bitfieldToString(item->flags1) << endl; - if (item->flags2.whole) - c->con << " flags2: " << bitfieldToString(item->flags2) << endl; - if (item->flags3.whole) - c->con << " flags3: " << bitfieldToString(item->flags3) << endl; - - if (!item->reaction_class.empty()) - c->con << " reaction class: " << item->reaction_class << endl; - if (!item->has_material_reaction_product.empty()) - c->con << " reaction product: " << item->has_material_reaction_product << endl; - if (item->has_tool_use >= 0) - c->con << " tool use: " << ENUM_KEY_STR(tool_uses, item->has_tool_use) << endl; -} - -static void print_job_details(Core *c, df::job *job) -{ - c->con << "Job " << job->id << ": " << ENUM_KEY_STR(job_type,job->job_type); - if (job->flags.whole) - c->con << " (" << bitfieldToString(job->flags) << ")"; - c->con << endl; - - MaterialInfo mat(job); - if (mat.isValid() || job->material_category.whole) - { - c->con << " material: " << mat.toString(); - if (job->material_category.whole) - c->con << " (" << bitfieldToString(job->material_category) << ")"; - c->con << endl; - } - - if (job->item_subtype >= 0 || job->item_category.whole) - c->con << " item: " << job->item_subtype - << " (" << bitfieldToString(job->item_category) << ")" << endl; - - if (job->hist_figure_id >= 0) - c->con << " figure: " << job->hist_figure_id << endl; - - if (!job->reaction_name.empty()) - c->con << " reaction: " << job->reaction_name << endl; - - for (unsigned i = 0; i < job->job_items.size(); 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) { CoreSuspender suspend(c); @@ -470,16 +307,16 @@ static command_result job_cmd(Core * c, vector & parameters) std::string cmd = parameters[0]; if (cmd == "query" || cmd == "list") { - df::job *job = getWorkshopJobSafe(c); + df::job *job = getSelectedWorkshopJob(c); if (!job) return CR_WRONG_USAGE; if (cmd == "query") { - print_job_details(c, job); + printJobDetails(c, job); } else { df::building *selected = world->selected_building; for (unsigned i = 0; i < selected->jobs.size(); i++) - print_job_details(c, selected->jobs[i]); + printJobDetails(c, selected->jobs[i]); } } else if (cmd == "item-material") @@ -487,7 +324,7 @@ static command_result job_cmd(Core * c, vector & parameters) if (parameters.size() < 1+1+1) return CR_WRONG_USAGE; - df::job *job = getWorkshopJobSafe(c); + df::job *job = getSelectedWorkshopJob(c); if (!job) return CR_WRONG_USAGE; @@ -508,7 +345,7 @@ static command_result job_cmd(Core * c, vector & parameters) if (!info.matches(*item)) { c->con.printerr("Material does not match the requirements.\n"); - print_job_details(c, job); + printJobDetails(c, job); return CR_FAILURE; } @@ -524,9 +361,12 @@ static command_result job_cmd(Core * c, vector & parameters) item->mat_index = info.index; c->con << "Job item " << v << " updated." << endl; - print_job_details(c, job); + printJobDetails(c, job); return CR_OK; } + else if (cmd == "item-type") + { + } else return CR_WRONG_USAGE;