From 284009e873b95eed32fae62703ab3bc59e8e905b Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Wed, 4 Jan 2012 19:39:38 +0400 Subject: [PATCH] Add a hotkey command to duplicate jobs in workshops. --- Memory.xml | 5 ++ library/include/DataDefs.h | 1 + library/include/MiscUtils.h | 14 +++++ plugins/jobutils.cpp | 100 ++++++++++++++++++++++++++++++++++-- 4 files changed, 117 insertions(+), 3 deletions(-) diff --git a/Memory.xml b/Memory.xml index 729759445..62f20f9ab 100644 --- a/Memory.xml +++ b/Memory.xml @@ -1094,6 +1094,7 @@
+
@@ -2345,6 +2346,8 @@
+ +
cmake @@ -3230,6 +3233,8 @@
+ +
diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index d3899854d..ff61d08f5 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -204,6 +204,7 @@ namespace df { GLOBAL(gview,interface) \ GLOBAL(init,init) \ GLOBAL(d_init,d_init) \ + SIMPLE_GLOBAL(job_next_id,int) \ SIMPLE_GLOBAL(ui_look_cursor,int) \ SIMPLE_GLOBAL(ui_workshop_job_cursor,int) \ SIMPLE_GLOBAL(ui_workshop_in_add,bool) \ diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index 05be881ee..961904e5c 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -172,6 +172,20 @@ CT *binsearch_in_vector(const std::vector &vec, FT CT::*field, FT value) return idx < 0 ? NULL : vec[idx]; } +/* + * List + */ + +template +Link *linked_list_append(Link *head, Link *tail) +{ + while (head->next) + head = head->next; + head->next = tail; + tail->prev = head; + return tail; +} + /* * MISC */ diff --git a/plugins/jobutils.cpp b/plugins/jobutils.cpp index 71ecc2b2c..bca8696f5 100644 --- a/plugins/jobutils.cpp +++ b/plugins/jobutils.cpp @@ -17,8 +17,11 @@ #include #include #include +#include #include #include +#include +#include using std::vector; using std::string; @@ -30,13 +33,16 @@ using df::global::world; using df::global::ui; using df::global::ui_build_selector; using df::global::ui_workshop_job_cursor; +using df::global::job_next_id; -static bool wokshop_job_hotkey(Core *c, df::viewscreen *top); -static bool build_selector_hotkey(Core *c, df::viewscreen *top); +/* 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); +static command_result job_material(Core *c, vector & parameters); +static command_result job_duplicate(Core *c, vector & parameters); static command_result job_cmd(Core *c, vector & parameters); DFhackCExport const char * plugin_name ( void ) @@ -75,6 +81,17 @@ DFhackCExport command_result plugin_init (Core *c, std::vector & ); } + if (ui_workshop_job_cursor && job_next_id) { + commands.push_back( + PluginCommand( + "job-duplicate", "Duplicate the selected job in a workshop.", + job_duplicate, workshop_job_hotkey, + " - In 'q' mode, when a job is highlighted within a workshop\n" + " or furnace building, instantly duplicates the job.\n" + ) + ); + } + return CR_OK; } @@ -83,6 +100,8 @@ DFhackCExport command_result plugin_shutdown ( Core * c ) return CR_OK; } +/* UI state guards */ + static bool workshop_job_hotkey(Core *c, df::viewscreen *top) { using namespace ui_sidebar_mode; @@ -150,6 +169,8 @@ static bool job_material_hotkey(Core *c, df::viewscreen *top) build_selector_hotkey(c, top); } +/* job-material implementation */ + static df::job *getWorkshopJob(Core *c) { df::building *selected = world->selected_building; @@ -288,6 +309,79 @@ static command_result job_material(Core * c, vector & parameters) return CR_WRONG_USAGE; } +/* job-duplicate implementation */ + +static df::job *clone_job(df::job *job) +{ + df::job *pnew = new df::job(*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; +} + +static command_result job_duplicate(Core * c, vector & parameters) +{ + if (!parameters.empty()) + return CR_WRONG_USAGE; + + df::job *job = getWorkshopJob(c); + if (!job) + return CR_FAILURE; + + if (!job->misc_links.empty() || job->job_items.empty()) + { + c->con.printerr("Cannot duplicate job %s\n", ENUM_KEY_STR(job_type,job->job_type)); + return CR_FAILURE; + } + + df::building *building = world->selected_building; + if (building->jobs.size() >= 10) + { + c->con.printerr("Job list is already full.\n"); + return CR_FAILURE; + } + + // Actually clone + df::job *pnew = clone_job(job); + + int pos = ++*ui_workshop_job_cursor; + building->jobs.insert(building->jobs.begin()+pos, pnew); + + return CR_OK; +} + +/* Main job command implementation */ + static void print_job_item_details(Core *c, df::job *job, df::job_item *item) { c->con << " Input Item: " << ENUM_KEY_STR(item_type,item->item_type);