From 11ee3a223da9ea34602f71b5a3f8dc3708d93f00 Mon Sep 17 00:00:00 2001 From: PassionateAngler Date: Thu, 17 Sep 2020 17:00:15 +0200 Subject: [PATCH 01/44] enumnick: command added to 'zone' plugin and other QoL improvements zone: enumnick command create nick for creature from given prefix and number uinfo displays "Matched creatures" i.e number of creatures matched by filter maxage, and minage filters accept float now slaughter flag displayed on uinfo cretures list --- plugins/zone.cpp | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/plugins/zone.cpp b/plugins/zone.cpp index 071d67a23..c32122241 100644 --- a/plugins/zone.cpp +++ b/plugins/zone.cpp @@ -133,6 +133,7 @@ const string zone_help = " with filters named units are ignored unless specified.\n" " unassign - unassign selected creature(s) from zone or cage\n" " nick - give unit(s) nicknames (e.g. all units in a cage)\n" + " enumnick - give unit(s) enumerated nicknames (e.g Hen 1, Hen 2)\n" " remnick - remove nicknames\n" " tocages - assign to (multiple) built cages inside a pen/pasture\n" " spreads creatures evenly among cages for faster hauling.\n" @@ -427,6 +428,7 @@ void unitInfo(color_ostream & out, df::unit* unit, bool verbose = false) out << ")"; out << ", age: " << getAge(unit, true); + if(isTame(unit)) out << ", tame"; if(isOwnCiv(unit)) @@ -445,7 +447,9 @@ void unitInfo(color_ostream & out, df::unit* unit, bool verbose = false) out << ", grazer"; if(isMilkable(unit)) out << ", milkable"; - + if(unit->flags2.bits.slaughter) + out << ", slaughter"; + if(verbose) { out << ". Pos: ("<pos.x << "/"<< unit->pos.y << "/" << unit->pos.z << ") " << endl; @@ -1398,7 +1402,7 @@ pair> createAgeFilter(vector &filter_a pair> createMinAgeFilter(vector &filter_args) { - int min_age; + double min_age; stringstream ss(filter_args[0]); ss >> min_age; @@ -1424,7 +1428,7 @@ pair> createMinAgeFilter(vector &filte pair> createMaxAgeFilter(vector &filter_args) { - int max_age; + double max_age; stringstream ss(filter_args[0]); ss >> max_age; @@ -1489,6 +1493,8 @@ command_result df_zone (color_ostream &out, vector & parameters) bool cagezone_assign = false; bool nick_set = false; string target_nick; + bool enum_nick = true; + string enum_prefix; bool verbose = false; @@ -1694,6 +1700,18 @@ command_result df_zone (color_ostream &out, vector & parameters) start_index = 2; out << "Set nickname to: " << target_nick << endl; } + else if(p0 == "enumnick") + { + if(parameters.size() <= 2) + { + out.printerr("No prefix specified! Use 'remnick' to remove nicknames!\n"); + return CR_WRONG_USAGE; + } + enum_nick = true; + enum_prefix = parameters[1]; + start_index = 2; + out << "Set nickname to: " << enum_prefix <<" " << endl; + } else if(p0 == "remnick") { nick_set = true; @@ -2070,6 +2088,7 @@ command_result df_zone (color_ostream &out, vector & parameters) { vector units_for_cagezone; int count = 0; + int matchedCount = 0; for(auto unit_it = world->units.all.begin(); unit_it != world->units.all.end(); ++unit_it) { df::unit *unit = *unit_it; @@ -2108,6 +2127,8 @@ command_result df_zone (color_ostream &out, vector & parameters) } continue; } + + matchedCount++; if(unit_info) { @@ -2118,6 +2139,12 @@ command_result df_zone (color_ostream &out, vector & parameters) { Units::setNickname(unit, target_nick); } + else if(enum_nick) + { + std::stringstream ss; + ss << enum_prefix << " " << matchedCount; + Units::setNickname(unit, ss.str()); + } else if(cagezone_assign) { units_for_cagezone.push_back(unit); @@ -2181,6 +2208,7 @@ command_result df_zone (color_ostream &out, vector & parameters) } out.color(COLOR_BLUE); + out << "Matched creatures: " << matchedCount << endl; out << "Processed creatures: " << count << endl; out.reset_color(); } From d3520a2f5f64870b3cef88d0acb757f1f0263d67 Mon Sep 17 00:00:00 2001 From: Quietust Date: Sun, 20 Sep 2020 16:11:41 -0600 Subject: [PATCH 02/44] Fix createitem to properly create plant growths (#898) --- plugins/createitem.cpp | 86 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/plugins/createitem.cpp b/plugins/createitem.cpp index 6032383d7..f32c51c03 100644 --- a/plugins/createitem.cpp +++ b/plugins/createitem.cpp @@ -26,6 +26,9 @@ #include "df/reaction_reagent.h" #include "df/reaction_product_itemst.h" #include "df/tool_uses.h" +#include "df/item_plant_growthst.h" +#include "df/plant_growth.h" +#include "df/plant_growth_print.h" using std::string; using std::vector; @@ -37,6 +40,7 @@ REQUIRE_GLOBAL(cursor); REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(gametype); +REQUIRE_GLOBAL(cur_year_tick); int dest_container = -1, dest_building = -1; @@ -51,6 +55,7 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector - 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" + " For PLANT_GROWTH, replace this with a plant ID and growth ID.\n" " [count] - How many of the item you wish to create.\n" "\n" "To obtain the item and material of an existing item, run \n" @@ -72,7 +77,7 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out ) return CR_OK; } -bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool second_item = false, bool move_to_cursor = false) +bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool second_item = false, bool move_to_cursor = false, int32_t growth_print = -1) { vector out_products; vector out_items; @@ -118,6 +123,8 @@ bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool second_it out_items[i]->moveToGround(cursor->x, cursor->y, cursor->z); else out_items[i]->moveToGround(unit->pos.x, unit->pos.y, unit->pos.z); + + // Special logic for making gloves if (is_gloves) { // if the reaction creates gloves without handedness, then create 2 sets (left and right) @@ -126,9 +133,14 @@ bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool second_it else out_items[i]->setGloveHandedness(second_item ? 2 : 1); } + + // Special logic for making plant growths + auto growth = virtual_cast(out_items[i]); + if (growth) + growth->growth_print = growth_print; } if ((is_gloves || is_shoes) && !second_item) - return makeItem(prod, unit, true, move_to_cursor); + return makeItem(prod, unit, true, move_to_cursor, growth_print); return true; } @@ -140,6 +152,7 @@ command_result df_createitem (color_ostream &out, vector & parameters) int16_t item_subtype = -1; int16_t mat_type = -1; int32_t mat_index = -1; + int32_t growth_print = -1; int count = 1; bool move_to_cursor = false; @@ -370,6 +383,73 @@ command_result df_createitem (color_ostream &out, vector & parameters) } break; + case item_type::PLANT_GROWTH: + split_string(&tokens, material_str, ":"); + if (tokens.size() == 1) + { + // default to empty to display a list of valid growths later + tokens.push_back(""); + } + else if (tokens.size() != 2) + { + out.printerr("You must specify a plant and growth ID for this item type!\n"); + return CR_FAILURE; + } + + for (size_t i = 0; i < world->raws.plants.all.size(); i++) + { + string growths = ""; + df::plant_raw *plant = world->raws.plants.all[i]; + if (plant->id != tokens[0]) + continue; + + for (size_t j = 0; j < plant->growths.size(); j++) + { + df::plant_growth *growth = plant->growths[j]; + growths += " " + growth->id; + if (growth->id != tokens[1]) + continue; + + // Plant growths specify the actual item type/subtype + // so that certain growths can drop as SEEDS items + item_type = growth->item_type; + item_subtype = growth->item_subtype; + mat_type = growth->mat_type; + mat_index = growth->mat_index; + + // Try and find a growth print matching the current time + // (in practice, only tree leaves use this for autumn color changes) + for (size_t k = 0; k < growth->prints.size(); k++) + { + df::plant_growth_print *print = growth->prints[k]; + if (print->timing_start <= *cur_year_tick && *cur_year_tick <= print->timing_end) + { + growth_print = k; + break; + } + } + // If we didn't find one, then pick the first one (if it exists) + if (growth_print == -1 && growth->prints.size() > 0) + growth_print = 0; + break; + } + if (mat_type == -1) + { + if (tokens[1].empty()) + out.printerr("You must also specify a growth ID.\n"); + else + out.printerr("The plant you specified has no such growth!\n"); + out.printerr("Valid growths:%s\n", growths.c_str()); + return CR_FAILURE; + } + } + if (mat_type == -1) + { + out.printerr("Unrecognized plant ID!\n"); + return CR_FAILURE; + } + break; + case item_type::CORPSE: case item_type::CORPSEPIECE: case item_type::FOOD: @@ -449,7 +529,7 @@ command_result df_createitem (color_ostream &out, vector & parameters) out.printerr("Previously selected building no longer exists - item will be placed on the floor.\n"); } - bool result = makeItem(prod, unit, false, move_to_cursor); + bool result = makeItem(prod, unit, false, move_to_cursor, growth_print); delete prod; if (!result) { From a3c565b2435919c701f1db8095ca372794734579 Mon Sep 17 00:00:00 2001 From: George Murray Date: Thu, 24 Sep 2020 07:31:10 -0700 Subject: [PATCH 03/44] Add to_search_normalized to search for characters with accents --- library/MiscUtils.cpp | 39 +++++++++++++++++++++++++++++++++++++ library/include/MiscUtils.h | 1 + plugins/search.cpp | 4 ++-- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/library/MiscUtils.cpp b/library/MiscUtils.cpp index 84dddbbd6..018ddd6c3 100644 --- a/library/MiscUtils.cpp +++ b/library/MiscUtils.cpp @@ -128,6 +128,45 @@ std::string toLower(const std::string &str) return rv; } +static const char *normalized_table[256] = { + //.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .A .B .C .D .E .F + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 0. + NULL, NULL, NULL, NULL, NULL, "S", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 1. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 2. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 3. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 4. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 5. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 6. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 7. + "C", "u", "e", "a", "a", "a", "a", "c", "e", "e", "e", "i", "i", "i", "A", "A", // 8. + "E", "ae", "Ae", "o", "o", "o", "u", "u", "y", "O", "U", "c", "L", "Y", NULL, "f", // 9. + "a", "i", "o", "u", "n", "N", "a", "o", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // A. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // B. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // C. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // D. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // E. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // F. +}; + +std::string to_search_normalized(const std::string &str) +{ + std::stringbuf result; + for (char c : str) + { + const char *mapped = normalized_table[(uint8_t)c]; + if (mapped == NULL) + result.sputc(tolower(c)); + else + while (*mapped != '\0') + { + result.sputc(tolower(c)); + ++mapped; + } + } + + return result.str(); +} + bool word_wrap(std::vector *out, const std::string &str, size_t line_length) { out->clear(); diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index 35f8be73b..4249abeef 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -366,6 +366,7 @@ DFHACK_EXPORT std::string join_strings(const std::string &separator, const std:: DFHACK_EXPORT std::string toUpper(const std::string &str); DFHACK_EXPORT std::string toLower(const std::string &str); +DFHACK_EXPORT std::string to_search_normalized(const std::string &str); DFHACK_EXPORT bool word_wrap(std::vector *out, const std::string &str, diff --git a/plugins/search.cpp b/plugins/search.cpp index 6e0b49e16..f053967d8 100644 --- a/plugins/search.cpp +++ b/plugins/search.cpp @@ -396,7 +396,7 @@ protected: clear_viewscreen_vectors(); - string search_string_l = toLower(search_string); + string search_string_l = to_search_normalized(search_string); for (size_t i = 0; i < saved_list1.size(); i++ ) { if (force_in_search(i)) @@ -409,7 +409,7 @@ protected: continue; T element = saved_list1[i]; - string desc = toLower(get_element_description(element)); + string desc = to_search_normalized(get_element_description(element)); if (desc.find(search_string_l) != string::npos) { add_to_filtered_list(i); From 38c9c2825012b5700a5e477f3e9e2e38e9a1c7ef Mon Sep 17 00:00:00 2001 From: George Murray Date: Thu, 24 Sep 2020 10:52:03 -0700 Subject: [PATCH 04/44] Fix wrong variable usage in to_search_normalized --- library/MiscUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/MiscUtils.cpp b/library/MiscUtils.cpp index 018ddd6c3..893c27b2c 100644 --- a/library/MiscUtils.cpp +++ b/library/MiscUtils.cpp @@ -159,7 +159,7 @@ std::string to_search_normalized(const std::string &str) else while (*mapped != '\0') { - result.sputc(tolower(c)); + result.sputc(tolower(*mapped)); ++mapped; } } From f5c3712778bb9021c2b3792cd88417ec6bbdb357 Mon Sep 17 00:00:00 2001 From: George Murray Date: Thu, 24 Sep 2020 14:32:58 -0700 Subject: [PATCH 05/44] Nicer formatting for the normalized character mapping table --- library/MiscUtils.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/library/MiscUtils.cpp b/library/MiscUtils.cpp index 893c27b2c..2659d5d43 100644 --- a/library/MiscUtils.cpp +++ b/library/MiscUtils.cpp @@ -129,23 +129,23 @@ std::string toLower(const std::string &str) } static const char *normalized_table[256] = { - //.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .A .B .C .D .E .F - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 0. - NULL, NULL, NULL, NULL, NULL, "S", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 1. - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 2. - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 3. - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 4. - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 5. - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 6. - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 7. - "C", "u", "e", "a", "a", "a", "a", "c", "e", "e", "e", "i", "i", "i", "A", "A", // 8. - "E", "ae", "Ae", "o", "o", "o", "u", "u", "y", "O", "U", "c", "L", "Y", NULL, "f", // 9. - "a", "i", "o", "u", "n", "N", "a", "o", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // A. - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // B. - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // C. - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // D. - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // E. - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // F. + //.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .A .B .C .D .E .F + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 0. + NULL, NULL, NULL, NULL, NULL, "S", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 1. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 2. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 3. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 4. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 5. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 6. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 7. + "C", "u", "e", "a", "a", "a", "a", "c", "e", "e", "e", "i", "i", "i", "A", "A", // 8. + "E", "ae", "Ae", "o", "o", "o", "u", "u", "y", "O", "U", "c", "L", "Y", NULL, "f", // 9. + "a", "i", "o", "u", "n", "N", "a", "o", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // A. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // B. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // C. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // D. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // E. + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // F. }; std::string to_search_normalized(const std::string &str) From 74a3e0eddf360534a028b29d7076cf65212b940b Mon Sep 17 00:00:00 2001 From: George Murray Date: Thu, 24 Sep 2020 15:22:58 -0700 Subject: [PATCH 06/44] Use a string and .reserve for normalizing instead of stringbuf --- library/MiscUtils.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/library/MiscUtils.cpp b/library/MiscUtils.cpp index 2659d5d43..56af85afe 100644 --- a/library/MiscUtils.cpp +++ b/library/MiscUtils.cpp @@ -150,21 +150,22 @@ static const char *normalized_table[256] = { std::string to_search_normalized(const std::string &str) { - std::stringbuf result; + std::string result; + result.reserve(str.size()); for (char c : str) { const char *mapped = normalized_table[(uint8_t)c]; if (mapped == NULL) - result.sputc(tolower(c)); + result += tolower(c); else while (*mapped != '\0') { - result.sputc(tolower(*mapped)); + result += tolower(*mapped); ++mapped; } } - return result.str(); + return result; } bool word_wrap(std::vector *out, const std::string &str, size_t line_length) From 5d98193c54a33cf3f210092a501018963d7edad6 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 1 Oct 2020 21:46:07 -0400 Subject: [PATCH 07/44] Convert quickfort user guide to RST using pandoc Unchanged. First pass of dfhack#1653 --- docs/tools/quickfort-user-guide.rst | 1138 +++++++++++++++++++++++++++ 1 file changed, 1138 insertions(+) create mode 100644 docs/tools/quickfort-user-guide.rst diff --git a/docs/tools/quickfort-user-guide.rst b/docs/tools/quickfort-user-guide.rst new file mode 100644 index 000000000..e0be9147a --- /dev/null +++ b/docs/tools/quickfort-user-guide.rst @@ -0,0 +1,1138 @@ +DFHack Quickfort User Manual +============================ + +DFHack Quickfort is a DFHack script that helps you build fortresses from +"blueprint" .csv and .xlsx files. Many applications exist to edit these files, +such as MS Excel and `Google Sheets `__. You can also build +your plan "for real" in Dwarf Fortress, and then export your map using DFHack's +`blueprint `__ +plugin. Most layout and building-oriented DF commands are supported through the +use of multiple files or spreadsheets, each describing a different phase of DF +construction: designation, building, placing stockpiles/zones, and setting +configuration. + +The original idea and 1.0 codebase came from +`Valdemar's `__ +auto-designation macro. Joel Thornton (joelpt) reimplemented the core logic in +Python and extended its functionality with `Quickfort +2.0 `__. This DFHack-native implementation, +called "DFHack Quickfort" or just "quickfort", builds upon Quickfort 2.0's +formats and features. DFHack Quickfort is written in Lua and interacts with +Dwarf Fortress memory structures directly, allowing for instantaneous blueprint +application, error checking and recovery, and many other advanced features. + +This document focuses on DFHack Quickfort's capabilities and teaches players how +to understand and build blueprint files. Some of the text was originally written +by Joel Thornton, reused here with his permission. + +For those just looking to apply blueprints, check out the `quickfort command +syntax `__ in +the DFHack Scripts documentation. There are also many ready-to-use blueprints +available in the ``blueprints/library`` subfolder in your DFHack installation. +Browse them on your computer or +`online `__, +or run ``quickfort list -l`` at the ``DFHack#`` prompt to list them, and then +``quickfort run`` to apply them to your fort! + +See the `Links section <#links>`__ for more information and online resources. + +Table of Contents +----------------- + +- `Features <#features>`__ +- `Editing Blueprints <#editing-blueprints>`__ + + - `Area expansion syntax <#area-expansion-syntax>`__ + - `Automatic area expansion <#automatic-area-expansion>`__ + - `Multilevel blueprints <#multilevel-blueprints>`__ + - `Marker mode <#marker-mode>`__ + - `Dig priorities <#dig-priorities>`__ + - `Stockpiles and zones <#stockpiles-and-zones>`__ + - `Minecart tracks <#minecart-tracks>`__ + - `Modeline markers `__ + - `Packaging a set of blueprints <#packaging-a-set-of-blueprints>`__ + - `Meta blueprints <#meta-blueprints>`__ + +- `Buildingplan integration <#buildingplan-integration>`__ +- `Generating manager orders <#generating-manager-orders>`__ +- `Tips and tricks <#tips-and-tricks>`__ +- `Caveats and limitations <#caveats-and-limitations>`__ +- `Links <#links>`__ + +Features +-------- + +- General + + - Manages blueprints to handle all phases of DF construction + - Supports .csv and multi-worksheet .xlsx blueprint files + - Near-instant application, even for very large and complex blueprints + - Blueprints can span multiple z-levels + - Supports multiple blueprints per .csv file/spreadsheet sheet + - "meta" blueprints that automate the application of sequences of blueprints + - Undo functionality for dig, build, place, and zone blueprints + - Automatic cropping of blueprints so you don't get errors if the blueprint + extends off the map + - Can generate manager orders for everything required by a build blueprint + - Library of ready-to-use blueprints included + - Verbose output mode for debugging + +- Dig mode + + - Supports all types of designations, including dumping/forbidding items and + setting traffic settings + - Supports setting dig priorities + - Supports applying dig blueprints in marker mode + - Handles carving arbitrarily complex minecart tracks, including tracks that + cross other tracks + +- Build mode + + - DFHack buildingplan integration + - Designate complete constructions at once, without having to wait for each + tile to become supported before you can build it + - Automatic expansion of building footprints to their minimum dimensions, so + only the center tile of a multi-tile building needs to be recorded in the + blueprint + - Tile occupancy and validity checking so, for example, buildings that + cannot be placed on a certain tile will simply be skipped instead of the + blueprint failing to apply. Blueprints that are only partially applied for + any reason (for example, you need to dig out some more tiles) can be + safely reapplied to build the remaining buildings. + - Relaxed rules for farm plot and road placement: you can still place the + building even if an invalid tile (e.g. stone tiles for farm plots) splits + the designated area into two parts + - Intelligent boundary detection for adjacent buildings of the same type + (e.g. a 6x6 block of ``wj`` cells will be correctly split into 4 jeweler's + workshops) + +- Place and zone modes + + - Define stockpiles and zones in any continguous shape, not just rectangular + blocks + - Configurable maximums for bins, barrels and wheelbarrows assigned to + created stockpiles + - Automatic splitting of stockpiles and zones that exceed maximum dimension + limits + +- Query mode + + - Send arbitrary keystroke sequences to the UI -- *anything* you can do + through the UI is supported + - Supports aliases to automate frequent keystroke combos + - Includes a library of pre-made and tested aliases to automate most common + tasks, such as configuring stockpiles for important item types or creating + named hauling routes for quantum stockpiles. + - Supports including aliases in other aliases, and repeating key sequences a + specified number of times + - Skips sending key sequences when the cursor is over a tile that does not + have a stockpile or building, so missing buildings won't desynchronize + your blueprint + - Instant halting of query blueprint application when keystroke errors are + detected, such as when a key sequence leaves us stuck in a submenu, to + make blueprint misconfigurations easier to debug + +Editing Blueprints +------------------ + +We recommend using a spreadsheet editor such as Excel, `Google +Sheets `__, or `LibreOffice `__ +to edit blueprint files, but any text editor will do. + +The format of Quickfort-compatible blueprint files is straightforward. The first +line (or upper-left cell) of the spreadsheet should look like this: + +:: + + #dig This is a decription. + +The keyword "dig" tells Quickfort we are going to be using the Designations menu +in DF. The following "mode" keywords are understood: + +:: + + dig Designations menu (d) + build Build menu (b) + place Place stockpiles menu (p) + zone Activity zones menu (i) + query Set building tasks/prefs menu (q) + +There are also "meta" blueprints, but we'll talk about those +`later <#meta-blueprints>`__. + +Optionally following this keyword and a space, you may enter a comment. This +comment will appear in the output of ``quickfort list`` when run from the +``DFHack#`` prompt. You can use this space for explanations, attribution, etc. + +Below this line begin entering the keys you want sent in each cell. For example, +we could dig out a 4x4 room like so (spaces are used as column separators here +for clarity, but a real .csv file would have commas): + +:: + + #dig + d d d d # + d d d d # + d d d d # + d d d d # + # # # # # + +Note the # symbols at the right end of each row and below the last row. These +are completely optional, but can be helpful to make the row and column positions +clear. + +Once the dwarves have that dug out, let's build a walled-in bedroom within our +dug-out area: + +:: + + #build + Cw Cw Cw Cw # + Cw b h Cw # + Cw Cw # + Cw Cw Cw # + # # # # # + +Note my generosity - in addition to the bed (b) I've built a chest (h) here for +the dwarf as well. You must use the full series of keys needed to build +something in each cell, e.g. 'Cw' enters DF's constructions submenu (C) and +selects walls (w). + +I'd also like to place a booze stockpile in the 2 unoccupied tiles in the room. + +:: + + #place Place a food stockpile + ` ` ` ` # + ` ` ` ` # + ` f(2x1)# + ` ` ` ` # + # # # # # + +This illustration may be a little hard to understand. The f(2x1) is in column 2, +row 3. All the other cells are empty. QF considers both "`" (backtick -- the +character under the tilde) and "~" (tilde) characters within cells to be empty +cells; this can help with multilayer or fortress-wide blueprint layouts as +'chalk lines'. + +With f(2x1), we've asked QF to place a food stockpile 2 units wide by 1 high +unit. Note that the f(2x1) syntax isn't actually necessary here; we could have +just used: + +:: + + #place Place a food stockpile + ` ` ` ` # + ` ` ` ` # + ` f f ` # + ` ` ` ` # + # # # # # + +QF is smart enough to recognize this as a 2x1 food stockpile, and creates it as +such rather than as two 1x1 food stockpiles. Quickfort recognizes any connected +region of identical designations as a single stockpile. The tiles can be +connected orthogonally or diagonally, just as long as they are touching somehow. + +Lastly, let's turn the bed into a bedroom and set the food stockpile to hold +only booze. + +:: + + #query + ` ` ` ` # + ` r& ` # + ` booze # + ` ` ` ` # + # # # # # + +In column 2, row 2 we have "r&". This sends the "r" key to DF when the cursor is +over the bed, causing us to 'make room' and "&", which is a special symbol that +expands to "{Enter}", to indicate that we're done. + +In column 2, row 3 we have "booze". This is one of many alias keywords defined +in the included `baseline aliases +file `__. +This particular alias sets a food stockpile to carry booze only. It sends the +keys needed to navigate DF's stockpile settings menu, and then sends an Escape +character ("^" or "{ESC}") to exit back to the map. It is important to exit out +of any menus that you enter while in query mode so that the cursor can move to +the next tile when it is done configuring the current tile. + +Check out the included `blueprint +library `__ +to see many more examples. Read the baseline aliases file for helpful +pre-packaged aliases, or create your own in +`dfhack-config/quickfort/aliases.txt `__ +in your DFHack installation. + +Area expansion syntax +--------------------- + +In Quickfort, the following blueprints are equivalent: + +:: + + #dig a 3x3 area + d d d # + d d d # + d d d # + # # # # + + #dig the same area with d(3x3) specified in row 1, col 1 + d(3x3)# + ` ` ` # + ` ` ` # + # # # # + +The second example uses Quickfort's "area expansion syntax", which takes the +form: + +:: + + keys(WxH) + +In Quickfort the above two examples of specifying a contiguous 3x3 area produce +identical output: a single 3x3 designation will be performed, rather than nine +1x1 designations as the first example might suggest. + +Area expansion syntax can only specify rectangular areas. If you want to create +extent-based structures (e.g. farm plots or stockpiles) in different shapes, use +the first format above. For example: + +:: + + #place L shaped food stockpile + f f ` ` # + f f ` ` # + f f f f # + f f f f # + # # # # # + +Area expansion syntax also sets boundaries, which can be useful if you want +adjacent, but separate, stockpiles of the same type: + +:: + + #place Two touching but separate food stockpiles + f(4x2) # + ~ ~ ~ ~ # + f(4x2) # + ~ ~ ~ ~ # + # # # # # + +As mentioned previously, "~" characters are ignored as comment characters and +can be used for visualizing the blueprint layout. The blueprint can be +equivalently written as: + +:: + + #place Two touching but separate food stockpiles + f(4x2) # + ~ ~ ~ ~ # + f f f f # + f f f f # + # # # # # + +since the area expansion syntax of the upper stockpile prevents it from +combining with the lower, freeform syntax stockpile. + +Area expansion syntax can also be used for buildings which have an adjustable +size, like bridges. The following blueprints are equivalent: + +:: + + #build a 4x2 bridge from row 1, col 1 + ga(4x2) ` # + ` ` ` ` # + # # # # # + + #build a 4x2 bridge from row 1, col 1 + ga ga ga ga # + ga ga ga ga # + # # # # # + +Automatic area expansion +------------------------ + +Buildings larger than 1x1, like workshops, can be represented in any of three +ways. You can designate just their center tile with empty cells around it to +leave room for the footprint, like this: + +:: + + #build a mason workshop in row 2, col 2 that will occupy the 3x3 area + ` ` ` # + ` wm ` # + ` ` ` # + # # # # + +Or you can fill out the entire footprint like this: + +:: + + #build a mason workshop + wm wm wm # + wm wm wm # + wm wm wm # + # # # # + +This format may be verbose for regular workshops, but it can be very helpful for +laying out structures like screw pump towers and waterwheels, whose "center +point" can be non-obvious. + +Finally, you can use area expansion syntax to represent the workshop: + +:: + + #build a mason workshop + wm(3x3) # + ` ` ` # + ` ` ` # + # # # # + +This style can be convenient for laying out multiple buildings of the same type. +If you are building a large-scale block factory, for example, this will create +20 mason workshops all in a row: + +:: + + #build line of 20 mason workshops + wm(60x3) # + +Quickfort will intelligently break large areas of the same designation into +appropriately-sized chunks. + +Multilevel blueprints +--------------------- + +Multilevel blueprints are accommodated by separating Z-levels of the blueprint +with ``#>`` (go down one z-level) or ``#<`` (go up one z-level) at the end of +each floor. + +:: + + #dig Stairs leading down to a small room below + j ` ` # + ` ` ` # + ` ` ` # + #> # # # + u d d # + d d d # + d d d # + # # # # + +The marker must appear in the first column of the row to be recognized, just +like a modeline. + +Dig priorities +-------------- + +DF designation priorities are supported for ``#dig`` blueprints. The full syntax +is ``[letter][number][expansion]``, where if the ``letter`` is not specified, +``d`` is assumed, and if ``number`` is not specified, ``4`` is assumed (the +default priority). So each of these blueprints is equivalent: + +:: + + #dig dig the interior of the room at high priority + d d d d d # + d d1 d1 d1 d # + d d1 d1 d1 d # + d d1 d1 d1 d # + d d d d d # + # # # # # # + + #dig dig the interior of the room at high priority + d d d d d # + d d1(3x3) d # + d ` ` ` d # + d ` ` ` d # + d d d d d # + # # # # # # + + #dig dig the interior of the room at high priority + 4 4 4 4 4 # + 4 1 1 1 4 # + 4 1 1 1 4 # + 4 1 1 1 4 # + 4 4 4 4 4 # + # # # # # # + +Marker mode +----------- + +Marker mode is useful for when you want to plan out your digging, but you don't +want to dig everything just yet. In ``#dig`` mode, you can add a ``m`` before +any other designation letter to indicate that the tile should be designated in +marker mode. For example, to dig out the perimeter of a room, but leave the +center of the room marked for digging later: + +:: + + #dig + d d d d d # + d md md md d # + d md md md d # + d md md md d # + d d d d d # + # # # # # # + +Then you can use "Toggle Standard/Marking" (``d-M``) to convert the center tiles +to regular designations at your leisure. + +To apply an entire dig blueprint in marker mode, regardless of what the +blueprint itself says, you can set the global quickfort setting +``force_marker_mode`` to ``true`` before you apply the blueprint. + +Note that the in-game UI setting "Standard/Marker Only" (``d-m``) does not have +any effect on quickfort. + +Stockpiles and zones +-------------------- + +It is very common to have stockpiles that accept multiple categories of items or +zones that permit more than one activity. Although it is perfectly valid to +declare a single-purpose stockpile or zone and then modify it with a ``#query`` +blueprint, quickfort also supports directly declaring all the types on the +``#place`` and ``#zone`` blueprints. For example, to declare a 10x10 area that +is a pasture, a fruit picking area, and a meeting area all at once, you could +write: + +:: + + #zone main pasture and picnic area + nmg(10x10) + +And similarly, to declare a stockpile that accepts both corpses and refuse, you +could write: + +:: + + #place refuse heap + yr(20x10) + +The order of the individual letters doesn't matter. + +To toggle the ``active`` flag for zones, add an ``a`` character to the string. +For example, to create a *disabled* pit zone (that you later intend to turn into +a pond and carefully fill to 3-depth water): + +:: + + #zone disabled future pond zone + pa(1x3) + +Note that while this notation covers most use cases, tweaking low-level zone +parameters, like hospital supply levels or converting between pits and ponds, +must still be done manually or with a ``#query`` blueprint. + +Minecart tracks +--------------- + +There are two ways to produce minecart tracks, and they are handled very +differently by the game. You can carve them into hard natural floors or you can +construct them out of building materials. Constructed tracks are conceptually +simpler, so we'll start with them. + +Constructed tracks +~~~~~~~~~~~~~~~~~~ + +Quickfort supports the designation of track stops and rollers through the normal +mechanisms: a ``#build`` blueprint with ``CS`` and some number of ``d`` and +``a`` characters (for selecting dump direction and friction) in a cell +designates a track stop and a ``#build`` blueprint with ``Mr`` and some number +of ``s`` and ``q`` characters (for direction and speed) designates a roller. +This can get confusing very quickly and is very difficult to read in a +blueprint. Constructed track segments don't even have keys associated with them +at all! + +To solve this problem, Quickfort provides the following keywords for use in +build blueprints: + +:: + + -- Track segments -- + trackN + trackS + trackE + trackW + trackNS + trackNE + trackNW + trackSE + trackSW + trackEW + trackNSE + trackNSW + trackNEW + trackSEW + trackNSEW + + -- Track/ramp segments -- + trackrampN + trackrampS + trackrampE + trackrampW + trackrampNS + trackrampNE + trackrampNW + trackrampSE + trackrampSW + trackrampEW + trackrampNSE + trackrampNSW + trackrampNEW + trackrampSEW + trackrampNSEW + + -- Horizontal and vertical roller segments -- + rollerH + rollerV + rollerNS + rollerSN + rollerEW + rollerWE + + Note: append up to four 'q' characters to roller keywords to set roller + speed. E.g. a roller that propels from East to West at the slowest speed can + be specified with 'rollerEWqqqq'. + + -- Track stops that (optionally) dump to the N/S/E/W -- + trackstop + trackstopN + trackstopS + trackstopE + trackstopW + + Note: append up to four 'a' characters to trackstop keywords to set friction + amount. E.g. a stop that applies the smallest amount of friction can be + specified with 'trackstopaaaa'. + +As an example, you can create an E-W track with stops at each end that dump to +their outside directions with the following blueprint: + +:: + + #build Example track + trackstopW trackEW trackEW trackEW trackstopE + +Note that the **only** way to build track and track/ramp segments is with the +keywords. The UI method of using "+" and "-" keys to select the track type from +a list does not work since DFHack Quickfort doesn't actually send keys to the UI +to build buildings. The text in your spreadsheet cells is mapped directly into +DFHack API calls. Only ``#query`` blueprints still send actual keycodes to the +UI. + +Carved tracks +~~~~~~~~~~~~~ + +In the game, you carve a minecart track by specifying a beginning and ending +tile and the game "adds" the designation to the tiles. You cannot designate +single tiles. For example to carve two track segments that cross each other, you +might use the cursor to designate a line of three vertical tiles like this: + +:: + + ` start here ` # + ` ` ` # + ` end here ` # + # # # # + +Then to carve the cross, you'd do a horizonal segment: + +:: + + ` ` ` # + start here ` end here # + ` ` ` # + # # # # + +This will result in a carved track that would be equivalent to a constructed +track of the form: + +:: + + #build + ` trackS ` # + trackE trackNSEW trackW # + ` trackN ` # + # # # # + +To carve this same track with a ``#dig`` blueprint, you'd use area expansion +syntax with a height or width of 1 to indicate the segments to designate: + +:: + + #dig + ` T(1x3) ` # + T(3x1) ` ` # + ` ` ` # + # # # # + +"But wait!", I can hear you say, "How do you designate a track corner that opens +to the South and East? You can't put both T(1xH) and T(Wx1) in the same cell!" +This is true, but you can specify both width and height, and for tracks, QF +interprets it as an upper-left corner extending to the right W tiles and down H +tiles. For example, to carve a track in a closed ring, you'd write: + +:: + + #dig + T(3x3) ` T(1x3) # + ` ` ` # + T(3x1) ` ` # + # # # # + +Which would result in a carved track simliar to a constructed track of the form: + +:: + + #build + trackSE trackEW trackSW # + trackNS ` trackNS # + trackNE trackEW trackNW # + # # # # + +Modeline markers +---------------- + +The modeline has some additional optional components that we haven't talked +about yet. You can: + +- give a blueprint a label by adding a ``label()`` marker +- set a cursor offset and/or start hint by adding a ``start()`` marker +- hide a blueprint from being listed with a ``hidden()`` marker +- register a message to be displayed after the blueprint is successfully + applied + +The full modeline syntax, when everything is specified, is: + +:: + + #mode label(mylabel) start(X;Y;STARTCOMMENT) hidden() message(mymessage) comment + +Note that all elements are optional except for the initial ``#mode``. Here are a +few examples of modelines with optional elements before we discuss them in more +detail: + +:: + + #dig start(3; 3; Center tile of a 5-tile square) Regular blueprint comment + #build label(noblebedroom) start(10;15) + #query label(configstockpiles) No explicit start() means cursor is at upper left corner + #meta label(digwholefort) start(center of stairs on surface) + #dig label(digdining) hidden() managed by the digwholefort meta blueprint + #zone label(pastures) message(remember to assign animals to the new pastures) + +Blueprint labels +~~~~~~~~~~~~~~~~ + +Labels are displayed in the ``quickfort list`` output and are used for +addressing specific blueprints when there are multiple blueprints in a single +file or spreadsheet sheet (see `Packaging a set of +blueprints <#packaging-a-set-of-blueprints>`__ below). If a blueprint has no +label, the label becomes the ordinal of the blueprint's position in the file or +sheet. For example, the label of the first blueprint will be "1" if it is not +otherwise set, the label of the second blueprint will be "2" if it is not +otherwise set, etc. Labels that are explicitly defined must start with a letter +to ensure the auto-generated labels don't conflict with user-defined labels. + +Start positions +~~~~~~~~~~~~~~~ + +Start positions specify a cursor offset for a particular blueprint, simplifying +the task of blueprint alignment. This is very helpful for blueprints that are +based on a central staircase, but it helps whenever a blueprint has an obvious +"center". For example: + +:: + + #build start(2;2;center of workshop) label(masonw) a mason workshop + wm wm wm # + wm wm wm # + wm wm wm # + # # # # + +will build the workshop *centered* on the cursor, not down and to the right of +the cursor. + +The two numbers specify the column and row (or X and Y offset) where the cursor +is expected to be when you apply the blueprint. Position 1;1 is the top left +cell. The optional comment will show up in the ``quickfort list`` output and +should contain information about where to position the cursor. If the start +position is 1;1, you can omit the numbers and just add a comment describing +where to put the cursor. This is also useful for meta blueprints that don't +actually care where the cursor is, but that refer to other blueprints that have +fully-specified ``start()`` markers. For example, a meta blueprint that refers +to the ``masonw`` blueprint above could look like this: + +:: + + #meta start(center of workshop) a mason workshop + /masonw + +Hiding blueprints +~~~~~~~~~~~~~~~~~ + +A blueprint with a ``hidden()`` marker won't appear in ``quickfort list`` output +unless the ``--hidden`` flag is specified. The primary reason for hiding a +blueprint (rather than, say, deleting it or moving it out of the ``blueprints/`` +folder) is if a blueprint is intended to be run as part of a larger sequence +managed by a `meta blueprint <#meta-blueprints>`__. + +Messages +~~~~~~~~ + +A blueprint with a ``message()`` marker will display a message after the +blueprint is applied with ``quickfort run``. This is useful for reminding +players to take manual steps that cannot be automated, like assigning animals to +a pasture or assigning minecarts to a route, or listing the next step in a +series of blueprints. For long or multi-part messages, you can embed newlines: + +:: + + "#meta label(surface1) message(This would be a good time to start digging the industry level. + Once the area is clear, continue with /surface2.) clear the embark site and set up pastures" + +Packaging a set of blueprints +----------------------------- + +A complete specification for a section of your fortress may contain 5 or more +separate blueprints, one for each "phase" of construction (dig, build, place +stockpiles, designate zones, query building adjustments). + +To manage all the separate blueprints, it is often convenient to keep related +blueprints in a single file. For .xlsx spreadsheets, you can keep each blueprint +in a separate sheet. Online spreadsheet applications like `Google +Sheets `__ make it easy to work with multiple related +blueprints, and, as a bonus, they retain any formatting you've set, like column +sizes and coloring. + +For both .csv files and .xlsx spreadsheets you can also add as many blueprints +as you want in a single file or sheet. Just add a modeline in the first column +to indicate the start of a new blueprint. Instead of multiple .csv files, you +can concatenate them into one single file. + +For example, you can store multiple blueprints together like this: + +:: + + #dig label(bed1) + d d d d # + d d d d # + d d d d # + d d d d # + # # # # # + #build label(bed2) + b f h # + # + # + n # + # # # # # + #place label(bed3) + # + f(2x2) # + # + # + # # # # # + #query label(bed4) + # + booze # + # + # + # # # # # + #query label(bed5) + r{+ 3}& # + # + # + # + # # # # # + +Of course, you could still choose to keep your blueprints in single-sheet .csv +files and just give related blueprints similar names: + +:: + + bedroom.1.dig.csv + bedroom.2.build.csv + bedroom.3.place.csv + bedroom.4.query.csv + bedroom.5.query2.csv + +But the naming and organization is completely up to you. + +Meta blueprints +--------------- + +Meta blueprints are blueprints that script a series of other blueprints. Many +blueprint packages follow this pattern: + +- Apply dig blueprint to designate dig areas +- Wait for miners to dig +- **Apply build buildprint** to designate buildings +- **Apply place buildprint** to designate stockpiles +- **Apply query blueprint** to configure stockpiles +- Wait for buildings to get built +- Apply a different query blueprint to configure rooms + +Those three "apply"s in the middle might as well get done in one command instead +of three. A meta blueprint can encode that sequence. A meta blueprint refers to +other blueprints by their label (see the `Modeline markers `__ +section above) in the same format used by the ``DFHack#`` quickfort command: +"/", or just "/" for blueprints in .csv files or blueprints in the same +spreadsheet sheet as the #meta blueprint that references them. + +A few examples might make this clearer. Say you have a .csv file with the "bed" +blueprints in the previous section: + +:: + + #dig label(bed1) + ... + #build label(bed2) + ... + #place label(bed3) + ... + #query label(bed4) + ... + #query label(bed5) + ... + +Note how I've given them all labels so we can address them safely. If I hadn't +given them labels, they would receive default labels of "1", "2", "3", etc, but +those labels would change if I ever add more blueprints at the top. This is not +a problem if we're just running the blueprints individually from the +``quickfort list`` command, but meta blueprints need a label name that isn't +going to change over time. + +So let's add a meta blueprint to this file that will combine the middle three +blueprints into one: + +:: + + "#meta plan bedroom: combines build, place, and stockpile config blueprints" + /bed2 + /bed3 + /bed4 + +Now your sequence is shortened to: + +- Apply dig blueprint to designate dig areas +- Wait for miners to dig +- **Apply meta buildprint** to build buildings and designate/configure + stockpiles +- Wait for buildings to get built +- Apply the final query blueprint to configure the room + +You can use meta blueprints to lay out your fortress at a larger scale as well. +The ``#<`` and ``#>`` notation is valid in meta blueprints, so you can, for +example, store the dig blueprints for all the levels of your fortress in +different sheets in a spreadsheet, and then use a meta blueprint to designate +your entire fortress for digging at once. For example, say you have a +spreadsheet with the following layout: + ++-------------------------------------------+----------------------------------+ +| Sheet name | contents | ++===========================================+==================================+ +| dig_farming | one #dig blueprint, no label | ++-------------------------------------------+----------------------------------+ +| dig_industry | one #dig blueprint, no label | ++-------------------------------------------+----------------------------------+ +| dig_dining | four #dig blueprints, with | +| | labels "main", "basement", | +| | "waterway", and "cistern" | ++-------------------------------------------+----------------------------------+ +| dig_guildhall | one #dig blueprint, no label | ++-------------------------------------------+----------------------------------+ +| dig_suites | one #dig blueprint, no label | ++-------------------------------------------+----------------------------------+ +| dig_bedrooms | one #dig blueprint, no label | ++-------------------------------------------+----------------------------------+ + +We can add a sheet named "dig_all" with the following contents (we're expecting +a big fort, so we're planning for a lot of bedrooms): + +:: + + #meta dig the whole fortress (remember to set force_marker_mode to true) + dig_farming/1 + #> + dig_industry/1 + #> + #> + dig_dining/main + #> + dig_dining/basement + #> + dig_dining/waterway + #> + dig_dining/cistern + #> + dig_guildhall/1 + #> + dig_suites/1 + #> + dig_bedrooms/1 + #> + dig_bedrooms/1 + #> + dig_bedrooms/1 + #> + dig_bedrooms/1 + #> + dig_bedrooms/1 + +Note that for blueprints without an explicit label, we still need to address +them by their auto-generated numerical label. + +You can then hide the blueprints that you now manage with the ``#meta``-mode +blueprint from ``quickfort list`` by adding a ``hidden()`` marker to their +modelines. That way the output of ``quickfort list`` won't be cluttered by +blueprints that you don't need to run directly. If you ever *do* need to access +the managed blueprints individually, you can still see them with +``quickfort list --hidden``. + +Buildingplan integration +------------------------ + +Buildingplan is a DFHack plugin that keeps jobs in a suspended state until the +materials required for the job are available. This prevents a building +designation from being canceled when a dwarf picks up the job but can't find the +materials. + +For all types that buildingplan supports, quickfort using buildingplan to manage +construction. Buildings are still constructed immediately if you have the +materials, but you now have the freedom to apply build blueprints before you +manufacture all required materials, and the jobs will be fulfilled as the +materials become available. + +If a ``#build`` blueprint only refers to supported types, the buildingplan +integration pairs well with the +`workflow `__ +plugin, which can build items a few at a time continuously as long as they are +needed. For building types that are not yet supported by buildingplan, a good +pattern to follow is to first run ``quickfort orders`` on the ``#build`` +blueprint to manufacture all the required items, then apply the blueprint +itself. + +See `buildingplan +documentation `__ +for a list of supported types. + +Generating manager orders +------------------------- + +Quickfort can generate manager orders to make sure you have the proper items in +stock to apply a ``#build`` blueprint. + +Many items can be manufactured from different source materials. Orders will +always choose rock when it can, then wood, then cloth, then iron. You can always +remove orders that don't make sense for your fort and manually enqueue a similar +order more to your liking. For example, if you want silk ropes instead of cloth +ropes, make a new manager order for an appropriate quantity of silk ropes, and +then remove the generated cloth rope order. + +Anything that requires generic building materials (workshops, constructions, +etc.) will result in an order for a rock block. One "Make rock blocks" job +produces four blocks per boulder, so the number of jobs ordered will be the +number of blocks you need divided by four (rounded up). You might end up with a +few extra blocks, but not too many. + +If you want your constructions to be in a consistent color, be sure to choose a +rock type for all of your 'Make rock blocks' orders by selecting the order and +hitting ``d``. You might want to set the rock type for other non-block orders to +something different if you fear running out of the type of rock that you want to +use for blocks. + +There are a few building types that will generate extra manager orders for +related materials: + +- Track stops will generate an order for a minecart +- Traction benches will generate orders for a table, mechanism, and rope +- Levers will generate an order for an extra two mechanisms for connecting the + lever to a target +- Cage traps will generate an order for a cage + +Tips and tricks +--------------- + +- During blueprint application, especially query blueprints, don't click the + mouse on the DF window or type any keys. They can change the state of the + game while the blueprint is being applied, resulting in strange errors. + +- After digging out an area, you may wish to smooth and/or engrave the area + before starting the build phase, as dwarves may be unable to access walls or + floors that are behind/under built objects. + +- If you are designating more than one level for digging at a time, you can + make your miners more efficient by using marker mode on all levels but one. + This prevents your miners from digging out a few tiles on one level, then + running down/up the stairs to do a few tiles on an adjacent level. With only + one level "live" and all other levels in marker mode, your miners can + concentrate on one level at a time. You just have to remember to "unmark" a + new level when your miners are done with their current one. + +- As of DF 0.34.x, it is no longer possible to build doors (d) at the same time + that you build adjacent walls (Cw). Doors must now be built *after* walls are + constructed for them to be next to. This does not affect the more common case + where walls exist as a side-effect of having dug-out a room in a #dig + blueprint. + +Caveats and limitations +----------------------- + +- Buildings will be designated regardless of whether you have the required + materials, but if materials are not available when the construction job is + picked up by a dwarf, the buildings will be canceled and the designations + will disappear. Until the buildingplan plugin can be extended to support all + building types, you should use ``quickfort orders`` to pre-manufacture all + the materials you need for a ``#build`` blueprint before you apply it. + +- If you use the ``jugs`` alias in your ``#query``-mode blueprints, be aware + that there is no way to differentiate jugs from other types of tools in the + game. Therefore, ``jugs`` stockpiles will also take nest boxes and other + tools. The only workaround is not to have other tools lying around in your + fort. + +- Likewise for bags. The game does not differentiate between empty and full + bags, so you'll get bags of gypsum power and sand in your bags stockpile + unless you avoid collecting sand and are careful to assign all your gypsum to + your hospital. + +- Weapon traps and upright spear/spike traps can currently only be built with a + single weapon. + +- Pressure plates can be built, but they cannot be usefully configured yet. + +- Building instruments, bookcases, display furniture, and offering places are + not yet supported by DFHack. + +- This script is relatively new, and there are bound to be bugs! Please report + them at the `DFHack issue + tracker `__ so they can be + addressed. + +Links +----- + +Quickfort links +~~~~~~~~~~~~~~~ + +- `Quickfort command + syntax `__ +- `Quickfort forum + thread `__ +- `Quickfort blueprints + library `__ +- `DFHack issue tracker `__ +- `Quickfort source + code `__ + +Related tools +~~~~~~~~~~~~~ + +- DFHack's `blueprint + plugin `__ can + generate blueprints from actual DF maps. +- `Python Quickfort `__ is the previous, + Python-based implementation that DFHack's quickfort script was inspired by. From 53b78d5266ff2d67d0ba9139d077fa61b8647e17 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 1 Oct 2020 21:59:48 -0400 Subject: [PATCH 08/44] Convert external docs links to internal links --- docs/tools/quickfort-user-guide.rst | 38 ++++++++++++----------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/docs/tools/quickfort-user-guide.rst b/docs/tools/quickfort-user-guide.rst index e0be9147a..f3e4e06b7 100644 --- a/docs/tools/quickfort-user-guide.rst +++ b/docs/tools/quickfort-user-guide.rst @@ -1,11 +1,10 @@ DFHack Quickfort User Manual ============================ -DFHack Quickfort is a DFHack script that helps you build fortresses from +`Quickfort ` is a DFHack script that helps you build fortresses from "blueprint" .csv and .xlsx files. Many applications exist to edit these files, such as MS Excel and `Google Sheets `__. You can also build -your plan "for real" in Dwarf Fortress, and then export your map using DFHack's -`blueprint `__ +your plan "for real" in Dwarf Fortress, and then export your map using the `blueprint` plugin. Most layout and building-oriented DF commands are supported through the use of multiple files or spreadsheets, each describing a different phase of DF construction: designation, building, placing stockpiles/zones, and setting @@ -25,13 +24,12 @@ This document focuses on DFHack Quickfort's capabilities and teaches players how to understand and build blueprint files. Some of the text was originally written by Joel Thornton, reused here with his permission. -For those just looking to apply blueprints, check out the `quickfort command -syntax `__ in -the DFHack Scripts documentation. There are also many ready-to-use blueprints +For those just looking to apply blueprints, check out the `quickfort command's +documentation ` for syntax. There are also many ready-to-use blueprints available in the ``blueprints/library`` subfolder in your DFHack installation. Browse them on your computer or `online `__, -or run ``quickfort list -l`` at the ``DFHack#`` prompt to list them, and then +or run ``quickfort list -l`` at the ``[DFHack]#`` prompt to list them, and then ``quickfort run`` to apply them to your fort! See the `Links section <#links>`__ for more information and online resources. @@ -1007,17 +1005,13 @@ manufacture all required materials, and the jobs will be fulfilled as the materials become available. If a ``#build`` blueprint only refers to supported types, the buildingplan -integration pairs well with the -`workflow `__ -plugin, which can build items a few at a time continuously as long as they are -needed. For building types that are not yet supported by buildingplan, a good -pattern to follow is to first run ``quickfort orders`` on the ``#build`` -blueprint to manufacture all the required items, then apply the blueprint -itself. - -See `buildingplan -documentation `__ -for a list of supported types. +integration pairs well with the `workflow` plugin, which can build items a few +at a time continuously as long as they are needed. For building types that are +not yet supported by buildingplan, a good pattern to follow is to first run +``quickfort orders`` on the ``#build`` blueprint to manufacture all the required +items, then apply the blueprint itself. + +See the `buildingplan documentation ` for a list of supported types. Generating manager orders ------------------------- @@ -1118,8 +1112,7 @@ Links Quickfort links ~~~~~~~~~~~~~~~ -- `Quickfort command - syntax `__ +- `Quickfort command syntax ` - `Quickfort forum thread `__ - `Quickfort blueprints @@ -1131,8 +1124,7 @@ Quickfort links Related tools ~~~~~~~~~~~~~ -- DFHack's `blueprint - plugin `__ can - generate blueprints from actual DF maps. +- DFHack's `blueprint plugin ` can generate blueprints from actual + DF maps. - `Python Quickfort `__ is the previous, Python-based implementation that DFHack's quickfort script was inspired by. From 77c37ebb73d2534da1ee9b5beed6d98183bdc6e9 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 1 Oct 2020 22:08:58 -0400 Subject: [PATCH 09/44] Switch to native RST table of contents --- docs/tools/quickfort-user-guide.rst | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/docs/tools/quickfort-user-guide.rst b/docs/tools/quickfort-user-guide.rst index f3e4e06b7..78bb24ea7 100644 --- a/docs/tools/quickfort-user-guide.rst +++ b/docs/tools/quickfort-user-guide.rst @@ -34,28 +34,11 @@ or run ``quickfort list -l`` at the ``[DFHack]#`` prompt to list them, and then See the `Links section <#links>`__ for more information and online resources. -Table of Contents ------------------ - -- `Features <#features>`__ -- `Editing Blueprints <#editing-blueprints>`__ - - - `Area expansion syntax <#area-expansion-syntax>`__ - - `Automatic area expansion <#automatic-area-expansion>`__ - - `Multilevel blueprints <#multilevel-blueprints>`__ - - `Marker mode <#marker-mode>`__ - - `Dig priorities <#dig-priorities>`__ - - `Stockpiles and zones <#stockpiles-and-zones>`__ - - `Minecart tracks <#minecart-tracks>`__ - - `Modeline markers `__ - - `Packaging a set of blueprints <#packaging-a-set-of-blueprints>`__ - - `Meta blueprints <#meta-blueprints>`__ - -- `Buildingplan integration <#buildingplan-integration>`__ -- `Generating manager orders <#generating-manager-orders>`__ -- `Tips and tricks <#tips-and-tricks>`__ -- `Caveats and limitations <#caveats-and-limitations>`__ -- `Links <#links>`__ + +.. contents:: Table of Contents + :local: + :depth: 2 + Features -------- From 4746e5c046634c7f8632ab612d4f11acf5b28b8b Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 1 Oct 2020 22:10:11 -0400 Subject: [PATCH 10/44] Change/remove headings to match original TOC nesting --- docs/tools/quickfort-user-guide.rst | 38 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/docs/tools/quickfort-user-guide.rst b/docs/tools/quickfort-user-guide.rst index 78bb24ea7..d7835f764 100644 --- a/docs/tools/quickfort-user-guide.rst +++ b/docs/tools/quickfort-user-guide.rst @@ -247,7 +247,7 @@ pre-packaged aliases, or create your own in in your DFHack installation. Area expansion syntax ---------------------- +~~~~~~~~~~~~~~~~~~~~~ In Quickfort, the following blueprints are equivalent: @@ -333,7 +333,7 @@ size, like bridges. The following blueprints are equivalent: # # # # # Automatic area expansion ------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~ Buildings larger than 1x1, like workshops, can be represented in any of three ways. You can designate just their center tile with empty cells around it to @@ -384,7 +384,7 @@ Quickfort will intelligently break large areas of the same designation into appropriately-sized chunks. Multilevel blueprints ---------------------- +~~~~~~~~~~~~~~~~~~~~~ Multilevel blueprints are accommodated by separating Z-levels of the blueprint with ``#>`` (go down one z-level) or ``#<`` (go up one z-level) at the end of @@ -406,7 +406,7 @@ The marker must appear in the first column of the row to be recognized, just like a modeline. Dig priorities --------------- +~~~~~~~~~~~~~~ DF designation priorities are supported for ``#dig`` blueprints. The full syntax is ``[letter][number][expansion]``, where if the ``letter`` is not specified, @@ -440,7 +440,7 @@ default priority). So each of these blueprints is equivalent: # # # # # # Marker mode ------------ +~~~~~~~~~~~ Marker mode is useful for when you want to plan out your digging, but you don't want to dig everything just yet. In ``#dig`` mode, you can add a ``m`` before @@ -469,7 +469,7 @@ Note that the in-game UI setting "Standard/Marker Only" (``d-m``) does not have any effect on quickfort. Stockpiles and zones --------------------- +~~~~~~~~~~~~~~~~~~~~ It is very common to have stockpiles that accept multiple categories of items or zones that permit more than one activity. Although it is perfectly valid to @@ -508,7 +508,7 @@ parameters, like hospital supply levels or converting between pits and ponds, must still be done manually or with a ``#query`` blueprint. Minecart tracks ---------------- +~~~~~~~~~~~~~~~ There are two ways to produce minecart tracks, and they are handled very differently by the game. You can carve them into hard natural floors or you can @@ -516,7 +516,7 @@ construct them out of building materials. Constructed tracks are conceptually simpler, so we'll start with them. Constructed tracks -~~~~~~~~~~~~~~~~~~ +`````````````````` Quickfort supports the designation of track stops and rollers through the normal mechanisms: a ``#build`` blueprint with ``CS`` and some number of ``d`` and @@ -605,7 +605,7 @@ DFHack API calls. Only ``#query`` blueprints still send actual keycodes to the UI. Carved tracks -~~~~~~~~~~~~~ +````````````` In the game, you carve a minecart track by specifying a beginning and ending tile and the game "adds" the designation to the tiles. You cannot designate @@ -675,7 +675,7 @@ Which would result in a carved track simliar to a constructed track of the form: # # # # Modeline markers ----------------- +~~~~~~~~~~~~~~~~ The modeline has some additional optional components that we haven't talked about yet. You can: @@ -706,7 +706,7 @@ detail: #zone label(pastures) message(remember to assign animals to the new pastures) Blueprint labels -~~~~~~~~~~~~~~~~ +```````````````` Labels are displayed in the ``quickfort list`` output and are used for addressing specific blueprints when there are multiple blueprints in a single @@ -719,7 +719,7 @@ otherwise set, etc. Labels that are explicitly defined must start with a letter to ensure the auto-generated labels don't conflict with user-defined labels. Start positions -~~~~~~~~~~~~~~~ +``````````````` Start positions specify a cursor offset for a particular blueprint, simplifying the task of blueprint alignment. This is very helpful for blueprints that are @@ -753,7 +753,7 @@ to the ``masonw`` blueprint above could look like this: /masonw Hiding blueprints -~~~~~~~~~~~~~~~~~ +````````````````` A blueprint with a ``hidden()`` marker won't appear in ``quickfort list`` output unless the ``--hidden`` flag is specified. The primary reason for hiding a @@ -762,7 +762,7 @@ folder) is if a blueprint is intended to be run as part of a larger sequence managed by a `meta blueprint <#meta-blueprints>`__. Messages -~~~~~~~~ +```````` A blueprint with a ``message()`` marker will display a message after the blueprint is applied with ``quickfort run``. This is useful for reminding @@ -776,7 +776,7 @@ series of blueprints. For long or multi-part messages, you can embed newlines: Once the area is clear, continue with /surface2.) clear the embark site and set up pastures" Packaging a set of blueprints ------------------------------ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A complete specification for a section of your fortress may contain 5 or more separate blueprints, one for each "phase" of construction (dig, build, place @@ -843,7 +843,7 @@ files and just give related blueprints similar names: But the naming and organization is completely up to you. Meta blueprints ---------------- +~~~~~~~~~~~~~~~ Meta blueprints are blueprints that script a series of other blueprints. Many blueprint packages follow this pattern: @@ -1092,8 +1092,7 @@ Caveats and limitations Links ----- -Quickfort links -~~~~~~~~~~~~~~~ +**Quickfort links:** - `Quickfort command syntax ` - `Quickfort forum @@ -1104,8 +1103,7 @@ Quickfort links - `Quickfort source code `__ -Related tools -~~~~~~~~~~~~~ +**Related tools:** - DFHack's `blueprint plugin ` can generate blueprints from actual DF maps. From 00cd52dca723c3c0c30b2fae6807f90b8a847f02 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 1 Oct 2020 22:17:53 -0400 Subject: [PATCH 11/44] Add user guides section to main toctree --- docs/guides/index.rst | 11 +++++++++++ docs/{tools => guides}/quickfort-user-guide.rst | 0 index.rst | 1 + 3 files changed, 12 insertions(+) create mode 100644 docs/guides/index.rst rename docs/{tools => guides}/quickfort-user-guide.rst (100%) diff --git a/docs/guides/index.rst b/docs/guides/index.rst new file mode 100644 index 000000000..7208b5276 --- /dev/null +++ b/docs/guides/index.rst @@ -0,0 +1,11 @@ +=========== +User Guides +=========== + +These pages are detailed guides covering DFHack tools. + +.. toctree:: + :maxdepth: 1 + :glob: + + * diff --git a/docs/tools/quickfort-user-guide.rst b/docs/guides/quickfort-user-guide.rst similarity index 100% rename from docs/tools/quickfort-user-guide.rst rename to docs/guides/quickfort-user-guide.rst diff --git a/index.rst b/index.rst index d0e90b741..4df56de58 100644 --- a/index.rst +++ b/index.rst @@ -31,5 +31,6 @@ User Manual /docs/Core /docs/Plugins /docs/Scripts + /docs/guides/index /docs/index-about /docs/index-dev From 90994f2abdec60d4310a00ec9164cd6c825372fe Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 1 Oct 2020 22:19:33 -0400 Subject: [PATCH 12/44] Standardize title --- docs/guides/quickfort-user-guide.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/quickfort-user-guide.rst b/docs/guides/quickfort-user-guide.rst index d7835f764..0ca4d67b5 100644 --- a/docs/guides/quickfort-user-guide.rst +++ b/docs/guides/quickfort-user-guide.rst @@ -1,5 +1,5 @@ -DFHack Quickfort User Manual -============================ +Quickfort User Guide +==================== `Quickfort ` is a DFHack script that helps you build fortresses from "blueprint" .csv and .xlsx files. Many applications exist to edit these files, From 8dfdf75e7c9557cadd29aee2b56c259443dc8171 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 2 Oct 2020 00:22:11 -0400 Subject: [PATCH 13/44] Add roles for links to source code on GitHub --- conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf.py b/conf.py index d6c40b0a7..e1bde4257 100644 --- a/conf.py +++ b/conf.py @@ -207,6 +207,8 @@ extlinks = { 'dffd': ('http://dffd.bay12games.com/file.php?id=%s', 'DFFD file '), 'bug': ('http://www.bay12games.com/dwarves/mantisbt/view.php?id=%s', 'Bug '), + 'source': ('https://github.com/DFHack/dfhack/tree/develop/%s', ''), + 'source:scripts': ('https://github.com/DFHack/scripts/tree/master/%s', ''), 'issue': ('https://github.com/DFHack/dfhack/issues/%s', 'Issue '), 'commit': ('https://github.com/DFHack/dfhack/commit/%s', 'Commit '), } From 5f47491e78d9aaa64604304070dad686f66290bd Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 2 Oct 2020 00:22:35 -0400 Subject: [PATCH 14/44] Use custom link roles when possible --- docs/guides/quickfort-user-guide.rst | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/docs/guides/quickfort-user-guide.rst b/docs/guides/quickfort-user-guide.rst index 0ca4d67b5..42127daa0 100644 --- a/docs/guides/quickfort-user-guide.rst +++ b/docs/guides/quickfort-user-guide.rst @@ -27,8 +27,7 @@ by Joel Thornton, reused here with his permission. For those just looking to apply blueprints, check out the `quickfort command's documentation ` for syntax. There are also many ready-to-use blueprints available in the ``blueprints/library`` subfolder in your DFHack installation. -Browse them on your computer or -`online `__, +Browse them on your computer or :source:`online `, or run ``quickfort list -l`` at the ``[DFHack]#`` prompt to list them, and then ``quickfort run`` to apply them to your fort! @@ -231,20 +230,17 @@ over the bed, causing us to 'make room' and "&", which is a special symbol that expands to "{Enter}", to indicate that we're done. In column 2, row 3 we have "booze". This is one of many alias keywords defined -in the included `baseline aliases -file `__. +in the included :source:`baseline aliases file `. This particular alias sets a food stockpile to carry booze only. It sends the keys needed to navigate DF's stockpile settings menu, and then sends an Escape character ("^" or "{ESC}") to exit back to the map. It is important to exit out of any menus that you enter while in query mode so that the cursor can move to the next tile when it is done configuring the current tile. -Check out the included `blueprint -library `__ +Check out the included :source:`blueprint library ` to see many more examples. Read the baseline aliases file for helpful pre-packaged aliases, or create your own in -`dfhack-config/quickfort/aliases.txt `__ -in your DFHack installation. +:source:`dfhack-config/quickfort/aliases.txt` in your DFHack installation. Area expansion syntax ~~~~~~~~~~~~~~~~~~~~~ @@ -1085,9 +1081,7 @@ Caveats and limitations not yet supported by DFHack. - This script is relatively new, and there are bound to be bugs! Please report - them at the `DFHack issue - tracker `__ so they can be - addressed. + them at the :issue:`DFHack issue tracker <>` so they can be addressed. Links ----- @@ -1095,13 +1089,10 @@ Links **Quickfort links:** - `Quickfort command syntax ` -- `Quickfort forum - thread `__ -- `Quickfort blueprints - library `__ -- `DFHack issue tracker `__ -- `Quickfort source - code `__ +- :forums:`Quickfort forum thread <176889>` +- :source:`Quickfort blueprints library ` +- :issue:`DFHack issue tracker <>` +- :source:scripts:`Quickfort source code ` **Related tools:** From 2ff4197afe9d7fc185f769b0395a9b687535772a Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Oct 2020 23:56:57 -0400 Subject: [PATCH 15/44] Add anchor --- docs/guides/quickfort-user-guide.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/guides/quickfort-user-guide.rst b/docs/guides/quickfort-user-guide.rst index 42127daa0..7147c5515 100644 --- a/docs/guides/quickfort-user-guide.rst +++ b/docs/guides/quickfort-user-guide.rst @@ -1,3 +1,5 @@ +.. _quickfort-user-guide: + Quickfort User Guide ==================== From 56d4b7241490e85320f1031113f75bee8a391b72 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Oct 2020 23:57:36 -0400 Subject: [PATCH 16/44] Replace blueprints/readme with pointer to docs --- data/blueprints/README.md | 758 +------------------------------------- 1 file changed, 3 insertions(+), 755 deletions(-) diff --git a/data/blueprints/README.md b/data/blueprints/README.md index 80023d313..b7f5421c0 100644 --- a/data/blueprints/README.md +++ b/data/blueprints/README.md @@ -1,756 +1,4 @@ +This folder contains blueprints used by the `quickfort` script. For more information, see: -[//]: # (The online version of this manual, which may be easier to read, is) -[//]: # (at https://github.com/DFHack/dfhack/tree/develop/data/blueprints) - -[//]: # (Note to editors: don't word wrap -- it breaks the formatting on GitHub) - -DFHack Quickfort User Manual -============================ - -DFHack Quickfort is a DFHack script that helps you build fortresses from "blueprint" .csv and .xlsx files. Many applications exist to edit these files, such as MS Excel and [Google Sheets](https://sheets.new). You can also build your plan "for real" in Dwarf Fortress, and then export your map using DFHack's [blueprint](https://docs.dfhack.org/en/stable/docs/Plugins.html#blueprint) plugin. Most layout and building-oriented DF commands are supported through the use of multiple files or spreadsheets, each describing a different phase of DF construction: designation, building, placing stockpiles/zones, and setting configuration. - -The original idea and 1.0 codebase came from [Valdemar's](https://dwarffortresswiki.org/index.php/User:Valdemar) auto-designation macro. Joel Thornton (joelpt) reimplemented the core logic in Python and extended its functionality with [Quickfort 2.0](https://github.com/joelpt/quickfort). This DFHack-native implementation, called "DFHack Quickfort" or just "quickfort", builds upon Quickfort 2.0's formats and features. DFHack Quickfort is written in Lua and interacts with Dwarf Fortress memory structures directly, allowing for instantaneous blueprint application, error checking and recovery, and many other advanced features. - -This document focuses on DFHack Quickfort's capabilities and teaches players how to understand and build blueprint files. Some of the text was originally written by Joel Thornton, reused here with his permission. - -For those just looking to apply blueprints, check out the [quickfort command syntax](https://docs.dfhack.org/en/stable/docs/_auto/base.html#quickfort) in the DFHack Scripts documentation. There are also many ready-to-use blueprints available in the `blueprints/library` subfolder in your DFHack installation. Browse them on your computer or [online](https://github.com/DFHack/dfhack/tree/develop/data/blueprints/library), or run `quickfort list -l` at the `DFHack#` prompt to list them, and then `quickfort run` to apply them to your fort! - -See the [Links section](#links) for more information and online resources. - - -Table of Contents ------------------ - -* [Features](#features) -* [Editing Blueprints](#editing-blueprints) - * [Area expansion syntax](#area-expansion-syntax) - * [Automatic area expansion](#automatic-area-expansion) - * [Multilevel blueprints](#multilevel-blueprints) - * [Marker mode](#marker-mode) - * [Dig priorities](#dig-priorities) - * [Stockpiles and zones](#stockpiles-and-zones) - * [Minecart tracks](#minecart-tracks) - * [Modeline markers](modeline-markers) - * [Packaging a set of blueprints](#packaging-a-set-of-blueprints) - * [Meta blueprints](#meta-blueprints) -* [Buildingplan integration](#buildingplan-integration) -* [Generating manager orders](#generating-manager-orders) -* [Tips and tricks](#tips-and-tricks) -* [Caveats and limitations](#caveats-and-limitations) -* [Links](#links) - - -Features --------- - -* General - * Manages blueprints to handle all phases of DF construction - * Supports .csv and multi-worksheet .xlsx blueprint files - * Near-instant application, even for very large and complex blueprints - * Blueprints can span multiple z-levels - * Supports multiple blueprints per .csv file/spreadsheet sheet - * "meta" blueprints that automate the application of sequences of blueprints - * Undo functionality for dig, build, place, and zone blueprints - * Automatic cropping of blueprints so you don't get errors if the blueprint extends off the map - * Can generate manager orders for everything required by a build blueprint - * Library of ready-to-use blueprints included - * Verbose output mode for debugging -* Dig mode - * Supports all types of designations, including dumping/forbidding items and setting traffic settings - * Supports setting dig priorities - * Supports applying dig blueprints in marker mode - * Handles carving arbitrarily complex minecart tracks, including tracks that cross other tracks -* Build mode - * DFHack buildingplan integration - * Designate complete constructions at once, without having to wait for each tile to become supported before you can build it - * Automatic expansion of building footprints to their minimum dimensions, so only the center tile of a multi-tile building needs to be recorded in the blueprint - * Tile occupancy and validity checking so, for example, buildings that cannot be placed on a certain tile will simply be skipped instead of the blueprint failing to apply. Blueprints that are only partially applied for any reason (for example, you need to dig out some more tiles) can be safely reapplied to build the remaining buildings. - * Relaxed rules for farm plot and road placement: you can still place the building even if an invalid tile (e.g. stone tiles for farm plots) splits the designated area into two parts - * Intelligent boundary detection for adjacent buildings of the same type (e.g. a 6x6 block of `wj` cells will be correctly split into 4 jeweler's workshops) -* Place and zone modes - * Define stockpiles and zones in any continguous shape, not just rectangular blocks - * Configurable maximums for bins, barrels and wheelbarrows assigned to created stockpiles - * Automatic splitting of stockpiles and zones that exceed maximum dimension limits -* Query mode - * Send arbitrary keystroke sequences to the UI -- *anything* you can do through the UI is supported - * Supports aliases to automate frequent keystroke combos - * Includes a library of pre-made and tested aliases to automate most common tasks, such as configuring stockpiles for important item types or creating named hauling routes for quantum stockpiles. - * Supports including aliases in other aliases, and repeating key sequences a specified number of times - * Skips sending key sequences when the cursor is over a tile that does not have a stockpile or building, so missing buildings won't desynchronize your blueprint - * Instant halting of query blueprint application when keystroke errors are detected, such as when a key sequence leaves us stuck in a submenu, to make blueprint misconfigurations easier to debug - - -Editing Blueprints ------------------- - -We recommend using a spreadsheet editor such as Excel, [Google Sheets](https://sheets.new), or [LibreOffice](https://www.libreoffice.org) to edit blueprint files, but any text editor will do. - -The format of Quickfort-compatible blueprint files is straightforward. The first line (or upper-left cell) of the spreadsheet should look like this: - - #dig This is a decription. - -The keyword "dig" tells Quickfort we are going to be using the Designations menu in DF. The following "mode" keywords are understood: - - dig Designations menu (d) - build Build menu (b) - place Place stockpiles menu (p) - zone Activity zones menu (i) - query Set building tasks/prefs menu (q) - -There are also "meta" blueprints, but we'll talk about those [later](#meta-blueprints). - -Optionally following this keyword and a space, you may enter a comment. This comment will appear in the output of `quickfort list` when run from the `DFHack#` prompt. You can use this space for explanations, attribution, etc. - -Below this line begin entering the keys you want sent in each cell. For example, we could dig out a 4x4 room like so (spaces are used as column separators here for clarity, but a real .csv file would have commas): - - #dig - d d d d # - d d d d # - d d d d # - d d d d # - # # # # # - -Note the # symbols at the right end of each row and below the last row. These are completely optional, but can be helpful to make the row and column positions clear. - -Once the dwarves have that dug out, let's build a walled-in bedroom within our dug-out area: - - #build - Cw Cw Cw Cw # - Cw b h Cw # - Cw Cw # - Cw Cw Cw # - # # # # # - -Note my generosity - in addition to the bed (b) I've built a chest (h) here for the dwarf as well. You must use the full series of keys needed to build something in each cell, e.g. 'Cw' enters DF's constructions submenu (C) and selects walls (w). - -I'd also like to place a booze stockpile in the 2 unoccupied tiles in the room. - - #place Place a food stockpile - ` ` ` ` # - ` ` ` ` # - ` f(2x1)# - ` ` ` ` # - # # # # # - -This illustration may be a little hard to understand. The f(2x1) is in column 2, row 3. All the other cells are empty. QF considers both "`" (backtick -- the character under the tilde) and "~" (tilde) characters within cells to be empty cells; this can help with multilayer or fortress-wide blueprint layouts as 'chalk lines'. - -With f(2x1), we've asked QF to place a food stockpile 2 units wide by 1 high unit. Note that the f(2x1) syntax isn't actually necessary here; we could have just used: - - #place Place a food stockpile - ` ` ` ` # - ` ` ` ` # - ` f f ` # - ` ` ` ` # - # # # # # - -QF is smart enough to recognize this as a 2x1 food stockpile, and creates it as such rather than as two 1x1 food stockpiles. Quickfort recognizes any connected region of identical designations as a single stockpile. The tiles can be connected orthogonally or diagonally, just as long as they are touching somehow. - -Lastly, let's turn the bed into a bedroom and set the food stockpile to hold only booze. - - #query - ` ` ` ` # - ` r& ` # - ` booze # - ` ` ` ` # - # # # # # - -In column 2, row 2 we have "r&". This sends the "r" key to DF when the cursor is over the bed, causing us to 'make room' and "&", which is a special symbol that expands to "{Enter}", to indicate that we're done. - -In column 2, row 3 we have "booze". This is one of many alias keywords defined in the included [baseline aliases file](https://github.com/DFHack/dfhack/tree/develop/data/quickfort/aliases-common.txt). This particular alias sets a food stockpile to carry booze only. It sends the keys needed to navigate DF's stockpile settings menu, and then sends an Escape character ("^" or "{ESC}") to exit back to the map. It is important to exit out of any menus that you enter while in query mode so that the cursor can move to the next tile when it is done configuring the current tile. - -Check out the included [blueprint library](https://github.com/DFHack/dfhack/tree/develop/data/blueprints/library) to see many more examples. Read the baseline aliases file for helpful pre-packaged aliases, or create your own in [dfhack-config/quickfort/aliases.txt](https://github.com/DFHack/dfhack/tree/develop/dfhack-config/quickfort/aliases.txt) in your DFHack installation. - - -Area expansion syntax ---------------------- - -In Quickfort, the following blueprints are equivalent: - - #dig a 3x3 area - d d d # - d d d # - d d d # - # # # # - - #dig the same area with d(3x3) specified in row 1, col 1 - d(3x3)# - ` ` ` # - ` ` ` # - # # # # - -The second example uses Quickfort's "area expansion syntax", which takes the form: - - keys(WxH) - -In Quickfort the above two examples of specifying a contiguous 3x3 area produce identical output: a single 3x3 designation will be performed, rather than nine 1x1 designations as the first example might suggest. - -Area expansion syntax can only specify rectangular areas. If you want to create extent-based structures (e.g. farm plots or stockpiles) in different shapes, use the first format above. For example: - - #place L shaped food stockpile - f f ` ` # - f f ` ` # - f f f f # - f f f f # - # # # # # - -Area expansion syntax also sets boundaries, which can be useful if you want adjacent, but separate, stockpiles of the same type: - - #place Two touching but separate food stockpiles - f(4x2) # - ~ ~ ~ ~ # - f(4x2) # - ~ ~ ~ ~ # - # # # # # - -As mentioned previously, "~" characters are ignored as comment characters and can be used for visualizing the blueprint layout. The blueprint can be equivalently written as: - - #place Two touching but separate food stockpiles - f(4x2) # - ~ ~ ~ ~ # - f f f f # - f f f f # - # # # # # - -since the area expansion syntax of the upper stockpile prevents it from combining with the lower, freeform syntax stockpile. - -Area expansion syntax can also be used for buildings which have an adjustable size, like bridges. The following blueprints are equivalent: - - #build a 4x2 bridge from row 1, col 1 - ga(4x2) ` # - ` ` ` ` # - # # # # # - - #build a 4x2 bridge from row 1, col 1 - ga ga ga ga # - ga ga ga ga # - # # # # # - - -Automatic area expansion ------------------------- - -Buildings larger than 1x1, like workshops, can be represented in any of three ways. You can designate just their center tile with empty cells around it to leave room for the footprint, like this: - - #build a mason workshop in row 2, col 2 that will occupy the 3x3 area - ` ` ` # - ` wm ` # - ` ` ` # - # # # # - -Or you can fill out the entire footprint like this: - - #build a mason workshop - wm wm wm # - wm wm wm # - wm wm wm # - # # # # - -This format may be verbose for regular workshops, but it can be very helpful for laying out structures like screw pump towers and waterwheels, whose "center point" can be non-obvious. - -Finally, you can use area expansion syntax to represent the workshop: - - #build a mason workshop - wm(3x3) # - ` ` ` # - ` ` ` # - # # # # - -This style can be convenient for laying out multiple buildings of the same type. If you are building a large-scale block factory, for example, this will create 20 mason workshops all in a row: - - #build line of 20 mason workshops - wm(60x3) # - -Quickfort will intelligently break large areas of the same designation into appropriately-sized chunks. - - -Multilevel blueprints ---------------------- - -Multilevel blueprints are accommodated by separating Z-levels of the blueprint with `#>` (go down one z-level) or `#<` (go up one z-level) at the end of each floor. - - #dig Stairs leading down to a small room below - j ` ` # - ` ` ` # - ` ` ` # - #> # # # - u d d # - d d d # - d d d # - # # # # - -The marker must appear in the first column of the row to be recognized, just like a modeline. - - -Dig priorities --------------- - -DF designation priorities are supported for `#dig` blueprints. The full syntax is `[letter][number][expansion]`, where if the `letter` is not specified, `d` is assumed, and if `number` is not specified, `4` is assumed (the default priority). So each of these blueprints is equivalent: - - #dig dig the interior of the room at high priority - d d d d d # - d d1 d1 d1 d # - d d1 d1 d1 d # - d d1 d1 d1 d # - d d d d d # - # # # # # # - - #dig dig the interior of the room at high priority - d d d d d # - d d1(3x3) d # - d ` ` ` d # - d ` ` ` d # - d d d d d # - # # # # # # - - #dig dig the interior of the room at high priority - 4 4 4 4 4 # - 4 1 1 1 4 # - 4 1 1 1 4 # - 4 1 1 1 4 # - 4 4 4 4 4 # - # # # # # # - - -Marker mode ------------ - -Marker mode is useful for when you want to plan out your digging, but you don't want to dig everything just yet. In `#dig` mode, you can add a `m` before any other designation letter to indicate that the tile should be designated in marker mode. For example, to dig out the perimeter of a room, but leave the center of the room marked for digging later: - - #dig - d d d d d # - d md md md d # - d md md md d # - d md md md d # - d d d d d # - # # # # # # - -Then you can use "Toggle Standard/Marking" (`d-M`) to convert the center tiles to regular designations at your leisure. - -To apply an entire dig blueprint in marker mode, regardless of what the blueprint itself says, you can set the global quickfort setting `force_marker_mode` to `true` before you apply the blueprint. - -Note that the in-game UI setting "Standard/Marker Only" (`d-m`) does not have any effect on quickfort. - - -Stockpiles and zones --------------------- - -It is very common to have stockpiles that accept multiple categories of items or zones that permit more than one activity. Although it is perfectly valid to declare a single-purpose stockpile or zone and then modify it with a `#query` blueprint, quickfort also supports directly declaring all the types on the `#place` and `#zone` blueprints. For example, to declare a 10x10 area that is a pasture, a fruit picking area, and a meeting area all at once, you could write: - - #zone main pasture and picnic area - nmg(10x10) - -And similarly, to declare a stockpile that accepts both corpses and refuse, you could write: - - #place refuse heap - yr(20x10) - -The order of the individual letters doesn't matter. - -To toggle the `active` flag for zones, add an `a` character to the string. For example, to create a *disabled* pit zone (that you later intend to turn into a pond and carefully fill to 3-depth water): - - #zone disabled future pond zone - pa(1x3) - -Note that while this notation covers most use cases, tweaking low-level zone parameters, like hospital supply levels or converting between pits and ponds, must still be done manually or with a `#query` blueprint. - - -Minecart tracks ---------------- - -There are two ways to produce minecart tracks, and they are handled very differently by the game. You can carve them into hard natural floors or you can construct them out of building materials. Constructed tracks are conceptually simpler, so we'll start with them. - -### Constructed tracks ### - -Quickfort supports the designation of track stops and rollers through the normal mechanisms: a `#build` blueprint with `CS` and some number of `d` and `a` characters (for selecting dump direction and friction) in a cell designates a track stop and a `#build` blueprint with `Mr` and some number of `s` and `q` characters (for direction and speed) designates a roller. This can get confusing very quickly and is very difficult to read in a blueprint. Constructed track segments don't even have keys associated with them at all! - -To solve this problem, Quickfort provides the following keywords for use in build blueprints: - - -- Track segments -- - trackN - trackS - trackE - trackW - trackNS - trackNE - trackNW - trackSE - trackSW - trackEW - trackNSE - trackNSW - trackNEW - trackSEW - trackNSEW - - -- Track/ramp segments -- - trackrampN - trackrampS - trackrampE - trackrampW - trackrampNS - trackrampNE - trackrampNW - trackrampSE - trackrampSW - trackrampEW - trackrampNSE - trackrampNSW - trackrampNEW - trackrampSEW - trackrampNSEW - - -- Horizontal and vertical roller segments -- - rollerH - rollerV - rollerNS - rollerSN - rollerEW - rollerWE - - Note: append up to four 'q' characters to roller keywords to set roller - speed. E.g. a roller that propels from East to West at the slowest speed can - be specified with 'rollerEWqqqq'. - - -- Track stops that (optionally) dump to the N/S/E/W -- - trackstop - trackstopN - trackstopS - trackstopE - trackstopW - - Note: append up to four 'a' characters to trackstop keywords to set friction - amount. E.g. a stop that applies the smallest amount of friction can be - specified with 'trackstopaaaa'. - -As an example, you can create an E-W track with stops at each end that dump to their outside directions with the following blueprint: - - #build Example track - trackstopW trackEW trackEW trackEW trackstopE - -Note that the **only** way to build track and track/ramp segments is with the keywords. The UI method of using "+" and "-" keys to select the track type from a list does not work since DFHack Quickfort doesn't actually send keys to the UI to build buildings. The text in your spreadsheet cells is mapped directly into DFHack API calls. Only `#query` blueprints still send actual keycodes to the UI. - -### Carved tracks ### - -In the game, you carve a minecart track by specifying a beginning and ending tile and the game "adds" the designation to the tiles. You cannot designate single tiles. For example to carve two track segments that cross each other, you might use the cursor to designate a line of three vertical tiles like this: - - ` start here ` # - ` ` ` # - ` end here ` # - # # # # - -Then to carve the cross, you'd do a horizonal segment: - - ` ` ` # - start here ` end here # - ` ` ` # - # # # # - -This will result in a carved track that would be equivalent to a constructed track of the form: - - #build - ` trackS ` # - trackE trackNSEW trackW # - ` trackN ` # - # # # # - -To carve this same track with a `#dig` blueprint, you'd use area expansion syntax with a height or width of 1 to indicate the segments to designate: - - #dig - ` T(1x3) ` # - T(3x1) ` ` # - ` ` ` # - # # # # - -"But wait!", I can hear you say, "How do you designate a track corner that opens to the South and East? You can't put both T(1xH) and T(Wx1) in the same cell!" This is true, but you can specify both width and height, and for tracks, QF interprets it as an upper-left corner extending to the right W tiles and down H tiles. For example, to carve a track in a closed ring, you'd write: - - #dig - T(3x3) ` T(1x3) # - ` ` ` # - T(3x1) ` ` # - # # # # - -Which would result in a carved track simliar to a constructed track of the form: - - #build - trackSE trackEW trackSW # - trackNS ` trackNS # - trackNE trackEW trackNW # - # # # # - - -Modeline markers ----------------- - -The modeline has some additional optional components that we haven't talked about yet. You can: - -* give a blueprint a label by adding a `label()` marker -* set a cursor offset and/or start hint by adding a `start()` marker -* hide a blueprint from being listed with a `hidden()` marker -* register a message to be displayed after the blueprint is successfully applied - -The full modeline syntax, when everything is specified, is: - - #mode label(mylabel) start(X;Y;STARTCOMMENT) hidden() message(mymessage) comment - -Note that all elements are optional except for the initial `#mode`. Here are a few examples of modelines with optional elements before we discuss them in more detail: - - #dig start(3; 3; Center tile of a 5-tile square) Regular blueprint comment - #build label(noblebedroom) start(10;15) - #query label(configstockpiles) No explicit start() means cursor is at upper left corner - #meta label(digwholefort) start(center of stairs on surface) - #dig label(digdining) hidden() managed by the digwholefort meta blueprint - #zone label(pastures) message(remember to assign animals to the new pastures) - -### Blueprint labels ### - -Labels are displayed in the `quickfort list` output and are used for addressing specific blueprints when there are multiple blueprints in a single file or spreadsheet sheet (see [Packaging a set of blueprints](#packaging-a-set-of-blueprints) below). If a blueprint has no label, the label becomes the ordinal of the blueprint's position in the file or sheet. For example, the label of the first blueprint will be "1" if it is not otherwise set, the label of the second blueprint will be "2" if it is not otherwise set, etc. Labels that are explicitly defined must start with a letter to ensure the auto-generated labels don't conflict with user-defined labels. - -### Start positions ### - -Start positions specify a cursor offset for a particular blueprint, simplifying the task of blueprint alignment. This is very helpful for blueprints that are based on a central staircase, but it helps whenever a blueprint has an obvious "center". For example: - - #build start(2;2;center of workshop) label(masonw) a mason workshop - wm wm wm # - wm wm wm # - wm wm wm # - # # # # - -will build the workshop *centered* on the cursor, not down and to the right of the cursor. - -The two numbers specify the column and row (or X and Y offset) where the cursor is expected to be when you apply the blueprint. Position 1;1 is the top left cell. The optional comment will show up in the `quickfort list` output and should contain information about where to position the cursor. If the start position is 1;1, you can omit the numbers and just add a comment describing where to put the cursor. This is also useful for meta blueprints that don't actually care where the cursor is, but that refer to other blueprints that have fully-specified `start()` markers. For example, a meta blueprint that refers to the `masonw` blueprint above could look like this: - - #meta start(center of workshop) a mason workshop - /masonw - -### Hiding blueprints ### - -A blueprint with a `hidden()` marker won't appear in `quickfort list` output unless the `--hidden` flag is specified. The primary reason for hiding a blueprint (rather than, say, deleting it or moving it out of the `blueprints/` folder) is if a blueprint is intended to be run as part of a larger sequence managed by a [meta blueprint](#meta-blueprints). - -### Messages ### - -A blueprint with a `message()` marker will display a message after the blueprint is applied with `quickfort run`. This is useful for reminding players to take manual steps that cannot be automated, like assigning animals to a pasture or assigning minecarts to a route, or listing the next step in a series of blueprints. For long or multi-part messages, you can embed newlines: - - "#meta label(surface1) message(This would be a good time to start digging the industry level. - Once the area is clear, continue with /surface2.) clear the embark site and set up pastures" - -Packaging a set of blueprints ------------------------------ - -A complete specification for a section of your fortress may contain 5 or more separate blueprints, one for each "phase" of construction (dig, build, place stockpiles, designate zones, query building adjustments). - -To manage all the separate blueprints, it is often convenient to keep related blueprints in a single file. For .xlsx spreadsheets, you can keep each blueprint in a separate sheet. Online spreadsheet applications like [Google Sheets](https://sheets.new) make it easy to work with multiple related blueprints, and, as a bonus, they retain any formatting you've set, like column sizes and coloring. - -For both .csv files and .xlsx spreadsheets you can also add as many blueprints as you want in a single file or sheet. Just add a modeline in the first column to indicate the start of a new blueprint. Instead of multiple .csv files, you can concatenate them into one single file. - -For example, you can store multiple blueprints together like this: - - #dig label(bed1) - d d d d # - d d d d # - d d d d # - d d d d # - # # # # # - #build label(bed2) - b f h # - # - # - n # - # # # # # - #place label(bed3) - # - f(2x2) # - # - # - # # # # # - #query label(bed4) - # - booze # - # - # - # # # # # - #query label(bed5) - r{+ 3}& # - # - # - # - # # # # # - - -Of course, you could still choose to keep your blueprints in single-sheet .csv files and just give related blueprints similar names: - - bedroom.1.dig.csv - bedroom.2.build.csv - bedroom.3.place.csv - bedroom.4.query.csv - bedroom.5.query2.csv - -But the naming and organization is completely up to you. - - -Meta blueprints ---------------- - -Meta blueprints are blueprints that script a series of other blueprints. Many blueprint packages follow this pattern: - -- Apply dig blueprint to designate dig areas -- Wait for miners to dig -- **Apply build buildprint** to designate buildings -- **Apply place buildprint** to designate stockpiles -- **Apply query blueprint** to configure stockpiles -- Wait for buildings to get built -- Apply a different query blueprint to configure rooms - -Those three "apply"s in the middle might as well get done in one command instead of three. A meta blueprint can encode that sequence. A meta blueprint refers to other blueprints by their label (see the [Modeline markers](modeline-markers) section above) in the same format used by the `DFHack#` quickfort command: "/