diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e922ecaca..83f3490da 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -129,14 +129,14 @@ jobs: python-version: 3 - name: Install dependencies run: | - pip install 'sphinx<4.4.0' + pip install 'sphinx' - name: Clone DFHack uses: actions/checkout@v1 with: submodules: true - name: Build docs run: | - sphinx-build -W --keep-going -j3 --color . docs/html + sphinx-build -W --keep-going -j auto --color . docs/html - name: Upload docs uses: actions/upload-artifact@v1 with: diff --git a/.gitignore b/.gitignore index 8e401a7df..e91dcab3b 100644 --- a/.gitignore +++ b/.gitignore @@ -15,9 +15,14 @@ build/VC2010 !build/ # Sphinx generated documentation -docs/_* +docs/changelogs/ docs/html/ docs/pdf/ +docs/pseudoxml/ +docs/tags/ +docs/text/ +docs/tools/ +docs/xml/ # in-place build build/Makefile diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 125b1e931..25f043624 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,11 +20,11 @@ repos: args: ['--fix=lf'] - id: trailing-whitespace - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.17.1 + rev: 0.18.2 hooks: - id: check-github-workflows - repo: https://github.com/Lucas-C/pre-commit-hooks - rev: v1.3.0 + rev: v1.3.1 hooks: - id: forbid-tabs exclude_types: diff --git a/CMakeLists.txt b/CMakeLists.txt index d01d105c5..8aa57d574 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # main project file. use it from a build sub-folder, see COMPILE for details ## some generic CMake magic -cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) +cmake_minimum_required(VERSION 3.6 FATAL_ERROR) cmake_policy(SET CMP0048 NEW) project(dfhack) @@ -442,43 +442,67 @@ endif() add_subdirectory(data) add_subdirectory(scripts) -find_package(Sphinx QUIET) if(BUILD_DOCS) + find_package(Python3) + find_package(Sphinx) + if(NOT SPHINX_FOUND) message(SEND_ERROR "Sphinx not found but BUILD_DOCS enabled") endif() - file(GLOB SPHINX_DEPS - "${CMAKE_CURRENT_SOURCE_DIR}/docs/*.rst" - "${CMAKE_CURRENT_SOURCE_DIR}/docs/guides/*.rst" - "${CMAKE_CURRENT_SOURCE_DIR}/docs/changelog.txt" - "${CMAKE_CURRENT_SOURCE_DIR}/docs/gen_changelog.py" + file(GLOB SPHINX_GLOB_DEPS + LIST_DIRECTORIES false "${CMAKE_CURRENT_SOURCE_DIR}/docs/images/*.png" "${CMAKE_CURRENT_SOURCE_DIR}/docs/styles/*" - "${CMAKE_CURRENT_SOURCE_DIR}/conf.py" - "${CMAKE_CURRENT_SOURCE_DIR}/scripts/about.txt" - "${CMAKE_CURRENT_SOURCE_DIR}/scripts/*/about.txt" + "${CMAKE_CURRENT_SOURCE_DIR}/data/init/*init" + ) + file(GLOB_RECURSE SPHINX_GLOB_RECURSE_DEPS + "${CMAKE_CURRENT_SOURCE_DIR}/*.rst" + "${CMAKE_CURRENT_SOURCE_DIR}/changelog.txt" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/*py" + ) + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/changelogs" + ) + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/html" ) - file(GLOB_RECURSE SPHINX_SCRIPT_DEPS - "${CMAKE_CURRENT_SOURCE_DIR}/scripts/*.lua" - "${CMAKE_CURRENT_SOURCE_DIR}/scripts/*.rb" + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/tags" ) - set(SPHINX_DEPS ${SPHINX_DEPS} ${SPHINX_SCRIPT_DEPS} - "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.rst" + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/text" + ) + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/tools" + ) + set(SPHINX_DEPS ${SPHINX_GLOB_DEPS} ${SPHINX_GLOB_RECURSE_DEPS} ${SPHINX_SCRIPT_DEPS} "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt" + "${CMAKE_CURRENT_SOURCE_DIR}/conf.py" ) set(SPHINX_OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/docs/html/.buildinfo") - set_source_files_properties(${SPHINX_OUTPUT} PROPERTIES GENERATED TRUE) + set_property( + DIRECTORY PROPERTY ADDITIONAL_CLEAN_FILES TRUE + "${CMAKE_CURRENT_SOURCE_DIR}/docs/changelogs" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/html" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/pdf" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/pseudoxml" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/tags" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/text" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/tools" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/xml" + "${CMAKE_BINARY_DIR}/docs/html" + "${CMAKE_BINARY_DIR}/docs/pdf" + "${CMAKE_BINARY_DIR}/docs/pseudoxml" + "${CMAKE_BINARY_DIR}/docs/text" + "${CMAKE_BINARY_DIR}/docs/xml" + ) add_custom_command(OUTPUT ${SPHINX_OUTPUT} - COMMAND ${SPHINX_EXECUTABLE} - -a -E -q -b html - "${CMAKE_CURRENT_SOURCE_DIR}" - "${CMAKE_CURRENT_SOURCE_DIR}/docs/html" - -w "${CMAKE_CURRENT_SOURCE_DIR}/docs/_sphinx-warnings.txt" - -j 2 + COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/docs/build.py" + html text --sphinx="${SPHINX_EXECUTABLE}" -- -q DEPENDS ${SPHINX_DEPS} - COMMENT "Building HTML documentation with Sphinx" + COMMENT "Building documentation with Sphinx" ) add_custom_target(dfhack_docs ALL @@ -490,8 +514,12 @@ if(BUILD_DOCS) COMMAND ${CMAKE_COMMAND} -E touch ${SPHINX_OUTPUT}) install(DIRECTORY ${dfhack_SOURCE_DIR}/docs/html/ + DESTINATION ${DFHACK_USERDOC_DESTINATION}/docs + FILES_MATCHING PATTERN "*" + PATTERN html/_sources EXCLUDE) + install(DIRECTORY ${dfhack_SOURCE_DIR}/docs/text/ DESTINATION ${DFHACK_USERDOC_DESTINATION}/docs) - install(FILES docs/_auto/news.rst docs/_auto/news-dev.rst DESTINATION ${DFHACK_USERDOC_DESTINATION}) + install(FILES docs/changelogs/news.rst docs/changelogs/news-dev.rst DESTINATION ${DFHACK_USERDOC_DESTINATION}) install(FILES "README.html" DESTINATION "${DFHACK_DATA_DESTINATION}") endif() diff --git a/conf.py b/conf.py index 71ba65fb7..68d11f0f9 100644 --- a/conf.py +++ b/conf.py @@ -15,186 +15,128 @@ serve to show the default. # pylint:disable=redefined-builtin import datetime -from io import open import os import re import shlex # pylint:disable=unused-import import sphinx import sys +sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'docs', 'sphinx_extensions')) +from dfhack.util import write_file_if_changed -# -- Support :dfhack-keybind:`command` ------------------------------------ -# this is a custom directive that pulls info from default keybindings +if os.environ.get('DFHACK_DOCS_BUILD_OFFLINE'): + # block attempted image downloads, particularly for the PDF builder + def request_disabled(*args, **kwargs): + raise RuntimeError('Offline build - network request blocked') -from docutils import nodes -from docutils.parsers.rst import roles + import urllib3.util + urllib3.util.create_connection = request_disabled -sphinx_major_version = sphinx.version_info[0] + import urllib3.connection + urllib3.connection.HTTPConnection.connect = request_disabled -def get_keybinds(root, files, keybindings): - """Add keybindings in the specified files to the - given keybindings dict. - """ - for file in files: - with open(os.path.join(root, file)) as f: - lines = [l.replace('keybinding add', '').strip() for l in f.readlines() - if l.startswith('keybinding add')] - for k in lines: - first, command = k.split(' ', 1) - bind, context = (first.split('@') + [''])[:2] - if ' ' not in command: - command = command.replace('"', '') - tool = command.split(' ')[0].replace('"', '') - keybindings[tool] = keybindings.get(tool, []) + [ - (command, bind.split('-'), context)] - -def get_all_keybinds(root_dir): - """Get the implemented keybinds, and return a dict of - {tool: [(full_command, keybinding, context), ...]}. - """ - keybindings = dict() - for root, _, files in os.walk(root_dir): - get_keybinds(root, files, keybindings) - return keybindings - -KEYBINDS = get_all_keybinds('data/init') - - -# pylint:disable=unused-argument,dangerous-default-value,too-many-arguments -def dfhack_keybind_role_func(role, rawtext, text, lineno, inliner, - options={}, content=[]): - """Custom role parser for DFHack default keybinds.""" - roles.set_classes(options) - if text not in KEYBINDS: - msg = inliner.reporter.error( - 'no keybinding for {} in dfhack.init-example'.format(text), - line=lineno) - prb = inliner.problematic(rawtext, rawtext, msg) - return [prb], [msg] - newnode = nodes.paragraph() - for cmd, key, ctx in KEYBINDS[text]: - n = nodes.paragraph() - newnode += n - n += nodes.strong('Keybinding: ', 'Keybinding: ') - for k in key: - n += nodes.inline(k, k, classes=['kbd']) - if cmd != text: - n += nodes.inline(' -> ', ' -> ') - n += nodes.literal(cmd, cmd, classes=['guilabel']) - if ctx: - n += nodes.inline(' in ', ' in ') - n += nodes.literal(ctx, ctx) - return [newnode], [] - - -roles.register_canonical_role('dfhack-keybind', dfhack_keybind_role_func) - -# -- Autodoc for DFhack scripts ------------------------------------------- - -def doc_dir(dirname, files): - """Yield (command, includepath) for each script in the directory.""" + import requests + requests.request = request_disabled + requests.get = request_disabled + + +# -- Autodoc for DFhack plugins and scripts ------------------------------- + +def doc_dir(dirname, files, prefix): + """Yield (name, includepath) for each file in the directory.""" sdir = os.path.relpath(dirname, '.').replace('\\', '/').replace('../', '') + if prefix == '.': + prefix = '' + else: + prefix += '/' for f in files: - if f[-3:] not in ('lua', '.rb'): + if f[-4:] != '.rst': continue - with open(os.path.join(dirname, f), 'r', encoding='utf8') as fstream: - text = [l.rstrip() for l in fstream.readlines() if l.strip()] - # Some legacy lua files use the ruby tokens (in 3rdparty scripts) - tokens = ('=begin', '=end') - if f[-4:] == '.lua' and any('[====[' in line for line in text): - tokens = ('[====[', ']====]') - command = None - for line in text: - if command and line == len(line) * '=': - yield command, sdir + '/' + f, tokens[0], tokens[1] - break - command = line + yield prefix + f[:-4], sdir + '/' + f def doc_all_dirs(): """Collect the commands and paths to include in our docs.""" - scripts = [] - for root, _, files in os.walk('scripts'): - scripts.extend(doc_dir(root, files)) - return tuple(scripts) + tools = [] + # TODO: as we scan the docs, parse out the tags and short descriptions and + # build a map for use in generating the tags pages and links in the tool + # doc footers + for root, _, files in os.walk('docs/builtins'): + tools.extend(doc_dir(root, files, os.path.relpath(root, 'docs/builtins'))) + for root, _, files in os.walk('docs/plugins'): + tools.extend(doc_dir(root, files, os.path.relpath(root, 'docs/plugins'))) + for root, _, files in os.walk('scripts/docs'): + tools.extend(doc_dir(root, files, os.path.relpath(root, 'scripts/docs'))) + return tuple(tools) DOC_ALL_DIRS = doc_all_dirs() -def document_scripts(): - """Autodoc for files with the magic script documentation marker strings. - - Returns a dict of script-kinds to lists of .rst include directives. +def get_tags(): + groups = {} + group_re = re.compile(r'"([^"]+)"') + tag_re = re.compile(r'- `tag/([^`]+)`: (.*)') + with open('docs/Tags.rst') as f: + lines = f.readlines() + for line in lines: + line = line.strip() + m = re.match(group_re, line) + if m: + group = m.group(1) + groups[group] = [] + continue + m = re.match(tag_re, line) + if m: + tag = m.group(1) + desc = m.group(2) + groups[group].append((tag, desc)) + return groups + + +def generate_tag_indices(): + os.makedirs('docs/tags', mode=0o755, exist_ok=True) + tag_groups = get_tags() + for tag_group in tag_groups: + with write_file_if_changed(('docs/tags/by{group}.rst').format(group=tag_group)) as topidx: + for tag_tuple in tag_groups[tag_group]: + tag = tag_tuple[0] + with write_file_if_changed(('docs/tags/{name}.rst').format(name=tag)) as tagidx: + tagidx.write('TODO: add links to the tools that have this tag') + topidx.write(('.. _tag/{name}:\n\n').format(name=tag)) + topidx.write(('{name}\n').format(name=tag)) + topidx.write(('{underline}\n').format(underline='*'*len(tag))) + topidx.write(('{desc}\n\n').format(desc=tag_tuple[1])) + topidx.write(('.. include:: /docs/tags/{name}.rst\n\n').format(name=tag)) + + +def write_tool_docs(): """ - # Next we split by type and create include directives sorted by command - kinds = {'base': [], 'devel': [], 'fix': [], 'gui': [], 'modtools': []} - for s in DOC_ALL_DIRS: - k_fname = s[0].split('/', 1) - if len(k_fname) == 1: - kinds['base'].append(s) - else: - kinds[k_fname[0]].append(s) - - def template(arg): - tmp = '.. _{}:\n\n.. include:: /{}\n' +\ - ' :start-after: {}\n :end-before: {}\n' - if arg[0] in KEYBINDS: - tmp += '\n:dfhack-keybind:`{}`\n'.format(arg[0]) - return tmp.format(*arg) - - return {key: '\n\n'.join(map(template, sorted(value))) - for key, value in kinds.items()} - - -def write_script_docs(): + Creates a file for each tool with the ".. include::" directives to pull in + the original documentation. Then we generate a label and useful info in the + footer. """ - Creates a file for eack kind of script (base/devel/fix/gui/modtools) - with all the ".. include::" directives to pull out docs between the - magic strings. - """ - kinds = document_scripts() - head = { - 'base': 'Basic Scripts', - 'devel': 'Development Scripts', - 'fix': 'Bugfixing Scripts', - 'gui': 'GUI Scripts', - 'modtools': 'Scripts for Modders'} - for k in head: - title = ('.. _scripts-{k}:\n\n{l}\n{t}\n{l}\n\n' - '.. include:: /scripts/{a}about.txt\n\n' - '.. contents:: Contents\n' - ' :local:\n\n').format( - k=k, t=head[k], - l=len(head[k])*'#', - a=('' if k == 'base' else k + '/') - ) - mode = 'w' if sys.version_info.major > 2 else 'wb' - with open('docs/_auto/{}.rst'.format(k), mode) as outfile: - outfile.write(title) - outfile.write(kinds[k]) - - -def all_keybinds_documented(): - """Check that all keybindings are documented with the :dfhack-keybind: - directive somewhere.""" - configured_binds = set(KEYBINDS) - script_commands = set(i[0] for i in DOC_ALL_DIRS) - with open('./docs/Plugins.rst') as f: - plugin_binds = set(re.findall(':dfhack-keybind:`(.*?)`', f.read())) - undocumented_binds = configured_binds - script_commands - plugin_binds - if undocumented_binds: - raise ValueError('The following DFHack commands have undocumented ' - 'keybindings: {}'.format(sorted(undocumented_binds))) + for k in DOC_ALL_DIRS: + header = ':orphan:\n' + label = ('.. _{name}:\n\n').format(name=k[0]) + include = ('.. include:: /{path}\n\n').format(path=k[1]) + # TODO: generate a footer with links to tools that share at least one + # tag with this tool. Just the tool names, strung across the bottom of + # the page in one long wrapped line, similar to how the wiki does it + os.makedirs(os.path.join('docs/tools', os.path.dirname(k[0])), + mode=0o755, exist_ok=True) + with write_file_if_changed('docs/tools/{}.rst'.format(k[0])) as outfile: + outfile.write(header) + if k[0] != 'search': + outfile.write(label) + outfile.write(include) # Actually call the docs generator and run test -write_script_docs() -all_keybinds_documented() +write_tool_docs() +generate_tag_indices() # -- General configuration ------------------------------------------------ -sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'docs', 'sphinx_extensions')) - # If your documentation needs a minimal Sphinx version, state it here. needs_sphinx = '1.8' @@ -205,8 +147,11 @@ extensions = [ 'sphinx.ext.extlinks', 'dfhack.changelog', 'dfhack.lexer', + 'dfhack.tool_docs', ] +sphinx_major_version = sphinx.version_info[0] + def get_caption_str(prefix=''): return prefix + (sphinx_major_version >= 5 and '%s' or '') @@ -286,12 +231,18 @@ today_fmt = html_last_updated_fmt = '%Y-%m-%d' # directories to ignore when looking for source files. exclude_patterns = [ 'README.md', - 'docs/html*', - 'depends/*', 'build*', - 'docs/_auto/news*', - 'docs/_changelogs/', + 'depends/*', + 'docs/html/*', + 'docs/tags/*', + 'docs/text/*', + 'docs/builtins/*', + 'docs/pdf/*', + 'docs/plugins/*', + 'docs/pseudoxml/*', + 'docs/xml/*', 'scripts/docs/*', + 'plugins/*', ] # The reST default role (used for this markup: `text`) to use for all @@ -367,8 +318,11 @@ html_sidebars = { # If false, no module index is generated. html_domain_indices = False -# If false, no index is generated. -html_use_index = False +# If false, no genindex.html is generated. +html_use_index = True + +# don't link to rst sources in the generated pages +html_show_sourcelink = False html_css_files = [ 'dfhack.css', @@ -388,3 +342,15 @@ latex_documents = [ ] latex_toplevel_sectioning = 'part' + +# -- Options for text output --------------------------------------------- + +from sphinx.writers import text + +# this value is arbitrary. it just needs to be bigger than the number of +# characters in the longest paragraph in the DFHack docs +text.MAXWIDTH = 1000000000 + +# this is the order that section headers will use the characters for underlines +# they are in the order of (subjective) text-mode readability +text_sectionchars = '=-~`+"*' diff --git a/data/blueprints/library/dreamfort.csv b/data/blueprints/library/dreamfort.csv index ff0b8b4fc..e26650943 100644 --- a/data/blueprints/library/dreamfort.csv +++ b/data/blueprints/library/dreamfort.csv @@ -33,7 +33,7 @@ Put that file in your dfhack-config/init/ directory -- the same directory that h "" "Also check out https://docs.dfhack.org/en/stable/docs/Plugins.html#professions for more information on the default labor professions that are distributed with DFHack, including suggestions on how many dwarves of each profession you are likely to need at each stage of fort maturity." "" -"Once you have your starting surface workshops up and running, you might want to configure buildingplan (in its global settings, accessible from any building placement screen, e.g.: b-a-G) to only use blocks for constructions so it won't use your precious wood, boulders, and bars to build floors and walls. If you bring at least 7 blocks with you on embark, you can even set this in your onMapLoad.init file like this:" +"Once you have your starting surface workshops up and running, you might want to configure buildingplan (in its global settings, accessible from any building placement screen, e.g.: b-a-G) to only use blocks for constructions so it won't use your precious wood, boulders, and bars to build floors and walls. If you bring at least 7 blocks with you on embark, you can even set this in your dfhack-config/init/onMapLoad.init file like this:" on-new-fortress buildingplan set boulders false; buildingplan set logs false "" "Directly after embark, run ""quickfort run library/dreamfort.csv -n /setup"" with your cursor on your wagon to set settings, and get started building your fort with ""quickfort run library/dreamfort.csv -n /surface1"" on the surface (see /surface_help for how to select a good spot). Read the walkthroughs for each level to understand what's going on and follow the checklist to keep track of where you are in the building process. Good luck, and have fun building an awesome Dreamfort-based fort!" @@ -50,6 +50,7 @@ interactively." "" -- Preparation (before you embark!) -- Copy hack/examples/init/onMapLoad_dreamfort.init to your dfhack-config/init directory inside your DF installation +Optionally copy the premade Dreamfort embark profile from the online spreadsheets to the data/init/embark_profiles.txt file "" -- Set settings and preload initial orders -- quickfort run library/dreamfort.csv -n /setup,# Run before making any manual adjustments to settings! Run the /setup_help blueprint for details on what this blueprint does. @@ -360,6 +361,7 @@ Once the marked trees are cleared and at least the beehives and weapon rack have place/surface_place build/surface_build query/surface_query +traffic/surface_traffic clear_large/surface_clear_large "" "#meta label(surface6) start(central stairs) message(Remember to enqueue manager orders for this blueprint. @@ -863,8 +865,8 @@ Feel free to assign an unimportant animal to the pasture in the main entranceway ,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,~,,,,,,~,`,,,,,,,Cf,Cf,`,,` ,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,Cf,Cf,Cf,Cf,Cf,~,~,,,,,,,,Cf,`,,` ,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,,~,~,~,,~,~,,,,,Cf,Cf,,Cf,`,,` -,,,`,,`,,Cf,,Cf,Cf,Cf,Cf,Cf,,Cf,,~,~,~,,Cf,,,,,,,,,Cf,`,,` -,,,`,,`,,Cf,,Cf,Cf,Cf,Cf,Cf,`,,,~,~,~,,,`,,,,,,,Cf,Cf,`,,` +,,,`,,`,,Cf,,Cf,Cf,Cf,Cf,Cf,,Cf,,~,~,~,,Cf,,,Cf,,,,,,Cf,`,,` +,,,`,,`,,Cf,,Cf,Cf,Cf,Cf,Cf,`,,,~,~,~,,,`,,Cf,,,,,Cf,Cf,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` ,,,`,Cf,,,,,,,,,Cf,,,,,~,,,,,Cf,,,,,,,,,Cf,` ,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` @@ -979,6 +981,40 @@ You might also want to set the ""trade goods quantum"" stockpile to Auto Trade i +#dig label(surface_traffic) start(19; 19) hidden() set traffic designations + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,or,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,`,,ol,ol,ol,ol,ol,,`,or,,,,,,,,`,,` +,,,`,,`,,,,,,,,,ol,ol,ol,ol,ol,ol,ol,ol,ol,or,,,,,,,,`,,` +,,,`,,`,,,,,,,,,ol,ol,,,,,,ol,ol,or,,,,,,,,`,,` +,,,`,,`,,,,,,,,,ol,ol,,,,,,ol,ol,or,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,or,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,ol,ol,ol,ol,ol,ol,ol,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,ol,ol,ol,ol,ol,ol,ol +,,,,,,,,,,,,,,,ol,ol,ol,ol,ol,ol,ol + #dig label(surface_clear_large) start(19; 19) hidden() clear wider area of trees t1(37x33) @@ -1107,8 +1143,8 @@ t1(37x33) ,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,~,~,`,,` ,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,`,,` ,,,`,,`,~,~,~,~,~,~,~,~,~,~,Cf,~,~,~,Cf,~,~,Cf,Cf,Cf,Cf,~,~,Cf,~,`,,` -,,,`,,`,Cf,~,Cf,~,~,~,~,~,~,~,Cf,~,~,~,Cf,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,`,,` -,,,`,,`,Cf,~,Cf,~,~,~,~,~,`,Cf,Cf,~,~,~,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,~,~,`,,` +,,,`,,`,Cf,~,Cf,~,~,~,~,~,~,~,Cf,~,~,~,Cf,~,~,Cf,~,Cf,Cf,Cf,Cf,Cf,~,`,,` +,,,`,,`,Cf,~,Cf,~,~,~,~,~,`,Cf,Cf,~,~,~,Cf,Cf,`,Cf,~,Cf,Cf,Cf,Cf,~,~,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,,` ,,,`,~,,,,,,,,,,,Cf,Cf,Cf,~,Cf,Cf,Cf,,,,,,,,,,,~,` ,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` @@ -1529,6 +1565,7 @@ Farming Walkthrough: Once furniture has been placed, continue with /farming3.) workshops, stockpiles, and important furniture" build/farming_build place/farming_place +traffic/farming_traffic query_stockpiles/farming_query_stockpiles link_stockpiles/farming_link "" @@ -1601,6 +1638,37 @@ build3/farming_build3 ,,,,,,,,,,,,,,,ry +#dig label(farming_traffic) start(16; 18) hidden() keep hungry dwarves away from the crops and food stores so they prefer the prepared meals + + +,,,,,,,,,ol,ol,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,,,ol,ol,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,,,ol,ol,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,,,,,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,ol,ol,ol,,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,ol,ol,ol,ol,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,ol,ol,ol,,ol,,or,or,or,or,or,,ol +,,,,,,,,,,,ol,,or,or,or,or,or,,ol,,ol,ol,ol +,,,,,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol,ol,ol,ol,ol +,,,,,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol,,ol,ol,ol +,,,ol,ol,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol +,,ol,ol,ol,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol,,ol,ol,ol,,ol,ol,ol +,,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,,or,,or,,,ol,ol,ol,ol,ol,ol,ol,ol,ol +,,,ol,ol,,ol,ol,ol,ol,,ol,ol,ol,ol,ol,ol,ol,ol,ol,,ol,ol,ol,,ol,ol,ol +,,,,or,,,or,,,,,,ol,`,`,`,ol,,,,,or,,,,or +,,or,or,or,or,or,or,or,or,or,or,,ol,`,~,`,ol,,or,or,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,or,or,or,ol,`,`,`,ol,or,or,or,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,or,or,,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,or,,,,ol,,ol,,,,or,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,,,ol,ol,ol,ol,ol,ol,ol,,,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,,ol,ol,,,ol,,,ol,ol,,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,,ol,ol,,ol,ol,ol,,ol,ol,,,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,ol,ol,ol,,,ol,,,ol,ol,ol,,or,or,or,or,or,or,or +,,,,,,,,,,,,,,,ol + + "#query label(farming_query_stockpiles) start(16; 18) hidden() message(remember to: - assign a minecart to the refuse quantum stockpile (run ""assign-minecarts all"") - if the industry level is already built, configure the jugs, pots, and bags stockpiles to take from the ""Goods"" quantum stockpile on the industry level) config stockpiles" @@ -1669,7 +1737,7 @@ build3/farming_build3 ,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,r&,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,r&a+&,,,,`,`,`,`,`,,`,`,`,` ,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,r+&h ,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` ,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,`,`,` @@ -2138,9 +2206,9 @@ Services Walkthrough: "#meta label(services2) start(central stairs) message(Remember to enqueue manager orders for this blueprint. Once furniture has been placed, continue with /services3.) dining hall anchors, stockpiles, hospital, garbage dump" +zones/services_zones build/services_build place/services_place -zones/services_zones name_zones/services_name_zones query_stockpiles/services_query_stockpiles "" @@ -2153,6 +2221,64 @@ build2/services_build2 build3/services_build3 place_jail/services_place_jail query_jail/services_query_jail +"#zone label(services_zones) start(18; 18) hidden() message(If you'd like to fill your wells via bucket brigade, activate the inactive pond zones one level down from where the wells will be built.) garbage dump, hospital, and pond zones" + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` +,,`,,,,`,,,,`,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,ht,ht,ht,ht,ht,ht,ht,ht,ht +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,ht,ht,ht,ht,ht,ht,ht,ht,ht,ht +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,ht,ht,ht,ht,ht,ht,ht,ht,ht,ht +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,ht,ht,ht,ht,ht,ht,ht,ht,ht,ht +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,ht,ht,ht,ht,ht,ht,ht,ht,ht,ht +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,ht,ht,ht,ht,ht,ht,ht,ht,ht,ht +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,ht,ht,ht,ht,ht,ht,ht,ht,ht,ht +,`,`,`,`,`,`,`,`,`,`,`,,,,,,d,,,,,ht,ht,ht,ht,ht,ht,ht,ht,ht,ht +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,ht,ht,ht,ht,ht,ht,ht,ht,ht +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#> + +,,,,,,,,,,,,,`,apPf,`,,`,,`,apPf,` +,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,`,apPf,`,,`,,`,apPf,` +,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,`,,,,,,,,,` +,,,,,,,,,,,,,,,,,`,,,,,,,,,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,`,apPf,` +,,,,,,,,,,,,,,,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,` + #build label(services_build) start(18; 18) hidden() build basic hospital and dining room anchor ,b,b,b,,b,b,b,,b,b,b,,`,`,`,,`,,`,`,` @@ -2225,64 +2351,6 @@ query_jail/services_query_jail ,`,`,`,`,`,,`,`,`,`,` ,`,`,`,`,`,,`,`,`,`,` -"#zone label(services_zones) start(18; 18) hidden() message(If you'd like to fill your wells via bucket brigade, activate the inactive pond zones one level down from where the wells will be built.) hospital, garbage dump, and pond zones" - -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,,`,,,,`,,,,`,,,,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,ht,,ht,,ht,,ht -,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,ht,,ht,,ht,,ht -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,ht,ht,ht,ht,ht,ht,ht,ht,ht -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,ht,ht,ht,ht,ht,ht,ht -,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,ht,ht,ht,ht,ht,ht,ht,ht,ht -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,ht,ht,ht,ht,ht,ht,ht -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,ht,ht,ht,ht,ht,ht,ht,ht,ht -,`,`,`,`,`,`,`,`,`,`,`,,,,,,d,,,,,,ht,,ht,,ht,,ht -,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,ht,,ht,,ht,,ht -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` - -#> - -,,,,,,,,,,,,,`,apPf,`,,`,,`,apPf,` -,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,`,apPf,`,,`,,`,apPf,` -,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,`,,,,,,,,,` -,,,,,,,,,,,,,,,,,`,,,,,,,,,` -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,` -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,`,`,` -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,`,apPf,` -,,,,,,,,,,,,,,,`,`,`,`,` -,,,,,,,,,,,,,,,`,`,`,`,` - #query label(services_name_zones) start(18; 18) hidden() ,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` @@ -2507,6 +2575,42 @@ query_jail/services_query_jail ,,,,,,,,,,,,,,,`,`,`,`,` ,,,,,,,,,,,,,,,`,`,`,`,` +#dig label(services_traffic) start(18; 18) hidden() promote the tavern as the place to eat + +,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,,or,,or,or,or +,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,or,or,or,or,or,or +,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,,or,,or,or,or +,,ol,,,,ol,,,,ol,,,,,,,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,,or,,or,or,or,,or,or,or,or,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,or,or,or,or,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,,or,,or,or,or,,or,or,or,or,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,,,,,or,,,,,,or,or,or,or,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,or,or,or,or,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,,,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,or,or,or,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,or,,or,,or,,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,,,,or,,or,,,,,or,,or,,or,,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,oh,oh,oh,oh,oh,,,,or,or,or,or,or,or,or,or,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,or,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,`,,oh,`,`,`,oh,,`,,oh,oh,oh,`,oh,or,or,or,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,or,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,oh,oh,oh,oh,oh,,,,or,or,or,or,or,or,or,or,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,,,`,,,,,,or,,or,,or,,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,,,,,,,,,or,,or,,or,,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,,,,oh,oh,,oh,oh +,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh + "#build label(services_build3) start(18; 18) hidden() jail, statues" ,~,~,~,,~,~,~,,~,~,~,,t,l,b,,`,,t,l,b diff --git a/data/init/dfhack.keybindings.init b/data/init/dfhack.keybindings.init index 85d010c84..2ee706b09 100644 --- a/data/init/dfhack.keybindings.init +++ b/data/init/dfhack.keybindings.init @@ -72,6 +72,9 @@ keybinding add Alt-Q@jobmanagement/Main gui/manager-quantity # re-check manager orders keybinding add Alt-R@jobmanagement/Main workorder-recheck +# workorder detail configuration +keybinding add D@workquota_details gui/workorder-details + # view combat reports for the selected unit/corpse/spatter keybinding add Ctrl-Shift-R view-unit-reports diff --git a/depends/clsocket b/depends/clsocket index ae19aebd7..6ed8aa464 160000 --- a/depends/clsocket +++ b/depends/clsocket @@ -1 +1 @@ -Subproject commit ae19aebd795d6d91803e60f46de037b604593cb4 +Subproject commit 6ed8aa46462ea01a1122fc49422840a2facc9757 diff --git a/docs/Core.rst b/docs/Core.rst index 0cc62bef9..09ae2577d 100644 --- a/docs/Core.rst +++ b/docs/Core.rst @@ -11,8 +11,7 @@ DFHack Core Command Implementation ====================== -DFHack commands can be implemented in three ways, all of which -are used in the same way: +DFHack commands can be implemented in any of three ways: :builtin: commands are implemented by the core of DFHack. They manage other DFHack tools, interpret commands, and control basic @@ -27,6 +26,7 @@ are used in the same way: more flexible about versions, and easier to distribute. Most third-party DFHack addons are scripts. +All tools distributed with DFHack are documented `here `. Using DFHack Commands ===================== @@ -113,260 +113,6 @@ second (Windows) example uses `kill-lua` to stop a Lua script. you have multiple copies of DF running simultaneously. To assign a different port, see `remote-server-config`. - -Built-in Commands -================= -The following commands are provided by the 'core' components -of DFHack, rather than plugins or scripts. - -.. contents:: - :local: - - -.. _alias: - -alias ------ -The ``alias`` command allows configuring aliases to other DFHack commands. -Aliases are resolved immediately after built-in commands, which means that an -alias cannot override a built-in command, but can override a command implemented -by a plugin or script. - -Usage: - -:``alias list``: lists all configured aliases -:``alias add [arguments...]``: adds an alias -:``alias replace [arguments...]``: replaces an existing - alias with a new command, or adds the alias if it does not already exist -:``alias delete ``: removes the specified alias - -Aliases can be given additional arguments when created and invoked, which will -be passed to the underlying command in order. An example with `devel/print-args`:: - - [DFHack]# alias add pargs devel/print-args example - [DFHack]# pargs text - example - text - - -.. _cls: - -cls ---- -Clear the terminal. Does not delete command history. - - -.. _die: - -die ---- -Instantly kills DF without saving. - - -.. _disable: - -.. _enable: - -enable ------- -Many plugins can be in a distinct enabled or disabled state. Some of -them activate and deactivate automatically depending on the contents -of the world raws. Others store their state in world data. However a -number of them have to be enabled globally, and the init file is the -right place to do it. - -Most such plugins or scripts support the built-in ``enable`` and ``disable`` -commands. Calling them at any time without arguments prints a list -of enabled and disabled plugins, and shows whether that can be changed -through the same commands. Passing plugin names to these commands will enable -or disable the specified plugins. For example, to enable the `manipulator` -plugin:: - - enable manipulator - -It is also possible to enable or disable multiple plugins at once:: - - enable manipulator search - - -.. _fpause: - -fpause ------- -Forces DF to pause. This is useful when your FPS drops below 1 and you lose -control of the game. - - -.. _help: - -help ----- -Most commands support using the ``help `` built-in command -to retrieve further help without having to look at this document. -``? `` and ``man `` are aliases. - -Some commands (including many scripts) instead take ``help`` or ``?`` -as an option on their command line - ie `` help``. - - -.. _hide: - -hide ----- -Hides the DFHack terminal window. Only available on Windows. - - -.. _keybinding: - -keybinding ----------- -To set keybindings, use the built-in ``keybinding`` command. Like any other -command it can be used at any time from the console, but bindings are not -remembered between runs of the game unless re-created in `dfhack.init`. - -Currently, any combinations of Ctrl/Alt/Shift with A-Z, 0-9, F1-F12 or \` -are supported. - -Possible ways to call the command: - -``keybinding list `` - List bindings active for the key combination. -``keybinding clear ...`` - Remove bindings for the specified keys. -``keybinding add "cmdline" "cmdline"...`` - Add bindings for the specified key. -``keybinding set "cmdline" "cmdline"...`` - Clear, and then add bindings for the specified key. - -The ```` parameter above has the following *case-sensitive* syntax:: - - [Ctrl-][Alt-][Shift-]KEY[@context[|context...]] - -where the *KEY* part can be any recognized key and [] denote optional parts. - -When multiple commands are bound to the same key combination, DFHack selects -the first applicable one. Later ``add`` commands, and earlier entries within one -``add`` command have priority. Commands that are not specifically intended for use -as a hotkey are always considered applicable. - -The ``context`` part in the key specifier above can be used to explicitly restrict -the UI state where the binding would be applicable. If called without parameters, -the ``keybinding`` command among other things prints the current context string. - -Only bindings with a ``context`` tag that either matches the current context fully, -or is a prefix ending at a ``/`` boundary would be considered for execution, i.e. -when in context ``foo/bar/baz``, keybindings restricted to any of ``@foo/bar/baz``, -``@foo/bar``, ``@foo`` or none will be active. - -Multiple contexts can be specified by separating them with a -pipe (``|``) - for example, ``@foo|bar|baz/foo`` would match -anything under ``@foo``, ``@bar``, or ``@baz/foo``. - -Interactive commands like `liquids` cannot be used as hotkeys. - - -.. _kill-lua: - -kill-lua --------- -Stops any currently-running Lua scripts. By default, scripts can -only be interrupted every 256 instructions. Use ``kill-lua force`` -to interrupt the next instruction. - - -.. _load: -.. _unload: -.. _reload: - -load ----- -``load``, ``unload``, and ``reload`` control whether a plugin is loaded -into memory - note that plugins are loaded but disabled unless you do -something. Usage:: - - load|unload|reload PLUGIN|(-a|--all) - -Allows dealing with plugins individually by name, or all at once. - -Note that plugins do not maintain their enabled state if they are reloaded, so -you may need to use `enable` to re-enable a plugin after reloading it. - - -.. _ls: - -ls --- -``ls`` does not list files like the Unix command, but rather -available commands - first built in commands, then plugins, -and scripts at the end. Usage: - -:ls -a: Also list scripts in subdirectories of ``hack/scripts/``, - which are generally not intended for direct use. -:ls : List subcommands for the given plugin. - - -.. _plug: - -plug ----- -Lists available plugins, including their state and detailed description. - -``plug`` - Lists available plugins (*not* commands implemented by plugins) -``plug [PLUGIN] [PLUGIN] ...`` - List state and detailed description of the given plugins, - including commands implemented by the plugin. - - -.. _sc-script: - -sc-script ---------- -Allows additional scripts to be run when certain events occur -(similar to onLoad*.init scripts) - - -.. _script: - -script ------- -Reads a text file, and runs each line as a DFHack command -as if it had been typed in by the user - treating the -input like `an init file `. - -Some other tools, such as `autobutcher` and `workflow`, export -their settings as the commands to create them - which are later -loaded with ``script`` - - -.. _show: - -show ----- -Shows the terminal window after it has been `hidden `. -Only available on Windows. You'll need to use it from a -`keybinding` set beforehand, or the in-game `command-prompt`. - -.. _type: - -type ----- -``type command`` shows where ``command`` is implemented. - -Other Commands --------------- -The following commands are *not* built-in, but offer similarly useful functions. - -* `command-prompt` -* `hotkeys` -* `lua` -* `multicmd` -* `nopause` -* `quicksave` -* `rb` -* `repeat` - - .. _dfhack-config: Configuration Files @@ -439,7 +185,7 @@ where ``*`` can be any string, including the empty string. A world being loaded can mean a fortress, an adventurer, or legends mode. These files are best used for non-persistent commands, such as setting -a `fix ` script to run on `repeat`. +a `tag/bugfix` script to run on `repeat`. .. _onMapLoad.init: diff --git a/docs/Dev-intro.rst b/docs/Dev-intro.rst index c87154594..a49cb96f6 100644 --- a/docs/Dev-intro.rst +++ b/docs/Dev-intro.rst @@ -41,7 +41,7 @@ Installed plugins live in the ``hack/plugins`` folder of a DFHack installation, and the `load` family of commands can be used to load a recompiled plugin without restarting DF. -See `plugins-index` for a list of all plugins included in DFHack. +Run `plug` at the DFHack prompt for a list of all plugins included in DFHack. Scripts ------- @@ -51,10 +51,10 @@ is more complete and currently better-documented, however. Referring to existing scripts as well as the API documentation can be helpful when developing new scripts. -`Scripts included in DFHack ` live in a separate `scripts repository `_. -This can be found in the ``scripts`` submodule if you have -`cloned DFHack `, or the ``hack/scripts`` folder -of an installed copy of DFHack. +Scripts included in DFHack live in a separate +:source-scripts:`scripts repository <>`. This can be found in the ``scripts`` +submodule if you have `cloned DFHack `, or the +``hack/scripts`` folder of an installed copy of DFHack. Core ---- diff --git a/docs/Documentation.rst b/docs/Documentation.rst index be4511ba8..1d30e72ff 100644 --- a/docs/Documentation.rst +++ b/docs/Documentation.rst @@ -5,20 +5,24 @@ DFHack Documentation System ########################### -DFHack documentation, like the file you are reading now, is created as ``.rst`` files, -which are in `reStructuredText (reST) `_ format. -This is a documentation format common in the Python community. It is very +DFHack documentation, like the file you are reading now, is created as a set of +``.rst`` files in `reStructuredText (reST) `_ +format. This is a documentation format common in the Python community. It is very similar in concept - and in syntax - to Markdown, as found on GitHub and many other places. However it is more advanced than Markdown, with more features available when compiled to HTML, such as automatic tables of contents, cross-linking, special external links (forum, wiki, etc) and more. The documentation is compiled by a -Python tool, `Sphinx `_. +Python tool named `Sphinx `_. -The DFHack build process will compile the documentation, but this is disabled -by default due to the additional Python and Sphinx requirements. You typically -only need to build the docs if you're changing them, or perhaps -if you want a local HTML copy; otherwise, you can read an -`online version hosted by ReadTheDocs `_. +The DFHack build process will compile and install the documentation so it can be +displayed in-game by the `help` and `ls` commands (and any other command or GUI that +displays help text), but documentation compilation is disabled by default due to the +additional Python and Sphinx requirements. If you already have a version of the docs +installed (say from a downloaded release binary), then you only need to build the docs +if you're changing them and want to see the changes reflected in your game. + +You can also build the docs if you just want a local HTML- or text-rendered copy, though +you can always read the `online version `_ too. (Note that even if you do want a local copy, it is certainly not necessary to compile the documentation in order to read it. Like Markdown, reST documents are @@ -28,116 +32,314 @@ The main thing you lose in plain text format is hyperlinking.) .. contents:: Contents :local: +Concepts and general guidance +============================= + +The source ``.rst`` files are compiled to HTML for viewing in a browser and to text +format for viewing in-game. For in-game help, the help text is read from its installed +location in ``hack/docs`` under the DF directory. + +When writing documentation, remember that everything should be documented! If it's not +clear *where* a particular thing should be documented, ask on Discord or in the DFHack +thread on Bay12 -- you'll not only be getting help, you'll also be providing valuable +feedback that makes it easier for future contributers to find documentation on how to +write the documentation! + +Try to keep lines within 80-100 characters, so it's readable in plain text +in the terminal - Sphinx (our documentation system) will make sure +paragraphs flow. + +Short descriptions +------------------ + +Each command that a user can run, as well as every plugin that can be enabled for some +lasting effect, needs to have a short (~54 character) descriptive string associated with +it. This description text is: + +- used in-game by the `ls` command and DFHack UI screens that list commands +- used in the generated index entries in the HTML docs + +Tags +---- + +To make it easier for players to find related commands, all plugins and commands are marked +with relevant tags. These are used to compile indices and generate cross-links between the +commands, both in the HTML documents and in-game. See the list of available `tag-list` and +think about which categories your new tool belongs in. + +Links +----- + +If it would be helpful to mention another DFHack command, don't just type the +name - add a hyperlink! Specify the link target in backticks, and it will be +replaced with the corresponding title and linked: e.g. ```autolabor``` +=> `autolabor`. Scripts and plugins have link targets that match their names +created for you automatically. + +If you want to link to a heading in your own page, you can specifiy it like this:: + + `Heading text exactly as written`_ + +Note that the DFHack documentation is configured so that single backticks (with +no prefix or suffix) produce links to internal link targets, such as the +``autolabor`` target shown above. This is different from the reStructuredText +default behavior of rendering such text in italics (as a reference to a title). +For alternative link behaviors, see: + +- `The reStructuredText documentation on roles `__ +- `The reStructuredText documentation on external links `__ +- `The Sphinx documentation on roles `__ + - ``:doc:`` is useful for linking to another document outside of DFHack. + .. _docs-standards: Documentation standards ======================= +.. highlight:: rst + Whether you're adding new code or just fixing old documentation (and there's plenty), there are a few important standards for completeness and consistent style. Treat this section as a guide rather than iron law, match the surrounding text, and you'll be fine. -Command documentation ---------------------- +Where do I add the help text? +----------------------------- -Each command should have a short (~54 character) help string, which is shown -by the `ls` command. For scripts, this is a comment on the first line -(the comment marker and whitespace is stripped). For plugins it's the second -argument to ``PluginCommand``. Please make this brief but descriptive! +For scripts and plugins that are distributed as part of DFHack, documentation files +should be added to the :source-scripts:`scripts/docs ` and :source:`docs/plugins` directories, +respectively, in a file named after the script or plugin. For example, a script named +``gui/foobar.lua`` (which provides the ``gui/foobar`` command) should be documented +in a file named ``docs/gui/foobar.rst`` in the scripts repo. Similarly, a plugin named +``foobaz`` should be documented in a file named ``docs/plugins/foobaz.rst`` in the dfhack repo. +For plugins, all commands provided by that plugin should be documented in that same file. -Everything should be documented! If it's not clear *where* a particular -thing should be documented, ask on IRC or in the DFHack thread on Bay12 - -as well as getting help, you'll be providing valuable feedback that -makes it easier for future readers! +Short descriptions (the ~54 character short help) are taken from the first "sentence" of +the help text for scripts and plugins that can be enabled. This means that the help should +begin with a sentence fragment that begins with a capital letter and ends in a full stop +(``.``). Please make this brief but descriptive! -Scripts can use a custom autodoc function, based on the Sphinx ``include`` -directive - anything between the tokens is copied into the appropriate scripts -documentation page. For Ruby, we follow the built-in docstring convention -(``=begin`` and ``=end``). For Lua, the tokens are ``[====[`` and ``]====]`` -- ordinary multi-line strings. It is highly encouraged to reuse this string -as the in-console documentation by (e.g.) printing it when a ``-help`` argument -is given. +Short descriptions for commands provided by plugins are taken from the ``description`` +parameter passed to the ``PluginCommand`` constructor used when the command is registered +in the plugin source file. -The docs **must** have a heading which exactly matches the command, underlined -with ``=====`` to the same length. For example, a lua file would have: +Header format +------------- -.. code-block:: lua +The docs **must** begin with a heading which exactly matches the script or plugin name, underlined +with ``=====`` to the same length. This should be followed by a ``.. dfhack-tool:`` directive with +at least the following parameters: - local helpstr = [====[ +* ``:summary:`` - a short, single-sentence description of the tool +* ``:tags:`` - a space-separated list of tags that apply to the tool - add-thought - =========== - Adds a thought or emotion to the selected unit. Can be used by other scripts, - or the gui invoked by running ``add-thought gui`` with a unit selected. +By default, ``dfhack-tool`` generates both a description of a tool and a command +with the same name. For tools (specifically plugins) that do not provide exactly +1 command with the same name as the tool, pass the ``:no-command:`` parameter (with +no content after it) to prevent the command block from being generated. - ]====] +For tools that provide multiple commands, or a command by the same name but with +significantly different functionality (e.g. a plugin that can be both enabled +and invoked as a command for different results), use the ``.. dfhack-command:`` +directive for each command. This takes only a ``:summary:`` argument, with the +same meaning as above. +For example, documentation for the ``build-now`` script might look like:: -.. highlight:: rst + build-now + ========= -Where the heading for a section is also the name of a command, the spelling -and case should exactly match the command to enter in the DFHack command line. + .. dfhack-tool:: + :summary: Instantly completes unsuspended building construction jobs. + :tags: fort armok buildings -Try to keep lines within 80-100 characters, so it's readable in plain text -in the terminal - Sphinx (our documentation system) will make sure -paragraphs flow. + By default, all buildings on the map are completed, but the area of effect is configurable. -Command usage -------------- +And documentation for the ``autodump`` plugin might look like:: -If there aren't many options or examples to show, they can go in a paragraph of -text. Use double-backticks to put commands in monospaced font, like this:: + autodump + ======== - You can use ``cleanowned scattered x`` to dump tattered or abandoned items. + .. dfhack-tool:: + :summary: Automatically set items in a stockpile to be dumped. + :tags: fort armok fps productivity items stockpiles + :no-command: -If the command takes more than three arguments, format the list as a table -called Usage. The table *only* lists arguments, not full commands. -Input values are specified in angle brackets. Example:: + .. dfhack-command:: autodump + :summary: Teleports items marked for dumping to the cursor position. - Usage: + .. dfhack-command:: autodump-destroy-here + :summary: Destroy items marked for dumping under the cursor. - :arg1: A simple argument. - :arg2 : Does something based on the input value. - :Very long argument: - Is very specific. + .. dfhack-command:: autodump-destroy-item + :summary: Destroys the selected item. -To demonstrate usage - useful mainly when the syntax is complicated, list the -full command with arguments in monospaced font, then indent the next line and -describe the effect:: + When `enabled `, this plugin adds an option to the :kbd:`q` menu for + stockpiles. - ``resume all`` - Resumes all suspended constructions. + When invoked as a command, it can instantly move all unforbidden items marked + for dumping to the tile under the cursor. -Links ------ +Usage help +---------- -If it would be helpful to mention another DFHack command, don't just type the -name - add a hyperlink! Specify the link target in backticks, and it will be -replaced with the corresponding title and linked: e.g. ```autolabor``` -=> `autolabor`. Link targets should be equivalent to the command -described (without file extension), and placed above the heading of that -section like this:: +The first section after the header and introductory text should be the usage section. You can +choose between two formats, based on whatever is cleaner or clearer for your syntax. The first +option is to show usage formats together, with an explanation following the block:: - .. _autolabor: + Usage + ----- - autolabor - ========= + :: -Add link targets if you need them, but otherwise plain headings are preferred. -Scripts have link targets created automatically. + build-now [] + build-now here [] + build-now [ []] [] -Note that the DFHack documentation is configured so that single backticks (with -no prefix or suffix) produce links to internal link targets, such as the -``autolabor`` target shown above. This is different from the reStructuredText -default behavior of rendering such text in italics (as a reference to a title). -For alternative link behaviors, see: + Where the optional ```` pair can be used to specify the + coordinate bounds within which ``build-now`` will operate. If + they are not specified, ``build-now`` will scan the entire map. + If only one ```` is specified, only the building at that + coordinate is built. -- `The reStructuredText documentation on roles `__ -- `The reStructuredText documentation on external links `__ -- `The Sphinx documentation on roles `__ + The ```` parameters can either be an ``,,`` triple + (e.g. ``35,12,150``) or the string ``here``, which means the + position of the active game cursor. + +The second option is to arrange the usage options in a list, with the full command +and arguments in monospaced font. Then indent the next line and describe the effect:: + + Usage + ----- + + ``build-now []`` + Scan the entire map and build all unsuspended constructions + and buildings. + ``build-now here []`` + Build the unsuspended construction or building under the + cursor. + ``build-now [ []] []`` + Build all unsuspended constructions within the specified + coordinate box. + + The ```` parameters are specified as... + +Note that in both options, the entire commandline syntax is written, including the command itself. +Literal text is written as-is (e.g. the word ``here`` in the above example), and text that +describes the kind of parameter that is being passed (e.g. ``pos`` or ``options``) is enclosed in +angle brackets (``<`` and ``>``). Optional elements are enclosed in square brackets (``[`` and ``]``). +If the command takes an arbitrary number of elements, use ``...``, for example:: + + prioritize [] [ ...] + +Examples +-------- + +If the only way to run the command is to type the command itself, then this section is not necessary. +Otherwise, please consider adding a section that shows some real, practical usage examples. For +many users, this will be the **only** section they will read. It is so important that it is a good +idea to include the ``Examples`` section **before** you describe any extended options your command +might take. Write examples for what you expect the popular use cases will be. Also be sure to write +examples showing specific, practical values being used for any parameter that takes a value. + +Examples should go in their own subheading with a single dash underline (``--------``). The examples +themselves should be organized in a list, the same as in option 2 for Usage above. Here is an +example Examples section:: + + Examples + -------- + + ``build-now`` + Completes all unsuspended construction jobs on the map. + ``build-now 37,20,154 here`` + Builds the unsuspended, unconstructed buildings in the box + bounded by the coordinate x=37,y=20,z=154 and the cursor. + +Options +------- + +The options header should follow the examples, with each option in the same list format as the +examples:: + + Options + ------- + + ``-h``, ``--help`` + Show help text. + ``-l``, ``--quality `` + Set the quality of the architecture for built architected + builtings. + ``-q``, ``--quiet`` + Suppress informational output (error messages are still + printed). + +Note that for parameters that have both short and long forms, any values that those options +take only need to be specified once (e.g. ````). + +External scripts and plugins +============================ + +Scripts and plugins distributed separately from DFHack's release packages don't have the +opportunity to add their documentation to the rendered HTML or text output. However, these +scripts and plugins can use a different mechanism to at least make their help text available +in-game. + +Note that since help text for external scripts and plugins is not rendered by Sphinx, +it should be written in plain text. Any reStructuredText markup will not be processed. + +For external scripts, the short description comes from a comment on the first line +(the comment marker and extra whitespace is stripped). For Lua, this would look like: - - ``:doc:`` is useful for linking to another document +.. code-block:: lua + + -- A short description of my cool script. + +and for Ruby scripts it would look like: + +.. code-block:: ruby + + # A short description of my cool script. + +The main help text for an external script needs to appear between two markers. For +Lua, these markers are ``[====[`` and ``]====]``, and for Ruby they are ``=begin`` and +``=end``. The documentation standards above still apply to external tools, but there is +no need to include backticks for links or monospaced fonts. Here is a Lua example for an +entire script header:: + + -- Inventory management for adventurers. + -- [====[ + gui/adv-inventory + ================= + Tags: adventure, items + + Allows you to quickly move items between containers. This + includes yourself and any followers you have. + + Usage: + + gui/adv-inventory [] + + Examples: + + gui/adv-inventory + Opens the GUI with nothing preselected + gui/adv-inventory take-all + Opens the GUI with all container items already selected and + ready to move into the adventurer's inventory. + + Options: + + take-all + Starts the GUI with container items pre-selected + give-all + Starts the GUI with your own items pre-selected + ]====] + +For external plugins, help text for provided commands can be passed as the ``usage`` +parameter when registering the commands with the ``PluginCommand`` constructor. There +is currently no way for associating help text with the plugin itself, so any +information about what the plugin does when enabled should be combined into the command +help. Required dependencies ===================== @@ -258,33 +460,48 @@ ways to do this: * On Windows, if you prefer to use the batch scripts, you can run ``generate-msvc-gui.bat`` and set ``BUILD_DOCS`` through the GUI. If you are running another file, such as ``generate-msvc-all.bat``, you will need to edit - it to add the flag. You can also run ``cmake`` on the command line, similar to - other platforms. + the batch script to add the flag. You can also run ``cmake`` on the command line, + similar to other platforms. -The generated documentation will be stored in ``docs/html`` in the root DFHack -folder, and will be installed to ``hack/docs`` when you next install DFHack in a -DF folder. +By default, both HTML and text docs are built by CMake. The generated +documentation is stored in ``docs/html`` and ``docs/text`` (respectively) in the +root DFHack folder, and will be installed to ``hack/docs`` when you install +DFHack. Running Sphinx manually ----------------------- You can also build the documentation without running CMake - this is faster if -you only want to rebuild the documentation regardless of any code changes. There -is a ``docs/build.sh`` script provided for Linux and macOS that will run -essentially the same command that CMake runs when building the docs - see the -script for additional options. +you only want to rebuild the documentation regardless of any code changes. The +``docs/build.py`` script will build the documentation in any specified formats +(HTML only by default) using essentially the same command that CMake runs when +building the docs. Run the script with ``--help`` to see additional options. + +Examples: + +* ``docs/build.py`` + Build just the HTML docs + +* ``docs/build.py html text`` + Build both the HTML and text docs -To build the documentation with default options, run the following command from -the root DFHack folder:: +* ``docs/build.py --clean`` + Build HTML and force a clean build (all source files are re-read) + +The resulting documentation will be stored in ``docs/html`` and/or ``docs/text``. + +Alternatively, you can run Sphinx manually with:: sphinx-build . docs/html -The resulting documentation will be stored in ``docs/html`` (you can specify -a different path when running ``sphinx-build`` manually, but be warned that -Sphinx may overwrite existing files in this folder). +or, to build plain-text output:: + + sphinx-build -b text . docs/text Sphinx has many options to enable clean builds, parallel builds, logging, and -more - run ``sphinx-build --help`` for details. +more - run ``sphinx-build --help`` for details. If you specify a different +output path, be warned that Sphinx may overwrite existing files in the output +folder. Building a PDF version ---------------------- @@ -295,10 +512,11 @@ want to build a PDF version locally, you will need ``pdflatex``, which is part of a TeX distribution. The following command will then build a PDF, located in ``docs/pdf/latex/DFHack.pdf``, with default options:: - sphinx-build -M latexpdf . docs/pdf + docs/build.py pdf + +Alternatively, you can run Sphinx manually with:: -There is a ``docs/build-pdf.sh`` script provided for Linux and macOS that runs -this command for convenience - see the script for additional options. + sphinx-build -M latexpdf . docs/pdf .. _build-changelog: @@ -318,10 +536,10 @@ changelogs are combined as part of the changelog build process: * ``scripts/changelog.txt`` for changes made to scripts in the ``scripts`` repo * ``library/xml/changelog.txt`` for changes made in the ``df-structures`` repo -Building the changelogs generates two files: ``docs/_auto/news.rst`` and -``docs/_auto/news-dev.rst``. These correspond to `changelog` and `dev-changelog` -and contain changes organized by stable and development DFHack releases, -respectively. For example, an entry listed under "0.44.05-alpha1" in +Building the changelogs generates two files: ``docs/changelogs/news.rst`` and +``docs/changelogs/news-dev.rst``. These correspond to `changelog` and +`dev-changelog` and contain changes organized by stable and development DFHack +releases, respectively. For example, an entry listed under "0.44.05-alpha1" in changelog.txt will be listed under that version in the development changelog as well, but under "0.44.05-r1" in the stable changelog (assuming that is the closest stable release after 0.44.05-alpha1). An entry listed under a stable diff --git a/docs/History.rst b/docs/History.rst index dc02d02b0..67b65f3bc 100644 --- a/docs/History.rst +++ b/docs/History.rst @@ -1350,7 +1350,7 @@ Misc improvements - `createitem`: in adventure mode it now defaults to the controlled unit as maker. - `autotrade`: adds "(Un)mark All" options to both panes of trade screen. - `mousequery`: several usability improvements; show live overlay (in menu area) of what's on the tile under the mouse cursor. -- `search`: workshop profile search added. +- `search-plugin`: workshop profile search added. - `dwarfmonitor`: add screen to summarise preferences of fortress dwarfs. - `getplants`: add autochop function to automate woodcutting. - `stocks`: added more filtering and display options. @@ -1510,7 +1510,7 @@ New binary patches New Plugins ----------- - `fix-armory`: Together with a couple of binary patches and the `gui/assign-rack` script, this plugin makes weapon racks, armor stands, chests and cabinets in properly designated barracks be used again for storage of squad equipment. -- `search`: Adds an incremental search function to the Stocks, Trading, Stockpile and Unit List screens. +- `search-plugin`: Adds an incremental search function to the Stocks, Trading, Stockpile and Unit List screens. - `automaterial`: Makes building constructions (walls, floors, fortifications, etc) a little bit easier by saving you from having to trawl through long lists of materials each time you place one. - Dfusion: Reworked to make use of lua modules, now all the scripts can be used from other scripts. - Eventful: A collection of lua events, that will allow new ways to interact with df world. diff --git a/docs/Installing.rst b/docs/Installing.rst index 5b564f45f..05db198b8 100644 --- a/docs/Installing.rst +++ b/docs/Installing.rst @@ -96,13 +96,14 @@ When you `download DFHack `, you will end up with a release archive operating system should have built-in utilities capable of extracting files from these archives. -The release archives contain several files and folders, including a ``hack`` -folder, a ``dfhack-config`` folder, and a ``dfhack.init-example`` file. To -install DFHack, copy all of the files from the DFHack archive into the root DF -folder, which should already include a ``data`` folder and a ``raw`` folder, -among other things. Some packs and other redistributions of Dwarf Fortress may -place DF in another folder, so ensure that the ``hack`` folder ends up next to -the ``data`` folder. +The release archives contain several folders, including a ``hack`` folder where +DFHack binary and system data is stored, a ``dfhack-config`` folder where user +data and configuration is stored, and a ``blueprints`` folder where `quickfort` +blueprints are stored. To install DFHack, copy all of the files from the DFHack +archive into the root DF folder, which should already include a ``data`` folder +and a ``raw`` folder, among other things. Some packs and other redistributions +of Dwarf Fortress may place DF in another folder, so ensure that the ``hack`` +folder ends up next to the ``data`` folder. .. note:: diff --git a/docs/Introduction.rst b/docs/Introduction.rst index 27c887a8b..ad24f8f43 100644 --- a/docs/Introduction.rst +++ b/docs/Introduction.rst @@ -21,7 +21,7 @@ enhancements by default, and more can be enabled. There are also many tools You can even add third-party scripts and plugins to do almost anything! For modders, DFHack makes many things possible. Custom reactions, new -interactions, magic creature abilities, and more can be set through `scripts-modtools` +interactions, magic creature abilities, and more can be set through `DFHack tools ` and custom raws. Non-standard DFHack scripts and inits can be stored in the raw directory, making raws or saves fully self-contained for distribution - or for coexistence in a single DF install, even with incompatible components. @@ -59,7 +59,43 @@ used by the DFHack console. * Finally, some commands are persistent once enabled, and will sit in the background managing or changing some aspect of the game if you `enable` them. +.. note:: + In order to avoid user confusion, as a matter of policy all GUI tools + display the word :guilabel:`DFHack` on the screen somewhere while active. + + When that is not appropriate because they merely add keybinding hints to + existing DF screens, they deliberately use red instead of green for the key. + +.. _support: Getting help ============ -There are several support channels available - see `support` for details. + +DFHack has several ways to get help online, including: + +- The `DFHack Discord server `__ +- The ``#dfhack`` IRC channel on `Libera `__ +- GitHub: + - for bugs, use the :issue:`issue tracker <>` + - for more open-ended questions, use the `discussion board + `__. Note that this is a + relatively-new feature as of 2021, but maintainers should still be + notified of any discussions here. +- The `DFHack thread on the Bay 12 Forum `__ + +Some additional, but less DFHack-specific, places where questions may be answered include: + +- The `/r/dwarffortress `_ questions thread on Reddit +- If you are using a starter pack, the relevant thread on the `Bay 12 Forum `__ - + see the :wiki:`DF Wiki ` for a list of these threads + +When reaching out to any support channels regarding problems with DFHack, please +remember to provide enough details for others to identify the issue. For +instance, specific error messages (copied text or screenshots) are helpful, as +well as any steps you can follow to reproduce the problem. Sometimes, log output +from ``stderr.log`` in the DF folder can point to the cause of issues as well. + +Some common questions may also be answered in documentation, including: + +- This documentation (`online here `__; search functionality available `here `) +- :wiki:`The DF wiki <>` diff --git a/docs/Lua API.rst b/docs/Lua API.rst index b60b67612..b0891da57 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -929,9 +929,9 @@ can be omitted. The following examples are equivalent:: - dfhack.run_command({'ls', '-a'}) - dfhack.run_command('ls', '-a') - dfhack.run_command('ls -a') -- not recommended + dfhack.run_command({'ls', 'quick'}) + dfhack.run_command('ls', 'quick') + dfhack.run_command('ls quick') -- not recommended * ``dfhack.run_command_silent(command[, ...])`` @@ -1993,6 +1993,12 @@ Functions: Returns: *tile, tile_grayscale*, or *nil* if not found. The values can then be used for the *tile* field of *pen* structures. +* ``dfhack.screen.hideGuard(screen,callback[,args...])`` + + Removes screen from the viewscreen stack, calls the callback (with optional + supplied arguments), and then restores the screen on the top of the viewscreen + stack. + * ``dfhack.screen.clear()`` Fills the screen with blank background. @@ -3109,9 +3115,11 @@ Each entry has several properties associated with it: Returns the short (~54 character) description for the given entry. -* ``helpdb.get_entry_long_help(entry)`` +* ``helpdb.get_entry_long_help(entry[, width])`` - Returns the full help text for the given entry. + Returns the full help text for the given entry. If ``width`` is specified, the + text will be wrapped at that width, preserving block indents. The wrap width + defaults to 80. * ``helpdb.get_entry_tags(entry)`` @@ -3987,6 +3995,9 @@ Attributes: widgets while it has focus. You can set this to ``true``, for example, if you don't want a ``List`` widget to react to arrow keys while the user is editing. +:ignore_keys: If specified, must be a list of key names that the edit field + should ignore. This is useful if you have plain string characters + that you want to use as hotkeys (like ``+``). An ``EditField`` will only read and process text input if it has keyboard focus. It will automatically acquire keyboard focus when it is added as a subview to @@ -4029,13 +4040,17 @@ It has the following attributes: keys to the number of lines to scroll as positive or negative integers or one of the keywords supported by the ``scroll`` method. The default is up/down arrows scrolling by one line and page up/down scrolling by one page. -:show_scroll_icons: Controls scroll icons' behaviour: ``false`` for no icons, ``'right'`` or ``'left'`` for +:show_scrollbar: Controls scrollbar display: ``false`` for no scrollbar, ``'right'`` or ``'left'`` for icons next to the text in an additional column (``frame_inset`` is adjusted to have ``.r`` or ``.l`` greater than ``0``), ``nil`` same as ``'right'`` but changes ``frame_inset`` only if a scroll icon is actually necessary (if ``getTextHeight()`` is greater than ``frame_body.height``). Default is ``nil``. -:up_arrow_icon: The symbol for scroll up arrow. Default is ``string.char(24)`` (``↑``). -:down_arrow_icon: The symbol for scroll down arrow. Default is ``string.char(25)`` (``↓``). -:scroll_icon_pen: Specifies the pen for scroll icons. Default is ``COLOR_LIGHTCYAN``. +:scrollbar_fg: Specifies the pen for the scroll icons and the active part of the bar. Default is ``COLOR_LIGHTGREEN`` (the same as the native DF help screens). +:scrollbar_bg: Specifies the pen for the background part of the scrollbar. Default is ``COLOR_CYAN`` (the same as the native DF help screens). + +If the scrollbar is shown, it will react to mouse clicks on the scrollbar itself. +Clicking on the arrows at the top or the bottom will scroll by one line, and +clicking on the unfilled portion of the scrollbar will scroll by a half page in +that direction. The text itself is represented as a complex structure, and passed to the object via the ``text`` argument of the constructor, or via @@ -4312,6 +4327,7 @@ supports: :edit_pen: If specified, used instead of ``cursor_pen`` for the edit field. :edit_below: If true, the edit field is placed below the list instead of above. :edit_key: If specified, the edit field is disabled until this key is pressed. +:edit_ignore_keys: If specified, must be a list of key names that the filter edit field should ignore. :not_found_label: Specifies the text of the label shown when no items match the filter. The list choices may include the following attributes: @@ -4394,7 +4410,7 @@ blueprint files: The names of the functions are also available as the keys of the ``valid_phases`` table. -.. _building-hacks: +.. _building-hacks-api: building-hacks ============== @@ -4533,7 +4549,7 @@ Native functions: The lua module file also re-exports functions from ``dfhack.burrows``. -.. _cxxrandom: +.. _cxxrandom-api: cxxrandom ========= @@ -4703,7 +4719,7 @@ The dig-now plugin exposes the following functions to Lua: command ``dig-now ``. See the `dig-now` documentation for details on default settings. -.. _eventful: +.. _eventful-api: eventful ======== @@ -4871,7 +4887,7 @@ Integrated tannery:: b=require "plugins.eventful" b.addReactionToShop("TAN_A_HIDE","LEATHERWORKS") -.. _luasocket: +.. _luasocket-api: luasocket ========= @@ -4942,7 +4958,7 @@ A class with all the tcp functionality. Tries connecting to that address and port. Returns ``client`` object. -.. _map-render: +.. _map-render-api: map-render ========== @@ -4958,7 +4974,7 @@ Functions returns a table with w*h*4 entries of rendered tiles. The format is same as ``df.global.gps.screen`` (tile,foreground,bright,background). -.. _pathable: +.. _pathable-api: pathable ======== @@ -4992,7 +5008,7 @@ sort The `sort ` plugin does not export any native functions as of now. Instead, it calls Lua code to perform the actual ordering of list items. -.. _xlsxreader: +.. _xlsxreader-api: xlsxreader ========== diff --git a/docs/Memory-research.rst b/docs/Memory-research.rst index 9729072f5..d9c0833e3 100644 --- a/docs/Memory-research.rst +++ b/docs/Memory-research.rst @@ -63,7 +63,7 @@ are not built by default, but can be built by setting the ``BUILD_DEVEL`` Scripts ~~~~~~~ -Several `development scripts ` can be useful for memory research. +Several `development tools ` can be useful for memory research. These include (but are not limited to): - `devel/dump-offsets` diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index f0c47fe96..f77737176 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -17,4 +17,4 @@ See `changelog` for a list of changes grouped by stable releases. :local: :depth: 1 -.. include:: /docs/_auto/news-dev.rst +.. include:: /docs/changelogs/news-dev.rst diff --git a/docs/NEWS.rst b/docs/NEWS.rst index 1283b079a..fb33aebf9 100644 --- a/docs/NEWS.rst +++ b/docs/NEWS.rst @@ -17,7 +17,7 @@ See `dev-changelog` for a list of changes grouped by development releases. :local: :depth: 1 -.. include:: /docs/_auto/news.rst +.. include:: /docs/changelogs/news.rst Older Changelogs diff --git a/docs/Plugins.rst b/docs/Plugins.rst deleted file mode 100644 index 8acddfc6d..000000000 --- a/docs/Plugins.rst +++ /dev/null @@ -1,3436 +0,0 @@ -.. _plugins-index: - -############## -DFHack Plugins -############## - -DFHack plugins are the commands, that are compiled with a specific version. -They can provide anything from a small keybinding, to a complete overhaul of -game subsystems or the entire renderer. - -Most commands offered by plugins are listed here, -hopefully organised in a way you will find useful. - -.. contents:: Contents - :local: - :depth: 2 - -======== -Bugfixes -======== - -.. contents:: - :local: - -.. _fix-armory: - -fix-armory -========== -`This plugin requires a binpatch `, which has not -been available since DF 0.34.11 - -.. _fix-unit-occupancy: - -fix-unit-occupancy -================== -This plugin fixes issues with unit occupancy, notably phantom -"unit blocking tile" messages (:bug:`3499`). It can be run manually, or -periodically when enabled with the built-in enable/disable commands: - -:(no argument): Run the plugin once immediately, for the whole map. -:-h, here, cursor: Run immediately, only operate on the tile at the cursor -:-n, dry, dry-run: Run immediately, do not write changes to map -:interval : Run the plugin every ``X`` ticks (when enabled). - The default is 1200 ticks, or 1 day. - Ticks are only counted when the game is unpaused. - -.. _fixveins: - -fixveins -======== -Removes invalid references to mineral inclusions and restores missing ones. -Use this if you broke your embark with tools like `tiletypes`, or if you -accidentally placed a construction on top of a valuable mineral floor. - -.. _petcapRemover: - -petcapRemover -============= -Allows you to remove or raise the pet population cap. In vanilla -DF, pets will not reproduce unless the population is below 50 and the number of -children of that species is below a certain percentage. This plugin allows -removing the second restriction and removing or raising the first. Pets still -require PET or PET_EXOTIC tags in order to reproduce. Type ``help petcapRemover`` -for exact usage. In order to make population more stable and avoid sudden -population booms as you go below the raised population cap, this plugin counts -pregnancies toward the new population cap. It can still go over, but only in the -case of multiple births. - -Usage: - -:petcapRemover: cause pregnancies now and schedule the next check -:petcapRemover every n: set how often in ticks the plugin checks for possible pregnancies -:petcapRemover cap n: set the new cap to n. if n = 0, no cap -:petcapRemover pregtime n: sets the pregnancy duration to n ticks. natural pregnancies are - 300000 ticks for the current race and 200000 for everyone else - -.. _tweak: - -tweak -===== -Contains various tweaks for minor bugs. - -One-shot subcommands: - -:clear-missing: Remove the missing status from the selected unit. - This allows engraving slabs for ghostly, but not yet - found, creatures. -:clear-ghostly: Remove the ghostly status from the selected unit and mark - it as dead. This allows getting rid of bugged ghosts - which do not show up in the engraving slab menu at all, - even after using clear-missing. It works, but is - potentially very dangerous - so use with care. Probably - (almost certainly) it does not have the same effects like - a proper burial. You've been warned. -:fixmigrant: Remove the resident/merchant flag from the selected unit. - Intended to fix bugged migrants/traders who stay at the - map edge and don't enter your fort. Only works for - dwarves (or generally the player's race in modded games). - Do NOT abuse this for 'real' caravan merchants (if you - really want to kidnap them, use 'tweak makeown' instead, - otherwise they will have their clothes set to forbidden etc). -:makeown: Force selected unit to become a member of your fort. - Can be abused to grab caravan merchants and escorts, even if - they don't belong to the player's race. Foreign sentients - (humans, elves) can be put to work, but you can't assign rooms - to them and they don't show up in DwarfTherapist because the - game treats them like pets. Grabbing draft animals from - a caravan can result in weirdness (animals go insane or berserk - and are not flagged as tame), but you are allowed to mark them - for slaughter. Grabbing wagons results in some funny spam, then - they are scuttled. - -Subcommands that persist until disabled or DF quits: - -.. comment: sort these alphabetically - -:adamantine-cloth-wear: Prevents adamantine clothing from wearing out while being worn (:bug:`6481`). -:advmode-contained: Works around :bug:`6202`, custom reactions with container inputs - in advmode. The issue is that the screen tries to force you to select - the contents separately from the container. This forcefully skips child - reagents. -:block-labors: Prevents labors that can't be used from being toggled -:burrow-name-cancel: Implements the "back" option when renaming a burrow, - which currently does nothing (:bug:`1518`) -:cage-butcher: Adds an option to butcher units when viewing cages with :kbd:`q` -:civ-view-agreement: Fixes overlapping text on the "view agreement" screen -:condition-material: Fixes a crash in the work order contition material list (:bug:`9905`). -:craft-age-wear: Fixes the behavior of crafted items wearing out over time (:bug:`6003`). - With this tweak, items made from cloth and leather will gain a level of - wear every 20 years. -:do-job-now: Adds a job priority toggle to the jobs list -:embark-profile-name: Allows the use of lowercase letters when saving embark profiles -:eggs-fertile: Displays a fertility indicator on nestboxes -:farm-plot-select: Adds "Select all" and "Deselect all" options to farm plot menus -:fast-heat: Further improves temperature update performance by ensuring that 1 degree - of item temperature is crossed in no more than specified number of frames - when updating from the environment temperature. This reduces the time it - takes for stable-temp to stop updates again when equilibrium is disturbed. -:fast-trade: Makes Shift-Down in the Move Goods to Depot and Trade screens select - the current item (fully, in case of a stack), and scroll down one line. -:fps-min: Fixes the in-game minimum FPS setting -:hide-priority: Adds an option to hide designation priority indicators -:hotkey-clear: Adds an option to clear currently-bound hotkeys (in the :kbd:`H` menu) -:import-priority-category: - Allows changing the priority of all goods in a - category when discussing an import agreement with the liaison -:kitchen-prefs-all: Adds an option to toggle cook/brew for all visible items in kitchen preferences -:kitchen-prefs-color: Changes color of enabled items to green in kitchen preferences -:kitchen-prefs-empty: Fixes a layout issue with empty kitchen tabs (:bug:`9000`) -:max-wheelbarrow: Allows assigning more than 3 wheelbarrows to a stockpile -:military-color-assigned: - Color squad candidates already assigned to other squads in yellow/green - to make them stand out more in the list. - - .. image:: images/tweak-mil-color.png - -:military-stable-assign: - Preserve list order and cursor position when assigning to squad, - i.e. stop the rightmost list of the Positions page of the military - screen from constantly resetting to the top. -:nestbox-color: Fixes the color of built nestboxes -:partial-items: Displays percentages on partially-consumed items such as hospital cloth -:reaction-gloves: Fixes reactions to produce gloves in sets with correct handedness (:bug:`6273`) -:shift-8-scroll: Gives Shift-8 (or :kbd:`*`) priority when scrolling menus, instead of scrolling the map -:stable-cursor: Saves the exact cursor position between t/q/k/d/b/etc menus of fortress mode, if the - map view is near enough to its previous position. -:stone-status-all: Adds an option to toggle the economic status of all stones -:title-start-rename: Adds a safe rename option to the title screen "Start Playing" menu -:tradereq-pet-gender: Displays pet genders on the trade request screen - -.. comment: sort these alphabetically - - -=============================== -Data inspection and visualizers -=============================== - -.. contents:: - :local: - -.. _blueprint: - -blueprint -========= -The ``blueprint`` command exports the structure of a portion of your fortress in -a blueprint file that you (or anyone else) can later play back with `quickfort`. - -Blueprints are ``.csv`` or ``.xlsx`` files created in the ``blueprints`` -subdirectory of your DF folder. The map area to turn into a blueprint is either -selected interactively with the ``blueprint gui`` command or, if the GUI is not -used, starts at the active cursor location and extends right and down for the -requested width and height. - -**Usage:** - - ``blueprint [] [ []] []`` - - ``blueprint gui [ []] []`` - -**Examples:** - -``blueprint gui`` - Runs `gui/blueprint`, the interactive frontend, where all configuration for - a ``blueprint`` command can be set visually and interactively. - -``blueprint 30 40 bedrooms`` - Generates blueprints for an area 30 tiles wide by 40 tiles tall, starting - from the active cursor on the current z-level. Blueprints are written - sequentially to ``bedrooms.csv`` in the ``blueprints`` directory. - -``blueprint 30 40 bedrooms dig --cursor 108,100,150`` - Generates only the ``#dig`` blueprint in the ``bedrooms.csv`` file, and - the start of the blueprint area is set to a specific value instead of using - the in-game cursor position. - -**Positional Parameters:** - -:``width``: Width of the area (in tiles) to translate. -:``height``: Height of the area (in tiles) to translate. -:``depth``: Number of z-levels to translate. Positive numbers go *up* from the - cursor and negative numbers go *down*. Defaults to 1 if not specified, - indicating that the blueprint should only include the current z-level. -:``name``: Base name for blueprint files created in the ``blueprints`` - directory. If no name is specified, "blueprint" is used by default. The - string must contain some characters other than numbers so the name won't be - confused with the optional ``depth`` parameter. - -**Phases:** - -If you want to generate blueprints only for specific phases, add their names to -the commandline, anywhere after the blueprint base name. You can list multiple -phases; just separate them with a space. - -:``dig``: Generate quickfort ``#dig`` blueprints for digging natural stone. -:``carve``: Generate quickfort ``#dig`` blueprints for smoothing and carving. -:``build``: Generate quickfort ``#build`` blueprints for constructions and - buildings. -:``place``: Generate quickfort ``#place`` blueprints for placing stockpiles. -:``zone``: Generate quickfort ``#zone`` blueprints for designating zones. -:``query``: Generate quickfort ``#query`` blueprints for configuring rooms. - -If no phases are specified, phases are autodetected. For example, a ``#place`` -blueprint will be created only if there are stockpiles in the blueprint area. - -**Options:** - -``-c``, ``--cursor ,,``: - Use the specified map coordinates instead of the current cursor position for - the upper left corner of the blueprint range. If this option is specified, - then an active game map cursor is not necessary. -``-e``, ``--engrave``: - Record engravings in the ``carve`` phase. If this option is not specified, - engravings are ignored. -``-f``, ``--format ``: - Select the output format of the generated files. See the ``Output formats`` - section below for options. If not specified, the output format defaults to - "minimal", which will produce a small, fast ``.csv`` file. -``-h``, ``--help``: - Show command help text. -``-s``, ``--playback-start ,,``: - Specify the column and row offsets (relative to the upper-left corner of the - blueprint, which is ``1,1``) where the player should put the cursor when the - blueprint is played back with `quickfort`, in - `quickfort start marker ` format, for example: - ``10,10,central stairs``. If there is a space in the comment, you will need - to surround the parameter string in double quotes: ``"-s10,10,central stairs"`` or - ``--playback-start "10,10,central stairs"`` or - ``"--playback-start=10,10,central stairs"``. -``-t``, ``--splitby ``: - Split blueprints into multiple files. See the ``Splitting output into - multiple files`` section below for details. If not specified, defaults to - "none", which will create a standard quickfort - `multi-blueprint ` file. - -**Output formats:** - -Here are the values that can be passed to the ``--format`` flag: - -:``minimal``: - Creates ``.csv`` files with minimal file size that are fast to read and - write. This is the default. -:``pretty``: - Makes the blueprints in the ``.csv`` files easier to read and edit with a text - editor by adding extra spacing and alignment markers. - -**Splitting output into multiple files:** - -The ``--splitby`` flag can take any of the following values: - -:``none``: - Writes all blueprints into a single file. This is the standard format for - quickfort fortress blueprint bundles and is the default. -:``phase``: - Creates a separate file for each phase. - -.. _cursecheck: - -cursecheck -========== -Checks a single map tile or the whole map/world for cursed creatures (ghosts, -vampires, necromancers, werebeasts, zombies). - -With an active in-game cursor only the selected tile will be observed. -Without a cursor the whole map will be checked. - -By default cursed creatures will be only counted in case you just want to find -out if you have any of them running around in your fort. Dead and passive -creatures (ghosts who were put to rest, killed vampires, ...) are ignored. -Undead skeletons, corpses, bodyparts and the like are all thrown into the curse -category "zombie". Anonymous zombies and resurrected body parts will show -as "unnamed creature". - -Options: - -:detail: Print full name, date of birth, date of curse and some status - info (some vampires might use fake identities in-game, though). -:ids: Print the creature and race IDs. -:nick: Set the type of curse as nickname (does not always show up - in-game, some vamps don't like nicknames). -:all: Include dead and passive cursed creatures (can result in a quite - long list after having FUN with necromancers). -:verbose: Print all curse tags (if you really want to know it all). - -Examples: - -``cursecheck detail all`` - Give detailed info about all cursed creatures including deceased ones (no - in-game cursor). -``cursecheck nick`` - Give a nickname all living/active cursed creatures on the map(no in-game - cursor). - -.. note:: - - If you do a full search (with the option "all") former ghosts will show up - with the cursetype "unknown" because their ghostly flag is not set. - - Please report any living/active creatures with cursetype "unknown" - - this is most likely with mods which introduce new types of curses. - -.. _flows: - -flows -===== -A tool for checking how many tiles contain flowing liquids. If you suspect that -your magma sea leaks into HFS, you can use this tool to be sure without -revealing the map. - -.. _isoworldremote: - -isoworldremote -============== -A plugin that implements a `remote API ` used by Isoworld. - -.. _probe: - -probe -===== - -This plugin provides multiple commands that print low-level properties of the -selected objects. - -* ``probe``: prints some properties of the tile selected with :kbd:`k`. Some of - these properties can be passed into `tiletypes`. -* ``cprobe``: prints some properties of the unit selected with :kbd:`v`, as well - as the IDs of any worn items. `gui/gm-unit` and `gui/gm-editor` are more - complete in-game alternatives. -* ``bprobe``: prints some properties of the building selected with :kbd:`q` or - :kbd:`t`. `gui/gm-editor` is a more complete in-game alternative. - -.. _prospect: -.. _prospector: - -prospect -======== - -**Usage:** - - ``prospect [all|hell] []`` - -Shows a summary of resources that exist on the map. By default, only the visible -part of the map is scanned. Include the ``all`` keyword if you want ``prospect`` -to scan the whole map as if it were revealed. Use ``hell`` instead of ``all`` if -you also want to see the Z range of HFS tubes in the 'features' report section. - -**Options:** - -:``-h``, ``--help``: - Shows this help text. -:``-s``, ``--show ``: - Shows only the named comma-separated list of report sections. Report section - names are: summary, liquids, layers, features, ores, gems, veins, shrubs, - and trees. If run during pre-embark, only the layers, ores, gems, and veins - report sections are available. -:``-v``, ``--values``: - Includes material value in the output. Most useful for the 'gems' report - section. - -**Examples:** - -``prospect all`` - Shows the entire report for the entire map. - -``prospect hell --show layers,ores,veins`` - Shows only the layers, ores, and other vein stone report sections, and - includes information on HFS tubes when a fort is loaded. - -``prospect all -sores`` - Show only information about ores for the pre-embark or fortress map report. - -**Pre-embark estimate:** - -If prospect is called during the embark selection screen, it displays an -estimate of layer stone availability. If the ``all`` keyword is specified, it -also estimates ores, gems, and vein material. The estimate covers all tiles of -the embark rectangle. - -.. note:: - - The results of pre-embark prospect are an *estimate*, and can at best be - expected to be somewhere within +/- 30% of the true amount; sometimes it - does a lot worse. Especially, it is not clear how to precisely compute how - many soil layers there will be in a given embark tile, so it can report a - whole extra layer, or omit one that is actually present. - -.. _remotefortressreader: - -remotefortressreader -==================== -An in-development plugin for realtime fortress visualisation. -See :forums:`Armok Vision <146473>`. - -.. _reveal: -.. _unreveal: -.. _revtoggle: -.. _revflood: -.. _revforget: - -reveal -====== -This reveals the map. By default, HFS will remain hidden so that the demons -don't spawn. You can use ``reveal hell`` to reveal everything. With hell revealed, -you won't be able to unpause until you hide the map again. If you really want -to unpause with hell revealed, use ``reveal demons``. - -Reveal also works in adventure mode, but any of its effects are negated once -you move. When you use it this way, you don't need to run ``unreveal``. - -Usage and related commands: - -:reveal: Reveal the whole map, except for HFS to avoid demons spawning -:reveal hell: Also show hell, but requires ``unreveal`` before unpausing -:reveal demon: Reveals everything and allows unpausing - good luck! -:unreveal: Reverts the effects of ``reveal`` -:revtoggle: Switches between ``reveal`` and ``unreveal`` -:revflood: Hide everything, then reveal tiles with a path to the cursor. - Note that tiles behind constructed walls are also revealed as a - workaround for :bug:`1871`. -:revforget: Discard info about what was visible before revealing the map. - Only useful where (e.g.) you abandoned with the fort revealed - and no longer want the data. - -.. _showmood: - -showmood -======== -Shows all items needed for the currently active strange mood. - -.. _spectate: - -spectate -======== -Simple plugin to automate following random dwarves. Most of the time things will -be weighted towards z-levels with the highest job activity. Simply enter the -``spectate`` command to toggle the plugin's state. - -.. _plugin-stonesense: - -stonesense -========== -An isometric visualizer that runs in a second window. Usage: - -:stonesense: Open the visualiser in a new window. Alias ``ssense``. -:ssense overlay: Overlay DF window, replacing the map area. - -For more information, see `the full Stonesense README `. - -=========================== -Job and Fortress management -=========================== - -.. contents:: - :local: - - -.. _autobutcher: - -autobutcher -=========== -Assigns lifestock for slaughter once it reaches a specific count. Requires that -you add the target race(s) to a watch list. Only tame units will be processed. - -Units will be ignored if they are: - -* Nicknamed (for custom protection; you can use the `rename` ``unit`` tool - individually, or `zone` ``nick`` for groups) -* Caged, if and only if the cage is defined as a room (to protect zoos) -* Trained for war or hunting - -Creatures who will not reproduce (because they're not interested in the -opposite sex or have been gelded) will be butchered before those who will. -Older adults and younger children will be butchered first if the population -is above the target (default 1 male, 5 female kids and adults). Note that -you may need to set a target above 1 to have a reliable breeding population -due to asexuality etc. See `fix-ster` if this is a problem. - -Options: - -:example: Print some usage examples. -:start: Start running every X frames (df simulation ticks). - Default: X=6000, which would be every 60 seconds at 100fps. -:stop: Stop running automatically. -:sleep : Changes the timer to sleep X frames between runs. -:watch R: Start watching a race. R can be a valid race RAW id (ALPACA, - BIRD_TURKEY, etc) or a list of ids seperated by spaces or - the keyword 'all' which affects all races on your current - watchlist. -:unwatch R: Stop watching race(s). The current target settings will be - remembered. R can be a list of ids or the keyword 'all'. -:forget R: Stop watching race(s) and forget it's/their target settings. - R can be a list of ids or the keyword 'all'. -:autowatch: Automatically adds all new races (animals you buy from merchants, - tame yourself or get from migrants) to the watch list using - default target count. -:noautowatch: Stop auto-adding new races to the watchlist. -:list: Print the current status and watchlist. -:list_export: Print the commands needed to set up status and watchlist, - which can be used to import them to another save (see notes). -:target : - Set target count for specified race(s). The first four arguments - are the number of female and male kids, and female and male adults. - R can be a list of spceies ids, or the keyword ``all`` or ``new``. - ``R = 'all'``: change target count for all races on watchlist - and set the new default for the future. ``R = 'new'``: don't touch - current settings on the watchlist, only set the new default - for future entries. -:list_export: Print the commands required to rebuild your current settings. - -.. note:: - - Settings and watchlist are stored in the savegame, so that you can have - different settings for each save. If you want to copy your watchlist to - another savegame you must export the commands required to recreate your settings. - - To export, open an external terminal in the DF directory, and run - ``dfhack-run autobutcher list_export > filename.txt``. To import, load your - new save and run ``script filename.txt`` in the DFHack terminal. - - -Examples: - -You want to keep max 7 kids (4 female, 3 male) and max 3 adults (2 female, -1 male) of the race alpaca. Once the kids grow up the oldest adults will get -slaughtered. Excess kids will get slaughtered starting with the youngest -to allow that the older ones grow into adults. Any unnamed cats will -be slaughtered as soon as possible. :: - - autobutcher target 4 3 2 1 ALPACA BIRD_TURKEY - autobutcher target 0 0 0 0 CAT - autobutcher watch ALPACA BIRD_TURKEY CAT - autobutcher start - -Automatically put all new races onto the watchlist and mark unnamed tame units -for slaughter as soon as they arrive in your fort. Settings already made -for specific races will be left untouched. :: - - autobutcher target 0 0 0 0 new - autobutcher autowatch - autobutcher start - -Stop watching the races alpaca and cat, but remember the target count -settings so that you can use 'unwatch' without the need to enter the -values again. Note: 'autobutcher unwatch all' works, but only makes sense -if you want to keep the plugin running with the 'autowatch' feature or manually -add some new races with 'watch'. If you simply want to stop it completely use -'autobutcher stop' instead. :: - - autobutcher unwatch ALPACA CAT - -.. _autochop: - -autochop -======== -Automatically manage tree cutting designation to keep available logs withing given -quotas. - -Open the dashboard by running:: - - enable autochop - -The plugin must be activated (with :kbd:`d`-:kbd:`t`-:kbd:`c`-:kbd:`a`) before -it can be used. You can then set logging quotas and restrict designations to -specific burrows (with 'Enter') if desired. The plugin's activity cycle runs -once every in game day. - -If you add ``enable autochop`` to your dfhack.init there will be a hotkey to -open the dashboard from the chop designation menu. - -.. _autoclothing: - -autoclothing -============ - -Automatically manage clothing work orders, allowing the user to set how many of -each clothing type every citizen should have. Usage:: - - autoclothing [number] - -Examples: - -* ``autoclothing cloth "short skirt" 10``: - Sets the desired number of cloth short skirts available per citizen to 10. -* ``autoclothing cloth dress``: - Displays the currently set number of cloth dresses chosen per citizen. - -.. _autodump: - -autodump -======== -This plugin adds an option to the :kbd:`q` menu for stckpiles when `enabled `. -When autodump is enabled for a stockpile, any items placed in the stockpile will -automatically be designated to be dumped. - -Alternatively, you can use it to quickly move all items designated to be dumped. -Items are instantly moved to the cursor position, the dump flag is unset, -and the forbid flag is set, as if it had been dumped normally. -Be aware that any active dump item tasks still point at the item. - -Cursor must be placed on a floor tile so the items can be dumped there. - -Options: - -:destroy: Destroy instead of dumping. Doesn't require a cursor. - If called again before the game is resumed, cancels destroy. -:destroy-here: As ``destroy``, but only the selected item in the :kbd:`k` list, - or inside a container. - Alias ``autodump-destroy-here``, for keybindings. - :dfhack-keybind:`autodump-destroy-here` -:visible: Only process items that are not hidden. -:hidden: Only process hidden items. -:forbidden: Only process forbidden items (default: only unforbidden). - -``autodump-destroy-item`` destroys the selected item, which may be selected -in the :kbd:`k` list, or inside a container. If called again before the game -is resumed, cancels destruction of the item. -:dfhack-keybind:`autodump-destroy-item` - -.. _autofarm: - -autofarm -======== - -Automatically handles crop selection in farm plots based on current plant -stocks, and selects crops for planting if current stock is below a threshold. -Selected crops are dispatched on all farmplots. (Note that this plugin replaces -an older Ruby script of the same name.) - -Use the `enable` or `disable ` commands to change whether this plugin is -enabled. - -Usage: - -* ``autofarm runonce``: - Updates all farm plots once, without enabling the plugin -* ``autofarm status``: - Prints status information, including any applied limits -* ``autofarm default 30``: - Sets the default threshold -* ``autofarm threshold 150 helmet_plump tail_pig``: - Sets thresholds of individual plants - -.. _autogems: - -autogems -======== -Creates a new Workshop Order setting, automatically cutting rough gems -when `enabled `. - -See `gui/autogems` for a configuration UI. If necessary, the ``autogems-reload`` -command reloads the configuration file produced by that script. - -.. _autohauler: - -autohauler -========== -Autohauler is an autolabor fork. - -Rather than the all-of-the-above means of autolabor, autohauler will instead -only manage hauling labors and leave skilled labors entirely to the user, who -will probably use Dwarf Therapist to do so. - -Idle dwarves will be assigned the hauling labors; everyone else (including -those currently hauling) will have the hauling labors removed. This is to -encourage every dwarf to do their assigned skilled labors whenever possible, -but resort to hauling when those jobs are not available. This also implies -that the user will have a very tight skill assignment, with most skilled -labors only being assigned to just one dwarf, no dwarf having more than two -active skilled labors, and almost every non-military dwarf having at least -one skilled labor assigned. - -Autohauler allows skills to be flagged as to prevent hauling labors from -being assigned when the skill is present. By default this is the unused -ALCHEMIST labor but can be changed by the user. - -.. _autolabor: - -autolabor -========= -Automatically manage dwarf labors to efficiently complete jobs. -Autolabor tries to keep as many dwarves as possible busy but -also tries to have dwarves specialize in specific skills. - -The key is that, for almost all labors, once a dwarf begins a job it will finish that -job even if the associated labor is removed. Autolabor therefore frequently checks -which dwarf or dwarves should take new jobs for that labor, and sets labors accordingly. -Labors with equipment (mining, hunting, and woodcutting), which are abandoned -if labors change mid-job, are handled slightly differently to minimise churn. - -.. warning:: - - *autolabor will override any manual changes you make to labors while - it is enabled, including through other tools such as Dwarf Therapist* - -Simple usage: - -:enable autolabor: Enables the plugin with default settings. (Persistent per fortress) -:disable autolabor: Disables the plugin. - -Anything beyond this is optional - autolabor works well on the default settings. - -By default, each labor is assigned to between 1 and 200 dwarves (2-200 for mining). -By default 33% of the workforce become haulers, who handle all hauling jobs as well -as cleaning, pulling levers, recovering wounded, removing constructions, and filling ponds. -Other jobs are automatically assigned as described above. Each of these settings can be adjusted. - -Jobs are rarely assigned to nobles with responsibilities for meeting diplomats or merchants, -never to the chief medical dwarf, and less often to the bookeeper and manager. - -Hunting is never assigned without a butchery, and fishing is never assigned without a fishery. - -For each labor a preference order is calculated based on skill, biased against masters of other -trades and excluding those who can't do the job. The labor is then added to the best -dwarves for that labor. We assign at least the minimum number of dwarfs, in order of preference, -and then assign additional dwarfs that meet any of these conditions: - -* The dwarf is idle and there are no idle dwarves assigned to this labor -* The dwarf has non-zero skill associated with the labor -* The labor is mining, hunting, or woodcutting and the dwarf currently has it enabled. - -We stop assigning dwarfs when we reach the maximum allowed. - -Advanced usage: - -:autolabor []: - Set number of dwarves assigned to a labor. -:autolabor haulers: Set a labor to be handled by hauler dwarves. -:autolabor disable: Turn off autolabor for a specific labor. -:autolabor reset: Return a labor to the default handling. -:autolabor reset-all: Return all labors to the default handling. -:autolabor list: List current status of all labors. -:autolabor status: Show basic status information. - -See `autolabor-artisans` for a differently-tuned setup. - -Examples: - -``autolabor MINE`` - Keep at least 5 dwarves with mining enabled. -``autolabor CUT_GEM 1 1`` - Keep exactly 1 dwarf with gemcutting enabled. -``autolabor COOK 1 1 3`` - Keep 1 dwarf with cooking enabled, selected only from the top 3. -``autolabor FEED_WATER_CIVILIANS haulers`` - Have haulers feed and water wounded dwarves. -``autolabor CUTWOOD disable`` - Turn off autolabor for wood cutting. - -.. _autonestbox: - -autonestbox -=========== -Assigns unpastured female egg-layers to nestbox zones. Requires that you create -pen/pasture zones above nestboxes. If the pen is bigger than 1x1 the nestbox -must be in the top left corner. Only 1 unit will be assigned per pen, regardless -of the size. The age of the units is currently not checked, most birds grow up -quite fast. Egglayers who are also grazers will be ignored, since confining them -to a 1x1 pasture is not a good idea. Only tame and domesticated own units are -processed since pasturing half-trained wild egglayers could destroy your neat -nestbox zones when they revert to wild. When called without options autonestbox -will instantly run once. - -Options: - -:start: Start running every X frames (df simulation ticks). - Default: X=6000, which would be every 60 seconds at 100fps. -:stop: Stop running automatically. -:sleep: Must be followed by number X. Changes the timer to sleep X - frames between runs. - -.. _clean: - -clean -===== -Cleans all the splatter that get scattered all over the map, items and -creatures. In an old fortress, this can significantly reduce FPS lag. It can -also spoil your !!FUN!!, so think before you use it. - -Options: - -:map: Clean the map tiles. By default, it leaves mud and snow alone. -:units: Clean the creatures. Will also clean hostiles. -:items: Clean all the items. Even a poisoned blade. - -Extra options for ``map``: - -:mud: Remove mud in addition to the normal stuff. -:snow: Also remove snow coverings. - -.. _cleanowned: - -cleanowned -========== -Confiscates items owned by dwarfs. By default, owned food on the floor -and rotten items are confistacted and dumped. - -Options: - -:all: confiscate all owned items -:scattered: confiscated and dump all items scattered on the floor -:x: confiscate/dump items with wear level 'x' and more -:X: confiscate/dump items with wear level 'X' and more -:dryrun: a dry run. combine with other options to see what will happen - without it actually happening. - -Example: - -``cleanowned scattered X`` - This will confiscate rotten and dropped food, garbage on the floors and any - worn items with 'X' damage and above. - -.. _dwarfmonitor: - -dwarfmonitor -============ -Records dwarf activity to measure fort efficiency. - -Options: - -:enable : Start monitoring ``mode``. ``mode`` can be "work", "misery", - "weather", or "all". This will enable all corresponding widgets, - if applicable. -:disable : Stop monitoring ``mode``, and disable corresponding widgets, if applicable. -:stats: Show statistics summary -:prefs: Show dwarf preferences summary -:reload: Reload configuration file (``dfhack-config/dwarfmonitor.json``) - -:dfhack-keybind:`dwarfmonitor` - -Widget configuration: - -The following types of widgets (defined in :file:`hack/lua/plugins/dwarfmonitor.lua`) -can be displayed on the main fortress mode screen: - -:date: Show the in-game date -:misery: Show overall happiness levels of all dwarves -:weather: Show current weather (rain/snow) -:cursor: Show the current mouse cursor position - -The file :file:`dfhack-config/dwarfmonitor.json` can be edited to control the -positions and settings of all widgets displayed. This file should contain a -JSON object with the key ``widgets`` containing an array of objects - see the -included file in the ``dfhack-config`` folder for an example: - -.. code-block:: lua - - { - "widgets": [ - { - "type": "widget type (weather, misery, etc.)", - "x": X coordinate, - "y": Y coordinate - <...additional options...> - } - ] - } - -X and Y coordinates begin at zero (in the upper left corner of the screen). -Negative coordinates will be treated as distances from the lower right corner, -beginning at 1 - e.g. an x coordinate of 0 is the leftmost column, while an x -coordinate of 1 is the rightmost column. - -By default, the x and y coordinates given correspond to the leftmost tile of -the widget. Including an ``anchor`` option set to ``right`` will cause the -rightmost tile of the widget to be located at this position instead. - -Some widgets support additional options: - -* ``date`` widget: - - * ``format``: specifies the format of the date. The following characters - are replaced (all others, such as punctuation, are not modified) - - * ``Y`` or ``y``: The current year - * ``M``: The current month, zero-padded if necessary - * ``m``: The current month, *not* zero-padded - * ``D``: The current day, zero-padded if necessary - * ``d``: The current day, *not* zero-padded - - The default date format is ``Y-M-D``, per the ISO8601_ standard. - - .. _ISO8601: https://en.wikipedia.org/wiki/ISO_8601 - -* ``cursor`` widget: - - * ``format``: Specifies the format. ``X``, ``x``, ``Y``, and ``y`` are - replaced with the corresponding cursor cordinates, while all other - characters are unmodified. - * ``show_invalid``: If set to ``true``, the mouse coordinates will both be - displayed as ``-1`` when the cursor is outside of the DF window; otherwise, - nothing will be displayed. - -.. _dwarfvet: - -dwarfvet -======== -Enables Animal Caretaker functionality - -Always annoyed your dragons become useless after a minor injury? Well, with -dwarfvet, your animals become first rate members of your fort. It can also -be used to train medical skills. - -Animals need to be treated in an animal hospital, which is simply a hospital -that is also an animal training zone. The console will print out a list on game -load, and whenever one is added or removed. Dwarfs must have the Animal Caretaker -labor to treat animals. Normal medical skills are used (and no experience is given -to the Animal Caretaker skill). - -Options: - -:enable: Enables Animal Caretakers to treat and manage animals -:disable: Turns off the plguin -:report: Reports all zones that the game considers animal hospitals - -.. _fix-job-postings: - -fix-job-postings ----------------- -This command fixes crashes caused by previous versions of workflow, mostly in -DFHack 0.40.24-r4, and should be run automatically when loading a world (but can -also be run manually if desired). - -.. _job: - -job -=== -Command for general job query and manipulation. - -Options: - -*no extra options* - Print details of the current job. The job can be selected - in a workshop, or the unit/jobs screen. -**list** - Print details of all jobs in the selected workshop. -**item-material ** - Replace the exact material id in the job item. -**item-type ** - Replace the exact item type id in the job item. - -.. _job-duplicate: - -job-duplicate -============= -In :kbd:`q` mode, when a job is highlighted within a workshop or furnace -building, calling ``job-duplicate`` instantly duplicates the job. - -:dfhack-keybind:`job-duplicate` - -.. _job-material: - -job-material -============ -Alter the material of the selected job. Similar to ``job item-material ...`` - -Invoked as:: - - job-material - -:dfhack-keybind:`job-material` - -* In :kbd:`q` mode, when a job is highlighted within a workshop or furnace, - changes the material of the job. Only inorganic materials can be used - in this mode. -* In :kbd:`b` mode, during selection of building components positions the cursor - over the first available choice with the matching material. - -.. _labormanager: - -labormanager -============ -Automatically manage dwarf labors to efficiently complete jobs. -Labormanager is derived from autolabor (above) but uses a completely -different approach to assigning jobs to dwarves. While autolabor tries -to keep as many dwarves busy as possible, labormanager instead strives -to get jobs done as quickly as possible. - -Labormanager frequently scans the current job list, current list of -dwarfs, and the map to determine how many dwarves need to be assigned to -what labors in order to meet all current labor needs without starving -any particular type of job. - -.. warning:: - - *As with autolabor, labormanager will override any manual changes you - make to labors while it is enabled, including through other tools such - as Dwarf Therapist* - -Simple usage: - -:enable labormanager: Enables the plugin with default settings. - (Persistent per fortress) - -:disable labormanager: Disables the plugin. - -Anything beyond this is optional - labormanager works fairly well on the -default settings. - -The default priorities for each labor vary (some labors are higher -priority by default than others). The way the plugin works is that, once -it determines how many of each labor is needed, it then sorts them by -adjusted priority. (Labors other than hauling have a bias added to them -based on how long it's been since they were last used, to prevent job -starvation.) The labor with the highest priority is selected, the "best -fit" dwarf for that labor is assigned to that labor, and then its -priority is *halved*. This process is repeated until either dwarfs or -labors run out. - -Because there is no easy way to detect how many haulers are actually -needed at any moment, the plugin always ensures that at least one dwarf -is assigned to each of the hauling labors, even if no hauling jobs are -detected. At least one dwarf is always assigned to construction removing -and cleaning because these jobs also cannot be easily detected. Lever -pulling is always assigned to everyone. Any dwarfs for which there are -no jobs will be assigned hauling, lever pulling, and cleaning labors. If -you use animal trainers, note that labormanager will misbehave if you -assign specific trainers to specific animals; results are only guaranteed -if you use "any trainer", and animal trainers will probably be -overallocated in any case. - -Labormanager also sometimes assigns extra labors to currently busy -dwarfs so that when they finish their current job, they will go off and -do something useful instead of standing around waiting for a job. - -There is special handling to ensure that at least one dwarf is assigned -to haul food whenever food is detected left in a place where it will rot -if not stored. This will cause a dwarf to go idle if you have no -storepiles to haul food to. - -Dwarfs who are unable to work (child, in the military, wounded, -handless, asleep, in a meeting) are entirely excluded from labor -assignment. Any dwarf explicitly assigned to a burrow will also be -completely ignored by labormanager. - -The fitness algorithm for assigning jobs to dwarfs generally attempts to -favor dwarfs who are more skilled over those who are less skilled. It -also tries to avoid assigning female dwarfs with children to jobs that -are "outside", favors assigning "outside" jobs to dwarfs who are -carrying a tool that could be used as a weapon, and tries to minimize -how often dwarfs have to reequip. - -Labormanager automatically determines medical needs and reserves health -care providers as needed. Note that this may cause idling if you have -injured dwarfs but no or inadequate hospital facilities. - -Hunting is never assigned without a butchery, and fishing is never -assigned without a fishery, and neither of these labors is assigned -unless specifically enabled. - -The method by which labormanager determines what labor is needed for a -particular job is complicated and, in places, incomplete. In some -situations, labormanager will detect that it cannot determine what labor -is required. It will, by default, pause and print an error message on -the dfhack console, followed by the message "LABORMANAGER: Game paused -so you can investigate the above message.". If this happens, please open -an issue on github, reporting the lines that immediately preceded this -message. You can tell labormanager to ignore this error and carry on by -typing ``labormanager pause-on-error no``, but be warned that some job may go -undone in this situation. - -Advanced usage: - -:labormanager enable: Turn plugin on. -:labormanager disable: Turn plugin off. -:labormanager priority : Set the priority value (see above) for labor to . -:labormanager reset : Reset the priority value of labor to its default. -:labormanager reset-all: Reset all priority values to their defaults. -:labormanager allow-fishing: Allow dwarfs to fish. *Warning* This tends to result in most of the fort going fishing. -:labormanager forbid-fishing: Forbid dwarfs from fishing. Default behavior. -:labormanager allow-hunting: Allow dwarfs to hunt. *Warning* This tends to result in as many dwarfs going hunting as you have crossbows. -:labormanager forbid-hunting: Forbid dwarfs from hunting. Default behavior. -:labormanager list: Show current priorities and current allocation stats. -:labormanager pause-on-error yes: Make labormanager pause if the labor inference engine fails. See above. -:labormanager pause-on-error no: Allow labormanager to continue past a labor inference engine failure. - -.. _nestboxes: - -nestboxes -========= - -Automatically scan for and forbid fertile eggs incubating in a nestbox. -Toggle status with `enable` or `disable `. - -.. _orders: - -orders -====== - -A plugin for manipulating manager orders. - -Subcommands: - -:list: Shows the list of previously exported orders, including the orders library. -:export NAME: Exports the current list of manager orders to a file named ``dfhack-config/orders/NAME.json``. -:import NAME: Imports manager orders from a file named ``dfhack-config/orders/NAME.json``. -:clear: Deletes all manager orders in the current embark. -:sort: Sorts current manager orders by repeat frequency so daily orders don't - prevent other orders from ever being completed: one-time orders first, then - yearly, seasonally, monthly, then finally daily. - -You can keep your orders automatically sorted by adding the following command to -your ``onMapLoad.init`` file:: - - repeat -name orders-sort -time 1 -timeUnits days -command [ orders sort ] - - -The orders library ------------------- - -DFHack comes with a library of useful manager orders that are ready for import: - -:source:`basic.json ` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This collection of orders handles basic fort necessities: - -- prepared meals and food products (and by-products like oil) -- booze/mead -- thread/cloth/dye -- pots/jugs/buckets/mugs -- bags of leather, cloth, silk, and yarn -- crafts and totems from otherwise unusable by-products -- mechanisms/cages -- splints/crutches -- lye/soap -- ash/potash -- beds/wheelbarrows/minecarts -- scrolls - -You should import it as soon as you have enough dwarves to perform the tasks. -Right after the first migration wave is usually a good time. - -:source:`furnace.json ` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This collection creates basic items that require heat. It is separated out from -``basic.json`` to give players the opportunity to set up magma furnaces first in -order to save resources. It handles: - -- charcoal (including smelting of bituminous coal and lignite) -- pearlash -- sand -- green/clear/crystal glass -- adamantine processing -- item melting - -Orders are missing for plaster powder until DF :bug:`11803` is fixed. - -:source:`military.json ` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This collection adds high-volume smelting jobs for military-grade metal ores and -produces weapons and armor: - -- leather backpacks/waterskins/cloaks/quivers/armor -- bone/wooden bolts -- smelting for platinum, silver, steel, bronze, bismuth bronze, and copper (and - their dependencies) -- bronze/bismuth bronze/copper bolts -- platinum/silver/steel/iron/bismuth bronze/bronze/copper weapons and armor, - with checks to ensure only the best available materials are being used - -If you set a stockpile to take weapons and armor of less than masterwork quality -and turn on `automelt` (like what `dreamfort` provides on its industry level), -these orders will automatically upgrade your military equipment to masterwork. -Make sure you have a lot of fuel (or magma forges and furnaces) before you turn -``automelt`` on, though! - -This file should only be imported, of course, if you need to equip a military. - -:source:`smelting.json ` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This collection adds smelting jobs for all ores. It includes handling the ores -already managed by ``military.json``, but has lower limits. This ensures all -ores will be covered if a player imports ``smelting`` but not ``military``, but -the higher-volume ``military`` orders will take priority if both are imported. - -:source:`rockstock.json ` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This collection of orders keeps a small stock of all types of rock furniture. -This allows you to do ad-hoc furnishings of guildhalls, libraries, temples, or -other rooms with `buildingplan` and your masons will make sure there is always -stock on hand to fulfill the plans. - -:source:`glassstock.json ` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Similar to ``rockstock`` above, this collection keeps a small stock of all types -of glass furniture. If you have a functioning glass industry, this is more -sustainable than ``rockstock`` since you can never run out of sand. If you have -plenty of rock and just want the variety, you can import both ``rockstock`` and -``glassstock`` to get a mixture of rock and glass furnishings in your fort. - -There are a few items that ``glassstock`` produces that ``rockstock`` does not, -since there are some items that can not be made out of rock, for example: - -- tubes and corkscrews for building magma-safe screw pumps -- windows -- terrariums (as an alternative to wooden cages) - -.. _seedwatch: - -seedwatch -========= -Watches the numbers of seeds available and enables/disables seed and plant cooking. - -Each plant type can be assigned a limit. If their number falls below that limit, -the plants and seeds of that type will be excluded from cookery. -If the number rises above the limit + 20, then cooking will be allowed. - -The plugin needs a fortress to be loaded and will deactivate automatically otherwise. -You have to reactivate with 'seedwatch start' after you load the game. - -Options: - -:all: Adds all plants from the abbreviation list to the watch list. -:start: Start watching. -:stop: Stop watching. -:info: Display whether seedwatch is watching, and the watch list. -:clear: Clears the watch list. - -Examples: - -``seedwatch MUSHROOM_HELMET_PLUMP 30`` - add ``MUSHROOM_HELMET_PLUMP`` to the watch list, limit = 30 -``seedwatch MUSHROOM_HELMET_PLUMP`` - removes ``MUSHROOM_HELMET_PLUMP`` from the watch list. -``seedwatch all 30`` - adds all plants from the abbreviation list to the watch list, the limit being 30. - -.. _spotclean: - -spotclean -========= -Works like ``clean map snow mud``, but only for the tile under the cursor. Ideal -if you want to keep that bloody entrance ``clean map`` would clean up. - -:dfhack-keybind:`spotclean` - -.. _stockflow: - -stockflow -========= -Allows the fortress bookkeeper to queue jobs through the manager, -based on space or items available in stockpiles. - -Inspired by `workflow`. - -Usage: - -``stockflow enable`` - Enable the plugin. -``stockflow disable`` - Disable the plugin. -``stockflow fast`` - Enable the plugin in fast mode. -``stockflow list`` - List any work order settings for your stockpiles. -``stockflow status`` - Display whether the plugin is enabled. - -While enabled, the :kbd:`q` menu of each stockpile will have two new options: - -* :kbd:`j`: Select a job to order, from an interface like the manager's screen. -* :kbd:`J`: Cycle between several options for how many such jobs to order. - -Whenever the bookkeeper updates stockpile records, new work orders will -be placed on the manager's queue for each such selection, reduced by the -number of identical orders already in the queue. - -In fast mode, new work orders will be enqueued once per day, instead of -waiting for the bookkeeper. - -.. _tailor: - -tailor -====== - -Whenever the bookkeeper updates stockpile records, this plugin will scan every unit in the fort, -count up the number that are worn, and then order enough more made to replace all worn items. -If there are enough replacement items in inventory to replace all worn items, the units wearing them -will have the worn items confiscated (in the same manner as the `cleanowned` plugin) so that they'll -reeequip with replacement items. - -Use the `enable` and `disable ` commands to toggle this plugin's status, or run -``tailor status`` to check its current status. - -.. _workflow: - -workflow -======== -Manage control of repeat jobs. `gui/workflow` provides a simple -front-end integrated in the game UI. - -Usage: - -``workflow enable [option...], workflow disable [option...]`` - If no options are specified, enables or disables the plugin. - Otherwise, enables or disables any of the following options: - - - drybuckets: Automatically empty abandoned water buckets. - - auto-melt: Resume melt jobs when there are objects to melt. -``workflow jobs`` - List workflow-controlled jobs (if in a workshop, filtered by it). -``workflow list`` - List active constraints, and their job counts. -``workflow list-commands`` - List active constraints as workflow commands that re-create them; - this list can be copied to a file, and then reloaded using the - ``script`` built-in command. -``workflow count [cnt-gap]`` - Set a constraint, counting every stack as 1 item. -``workflow amount [cnt-gap]`` - Set a constraint, counting all items within stacks. -``workflow unlimit `` - Delete a constraint. -``workflow unlimit-all`` - Delete all constraints. - -Function --------- -When the plugin is enabled, it protects all repeat jobs from removal. -If they do disappear due to any cause, they are immediately re-added to their -workshop and suspended. - -In addition, when any constraints on item amounts are set, repeat jobs that -produce that kind of item are automatically suspended and resumed as the item -amount goes above or below the limit. The gap specifies how much below the limit -the amount has to drop before jobs are resumed; this is intended to reduce -the frequency of jobs being toggled. - -Constraint format ------------------ -The constraint spec consists of 4 parts, separated with ``/`` characters:: - - ITEM[:SUBTYPE]/[GENERIC_MAT,...]/[SPECIFIC_MAT:...]/[LOCAL,] - -The first part is mandatory and specifies the item type and subtype, -using the raw tokens for items (the same syntax used custom reaction inputs). -For more information, see :wiki:`this wiki page `. - -The subsequent parts are optional: - -- A generic material spec constrains the item material to one of - the hard-coded generic classes, which currently include:: - - PLANT WOOD CLOTH SILK LEATHER BONE SHELL SOAP TOOTH HORN PEARL YARN - METAL STONE SAND GLASS CLAY MILK - -- A specific material spec chooses the material exactly, using the - raw syntax for reaction input materials, e.g. ``INORGANIC:IRON``, - although for convenience it also allows just ``IRON``, or ``ACACIA:WOOD`` etc. - See the link above for more details on the unabbreviated raw syntax. - -- A comma-separated list of miscellaneous flags, which currently can - be used to ignore imported items or items below a certain quality. - -Constraint examples -------------------- -Keep metal bolts within 900-1000, and wood/bone within 150-200:: - - workflow amount AMMO:ITEM_AMMO_BOLTS/METAL 1000 100 - workflow amount AMMO:ITEM_AMMO_BOLTS/WOOD,BONE 200 50 - -Keep the number of prepared food & drink stacks between 90 and 120:: - - workflow count FOOD 120 30 - workflow count DRINK 120 30 - -Make sure there are always 25-30 empty bins/barrels/bags:: - - workflow count BIN 30 - workflow count BARREL 30 - workflow count BOX/CLOTH,SILK,YARN 30 - -Make sure there are always 15-20 coal and 25-30 copper bars:: - - workflow count BAR//COAL 20 - workflow count BAR//COPPER 30 - -Produce 15-20 gold crafts:: - - workflow count CRAFTS//GOLD 20 - -Collect 15-20 sand bags and clay boulders:: - - workflow count POWDER_MISC/SAND 20 - workflow count BOULDER/CLAY 20 - -Make sure there are always 80-100 units of dimple dye:: - - workflow amount POWDER_MISC//MUSHROOM_CUP_DIMPLE:MILL 100 20 - -.. note:: - - In order for this to work, you have to set the material of the PLANT input - on the Mill Plants job to MUSHROOM_CUP_DIMPLE using the `job item-material ` - command. Otherwise the plugin won't be able to deduce the output material. - -Maintain 10-100 locally-made crafts of exceptional quality:: - - workflow count CRAFTS///LOCAL,EXCEPTIONAL 100 90 - -.. _workNow: - -workNow -======= -Don't allow dwarves to idle if any jobs are available. - -When workNow is active, every time the game pauses, DF will make dwarves -perform any appropriate available jobs. This includes when you one step -through the game using the pause menu. Usage: - -:workNow: print workNow status -:workNow 0: deactivate workNow -:workNow 1: activate workNow (look for jobs on pause, and only then) -:workNow 2: make dwarves look for jobs whenever a job completes - -.. _zone: - -zone -==== -Helps a bit with managing activity zones (pens, pastures and pits) and cages. - -:dfhack-keybind:`zone` - -Options: - -:set: Set zone or cage under cursor as default for future assigns. -:assign: Assign unit(s) to the pen or pit marked with the 'set' command. - If no filters are set a unit must be selected in the in-game ui. - Can also be followed by a valid zone id which will be set - instead. -:unassign: Unassign selected creature from it's zone. -:nick: Mass-assign nicknames, must be followed by the name you want - to set. -:remnick: Mass-remove nicknames. -:enumnick: Assign enumerated nicknames (e.g. "Hen 1", "Hen 2"...). Must be - followed by the prefix to use in nicknames. -:tocages: Assign unit(s) to cages inside a pasture. -:uinfo: Print info about unit(s). If no filters are set a unit must - be selected in the in-game ui. -:zinfo: Print info about zone(s). If no filters are set zones under - the cursor are listed. -:verbose: Print some more info. -:filters: Print list of valid filter options. -:examples: Print some usage examples. -:not: Negates the next filter keyword. - -Filters: - -:all: Process all units (to be used with additional filters). -:count: Must be followed by a number. Process only n units (to be used - with additional filters). -:unassigned: Not assigned to zone, chain or built cage. -:minage: Minimum age. Must be followed by number. -:maxage: Maximum age. Must be followed by number. -:race: Must be followed by a race RAW ID (e.g. BIRD_TURKEY, ALPACA, - etc). Negatable. -:caged: In a built cage. Negatable. -:own: From own civilization. Negatable. -:merchant: Is a merchant / belongs to a merchant. Should only be used for - pitting, not for stealing animals (slaughter should work). -:war: Trained war creature. Negatable. -:hunting: Trained hunting creature. Negatable. -:tamed: Creature is tame. Negatable. -:trained: Creature is trained. Finds war/hunting creatures as well as - creatures who have a training level greater than 'domesticated'. - If you want to specifically search for war/hunting creatures use - 'war' or 'hunting' Negatable. -:trainablewar: Creature can be trained for war (and is not already trained for - war/hunt). Negatable. -:trainablehunt: Creature can be trained for hunting (and is not already trained - for war/hunt). Negatable. -:male: Creature is male. Negatable. -:female: Creature is female. Negatable. -:egglayer: Race lays eggs. Negatable. -:grazer: Race is a grazer. Negatable. -:milkable: Race is milkable. Negatable. - -Usage with single units ------------------------ -One convenient way to use the zone tool is to bind the command 'zone assign' to -a hotkey, maybe also the command 'zone set'. Place the in-game cursor over -a pen/pasture or pit, use 'zone set' to mark it. Then you can select units -on the map (in 'v' or 'k' mode), in the unit list or from inside cages -and use 'zone assign' to assign them to their new home. Allows pitting your -own dwarves, by the way. - -Usage with filters ------------------- -All filters can be used together with the 'assign' command. - -Restrictions: It's not possible to assign units who are inside built cages -or chained because in most cases that won't be desirable anyways. -It's not possible to cage owned pets because in that case the owner -uncages them after a while which results in infinite hauling back and forth. - -Usually you should always use the filter 'own' (which implies tame) unless you -want to use the zone tool for pitting hostiles. 'own' ignores own dwarves unless -you specify 'race DWARF' (so it's safe to use 'assign all own' to one big -pasture if you want to have all your animals at the same place). 'egglayer' and -'milkable' should be used together with 'female' unless you have a mod with -egg-laying male elves who give milk or whatever. Merchants and their animals are -ignored unless you specify 'merchant' (pitting them should be no problem, -but stealing and pasturing their animals is not a good idea since currently they -are not properly added to your own stocks; slaughtering them should work). - -Most filters can be negated (e.g. 'not grazer' -> race is not a grazer). - -Mass-renaming -------------- -Using the 'nick' command you can set the same nickname for multiple units. -If used without 'assign', 'all' or 'count' it will rename all units in the -current default target zone. Combined with 'assign', 'all' or 'count' (and -further optional filters) it will rename units matching the filter conditions. - -Cage zones ----------- -Using the 'tocages' command you can assign units to a set of cages, for example -a room next to your butcher shop(s). They will be spread evenly among available -cages to optimize hauling to and butchering from them. For this to work you need -to build cages and then place one pen/pasture activity zone above them, covering -all cages you want to use. Then use 'zone set' (like with 'assign') and use -'zone tocages filter1 filter2 ...'. 'tocages' overwrites 'assign' because it -would make no sense, but can be used together with 'nick' or 'remnick' and all -the usual filters. - -Examples --------- -``zone assign all own ALPACA minage 3 maxage 10`` - Assign all own alpacas who are between 3 and 10 years old to the selected - pasture. -``zone assign all own caged grazer nick ineedgrass`` - Assign all own grazers who are sitting in cages on stockpiles (e.g. after - buying them from merchants) to the selected pasture and give them - the nickname 'ineedgrass'. -``zone assign all own not grazer not race CAT`` - Assign all own animals who are not grazers, excluding cats. -``zone assign count 5 own female milkable`` - Assign up to 5 own female milkable creatures to the selected pasture. -``zone assign all own race DWARF maxage 2`` - Throw all useless kids into a pit :) -``zone nick donttouchme`` - Nicknames all units in the current default zone or cage to 'donttouchme'. - Mostly intended to be used for special pastures or cages which are not marked - as rooms you want to protect from autobutcher. -``zone tocages count 50 own tame male not grazer`` - Stuff up to 50 owned tame male animals who are not grazers into cages built - on the current default zone. - -================ -Map modification -================ - -.. contents:: - :local: - -.. _3dveins: - -3dveins -======= -Removes all existing veins from the map and generates new ones using -3D Perlin noise, in order to produce a layout that smoothly flows between -Z levels. The vein distribution is based on the world seed, so running -the command for the second time should produce no change. It is best to -run it just once immediately after embark. - -This command is intended as only a cosmetic change, so it takes -care to exactly preserve the mineral counts reported by `prospect` ``all``. -The amounts of different layer stones may slightly change in some cases -if vein mass shifts between Z layers. - -The only undo option is to restore your save from backup. - -.. _alltraffic: - -alltraffic -========== -Set traffic designations for every single tile of the map - useful for resetting -traffic designations. See also `filltraffic`, `restrictice`, and `restrictliquids`. - -Options: - -:H: High Traffic -:N: Normal Traffic -:L: Low Traffic -:R: Restricted Traffic - -.. _burrows: - -burrows -======= -Miscellaneous burrow control. Allows manipulating burrows and automated burrow -expansion while digging. - -Options: - -:enable feature ...: - Enable features of the plugin. -:disable feature ...: - Disable features of the plugin. -:clear-unit burrow burrow ...: - Remove all units from the burrows. -:clear-tiles burrow burrow ...: - Remove all tiles from the burrows. -:set-units target-burrow src-burrow ...: - Clear target, and adds units from source burrows. -:add-units target-burrow src-burrow ...: - Add units from the source burrows to the target. -:remove-units target-burrow src-burrow ...: - Remove units in source burrows from the target. -:set-tiles target-burrow src-burrow ...: - Clear target and adds tiles from the source burrows. -:add-tiles target-burrow src-burrow ...: - Add tiles from the source burrows to the target. -:remove-tiles target-burrow src-burrow ...: - Remove tiles in source burrows from the target. - - For these three options, in place of a source burrow it is - possible to use one of the following keywords: ABOVE_GROUND, - SUBTERRANEAN, INSIDE, OUTSIDE, LIGHT, DARK, HIDDEN, REVEALED - -Features: - -:auto-grow: When a wall inside a burrow with a name ending in '+' is dug - out, the burrow is extended to newly-revealed adjacent walls. - This final '+' may be omitted in burrow name args of commands above. - Digging 1-wide corridors with the miner inside the burrow is SLOW. - -.. _changeitem: - -changeitem -========== -Allows changing item material and base quality. By default the item currently -selected in the UI will be changed (you can select items in the 'k' list -or inside containers/inventory). By default change is only allowed if materials -is of the same subtype (for example wood<->wood, stone<->stone etc). But since -some transformations work pretty well and may be desired you can override this -with 'force'. Note that some attributes will not be touched, possibly resulting -in weirdness. To get an idea how the RAW id should look like, check some items -with 'info'. Using 'force' might create items which are not touched by -crafters/haulers. - -Options: - -:info: Don't change anything, print some info instead. -:here: Change all items at the cursor position. Requires in-game cursor. -:material, m: Change material. Must be followed by valid material RAW id. -:quality, q: Change base quality. Must be followed by number (0-5). -:force: Ignore subtypes, force change to new material. - -Examples: - -``changeitem m INORGANIC:GRANITE here`` - Change material of all items under the cursor to granite. -``changeitem q 5`` - Change currently selected item to masterpiece quality. - -.. _changelayer: - -changelayer -=========== -Changes material of the geology layer under cursor to the specified inorganic -RAW material. Can have impact on all surrounding regions, not only your embark! -By default changing stone to soil and vice versa is not allowed. By default -changes only the layer at the cursor position. Note that one layer can stretch -across lots of z levels. By default changes only the geology which is linked -to the biome under the cursor. That geology might be linked to other biomes -as well, though. Mineral veins and gem clusters will stay on the map. Use -`changevein` for them. - -tl;dr: You will end up with changing quite big areas in one go, especially if -you use it in lower z levels. Use with care. - -Options: - -:all_biomes: Change selected layer for all biomes on your map. - Result may be undesirable since the same layer can AND WILL - be on different z-levels for different biomes. Use the tool - 'probe' to get an idea how layers and biomes are distributed - on your map. -:all_layers: Change all layers on your map (only for the selected biome - unless 'all_biomes' is added). - Candy mountain, anyone? Will make your map quite boring, - but tidy. -:force: Allow changing stone to soil and vice versa. !!THIS CAN HAVE - WEIRD EFFECTS, USE WITH CARE!! - Note that soil will not be magically replaced with stone. - You will, however, get a stone floor after digging so it - will allow the floor to be engraved. - Note that stone will not be magically replaced with soil. - You will, however, get a soil floor after digging so it - could be helpful for creating farm plots on maps with no - soil. -:verbose: Give some details about what is being changed. -:trouble: Give some advice about known problems. - -Examples: - -``changelayer GRANITE`` - Convert layer at cursor position into granite. -``changelayer SILTY_CLAY force`` - Convert layer at cursor position into clay even if it's stone. -``changelayer MARBLE all_biomes all_layers`` - Convert all layers of all biomes which are not soil into marble. - -.. note:: - - * If you use changelayer and nothing happens, try to pause/unpause the game - for a while and try to move the cursor to another tile. Then try again. - If that doesn't help try temporarily changing some other layer, undo your - changes and try again for the layer you want to change. Saving - and reloading your map might also help. - * You should be fine if you only change single layers without the use - of 'force'. Still it's advisable to save your game before messing with - the map. - * When you force changelayer to convert soil to stone you might experience - weird stuff (flashing tiles, tiles changed all over place etc). - Try reverting the changes manually or even better use an older savegame. - You did save your game, right? - -.. _changevein: - -changevein -========== -Changes material of the vein under cursor to the specified inorganic RAW -material. Only affects tiles within the current 16x16 block - for veins and -large clusters, you will need to use this command multiple times. - -Example: - -``changevein NATIVE_PLATINUM`` - Convert vein at cursor position into platinum ore. - -.. _cleanconst: - -cleanconst -========== -Cleans up construction materials. - -This utility alters all constructions on the map so that they spawn their -building component when they are disassembled, allowing their actual -build items to be safely deleted. This can improve FPS in extreme situations. - -.. _deramp: - -deramp -====== -Removes all ramps designated for removal from the map. This is useful for -replicating the old channel digging designation. It also removes any and -all 'down ramps' that can remain after a cave-in (you don't have to designate -anything for that to happen). - -.. _dig: -.. _digv: -.. _digvx: -.. _digl: -.. _diglx: - -dig -=== -This plugin makes many automated or complicated dig patterns easy. - -Basic commands: - -:digv: Designate all of the selected vein for digging. -:digvx: Also cross z-levels, digging stairs as needed. Alias for ``digv x``. -:digl: Like ``digv``, for layer stone. Also supports an ``undo`` option - to remove designations, for if you accidentally set 50 levels at once. -:diglx: Also cross z-levels, digging stairs as needed. Alias for ``digl x``. - -:dfhack-keybind:`digv` - -.. note:: - - All commands implemented by the `dig` plugin (listed by ``ls dig``) support - specifying the designation priority with ``-p#``, ``-p #``, or ``p=#``, - where ``#`` is a number from 1 to 7. If a priority is not specified, the - priority selected in-game is used as the default. - -.. _digcircle: - -digcircle -========= -A command for easy designation of filled and hollow circles. -It has several types of options. - -Shape: - -:hollow: Set the circle to hollow (default) -:filled: Set the circle to filled -:#: Diameter in tiles (default = 0, does nothing) - -Action: - -:set: Set designation (default) -:unset: Unset current designation -:invert: Invert designations already present - -Designation types: - -:dig: Normal digging designation (default) -:ramp: Ramp digging -:ustair: Staircase up -:dstair: Staircase down -:xstair: Staircase up/down -:chan: Dig channel - -After you have set the options, the command called with no options -repeats with the last selected parameters. - -Examples: - -``digcircle filled 3`` - Dig a filled circle with diameter = 3. -``digcircle`` - Do it again. - -.. _digexp: - -digexp -====== -This command is for :wiki:`exploratory mining `. - -There are two variables that can be set: pattern and filter. - -Patterns: - -:diag5: diagonals separated by 5 tiles -:diag5r: diag5 rotated 90 degrees -:ladder: A 'ladder' pattern -:ladderr: ladder rotated 90 degrees -:clear: Just remove all dig designations -:cross: A cross, exactly in the middle of the map. - -Filters: - -:all: designate whole z-level -:hidden: designate only hidden tiles of z-level (default) -:designated: Take current designation and apply pattern to it. - -After you have a pattern set, you can use ``expdig`` to apply it again. - -Examples: - -``expdig diag5 hidden`` - Designate the diagonal 5 patter over all hidden tiles -``expdig`` - Apply last used pattern and filter -``expdig ladder designated`` - Take current designations and replace them with the ladder pattern - -.. _digFlood: - -digFlood -======== -Automatically digs out specified veins as they are discovered. It runs once -every time a dwarf finishes a dig job. It will only dig out appropriate tiles -that are adjacent to the finished dig job. To add a vein type, use ``digFlood 1 [type]``. -This will also enable the plugin. To remove a vein type, use ``digFlood 0 [type] 1`` -to disable, then remove, then re-enable. - -Usage: - -:help digflood: detailed help message -:digFlood 0: disable the plugin -:digFlood 1: enable the plugin -:digFlood 0 MICROCLINE COAL_BITUMINOUS 1: - disable plugin, remove microcline and bituminous coal from monitoring, then re-enable the plugin -:digFlood CLEAR: remove all inorganics from monitoring -:digFlood digAll1: ignore the monitor list and dig any vein -:digFlood digAll0: disable digAll mode - -.. _digtype: - -digtype -======= -For every tile on the map of the same vein type as the selected tile, -this command designates it to have the same designation as the -selected tile. If the selected tile has no designation, they will be -dig designated. -If an argument is given, the designation of the selected tile is -ignored, and all appropriate tiles are set to the specified -designation. - -Options: - -:dig: -:channel: -:ramp: -:updown: up/down stairs -:up: up stairs -:down: down stairs -:clear: clear designation - -.. _filltraffic: - -filltraffic -=========== -Set traffic designations using flood-fill starting at the cursor. -See also `alltraffic`, `restrictice`, and `restrictliquids`. Options: - -:H: High Traffic -:N: Normal Traffic -:L: Low Traffic -:R: Restricted Traffic -:X: Fill across z-levels. -:B: Include buildings and stockpiles. -:P: Include empty space. - -Example: - -``filltraffic H`` - When used in a room with doors, it will set traffic to HIGH in just that room. - -.. _getplants: - -getplants -========= -This tool allows plant gathering and tree cutting by RAW ID. Specify the types -of trees to cut down and/or shrubs to gather by their plant names, separated -by spaces. - -Options: - -:``-t``: Tree: Select trees only (exclude shrubs) -:``-s``: Shrub: Select shrubs only (exclude trees) -:``-f``: Farming: Designate only shrubs that yield seeds for farming. Implies -s -:``-c``: Clear: Clear designations instead of setting them -:``-x``: eXcept: Apply selected action to all plants except those specified (invert - selection) -:``-a``: All: Select every type of plant (obeys ``-t``/``-s``/``-f``) -:``-v``: Verbose: Lists the number of (un)designations per plant -:``-n *``: Number: Designate up to * (an integer number) plants of each species - -Specifying both ``-t`` and ``-s`` or ``-f`` will have no effect. If no plant IDs are -specified, all valid plant IDs will be listed, with ``-t``, ``-s``, and ``-f`` -restricting the list to trees, shrubs, and farmable shrubs, respectively. - -.. note:: - - DF is capable of determining that a shrub has already been picked, leaving - an unusable structure part behind. This plugin does not perform such a check - (as the location of the required information has not yet been identified). - This leads to some shrubs being designated when they shouldn't be, causing a - plant gatherer to walk there and do nothing (except clearing the - designation). See :issue:`1479` for details. - - The implementation another known deficiency: it's incapable of detecting that - raw definitions that specify a seed extraction reaction for the structural part - but has no other use for it cannot actually yield any seeds, as the part is - never used (parts of :bug:`6940`, e.g. Red Spinach), even though DF - collects it, unless there's a workshop reaction to do it (which there isn't - in vanilla). - -.. _infiniteSky: - -infiniteSky -=========== -Automatically allocates new z-levels of sky at the top of the map as you build up, -or on request allocates many levels all at once. - -Usage: - -``infiniteSky n`` - Raise the sky by n z-levels. -``infiniteSky enable/disable`` - Enables/disables monitoring of constructions. If you build anything in the second to highest z-level, it will allocate one more sky level. This is so you can continue to build stairs upward. - -.. warning:: - - :issue:`Sometimes <254>` new z-levels disappear and cause cave-ins. - Saving and loading after creating new z-levels should fix the problem. - -.. _liquids: - -liquids -======= -Allows adding magma, water and obsidian to the game. It replaces the normal -dfhack command line and can't be used from a hotkey. Settings will be remembered -as long as dfhack runs. Intended for use in combination with the command -``liquids-here`` (which can be bound to a hotkey). See also :issue:`80`. - -.. warning:: - - Spawning and deleting liquids can mess up pathing data and - temperatures (creating heat traps). You've been warned. - -.. note:: - - `gui/liquids` is an in-game UI for this script. - -Settings will be remembered until you quit DF. You can call `liquids-here` to execute -the last configured action, which is useful in combination with keybindings. - -Usage: point the DF cursor at a tile you want to modify and use the commands. - -If you only want to add or remove water or magma from one tile, -`source` may be easier to use. - -Commands --------- -Misc commands: - -:q: quit -:help, ?: print this list of commands -:: put liquid - -Modes: - -:m: switch to magma -:w: switch to water -:o: make obsidian wall instead -:of: make obsidian floors -:rs: make a river source -:f: flow bits only -:wclean: remove salt and stagnant flags from tiles - -Set-Modes and flow properties (only for magma/water): - -:s+: only add mode -:s.: set mode -:s-: only remove mode -:f+: make the spawned liquid flow -:f.: don't change flow state (read state in flow mode) -:f-: make the spawned liquid static - -Permaflow (only for water): - -:pf.: don't change permaflow state -:pf-: make the spawned liquid static -:pf[NS][EW]: make the spawned liquid permanently flow -:0-7: set liquid amount - -Brush size and shape: - -:p, point: Single tile -:r, range: Block with cursor at bottom north-west (any place, any size) -:block: DF map block with cursor in it (regular spaced 16x16x1 blocks) -:column: Column from cursor, up through free space -:flood: Flood-fill water tiles from cursor (only makes sense with wclean) - -.. _liquids-here: - -liquids-here ------------- -Run the liquid spawner with the current/last settings made in liquids (if no -settings in liquids were made it paints a point of 7/7 magma by default). - -Intended to be used as keybinding. Requires an active in-game cursor. - -.. _plant: - -plant -===== -A tool for creating shrubs, growing, or getting rid of them. - -Subcommands: - -:create: Creates a new sapling under the cursor. Takes a raw ID as argument - (e.g. TOWER_CAP). The cursor must be located on a dirt or grass floor tile. -:grow: Turns saplings into trees; under the cursor if a sapling is selected, - or every sapling on the map if the cursor is hidden. - -For mass effects, use one of the additional options: - -:shrubs: affect all shrubs on the map -:trees: affect all trees on the map -:all: affect every plant! - -.. _regrass: - -regrass -======= -Regrows all the grass. Not much to it ;) - -.. _restrictice: - -restrictice -=========== -Restrict traffic on all tiles on top of visible ice. -See also `alltraffic`, `filltraffic`, and `restrictliquids`. - -.. _restrictliquids: - -restrictliquids -=============== -Restrict traffic on all visible tiles with liquid. -See also `alltraffic`, `filltraffic`, and `restrictice`. - -.. _tiletypes: - -tiletypes -========= -Can be used for painting map tiles and is an interactive command, much like -`liquids`. Some properties of existing tiles can be looked up with `probe`. If -something goes wrong, `fixveins` may help. - -The tool works with two set of options and a brush. The brush determines which -tiles will be processed. First set of options is the filter, which can exclude -some of the tiles from the brush by looking at the tile properties. The second -set of options is the paint - this determines how the selected tiles are -changed. - -Both paint and filter can have many different properties including things like -general shape (WALL, FLOOR, etc.), general material (SOIL, STONE, MINERAL, -etc.), state of 'designated', 'hidden' and 'light' flags. - -The properties of filter and paint can be partially defined. This means that -you can for example turn all stone fortifications into floors, preserving the -material:: - - filter material STONE - filter shape FORTIFICATION - paint shape FLOOR - -Or turn mineral vein floors back into walls:: - - filter shape FLOOR - filter material MINERAL - paint shape WALL - -The tool also allows tweaking some tile flags:: - - paint hidden 1 - paint hidden 0 - -This will hide previously revealed tiles (or show hidden with the 0 option). - -More recently, the tool supports changing the base material of the tile to -an arbitrary stone from the raws, by creating new veins as required. Note -that this mode paints under ice and constructions, instead of overwriting -them. To enable, use:: - - paint stone MICROCLINE - -This mode is incompatible with the regular ``material`` setting, so changing -it cancels the specific stone selection:: - - paint material ANY - -Since different vein types have different drop rates, it is possible to choose -which one to use in painting:: - - paint veintype CLUSTER_SMALL - -When the chosen type is ``CLUSTER`` (the default), the tool may automatically -choose to use layer stone or lava stone instead of veins if its material matches -the desired one. - -Any paint or filter option (or the entire paint or filter) can be disabled entirely by using the ANY keyword:: - - paint hidden ANY - paint shape ANY - filter material any - filter shape any - filter any - -You can use several different brushes for painting tiles: - -:point: a single tile -:range: a rectangular range -:column: a column ranging from current cursor to the first solid tile above -:block: a DF map block - 16x16 tiles, in a regular grid - -Example:: - - range 10 10 1 - -This will change the brush to a rectangle spanning 10x10 tiles on one z-level. -The range starts at the position of the cursor and goes to the east, south and -up. - -For more details, use ``tiletypes help``. - -.. _tiletypes-command: - -tiletypes-command ------------------ -Runs tiletypes commands, separated by ``;``. This makes it possible to change -tiletypes modes from a hotkey or via dfhack-run. - -Example:: - - tiletypes-command p any ; p s wall ; p sp normal - -This resets the paint filter to unsmoothed walls. - -.. _tiletypes-here: - -tiletypes-here --------------- -Apply the current tiletypes options at the in-game cursor position, including -the brush. Can be used from a hotkey. - -Options: - -:``-c``, ``--cursor ,,``: - Use the specified map coordinates instead of the current cursor position. If - this option is specified, then an active game map cursor is not necessary. -:``-h``, ``--help``: - Show command help text. -:``-q``, ``--quiet``: - Suppress non-error status output. - -.. _tiletypes-here-point: - -tiletypes-here-point --------------------- -Apply the current tiletypes options at the in-game cursor position to a single -tile. Can be used from a hotkey. - -This command supports the same options as `tiletypes-here` above. - -.. _tubefill: - -tubefill -======== -Fills all the adamantine veins again. Veins that were hollow will be left -alone. - -Options: - -:hollow: fill in naturally hollow veins too - -Beware that filling in hollow veins will trigger a demon invasion on top of -your miner when you dig into the region that used to be hollow. - - - -================= -Mods and Cheating -================= - -.. contents:: - :local: - -.. _add-spatter: - -add-spatter -=========== -This plugin makes reactions with names starting with ``SPATTER_ADD_`` -produce contaminants on the items instead of improvements. The plugin is -intended to give some use to all those poisons that can be bought from caravans, -so they're immune to being washed away by water or destroyed by `clean`. - -.. _adv-bodyswap: - -adv-bodyswap -============ -This allows taking control over your followers and other creatures in adventure -mode. For example, you can make them pick up new arms and armor and equip them -properly. - -Usage: - -* When viewing unit details, body-swaps into that unit. -* In the main adventure mode screen, reverts transient swap. - -:dfhack-keybind:`adv-bodyswap` - -.. _createitem: - -createitem -========== -Allows creating new items of arbitrary types and made of arbitrary materials. A -unit must be selected in-game to use this command. By default, items created are -spawned at the feet of the selected unit. - -Specify the item and material information as you would indicate them in -custom reaction raws, with the following differences: - -* Separate the item and material with a space rather than a colon -* If the item has no subtype, the ``:NONE`` can be omitted -* If the item is ``REMAINS``, ``FISH``, ``FISH_RAW``, ``VERMIN``, ``PET``, or ``EGG``, - specify a ``CREATURE:CASTE`` pair instead of a material token. -* If the item is a ``PLANT_GROWTH``, specify a ``PLANT_ID:GROWTH_ID`` pair - instead of a material token. - -Corpses, body parts, and prepared meals cannot be created using this tool. - -To obtain the item and material tokens of an existing item, run -``createitem inspect``. Its output can be passed directly as arguments to -``createitem`` to create new matching items, as long as the item type is -supported. - -Examples: - -* Create 2 pairs of steel gauntlets:: - - createitem GLOVES:ITEM_GLOVES_GAUNTLETS INORGANIC:STEEL 2 - -* Create tower-cap logs:: - - createitem WOOD PLANT_MAT:TOWER_CAP:WOOD - -* Create bilberries:: - - createitem PLANT_GROWTH BILBERRY:FRUIT - -For more examples, :wiki:`see this wiki page `. - -To change where new items are placed, first run the command with a -destination type while an appropriate destination is selected. - -Options: - -:floor: Subsequent items will be placed on the floor beneath the selected unit's feet. -:item: Subsequent items will be stored inside the currently selected item. -:building: Subsequent items will become part of the currently selected building. - Good for loading traps; do not use with workshops (or deconstruct to use the item). - -.. _dig-now: - -dig-now -======= - -Instantly completes non-marker dig designations, modifying tile shapes and -creating boulders, ores, and gems as if a miner were doing the mining or -engraving. By default, the entire map is processed and boulder generation -follows standard game rules, but the behavior is configurable. - -Note that no units will get mining or engraving experience for the dug/engraved -tiles. - -Trees and roots are not currently handled by this plugin and will be skipped. -Requests for engravings are also skipped since they would depend on the skill -and creative choices of individual engravers. Other types of engraving (i.e. -smoothing and track carving) are handled. - -Usage:: - - dig-now [ []] [] - -Where the optional ```` pair can be used to specify the coordinate bounds -within which ``dig-now`` will operate. If they are not specified, ``dig-now`` -will scan the entire map. If only one ```` is specified, only the tile at -that coordinate is processed. - -Any ```` parameters can either be an ``,,`` triple (e.g. -``35,12,150``) or the string ``here``, which means the position of the active -game cursor should be used. - -Examples: - -``dig-now`` - Dig designated tiles according to standard game rules. - -``dig-now --clean`` - Dig designated tiles, but don't generate any boulders, ores, or gems. - -``dig-now --dump here`` - Dig tiles and dump all generated boulders, ores, and gems at the tile under - the game cursor. - -Options: - -:``-c``, ``--clean``: - Don't generate any boulders, ores, or gems. Equivalent to - ``--percentages 0,0,0,0``. -:``-d``, ``--dump ``: - Dump any generated items at the specified coordinates. If the tile at those - coordinates is open space or is a wall, items will be generated on the - closest walkable tile below. -:``-e``, ``--everywhere``: - Generate a boulder, ore, or gem for every tile that can produce one. - Equivalent to ``--percentages 100,100,100,100``. -:``-h``, ``--help``: - Show quick usage help text. -:``-p``, ``--percentages ,,,``: - Set item generation percentages for each of the tile categories. The - ``vein`` category includes both the large oval clusters and the long stringy - mineral veins. Default is ``25,33,100,100``. -:``-z``, ``--cur-zlevel``: - Restricts the bounds to the currently visible z-level. - -.. _diggingInvaders: - -diggingInvaders -=============== -Makes invaders dig or destroy constructions to get to your dwarves. - -To enable/disable the pluging, use: ``diggingInvaders (1|enable)|(0|disable)`` - -Basic usage: - -:add GOBLIN: registers the race GOBLIN as a digging invader. Case-sensitive. -:remove GOBLIN: unregisters the race GOBLIN as a digging invader. Case-sensitive. -:now: makes invaders try to dig now, if plugin is enabled -:clear: clears all digging invader races -:edgesPerTick n: makes the pathfinding algorithm work on at most n edges per tick. - Set to 0 or lower to make it unlimited. - -You can also use ``diggingInvaders setCost (race) (action) n`` to set the -pathing cost of particular action, or ``setDelay`` to set how long it takes. -Costs and delays are per-tile, and the table shows default values. - -============================== ======= ====== ================================= -Action Cost Delay Notes -============================== ======= ====== ================================= -``walk`` 1 0 base cost in the path algorithm -``destroyBuilding`` 2 1,000 delay adds to the job_completion_timer of destroy building jobs that are assigned to invaders -``dig`` 10,000 1,000 digging soil or natural stone -``destroyRoughConstruction`` 1,000 1,000 constructions made from boulders -``destroySmoothConstruction`` 100 100 constructions made from blocks or bars -============================== ======= ====== ================================= - - -.. _fastdwarf: - -fastdwarf -========= -Controls speedydwarf and teledwarf. Speedydwarf makes dwarves move quickly -and perform tasks quickly. Teledwarf makes dwarves move instantaneously, -but do jobs at the same speed. - -:fastdwarf 0: disables both (also ``0 0``) -:fastdwarf 1: enables speedydwarf and disables teledwarf (also ``1 0``) -:fastdwarf 2: sets a native debug flag in the game memory that implements an - even more aggressive version of speedydwarf. -:fastdwarf 0 1: disables speedydwarf and enables teledwarf -:fastdwarf 1 1: enables both - -See `superdwarf` for a per-creature version. - -.. _forceequip: - -forceequip -========== -Forceequip moves local items into a unit's inventory. It is typically used to -equip specific clothing/armor items onto a dwarf, but can also be used to put -armor onto a war animal or to add unusual items (such as crowns) to any unit. - -For more information run ``forceequip help``. See also `modtools/equip-item`. - -.. _generated-creature-renamer: - -generated-creature-renamer -========================== -Automatically renames generated creatures, such as forgotten beasts, titans, -etc, to have raw token names that match the description given in-game. - -The ``list-generated`` command can be used to list the token names of all -generated creatures in a given save, with an optional ``detailed`` argument -to show the accompanying description. - -The ``save-generated-raws`` command will save a sample creature graphics file in -the Dwarf Fortress root directory, to use as a start for making a graphics set -for generated creatures using the new names that they get with this plugin. - -The new names are saved with the save, and the plugin, when enabled, only runs once -per save, unless there's an update. - -.. _lair: - -lair -==== -This command allows you to mark the map as a monster lair, preventing item -scatter on abandon. When invoked as ``lair reset``, it does the opposite. - -Unlike `reveal`, this command doesn't save the information about tiles - you -won't be able to restore state of real monster lairs using ``lair reset``. - -Options: - -:lair: Mark the map as monster lair -:lair reset: Mark the map as ordinary (not lair) - -.. _misery: - -misery -====== -When enabled, fake bad thoughts will be added to all dwarves. - -Usage: - -:misery enable n: enable misery with optional magnitude n. If specified, n must - be positive. -:misery n: same as "misery enable n" -:misery enable: same as "misery enable 1" -:misery disable: stop adding new negative thoughts. This will not remove - existing negative thoughts. Equivalent to "misery 0". -:misery clear: remove fake thoughts, even after saving and reloading. Does - not change factor. - -.. _mode: - -mode -==== -This command lets you see and change the game mode directly. - -.. warning:: - - Only use ``mode`` after making a backup of your save! - - Not all combinations are good for every situation and most of them will - produce undesirable results. There are a few good ones though. - -Examples: - - * You are in fort game mode, managing your fortress and paused. - * You switch to the arena game mode, *assume control of a creature* and then - * switch to adventure game mode(1). - You just lost a fortress and gained an adventurer. Alternatively: - - * You are in fort game mode, managing your fortress and paused at the esc menu. - * You switch to the adventure game mode, assume control of a creature, then save or retire. - * You just created a returnable mountain home and gained an adventurer. - -.. _power-meter: - -power-meter -=========== -The power-meter plugin implements a modified pressure plate that detects power being -supplied to gear boxes built in the four adjacent N/S/W/E tiles. - -The configuration front-end is implemented by `gui/power-meter`. - -.. _siege-engine: - -siege-engine -============ -Siege engines in DF haven't been updated since the game was 2D, and can -only aim in four directions. To make them useful above-ground, -this plugin allows you to: - -* link siege engines to stockpiles -* restrict operator skill levels (like workshops) -* load any object into a catapult, not just stones -* aim at a rectangular area in any direction, and across Z-levels - -The front-end is implemented by `gui/siege-engine`. - -.. _steam-engine: - -steam-engine -============ -The steam-engine plugin detects custom workshops with STEAM_ENGINE in -their token, and turns them into real steam engines. - -The vanilla game contains only water wheels and windmills as sources of -power, but windmills give relatively little power, and water wheels require -flowing water, which must either be a real river and thus immovable and -limited in supply, or actually flowing and thus laggy. - -Compared to the :wiki:`water reactor ` -exploit, steam engines make a lot of sense! - -Construction ------------- -The workshop needs water as its input, which it takes via a -passable floor tile below it, like usual magma workshops do. -The magma version also needs magma. - -Due to DFHack limits, the workshop will collapse over true open space. -However down stairs are passable but support machines, so you can use them. - -After constructing the building itself, machines can be connected -to the edge tiles that look like gear boxes. Their exact position -is extracted from the workshop raws. - -Like with collapse above, due to DFHack limits the workshop -can only immediately connect to machine components built AFTER it. -This also means that engines cannot be chained without intermediate -axles built after both engines. - -Operation ---------- -In order to operate the engine, queue the Stoke Boiler job (optionally -on repeat). A furnace operator will come, possibly bringing a bar of fuel, -and perform it. As a result, a "boiling water" item will appear -in the :kbd:`t` view of the workshop. - -.. note:: - - The completion of the job will actually consume one unit - of the appropriate liquids from below the workshop. This means - that you cannot just raise 7 units of magma with a piston and - have infinite power. However, liquid consumption should be slow - enough that water can be supplied by a pond zone bucket chain. - -Every such item gives 100 power, up to a limit of 300 for coal, -and 500 for a magma engine. The building can host twice that -amount of items to provide longer autonomous running. When the -boiler gets filled to capacity, all queued jobs are suspended; -once it drops back to 3+1 or 5+1 items, they are re-enabled. - -While the engine is providing power, steam is being consumed. -The consumption speed includes a fixed 10% waste rate, and -the remaining 90% are applied proportionally to the actual -load in the machine. With the engine at nominal 300 power with -150 load in the system, it will consume steam for actual -300*(10% + 90%*150/300) = 165 power. - -Masterpiece mechanism and chain will decrease the mechanical -power drawn by the engine itself from 10 to 5. Masterpiece -barrel decreases waste rate by 4%. Masterpiece piston and pipe -decrease it by further 4%, and also decrease the whole steam -use rate by 10%. - -Explosions ----------- -The engine must be constructed using barrel, pipe and piston -from fire-safe, or in the magma version magma-safe metals. - -During operation weak parts get gradually worn out, and -eventually the engine explodes. It should also explode if -toppled during operation by a building destroyer, or a -tantruming dwarf. - -Save files ----------- -It should be safe to load and view engine-using fortresses -from a DF version without DFHack installed, except that in such -case the engines won't work. However actually making modifications -to them, or machines they connect to (including by pulling levers), -can easily result in inconsistent state once this plugin is -available again. The effects may be as weird as negative power -being generated. - -.. _strangemood: - -strangemood -=========== -Creates a strange mood job the same way the game itself normally does it. - -Options: - -:-force: Ignore normal strange mood preconditions (no recent mood, minimum - moodable population, artifact limit not reached). -:-unit: Make the strange mood strike the selected unit instead of picking - one randomly. Unit eligibility is still enforced. -:-type : Force the mood to be of a particular type instead of choosing randomly based on happiness. - Valid values for T are "fey", "secretive", "possessed", "fell", and "macabre". -:-skill S: Force the mood to use a specific skill instead of choosing the highest moodable skill. - Valid values are "miner", "carpenter", "engraver", "mason", "tanner", "weaver", - "clothier", "weaponsmith", "armorsmith", "metalsmith", "gemcutter", "gemsetter", - "woodcrafter", "stonecrafter", "metalcrafter", "glassmaker", "leatherworker", - "bonecarver", "bowyer", and "mechanic". - -Known limitations: if the selected unit is currently performing a job, the mood will not be started. - -============== -Plugin Lua API -============== - -Some plugins consist solely of native libraries exposed to Lua. They are listed -in the `lua-api` file under `lua-plugins`: - -* `building-hacks` -* `cxxrandom` -* `eventful` -* `luasocket` -* `map-render` -* `pathable` -* `xlsxreader` - -=========== -UI Upgrades -=========== - -.. note:: - In order to avoid user confusion, as a matter of policy all GUI tools - display the word :guilabel:`DFHack` on the screen somewhere while active. - - When that is not appropriate because they merely add keybinding hints to - existing DF screens, they deliberately use red instead of green for the key. - -.. contents:: - :local: - - -.. _automaterial: - -automaterial -============ -This makes building constructions (walls, floors, fortifications, etc) a little bit -easier by saving you from having to trawl through long lists of materials each time -you place one. - -Firstly, it moves the last used material for a given construction type to the top of -the list, if there are any left. So if you build a wall with chalk blocks, the next -time you place a wall the chalk blocks will be at the top of the list, regardless of -distance (it only does this in "grouped" mode, as individual item lists could be huge). -This should mean you can place most constructions without having to search for your -preferred material type. - -.. image:: images/automaterial-mat.png - -Pressing :kbd:`a` while highlighting any material will enable that material for "auto select" -for this construction type. You can enable multiple materials as autoselect. Now the next -time you place this type of construction, the plugin will automatically choose materials -for you from the kinds you enabled. If there is enough to satisfy the whole placement, -you won't be prompted with the material screen - the construction will be placed and you -will be back in the construction menu as if you did it manually. - -When choosing the construction placement, you will see a couple of options: - -.. image:: images/automaterial-pos.png - -Use :kbd:`a` here to temporarily disable the material autoselection, e.g. if you need -to go to the material selection screen so you can toggle some materials on or off. - -The other option (auto type selection, off by default) can be toggled on with :kbd:`t`. If you -toggle this option on, instead of returning you to the main construction menu after selecting -materials, it returns you back to this screen. If you use this along with several autoselect -enabled materials, you should be able to place complex constructions more conveniently. - -.. _automelt: - -automelt -======== -When automelt is enabled for a stockpile, any meltable items placed -in it will be designated to be melted. -This plugin adds an option to the :kbd:`q` menu when `enabled `. - -.. _autotrade: - -autotrade -========= -When autotrade is enabled for a stockpile, any items placed in it will be -designated to be taken to the Trade Depot whenever merchants are on the map. -This plugin adds an option to the :kbd:`q` menu when `enabled `. - -.. _buildingplan: - -buildingplan -============ -When active (via ``enable buildingplan``), this plugin adds a planning mode for -building placement. You can then place furniture, constructions, and other buildings -before the required materials are available, and they will be created in a suspended -state. Buildingplan will periodically scan for appropriate items, and the jobs will -be unsuspended when the items are available. - -This is very useful when combined with `workflow` - you can set a constraint -to always have one or two doors/beds/tables/chairs/etc available, and place -as many as you like. The plugins then take over and fulfill the orders, -with minimal space dedicated to stockpiles. - -.. _buildingplan-filters: - -Item filtering --------------- - -While placing a building, you can set filters for what materials you want the building made -out of, what quality you want the component items to be, and whether you want the items to -be decorated. - -If a building type takes more than one item to construct, use :kbd:`Ctrl`:kbd:`Left` and -:kbd:`Ctrl`:kbd:`Right` to select the item that you want to set filters for. Any filters that -you set will be used for all buildings of the selected type placed from that point onward -(until you set a new filter or clear the current one). Buildings placed before the filters -were changed will keep the filter values that were set when the building was placed. - -For example, you can be sure that all your constructed walls are the same color by setting -a filter to accept only certain types of stone. - -Quickfort mode --------------- - -If you use the external Python Quickfort to apply building blueprints instead of the native -DFHack `quickfort` script, you must enable Quickfort mode. This temporarily enables -buildingplan for all building types and adds an extra blank screen after every building -placement. This "dummy" screen is needed for Python Quickfort to interact successfully with -Dwarf Fortress. - -Note that Quickfort mode is only for compatibility with the legacy Python Quickfort. The -DFHack `quickfort` script does not need Quickfort mode to be enabled. The `quickfort` script -will successfully integrate with buildingplan as long as the buildingplan plugin is enabled. - -.. _buildingplan-settings: - -Global settings ---------------- - -The buildingplan plugin has several global settings that can be set from the UI (:kbd:`G` -from any building placement screen, for example: :kbd:`b`:kbd:`a`:kbd:`G`). These settings -can also be set from the ``DFHack#`` prompt once a map is loaded (or from your -``onMapLoad.init`` file) with the syntax:: - - buildingplan set - -and displayed with:: - - buildingplan set - -The available settings are: - -+----------------+---------+-----------+---------------------------------------+ -| Setting | Default | Persisted | Description | -+================+=========+===========+=======================================+ -| all_enabled | false | no | Enable planning mode for all building | -| | | | types. | -+----------------+---------+-----------+---------------------------------------+ -| blocks | true | yes | Allow blocks, boulders, logs, or bars | -+----------------+---------+ | to be matched for generic "building | -| boulders | true | | material" items | -+----------------+---------+ | | -| logs | true | | | -+----------------+---------+ | | -| bars | false | | | -+----------------+---------+-----------+---------------------------------------+ -| quickfort_mode | false | no | Enable compatibility mode for the | -| | | | legacy Python Quickfort (not required | -| | | | for DFHack quickfort) | -+----------------+---------+-----------+---------------------------------------+ - -For example, to ensure you only use blocks when a "building material" item is required, you -could add this to your ``onMapLoad.init`` file:: - - on-new-fortress buildingplan set boulders false; buildingplan set logs false - -Persisted settings (i.e. ``blocks``, ``boulders``, ``logs``, and ``bars``) are saved with -your game, so you only need to set them to the values you want once. - -.. _command-prompt: - -command-prompt -============== -An in-game DFHack terminal, where you can enter other commands. - -:dfhack-keybind:`command-prompt` - -Usage: ``command-prompt [entry]`` - -If called with an entry, it starts with that text filled in. -Most useful for developers, who can set a keybinding to open -a laungage interpreter for lua or Ruby by starting with the -`:lua ` or `:rb ` commands. - -Otherwise somewhat similar to `gui/quickcmd`. - -.. image:: images/command-prompt.png - -.. _confirm: - -confirm -======= -Implements several confirmation dialogs for potentially destructive actions -(for example, seizing goods from traders or deleting hauling routes). - -Usage: - -:enable confirm: Enable all confirmations; alias ``confirm enable all``. - Replace with ``disable`` to disable. -:confirm help: List available confirmation dialogues. -:confirm enable option1 [option2...]: - Enable (or disable) specific confirmation dialogues. - -.. _debug: - -debug -===== -Manager for DFHack runtime debug prints. Debug prints are grouped by plugin name, -category name and print level. Levels are ``trace``, ``debug``, ``info``, -``warning`` and ``error``. - -The runtime message printing is controlled using filters. Filters set the -visible messages of all matching categories. Matching uses regular expression syntax, -which allows listing multiple alternative matches or partial name matches. -This syntax is a C++ version of the ECMA-262 grammar (Javascript regular expressions). -Details of differences can be found at -https://en.cppreference.com/w/cpp/regex/ecmascript - -Persistent filters are stored in ``dfhack-config/runtime-debug.json``. -Oldest filters are applied first. That means a newer filter can override the -older printing level selection. - -Usage: ``debugfilter [subcommand] [parameters...]`` - -The following subcommands are supported: - -help ----- -Give overall help or a detailed help for a subcommand. - -Usage: ``debugfilter help [subcommand]`` - -category --------- -List available debug plugin and category names. - -Usage: ``debugfilter category [plugin regex] [category regex]`` - -The list can be filtered using optional regex parameters. If filters aren't -given then the it uses ``"."`` regex which matches any character. The regex -parameters are good way to test regex before passing them to ``set``. - -filter ------- -List active and passive debug print level changes. - -Usage: ``debugfilter filter [id]`` - -Optional ``id`` parameter is the id listed as first column in the filter list. -If id is given then the command shows information for the given filter only in -multi line format that is better format if filter has long regex. - -set ---- -Creates a new debug filter to set category printing levels. - -Usage: ``debugfilter set [level] [plugin regex] [category regex]`` - -Adds a filter that will be deleted when DF process exists or plugin is unloaded. - -Usage: ``debugfilter set persistent [level] [plugin regex] [category regex]`` - -Stores the filter in the configuration file to until ``unset`` is used to remove -it. - -Level is the minimum debug printing level to show in log. - -* ``trace``: Possibly very noisy messages which can be printed many times per second - -* ``debug``: Messages that happen often but they should happen only a couple of times per second - -* ``info``: Important state changes that happen rarely during normal execution - -* ``warning``: Enabled by default. Shows warnings about unexpected events which code managed to handle correctly. - -* ``error``: Enabled by default. Shows errors which code can't handle without user intervention. - -unset ------ -Delete a space separated list of filters - -Usage: ``debugfilter unset [id...]`` - -disable -------- -Disable a space separated list of filters but keep it in the filter list - -Usage: ``debugfilter disable [id...]`` - -enable ------- -Enable a space sperate list of filters - -Usage: ``debugfilter enable [id...]`` - -.. _embark-assistant: - -embark-assistant -================ - -This plugin provides embark site selection help. It has to be run with the -``embark-assistant`` command while the pre-embark screen is displayed and shows -extended (and correct(?)) resource information for the embark rectangle as well -as normally undisplayed sites in the current embark region. It also has a site -selection tool with more options than DF's vanilla search tool. For detailed -help invoke the in game info screen. - -.. _embark-tools: - -embark-tools -============ -A collection of embark-related tools. Usage and available tools:: - - embark-tools enable/disable tool [tool]... - -:anywhere: Allows embarking anywhere (including sites, mountain-only biomes, - and oceans). Use with caution. -:mouse: Implements mouse controls (currently in the local embark region only) -:sand: Displays an indicator when sand is present in the currently-selected - area, similar to the default clay/stone indicators. -:sticky: Maintains the selected local area while navigating the world map - -.. _follow: - -follow -====== -Makes the game view follow the currently highlighted unit after you exit from the -current menu or cursor mode. Handy for watching dwarves running around. Deactivated -by moving the view manually. - -.. _hotkeys: - -hotkeys -======= -Opens an in-game screen showing which DFHack keybindings are -active in the current context. See also `hotkey-notes`. - -.. image:: images/hotkeys.png - -:dfhack-keybind:`hotkeys` - -.. _manipulator: - -manipulator -=========== -An in-game equivalent to the popular program Dwarf Therapist. - -To activate, open the unit screen and press :kbd:`l`. - -.. image:: images/manipulator.png - -The far left column displays the unit's Happiness (color-coded based on its -value), Name, Profession/Squad, and the right half of the screen displays each -dwarf's labor settings and skill levels (0-9 for Dabbling through Professional, -A-E for Great through Grand Master, and U-Z for Legendary through Legendary+5). - -Cells with teal backgrounds denote skills not controlled by labors, e.g. -military and social skills. - -.. image:: images/manipulator2.png - -Press :kbd:`t` to toggle between Profession, Squad, and Job views. - -.. image:: images/manipulator3.png - -Use the arrow keys or number pad to move the cursor around, holding :kbd:`Shift` to -move 10 tiles at a time. - -Press the Z-Up (:kbd:`<`) and Z-Down (:kbd:`>`) keys to move quickly between labor/skill -categories. The numpad Z-Up and Z-Down keys seek to the first or last unit -in the list. :kbd:`Backspace` seeks to the top left corner. - -Press Enter to toggle the selected labor for the selected unit, or Shift+Enter -to toggle all labors within the selected category. - -Press the :kbd:`+`:kbd:`-` keys to sort the unit list according to the currently selected -skill/labor, and press the :kbd:`*`:kbd:`/` keys to sort the unit list by Name, Profession/Squad, -Happiness, or Arrival order (using :kbd:`Tab` to select which sort method to use here). - -With a unit selected, you can press the :kbd:`v` key to view its properties (and -possibly set a custom nickname or profession) or the :kbd:`c` key to exit -Manipulator and zoom to its position within your fortress. - -The following mouse shortcuts are also available: - -* Click on a column header to sort the unit list. Left-click to sort it in one - direction (descending for happiness or labors/skills, ascending for name, - profession or squad) and right-click to sort it in the opposite direction. -* Left-click on a labor cell to toggle that labor. Right-click to move the - cursor onto that cell instead of toggling it. -* Left-click on a unit's name, profession or squad to view its properties. -* Right-click on a unit's name, profession or squad to zoom to it. - -Pressing :kbd:`Esc` normally returns to the unit screen, but :kbd:`Shift`:kbd:`Esc` would exit -directly to the main dwarf mode screen. - -Professions ------------ - -The manipulator plugin supports saving professions: a named set of labors that can be -quickly applied to one or multiple dwarves. - -To save a profession, highlight a dwarf and press :kbd:`P`. The profession will be saved using -the custom profession name of the dwarf, or the default for that dwarf if no custom profession -name has been set. - -To apply a profession, either highlight a single dwarf or select multiple with -:kbd:`x`, and press :kbd:`p` to select the profession to apply. All labors for -the selected dwarves will be reset to the labors of the chosen profession. - -Professions are saved as human-readable text files in the -``dfhack-config/professions`` folder within the DF folder, and can be edited or -deleted there. - -The professions library -~~~~~~~~~~~~~~~~~~~~~~~ - -The manipulator plugin comes with a library of professions that you can assign -to your dwarves. - -If you'd rather use Dwarf Therapist to manage your labors, it is easy to import -these professions to DT and use them there. Simply assign the professions you -want to import to a dwarf. Once you have assigned a profession to at least one -dwarf, you can select "Import Professions from DF" in the DT "File" menu. The -professions will then be available for use in DT. - -In the charts below, the "At Start" and "Max" columns indicate the approximate -number of dwarves of each profession that you are likely to need at the start of -the game and how many you are likely to need in a mature fort. These are just -approximations. Your playstyle may demand more or fewer of each profession. - -============= ======== ===== ================================================= -Profession At Start Max Description -============= ======== ===== ================================================= -Chef 0 3 Buchery, Tanning, and Cooking. It is important to - focus just a few dwarves on cooking since - well-crafted meals make dwarves very happy. They - are also an excellent trade good. -Craftsdwarf 0 4-6 All labors used at Craftsdwarf's workshops, - Glassmaker's workshops, and kilns. -Doctor 0 2-4 The full suite of medical labors, plus Animal - Caretaking for those using the dwarfvet plugin. -Farmer 1 4 Food- and animal product-related labors. This - profession also has the ``Alchemist`` labor - enabled since they need to focus on food-related - jobs, though you might want to disable - ``Alchemist`` for your first farmer until there - are actual farming duties to perform. -Fisherdwarf 0 0-1 Fishing and fish cleaning. If you assign this - profession to any dwarf, be prepared to be - inundated with fish. Fisherdwarves *never stop - fishing*. Be sure to also run ``prioritize -a - PrepareRawFish ExtractFromRawFish`` or else - caught fish will just be left to rot. -Hauler 0 >20 All hauling labors plus Siege Operating, Mechanic - (so haulers can assist in reloading traps) and - Architecture (so haulers can help build massive - windmill farms and pump stacks). As you - accumulate enough Haulers, you can turn off - hauling labors for other dwarves so they can - focus on their skilled tasks. You may also want - to restrict your Mechanic's workshops to only - skilled mechanics so your haulers don't make - low-quality mechanisms. -Laborer 0 10-12 All labors that don't improve quality with skill, - such as Soapmaking and furnace labors. -Marksdwarf 0 10-30 Similar to Hauler. See the description for - Meleedwarf below for more details. -Mason 2 2-4 Masonry and Gem Cutting/Encrusting. In the early - game, you may need to run "`prioritize` - ConstructBuilding" to get your masons to build - wells and bridges if they are too busy crafting - stone furniture. -Meleedwarf 0 20-50 Similar to Hauler, but without most civilian - labors. This profession is separate from Hauler - so you can find your military dwarves easily. - Meleedwarves and Marksdwarves have Mechanics and - hauling labors enabled so you can temporarily - deactivate your military after sieges and allow - your military dwarves to help clean up. -Migrant 0 0 You can assign this profession to new migrants - temporarily while you sort them into professions. - Like Marksdwarf and Meleedwarf, the purpose of - this profession is so you can find your new - dwarves more easily. -Miner 2 2-10 Mining and Engraving. This profession also has - the ``Alchemist`` labor enabled, which disables - hauling for those using the `autohauler` plugin. - Once the need for Miners tapers off in the late - game, dwarves with this profession make good - military dwarves, wielding their picks as - weapons. -Outdoorsdwarf 1 2-4 Carpentry, Bowyery, Woodcutting, Animal Training, - Trapping, Plant Gathering, Beekeeping, and Siege - Engineering. -Smith 0 2-4 Smithing labors. You may want to specialize your - Smiths to focus on a single smithing skill to - maximize equipment quality. -StartManager 1 0 All skills not covered by the other starting - professions (Miner, Mason, Outdoorsdwarf, and - Farmer), plus a few overlapping skills to - assist in critical tasks at the beginning of the - game. Individual labors should be turned off as - migrants are assigned more specialized - professions that cover them, and the StartManager - dwarf can eventually convert to some other - profession. -Tailor 0 2 Textile industry labors: Dying, Leatherworking, - Weaving, and Clothesmaking. -============= ======== ===== ================================================= - -A note on autohauler -~~~~~~~~~~~~~~~~~~~~ - -These profession definitions are designed to work well with or without the -`autohauler` plugin (which helps to keep your dwarves focused on skilled labors -instead of constantly being distracted by hauling). If you do want to use -autohauler, adding the following lines to your ``onMapLoad.init`` file will -configure it to let the professions manage the "Feed water to civilians" and -"Recover wounded" labors instead of enabling those labors for all hauling -dwarves:: - - on-new-fortress enable autohauler - on-new-fortress autohauler FEED_WATER_CIVILIANS allow - on-new-fortress autohauler RECOVER_WOUNDED allow - -.. _mousequery: - -mousequery -========== -Adds mouse controls to the DF interface, e.g. click-and-drag designations. - -Options: - -:plugin: enable/disable the entire plugin -:rbutton: enable/disable right mouse button -:track: enable/disable moving cursor in build and designation mode -:edge: enable/disable active edge scrolling (when on, will also enable tracking) -:live: enable/disable query view when unpaused -:delay: Set delay when edge scrolling in tracking mode. Omit amount to display current setting. - -Usage:: - - mousequery [plugin] [rbutton] [track] [edge] [live] [enable|disable] - -.. _nopause: - -nopause -======= -Disables pausing (both manual and automatic) with the exception of pause forced -by `reveal` ``hell``. This is nice for digging under rivers. - -.. _rename: - -rename -====== -Allows renaming various things. Use `gui/rename` for an in-game interface. - -Options: - -``rename squad "name"`` - Rename squad by index to 'name'. -``rename hotkey \"name\"`` - Rename hotkey by index. This allows assigning - longer commands to the DF hotkeys. -``rename unit "nickname"`` - Rename a unit/creature highlighted in the DF user interface. -``rename unit-profession "custom profession"`` - Change proffession name of the highlighted unit/creature. -``rename building "name"`` - Set a custom name for the selected building. - The building must be one of stockpile, workshop, furnace, trap, - siege engine or an activity zone. - -.. _rendermax: - -rendermax -========= -A collection of renderer replacing/enhancing filters. For better effect try changing the -black color in palette to non totally black. See :forums:`128487` for more info. - -Options: - -:trippy: Randomizes the color of each tiles. Used for fun, or testing. -:light: Enable lighting engine. -:light reload: Reload the settings file. -:light sun |cycle: Set time to (in hours) or set it to df time cycle. -:occlusionON, occlusionOFF: Show debug occlusion info. -:disable: Disable any filter that is enabled. - -An image showing lava and dragon breath. Not pictured here: sunlight, shining items/plants, -materials that color the light etc... - -.. image:: images/rendermax.png - -.. _resume: - -resume -====== -Allows automatic resumption of suspended constructions, along with colored -UI hints for construction status. - -.. _rb: -.. _ruby: - -ruby -==== -Ruby language plugin, which evaluates the following arguments as a ruby string. -Best used as ``:rb [string]``, for the special parsing mode. Alias ``rb_eval``. - -.. comment - the link target "search" is reserved for the Sphinx search page -.. _search-plugin: - -search -====== -The search plugin adds search to the Stocks, Animals, Trading, Stockpile, -Noble (assignment candidates), Military (position candidates), Burrows -(unit list), Rooms, Announcements, Job List and Unit List screens. - -.. image:: images/search.png - -Searching works the same way as the search option in :guilabel:`Move to Depot`. -You will see the Search option displayed on screen with a hotkey (usually :kbd:`s`). -Pressing it lets you start typing a query and the relevant list will start -filtering automatically. - -Pressing :kbd:`Enter`, :kbd:`Esc` or the arrow keys will return you to browsing the now -filtered list, which still functions as normal. You can clear the filter -by either going back into search mode and backspacing to delete it, or -pressing the "shifted" version of the search hotkey while browsing the -list (e.g. if the hotkey is :kbd:`s`, then hitting :kbd:`Shift`:kbd:`s` will clear any -filter). - -Leaving any screen automatically clears the filter. - -In the Trade screen, the actual trade will always only act on items that -are actually visible in the list; the same effect applies to the Trade -Value numbers displayed by the screen. Because of this, the :kbd:`t` key is -blocked while search is active, so you have to reset the filters first. -Pressing :kbd:`Alt`:kbd:`C` will clear both search strings. - -In the stockpile screen the option only appears if the cursor is in the -rightmost list: - -.. image:: images/search-stockpile.png - -Note that the 'Permit XXX'/'Forbid XXX' keys conveniently operate only -on items actually shown in the rightmost list, so it is possible to select -only fat or tallow by forbidding fats, then searching for fat/tallow, and -using Permit Fats again while the list is filtered. - -.. _sort: -.. _sort-items: - -sort-items -========== -Sort the visible item list:: - - sort-items order [order...] - -Sort the item list using the given sequence of comparisons. -The ``<`` prefix for an order makes undefined values sort first. -The ``>`` prefix reverses the sort order for defined values. - -Item order examples:: - - description material wear type quality - -The orderings are defined in ``hack/lua/plugins/sort/*.lua`` - -.. _sort-units: - -sort-units -========== -Sort the visible unit list:: - - sort-units order [order...] - -Sort the unit list using the given sequence of comparisons. -The ``<`` prefix for an order makes undefined values sort first. -The ``>`` prefix reverses the sort order for defined values. - -Unit order examples:: - - name age arrival squad squad_position profession - -The orderings are defined in ``hack/lua/plugins/sort/*.lua`` - -:dfhack-keybind:`sort-units` - -.. _stocksettings: -.. _stockpiles: - -stockpiles -========== -Offers the following commands to save and load stockpile settings. -See `gui/stockpiles` for an in-game interface. - -:copystock: Copies the parameters of the currently highlighted stockpile to the custom - stockpile settings and switches to custom stockpile placement mode, effectively - allowing you to copy/paste stockpiles easily. - :dfhack-keybind:`copystock` - -:savestock: Saves the currently highlighted stockpile's settings to a file in your Dwarf - Fortress folder. This file can be used to copy settings between game saves or - players. e.g.: ``savestock food_settings.dfstock`` - -:loadstock: Loads a saved stockpile settings file and applies it to the currently selected - stockpile. e.g.: ``loadstock food_settings.dfstock`` - -To use savestock and loadstock, use the :kbd:`q` command to highlight a stockpile. -Then run savestock giving it a descriptive filename. Then, in a different (or -the same!) gameworld, you can highlight any stockpile with :kbd:`q` then execute the -``loadstock`` command passing it the name of that file. The settings will be -applied to that stockpile. - -Note that files are relative to the DF folder, so put your files there or in a -subfolder for easy access. Filenames should not have spaces. Generated materials, -divine metals, etc are not saved as they are different in every world. - -.. _stocks: - -stocks -====== -Replaces the DF stocks screen with an improved version. - -:dfhack-keybind:`stocks` - - -.. _title-folder: - -title-folder -============= -Displays the DF folder name in the window title bar when enabled. - -.. _title-version: - -title-version -============= -Displays the DFHack version on DF's title screen when enabled. - -.. _trackstop: - -trackstop -========= -Adds a :kbd:`q` menu for track stops, which is completely blank by default. -This allows you to view and/or change the track stop's friction and dump -direction settings, using the keybindings from the track stop building interface. diff --git a/docs/Removed.rst b/docs/Removed.rst index e94b04cf8..f9bf1c62e 100644 --- a/docs/Removed.rst +++ b/docs/Removed.rst @@ -10,14 +10,6 @@ work (e.g. links from the `changelog`). :local: :depth: 1 -.. _devel/unforbidall: - -devel/unforbidall -================= - -Replaced by the `unforbid` script. Run ``unforbid all --quiet`` to match the -behavior of the original ``devel/unforbidall`` script. - .. _deteriorateclothes: deteriorateclothes @@ -39,6 +31,13 @@ deterioratefood Replaced by the new combined `deteriorate` script. Run ``deteriorate --types=food``. +.. _devel/unforbidall: + +devel/unforbidall +================= +Replaced by the `unforbid` script. Run ``unforbid all --quiet`` to match the +behavior of the original ``devel/unforbidall`` script. + .. _digfort: digfort @@ -49,6 +48,44 @@ existing .csv files. Just move them to the ``blueprints`` folder in your DF installation, and instead of ``digfort file.csv``, run ``quickfort run file.csv``. +.. _fix-armory: + +fix-armory +========== +Allowed the military to store equipment in barracks containers. Removed because +it required a binary patch to DF in order to function, and no such patch has +existed since DF 0.34.11. + +.. _fix/build-location: + +fix/build-location +================== +The corresponding DF :bug:`5991` was fixed in DF 0.40.05. + +.. _fix/diplomats: + +fix/diplomats +============= +The corresponding DF :bug:`3295` was fixed in DF 0.40.05. + +.. _fix/fat-dwarves: + +fix/fat-dwarves +=============== +The corresponding DF :bug:`5971` was fixed in DF 0.40.05. + +.. _fix/feeding-timers: + +fix/feeding-timers +================== +The corresponding DF :bug:`2606` was fixed in DF 0.40.12. + +.. _fix/merchants: + +fix/merchants +============= +Humans can now make trade agreements. This fix is no longer necessary. + .. _fortplan: fortplan @@ -59,8 +96,30 @@ script instead. You can use your existing .csv files. Just move them to the ``blueprints`` folder in your DF installation, and instead of ``fortplan file.csv`` run ``quickfort run file.csv``. +.. _gui/assign-rack: + +gui/assign-rack +=============== +This script is no longer useful in current DF versions. The script required a +binpatch `, which has not been available since DF +0.34.11. + +.. _gui/hack-wish: + +gui/hack-wish +============= +Replaced by `gui/create-item`. + +.. _gui/no-dfhack-init: + +gui/no-dfhack-init +================== +Tool that warned the user when the ``dfhack.init`` file did not exist. Now that +``dfhack.init`` is autogenerated in ``dfhack-config/init``, this warning is no +longer necessary. + .. _warn-stuck-trees: warn-stuck-trees ================ -The corresponding DF bug, :bug:`9252` was fixed in DF 0.44.01. +The corresponding DF :bug:`9252` was fixed in DF 0.44.01. diff --git a/docs/Scripts.rst b/docs/Scripts.rst deleted file mode 100644 index 419385582..000000000 --- a/docs/Scripts.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. _scripts-index: - -############## -DFHack Scripts -############## - -Lua or ruby scripts placed in the :file:`hack/scripts/` directory -are considered for execution as if they were native DFHack commands. - -The following pages document all the scripts in the DFHack standard library. - -.. toctree:: - :maxdepth: 2 - - /docs/_auto/base - /docs/_auto/devel - /docs/_auto/fix - /docs/_auto/gui - /docs/_auto/modtools diff --git a/docs/Support.rst b/docs/Support.rst index 00e055baa..af8bd583c 100644 --- a/docs/Support.rst +++ b/docs/Support.rst @@ -1,34 +1,3 @@ -.. _support: +:orphan: -=============== -Getting Support -=============== - -DFHack has several ways to get help online, including: - -- The `DFHack Discord server `__ -- The ``#dfhack`` IRC channel on `Libera `__ -- GitHub: - - for bugs, use the :issue:`issue tracker <>` - - for more open-ended questions, use the `discussion board - `__. Note that this is a - relatively-new feature as of 2021, but maintainers should still be - notified of any discussions here. -- The `DFHack thread on the Bay 12 Forum `__ - -Some additional, but less DFHack-specific, places where questions may be answered include: - -- The `/r/dwarffortress `_ questions thread on Reddit -- If you are using a starter pack, the relevant thread on the `Bay 12 Forum `__ - - see the :wiki:`DF Wiki ` for a list of these threads - -When reaching out to any support channels regarding problems with DFHack, please -remember to provide enough details for others to identify the issue. For -instance, specific error messages (copied text or screenshots) are helpful, as -well as any steps you can follow to reproduce the problem. Sometimes, log output -from ``stderr.log`` in the DF folder can point to the cause of issues as well. - -Some common questions may also be answered in documentation, including: - -- This documentation (`online here `__; search functionality available `here `) -- :wiki:`The DF wiki <>` +Please continue to the new `support` page. diff --git a/docs/Tags.rst b/docs/Tags.rst new file mode 100644 index 000000000..9f3906d58 --- /dev/null +++ b/docs/Tags.rst @@ -0,0 +1,48 @@ +:orphan: + +.. _tag-list: + +DFHack tool tags +================ + +A tool often has at least one tag per group, encompassing when you use the tool, +why you might want to use it, and what kind of thing you're trying to affect. + +See https://docs.google.com/spreadsheets/d/1hiDlo8M_bB_1jE-5HRs2RrrA_VZ4cRu9VXaTctX_nwk/edit#gid=1774645373 +for the tag assignment spreadsheet. + +"when" tags +----------- +- `tag/adventure`: Tools that are useful while in adventure mode. Note that some tools only tagged with "fort" might also work in adventure mode, but not always in expected ways. Feel free to experiment, though! +- `tag/dfhack`: Tools that you use to run DFHack commands or interact with the DFHack library. This tag also includes tools that help you manage the DF game itself (e.g. settings, saving, etc.) +- `tag/embark`: Tools that are useful while on the fort embark screen or while creating an adventurer. +- `tag/fort`: Tools that are useful while in fort mode. +- `tag/legends`: Tools that are useful while in legends mode. + +"why" tags +---------- +- `tag/armok`: Tools that give you complete control over an aspect of the game or provide access to information that the game intentionally keeps hidden. +- `tag/auto`: Tools that run in the background and automatically manage routine, toilsome aspects of your fortress. +- `tag/bugfix`: Tools that fix specific bugs, either permanently or on-demand. +- `tag/design`: Tools that help you design your fort. +- `tag/dev`: Tools that are useful when developing scripts or mods. +- `tag/fps`: Tools that help you manage FPS drop. +- `tag/gameplay`: Tools that introduce new gameplay elements. +- `tag/inspection`: Tools that let you view information that is otherwise difficult to find. +- `tag/productivity`: Tools that help you do things that you could do manually, but using the tool is better and faster. + +"what" tags +----------- +- `tag/animals`: Tools that interact with animals. +- `tag/buildings`: Tools that interact with buildings and furniture. +- `tag/graphics`: Tools that interact with game graphics. +- `tag/interface`: Tools that interact with or extend the DF user interface. +- `tag/items`: Tools that interact with in-game items. +- `tag/jobs`: Tools that interact with jobs. +- `tag/labors`: Tools that deal with labor assignment. +- `tag/map`: Tools that interact with the game map. +- `tag/military`: Tools that interact with the military. +- `tag/plants`: Tools that interact with trees, shrubs, and crops. +- `tag/stockpiles`: Tools that interact wtih stockpiles. +- `tag/units`: Tools that interact with units. +- `tag/workorders`: Tools that interact with workorders. diff --git a/docs/Tools.rst b/docs/Tools.rst new file mode 100644 index 000000000..623fc9c1f --- /dev/null +++ b/docs/Tools.rst @@ -0,0 +1,50 @@ +.. _tools: + +DFHack tools +============ + +DFHack has **a lot** of tools. This page attempts to make it clearer what they +are, how they work, and how to find the ones you want. + +.. contents:: Contents + :local: + +What tools are and how they work +-------------------------------- + +DFHack is a Dwarf Fortress memory access and modification framework, so DFHack +tools normally access Dwarf Fortress internals and make some specific changes. + +Some tools just make a targeted change when you run them, like `unforbid`, which +scans through all your items and removes the ``forbidden`` flag from each of +them. + +Some tools need to be enabled, and then they run in the background and make +changes to the game on your behalf, like `autobutcher`, which monitors your +livestock population and automatically marks excess animals for butchering. + +And some tools just exist to give you information that is otherwise hard to +come by, like `gui/petitions`, which shows you the active petitions for +guildhalls and temples that you have agreed to. + +Finding the tool you need +------------------------- + +DFHack tools are tagged with categories to make them easier to find. Note that a +tool can belong to more than one category. If you'd like to see the full list of +tools in one flat list, please refer to the `index `. + +DFHack tools by game mode +------------------------- + +.. include:: tags/bywhen.rst + +DFHack tools by theme +--------------------- + +.. include:: tags/bywhy.rst + +DFHack tools by what they affect +-------------------------------- + +.. include:: tags/bywhat.rst diff --git a/docs/_auto/.gitignore b/docs/_auto/.gitignore deleted file mode 100644 index 30d85567b..000000000 --- a/docs/_auto/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.rst diff --git a/docs/_changelogs/.gitignore b/docs/_changelogs/.gitignore deleted file mode 100644 index 2211df63d..000000000 --- a/docs/_changelogs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.txt diff --git a/docs/build-pdf.sh b/docs/build-pdf.sh deleted file mode 100755 index 76908b49b..000000000 --- a/docs/build-pdf.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -# usage: -# ./build-pdf.sh -# SPHINX=/path/to/sphinx-build ./build-pdf.sh -# JOBS=3 ./build-pdf.sh ... -# all command-line arguments are passed directly to sphinx-build - run -# ``sphinx-build --help`` for a list, or see -# https://www.sphinx-doc.org/en/master/man/sphinx-build.html - -cd $(dirname "$0") -cd .. - -sphinx=sphinx-build -if [ -n "$SPHINX" ]; then - sphinx=$SPHINX -fi - -if [ -z "$JOBS" ]; then - JOBS=2 -fi - -"$sphinx" -M latexpdf . ./docs/pdf -w ./docs/_sphinx-warnings.txt -j "$JOBS" "$@" diff --git a/docs/build.py b/docs/build.py new file mode 100755 index 000000000..6a63ed59e --- /dev/null +++ b/docs/build.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 + +# for help, run: python3 build.py --help + +import argparse +import os +import subprocess +import sys + +class SphinxOutputFormat: + def __init__(self, name, pre_args): + self.name = str(name) + self.pre_args = tuple(pre_args) + + @property + def args(self): + output_dir = os.path.join('docs', self.name) + artifacts_dir = os.path.join('build', 'docs', self.name) # for artifacts not part of the final documentation + return [ + *self.pre_args, + '.', # source dir + output_dir, + '-d', artifacts_dir, + '-w', os.path.join(artifacts_dir, 'sphinx-warnings.txt'), + ] + +OUTPUT_FORMATS = { + 'html': SphinxOutputFormat('html', pre_args=['-b', 'html']), + 'text': SphinxOutputFormat('text', pre_args=['-b', 'text']), + 'pdf': SphinxOutputFormat('pdf', pre_args=['-M', 'latexpdf']), + 'xml': SphinxOutputFormat('xml', pre_args=['-b', 'xml']), + 'pseudoxml': SphinxOutputFormat('pseudoxml', pre_args=['-b', 'pseudoxml']), +} + +def _parse_known_args(parser, source_args): + # pass along any arguments after '--' + ignored_args = [] + if '--' in source_args: + source_args, ignored_args = source_args[:source_args.index('--')], source_args[source_args.index('--')+1:] + args, forward_args = parser.parse_known_args(source_args) + forward_args += ignored_args + return args, forward_args + +def parse_args(source_args): + def output_format(s): + if s in OUTPUT_FORMATS: + return s + raise ValueError + + parser = argparse.ArgumentParser(usage='%(prog)s [{} ...] [options] [--] [sphinx_options]'.format('|'.join(OUTPUT_FORMATS.keys())), description=''' + DFHack wrapper around sphinx-build. + + Any unrecognized options are passed directly to sphinx-build, as well as any + options following a '--' argument, if specified. + ''') + parser.add_argument('format', nargs='*', type=output_format, action='append', + help='Documentation format(s) to build - choose from {}'.format(', '.join(OUTPUT_FORMATS.keys()))) + parser.add_argument('-E', '--clean', action='store_true', + help='Re-read all input files') + parser.add_argument('--sphinx', type=str, default=os.environ.get('SPHINX', 'sphinx-build'), + help='Sphinx executable to run [environment variable: SPHINX; default: "sphinx-build"]') + parser.add_argument('-j', '--jobs', type=str, default=os.environ.get('JOBS', 'auto'), + help='Number of Sphinx threads to run [environment variable: JOBS; default: "auto"]') + parser.add_argument('--debug', action='store_true', + help='Log commands that are run, etc.') + parser.add_argument('--offline', action='store_true', + help='Disable network connections') + args, forward_args = _parse_known_args(parser, source_args) + + # work around weirdness with list args + args.format = args.format[0] + if not args.format: + args.format = ['html'] + + return args, forward_args + +if __name__ == '__main__': + os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + if not os.path.isfile('conf.py'): + print('Could not find conf.py', file=sys.stderr) + exit(1) + + args, forward_args = parse_args(sys.argv[1:]) + + sphinx_env = os.environ.copy() + if args.offline: + sphinx_env['DFHACK_DOCS_BUILD_OFFLINE'] = '1' + + for format_name in args.format: + command = [args.sphinx] + OUTPUT_FORMATS[format_name].args + ['-j', args.jobs] + if args.clean: + command += ['-E'] + command += forward_args + + if args.debug: + print('Building:', format_name) + print('Running:', command) + subprocess.run(command, check=True, env=sphinx_env) + + print('') diff --git a/docs/build.sh b/docs/build.sh deleted file mode 100755 index 95a97e539..000000000 --- a/docs/build.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -# usage: -# ./build.sh -# SPHINX=/path/to/sphinx-build ./build.sh -# JOBS=3 ./build.sh ... -# all command-line arguments are passed directly to sphinx-build - run -# ``sphinx-build --help`` for a list, or see -# https://www.sphinx-doc.org/en/master/man/sphinx-build.html - -cd $(dirname "$0") -cd .. - -sphinx=sphinx-build -if [ -n "$SPHINX" ]; then - sphinx=$SPHINX -fi - -if [ -z "$JOBS" ]; then - JOBS=2 -fi - -"$sphinx" -a -b html . ./docs/html -w ./docs/_sphinx-warnings.txt -j "$JOBS" "$@" diff --git a/docs/builtins/alias.rst b/docs/builtins/alias.rst new file mode 100644 index 000000000..69ca42ba0 --- /dev/null +++ b/docs/builtins/alias.rst @@ -0,0 +1,36 @@ +alias +===== + +.. dfhack-tool:: + :summary: Configure helper aliases for other DFHack commands. + :tags: dfhack + +Aliases are resolved immediately after built-in commands, which means that an +alias cannot override a built-in command, but can override a command implemented +by a plugin or script. + +Usage +----- + +``alias list`` + Lists all configured aliases +``alias add [arguments...]`` + Adds an alias +``alias replace [arguments...]`` + Replaces an existing alias with a new command, or adds the alias if it does + not already exist +``alias delete `` + Removes the specified alias + +Aliases can be given additional arguments when created and invoked, which will +be passed to the underlying command in order. + +Example +------- + +:: + + [DFHack]# alias add pargs devel/print-args example + [DFHack]# pargs text + example + text diff --git a/docs/builtins/cls.rst b/docs/builtins/cls.rst new file mode 100644 index 000000000..a5fc391cd --- /dev/null +++ b/docs/builtins/cls.rst @@ -0,0 +1,16 @@ +cls +=== + +.. dfhack-tool:: + :summary: Clear the terminal screen. + :tags: dfhack + +Can also be invoked as ``clear``. Note that this command does not delete command +history. It just clears the text on the screen. + +Usage +----- + +:: + + cls diff --git a/docs/builtins/devel/dump-rpc.rst b/docs/builtins/devel/dump-rpc.rst new file mode 100644 index 000000000..957233b62 --- /dev/null +++ b/docs/builtins/devel/dump-rpc.rst @@ -0,0 +1,15 @@ +devel/dump-rpc +============== + +.. dfhack-tool:: + :summary: Dump RPC endpoint info. + :tags: dev + +Write RPC endpoint information to the specified file. + +Usage +----- + +:: + + devel/dump-rpc diff --git a/docs/builtins/die.rst b/docs/builtins/die.rst new file mode 100644 index 000000000..3b9a08380 --- /dev/null +++ b/docs/builtins/die.rst @@ -0,0 +1,15 @@ +die +=== + +.. dfhack-tool:: + :summary: Instantly exit DF without saving. + :tags: dfhack + +Use to exit DF quickly and safely. + +Usage +----- + +:: + + die diff --git a/docs/builtins/disable.rst b/docs/builtins/disable.rst new file mode 100644 index 000000000..7c64f4b39 --- /dev/null +++ b/docs/builtins/disable.rst @@ -0,0 +1,15 @@ +disable +======= + +.. dfhack-tool:: + :summary: Deactivate a DFHack tool that has some persistent effect. + :tags: dfhack + +See the `enable` command for more info. + +Usage +----- + +:: + + disable [ ...] diff --git a/docs/builtins/enable.rst b/docs/builtins/enable.rst new file mode 100644 index 000000000..7af10a9f3 --- /dev/null +++ b/docs/builtins/enable.rst @@ -0,0 +1,33 @@ +enable +====== + +.. dfhack-tool:: + :summary: Activate a DFHack tool that has some persistent effect. + :tags: dfhack + +Many plugins and scripts can be in a distinct enabled or disabled state. Some +of them activate and deactivate automatically depending on the contents of the +world raws. Others store their state in world data. However a number of them +have to be enabled globally, and the init file is the right place to do it. + +Most such plugins or scripts support the built-in ``enable`` and `disable` +commands. Calling them at any time without arguments prints a list of enabled +and disabled plugins, and shows whether that can be changed through the same +commands. Passing plugin names to these commands will enable or disable the +specified plugins. + +Usage +----- + +:: + + enable + enable [ ...] + +Examples +-------- + +``enable manipulator`` + Enable the ``manipulator`` plugin. +``enable manipulator search`` + Enable multiple plugins at once. diff --git a/docs/builtins/fpause.rst b/docs/builtins/fpause.rst new file mode 100644 index 000000000..ed5a40cad --- /dev/null +++ b/docs/builtins/fpause.rst @@ -0,0 +1,15 @@ +fpause +====== + +.. dfhack-tool:: + :summary: Forces DF to pause. + :tags: dfhack + +This is useful when your FPS drops below 1 and you lose control of the game. + +Usage +----- + +:: + + fpause diff --git a/docs/builtins/help.rst b/docs/builtins/help.rst new file mode 100644 index 000000000..a744e8d69 --- /dev/null +++ b/docs/builtins/help.rst @@ -0,0 +1,29 @@ +help +==== + +.. dfhack-tool:: + :summary: Display help about a command or plugin. + :tags: dfhack + +Can also be invoked as ``?`` or ``man`` (short for "manual"). + +Usage +----- + +:: + + help|?|man + help|?|man + +Examples +-------- + +:: + + help blueprint + man blueprint + +Both examples above will display the help text for the `blueprint` command. + +Some commands also take ``help`` or ``?`` as an option on their command line +for the same effect -- e.g. ``blueprint help``. diff --git a/docs/builtins/hide.rst b/docs/builtins/hide.rst new file mode 100644 index 000000000..037679d69 --- /dev/null +++ b/docs/builtins/hide.rst @@ -0,0 +1,18 @@ +hide +==== + +.. dfhack-tool:: + :summary: Hide the DFHack terminal window. + :tags: dfhack + +You can show it again with the `show` command, though you'll need to use it from +a `keybinding` set beforehand or the in-game `command-prompt`. + +Only available on Windows. + +Usage +----- + +:: + + hide diff --git a/docs/builtins/keybinding.rst b/docs/builtins/keybinding.rst new file mode 100644 index 000000000..e7e738bc8 --- /dev/null +++ b/docs/builtins/keybinding.rst @@ -0,0 +1,61 @@ +keybinding +========== + +.. dfhack-tool:: + :summary: Create hotkeys that will run DFHack commands. + :tags: dfhack + +Like any other command, it can be used at any time from the console, but +bindings are not remembered between runs of the game unless re-created in +`dfhack.init`. + +Hotkeys can be any combinations of Ctrl/Alt/Shift with A-Z, 0-9, F1-F12, or +``\``` (the key below the ``Esc`` key. + +Usage +----- + +``keybinding`` + Show some useful information, including the current game context. +``keybinding list `` + List bindings active for the key combination. +``keybinding clear [...]`` + Remove bindings for the specified keys. +``keybinding add "cmdline" ["cmdline"...]`` + Add bindings for the specified key. +``keybinding set "cmdline" ["cmdline"...]`` + Clear, and then add bindings for the specified key. + +The ```` parameter above has the following **case-sensitive** syntax:: + + [Ctrl-][Alt-][Shift-]KEY[@context[|context...]] + +where the ``KEY`` part can be any recognized key and [] denote optional parts. + +When multiple commands are bound to the same key combination, DFHack selects +the first applicable one. Later ``add`` commands, and earlier entries within one +``add`` command have priority. Commands that are not specifically intended for +use as a hotkey are always considered applicable. + +The ``context`` part in the key specifier above can be used to explicitly +restrict the UI state where the binding would be applicable. + +Only bindings with a ``context`` tag that either matches the current context +fully, or is a prefix ending at a ``/`` boundary would be considered for +execution, i.e. when in context ``foo/bar/baz``, keybindings restricted to any +of ``@foo/bar/baz``, ``@foo/bar``, ``@foo``, or none will be active. + +Multiple contexts can be specified by separating them with a pipe (``|``) - for +example, ``@foo|bar|baz/foo`` would match anything under ``@foo``, ``@bar``, or +``@baz/foo``. + +Interactive commands like `liquids` cannot be used as hotkeys. + +Examples +-------- + +``keybinding add Alt-F1 hotkeys`` + Bind Alt-F1 to run the `hotkeys` command on any screen at any time. +``keybinding add Alt-F@dwarfmode gui/quickfort`` + Bind Alt-F to run `gui/quickfort`, but only when on a screen that shows the + main map. diff --git a/docs/builtins/kill-lua.rst b/docs/builtins/kill-lua.rst new file mode 100644 index 000000000..4cb3e203c --- /dev/null +++ b/docs/builtins/kill-lua.rst @@ -0,0 +1,18 @@ +kill-lua +======== + +.. dfhack-tool:: + :summary: Gracefully stop any currently-running Lua scripts. + :tags: dfhack + +Use this command to stop a misbehaving script that appears to be stuck. + +Usage +----- + +:: + + kill-lua + kill-lua force + +Use ``kill-lua force`` if just ``kill-lua`` doesn't seem to work. diff --git a/docs/builtins/load.rst b/docs/builtins/load.rst new file mode 100644 index 000000000..a91316262 --- /dev/null +++ b/docs/builtins/load.rst @@ -0,0 +1,19 @@ +load +==== + +.. dfhack-tool:: + :summary: Load and register a plugin library. + :tags: dfhack + +Also see `unload` and `reload` for related actions. + +Usage +----- + +:: + + load [ ...] + load -a|--all + +You can load individual named plugins or all plugins at once. Note that plugins +are disabled after loading/reloading until you explicitly `enable` them. diff --git a/docs/builtins/ls.rst b/docs/builtins/ls.rst new file mode 100644 index 000000000..7305a0256 --- /dev/null +++ b/docs/builtins/ls.rst @@ -0,0 +1,42 @@ +ls +== + +.. dfhack-tool:: + :summary: List available DFHack commands. + :tags: dfhack + +In order to group related commands, each command is associated with a list of +tags. You can filter the listed commands by a tag or a substring of the +command name. Can also be invoked as ``dir``. + +Usage +----- + +``ls []`` + Lists all available commands and the tags associated with them. +``ls []`` + Shows only commands that have the given tag. Use the `tags` command to see + the list of available tags. +``ls []`` + Shows commands that include the given string. E.g. ``ls quick`` will show + all the commands with "quick" in their names. If the string is also the + name of a tag, then it will be interpreted as a tag name. + +Examples +-------- + +``ls quick`` + List all commands that match the substring "quick". +``ls adventure`` + List all commands with the ``adventure`` tag. +``ls --dev trigger`` + List all commands, including developer and modding commands, that match the + substring "trigger". + +Options +------- + +``--notags`` + Don't print out the tags associated with each command. +``--dev`` + Include commands intended for developers and modders. diff --git a/docs/builtins/plug.rst b/docs/builtins/plug.rst new file mode 100644 index 000000000..8df378d3c --- /dev/null +++ b/docs/builtins/plug.rst @@ -0,0 +1,16 @@ +plug +==== + +.. dfhack-tool:: + :summary: List available plugins and whether they are enabled. + :tags: dfhack + +Usage +----- + +:: + + plug [ [ ...]] + +If run with parameters, it lists only the named plugins. Otherwise it will list +all available plugins. diff --git a/docs/builtins/reload.rst b/docs/builtins/reload.rst new file mode 100644 index 000000000..9ee9061a2 --- /dev/null +++ b/docs/builtins/reload.rst @@ -0,0 +1,21 @@ +reload +====== + +.. dfhack-tool:: + :summary: Reload a loaded plugin. + :tags: dfhack + +Developers use this command to reload a plugin that they are actively modifying. +Also see `load` and `unload` for related actions. + +Usage +----- + +:: + + reload [ ...] + reload -a|--all + +You can reload individual named plugins or all plugins at once. Note that +plugins are disabled after loading/reloading until you explicitly `enable` +them. diff --git a/docs/builtins/sc-script.rst b/docs/builtins/sc-script.rst new file mode 100644 index 000000000..f66aeb412 --- /dev/null +++ b/docs/builtins/sc-script.rst @@ -0,0 +1,26 @@ +sc-script +========= + +.. dfhack-tool:: + :summary: Run commands when game state changes occur. + :tags: dfhack + +This is similar to the static `init-files` but is slightly more flexible since +it can be set dynamically. + +Usage +----- + +``sc-script [help]`` + Show the list of valid event names. +``sc-script list []`` + List the currently registered files for all events or the specified event. +``sc-script add|remove [ ...]`` + Register or unregister a file to be run for the specified event. + +Example +------- + +``sc-script add SC_MAP_LOADED spawn_extra_monsters.init`` + Registers the ``spawn_extra_monsters.init`` file to be run whenever a new + map is loaded. diff --git a/docs/builtins/script.rst b/docs/builtins/script.rst new file mode 100644 index 000000000..0c4ca8c3d --- /dev/null +++ b/docs/builtins/script.rst @@ -0,0 +1,26 @@ +script +====== + +.. dfhack-tool:: + :summary: Execute a batch file of DFHack commands. + :tags: dfhack + +It reads a text file and runs each line as a DFHack command as if it had been +typed in by the user -- treating the input like `an init file `. + +Some other tools, such as `autobutcher` and `workflow`, export their settings as +the commands to create them - which can later be reloaded with ``script``. + +Usage +----- + +:: + + script + +Example +------- + +``script startup.txt`` + Executes the commands in ``startup.txt``, which exists in your DF game + directory. diff --git a/docs/builtins/show.rst b/docs/builtins/show.rst new file mode 100644 index 000000000..cbfa3a386 --- /dev/null +++ b/docs/builtins/show.rst @@ -0,0 +1,19 @@ +show +==== + +.. dfhack-tool:: + :summary: Unhides the DFHack terminal window. + :tags: dfhack + +Useful if you have hidden the terminal with `hide` and you want it back. Since +the terminal window won't be available to run this command, you'll need to use +it from a `keybinding` set beforehand or the in-game `command-prompt`. + +Only available on Windows. + +Usage +----- + +:: + + show diff --git a/docs/builtins/tags.rst b/docs/builtins/tags.rst new file mode 100644 index 000000000..985943647 --- /dev/null +++ b/docs/builtins/tags.rst @@ -0,0 +1,16 @@ +tags +==== + +.. dfhack-tool:: + :summary: List the strings that DFHack tools can be tagged with. + :tags: dfhack + +You can find groups of related tools by passing the tag name to the `ls` +command. + +Usage +----- + +:: + + tags diff --git a/docs/builtins/type.rst b/docs/builtins/type.rst new file mode 100644 index 000000000..1bf86e588 --- /dev/null +++ b/docs/builtins/type.rst @@ -0,0 +1,17 @@ +type +==== + +.. dfhack-tool:: + :summary: Describe how a command is implemented. + :tags: dfhack + +DFHack commands can be provided by plugins, scripts, or by the core library +itself. The ``type`` command can tell you which is the source of a particular +command. + +Usage +----- + +:: + + type diff --git a/docs/builtins/unload.rst b/docs/builtins/unload.rst new file mode 100644 index 000000000..6fa52ea9e --- /dev/null +++ b/docs/builtins/unload.rst @@ -0,0 +1,18 @@ +unload +====== + +.. dfhack-tool:: + :summary: Unload a plugin from memory. + :tags: dfhack + +Also see `load` and `reload` for related actions. + +Usage +----- + +:: + + unload [ ...] + unload -a|--all + +You can unload individual named plugins or all plugins at once. diff --git a/docs/changelog.txt b/docs/changelog.txt index ae50a31df..f46b197ab 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -39,14 +39,23 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## New Tweaks +## New Internal Commands +- `tags`: new built-in command to list the tool category tags and their definitions. tags associated with each tool are visible in the tool help and in the output of `ls`. + ## Fixes +- `autochop`: designate largest trees for chopping first, instead of the smallest +- ``dfhack.run_script``: ensure the arguments passed to scripts are always strings. This allows other scripts to call ``run_script`` with numeric args and it won't break parameter parsing. +- `dig-now`: Fix direction of smoothed walls when adjacent to a door or floodgate - ``job.removeJob()``: ensure jobs are removed from the world list when they are canceled +- `quickfort`: `Dreamfort ` blueprint set: declare the hospital zone before building the coffer; otherwise DF fails to stock the hospital with materials ## Misc Improvements - Init scripts: ``dfhack.init`` and other init scripts have moved to ``dfhack-config/init/``. If you have customized your ``dfhack.init`` file and want to keep your changes, please move the part that you have customized to the new location at ``dfhack-config/init/dfhack.init``. If you do not have changes that you want to keep, do not copy anything, and the new defaults will be used automatically. - History files: ``dfhack.history``, ``tiletypes.history``, ``lua.history``, and ``liquids.history`` have moved to the ``dfhack-config`` directory. If you'd like to keep the contents of your current history files, please move them to ``dfhack-config``. - `do-job-now`: new global keybinding for boosting the priority of the jobs associated with the selected building/work order/unit/item etc.: Alt-N +- `gui/workorder-details`: new keybinding on the workorder details screen: ``D`` - `keybinding`: support backquote (\`) as a hotkey (and assign the hotkey to the new `gui/launcher` interface) +- `ls`: can now filter tools by substring or tag. note that dev scripts are hidden by default. pass the ``--dev`` option to show them. - `manipulator`: add a library of useful default professions - `manipulator`: move professions configuration from ``professions/`` to ``dfhack-config/professions/`` to keep it together with other dfhack configuration. If you have saved professions that you would like to keep, please manually move them to the new folder. - ``materials.ItemTraitsDialog``: added a default ``on_select``-handler which toggles the traits. @@ -55,9 +64,13 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `seedwatch`: ``seedwatch all`` now adds all plants with seeds to the watchlist, not just the "basic" crops. - UX: You can now move the cursor around in DFHack text fields in ``gui/`` scripts (e.g. `gui/blueprint`, `gui/quickfort`, or `gui/gm-editor`). You can move the cursor by clicking where you want it to go with the mouse or using the Left/Right arrow keys. Ctrl+Left/Right will move one word at a time, and Alt+Left/Right will move to the beginning/end of the text. - UX: You can now click on the hotkey hint text in many ``gui/`` script windows to activate the hotkey, like a button. Not all scripts have been updated to use the clickable widget yet, but you can try it in `gui/blueprint` or `gui/quickfort`. +- UX: Label widget scroll icons are replaced with scrollbars that represent the percentage of text on the screen and move with the position of the visible text, just like web browser scrollbars. +- `quickfort`: `Dreamfort ` blueprint set improvements: set traffic designations to encourage dwarves to eat cooked food instead of raw ingredients ## Documentation - Added `modding-guide` +- Update all DFHack tool documentation (300+ pages) with standard syntax formatting, usage examples, and overall clarified text. +- Group DFHack tools by `tag ` so similar tools are grouped and easy to find ## API - Removed "egg" ("eggy") hook support (Linux only). The only remaining method of hooking into DF is by interposing SDL calls, which has been the method used by all binary releases of DFHack. @@ -69,10 +82,14 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Lua - History: added ``dfhack.getCommandHistory(history_id, history_filename)`` and ``dfhack.addCommandToHistory(history_id, history_filename, command)`` so gui scripts can access a commandline history without requiring a terminal. +- Added ``dfhack.screen.hideGuard()``: exposes the C++ ``Screen::Hide`` to Lua - ``helpdb``: database and query interface for DFHack tool help text - ``tile-material``: fix the order of declarations. The ``GetTileMat`` function now returns the material as intended (always returned nil before). Also changed the license info, with permission of the original author. +- ``utils.df_expr_to_ref()``: fixed some errors that could occur when navigating tables - ``widgets.EditField``: new ``onsubmit2`` callback attribute is called when the user hits Shift-Enter. - ``widgets.EditField``: new function: ``setCursor(position)`` sets the input cursor. +- ``widgets.EditField``: new attribute: ``ignore_keys`` lets you ignore specified characters if you want to use them as hotkeys +- ``widgets.FilteredList``: new attribute: ``edit_ignore_keys`` gets passed to the filter EditField as ``ignore_keys`` - ``widgets.Label``: ``scroll`` function now interprets the keywords ``+page``, ``-page``, ``+halfpage``, and ``-halfpage`` in addition to simple positive and negative numbers. - ``widgets.HotkeyLabel``: clicking on the widget will now call ``on_activate()``. - ``widgets.CycleHotkeyLabel``: clicking on the widget will now cycle the options and trigger ``on_change()``. This also applies to the ``ToggleHotkeyLabel`` subclass. @@ -1054,7 +1071,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `caravan`: documented (new in 0.44.10-alpha1) - `deathcause`: added "slaughtered" to descriptions - `fix/retrieve-units`: now re-adds units to active list to counteract `fix/dead-units` -- `item-descriptions`: fixed several grammatical errors +- ``item-descriptions``: fixed several grammatical errors - `modtools/create-unit`: - added quantity argument - now selects a caste at random if none is specified diff --git a/docs/guides/examples-guide.rst b/docs/guides/examples-guide.rst index b699b8204..74f94c20b 100644 --- a/docs/guides/examples-guide.rst +++ b/docs/guides/examples-guide.rst @@ -1,8 +1,8 @@ .. _config-examples-guide: .. _dfhack-examples-guide: -DFHack Example Configuration File Index -======================================= +DFHack Config File Examples +=========================== The :source:`hack/examples ` folder contains ready-to-use examples of various DFHack configuration files. You can use them by copying them @@ -14,8 +14,8 @@ The ``init/`` subfolder ----------------------- The :source:`init/ ` subfolder contains useful DFHack -`init-files` that you can copy into your main Dwarf Fortress folder -- the same -directory as ``dfhack.init``. +`init-files` that you can copy into your :file:`dfhack-config/init` folder -- +the same directory as ``dfhack.init``. .. _onMapLoad-dreamfort-init: @@ -28,14 +28,14 @@ it is useful (and customizable) for any fort. It includes the following config: - Calls `ban-cooking` for items that have important alternate uses and should not be cooked. This configuration is only set when a fortress is first started, so later manual changes will not be overridden. -- Automates calling of various fort maintenance and `scripts-fix`, like - `cleanowned` and `fix/stuckdoors`. +- Automates calling of various fort maintenance scripts, like `cleanowned` and + `fix/stuckdoors`. - Keeps your manager orders intelligently ordered with `orders` ``sort`` so no orders block other orders from ever getting completed. - Periodically enqueues orders to shear and milk shearable and milkable pets. - Sets up `autofarm` to grow 30 units of every crop, except for pig tails, which is set to 150 units to support the textile industry. -- Sets up `seedwatch` to keep 30 of every type of seed. +- Sets up `seedwatch` to protect 30 of every type of seed. - Configures `prioritize` to automatically boost the priority of important and time-sensitive tasks that could otherwise get ignored in busy forts, like hauling food, tanning hides, storing items in vehicles, pulling levers, and diff --git a/docs/guides/index.rst b/docs/guides/index.rst index 7208b5276..d0125921f 100644 --- a/docs/guides/index.rst +++ b/docs/guides/index.rst @@ -6,6 +6,8 @@ These pages are detailed guides covering DFHack tools. .. toctree:: :maxdepth: 1 - :glob: - * + /docs/guides/examples-guide + /docs/guides/quickfort-library-guide + /docs/guides/quickfort-user-guide + /docs/guides/quickfort-alias-guide diff --git a/docs/guides/quickfort-alias-guide.rst b/docs/guides/quickfort-alias-guide.rst index 6afad7569..d4be8aecd 100644 --- a/docs/guides/quickfort-alias-guide.rst +++ b/docs/guides/quickfort-alias-guide.rst @@ -1,10 +1,11 @@ .. _quickfort-alias-guide: -Quickfort Keystroke Alias Guide -=============================== +Quickfort Keystroke Alias Reference +=================================== Aliases allow you to use simple words to represent complicated key sequences -when configuring buildings and stockpiles in quickfort ``#query`` blueprints. +when configuring buildings and stockpiles in quickfort ``#query`` and +``#config`` blueprints. For example, say you have the following ``#build`` and ``#place`` blueprints:: diff --git a/docs/guides/quickfort-library-guide.rst b/docs/guides/quickfort-library-guide.rst index ab80bab5f..de5409ab3 100644 --- a/docs/guides/quickfort-library-guide.rst +++ b/docs/guides/quickfort-library-guide.rst @@ -1,13 +1,11 @@ .. _blueprint-library-guide: .. _quickfort-library-guide: -Blueprint Library Index -======================= +Quickfort Blueprint Library +=========================== This guide contains a high-level overview of the blueprints available in the -:source:`quickfort blueprint library `. You can list -library blueprints by running ``quickfort list --library`` or by hitting -:kbd:`Alt`:kbd:`l` in the ``gui/quickfort`` file load dialog. +:source:`quickfort blueprint library `. Each file is hyperlinked to its online version so you can see exactly what the blueprints do before you run them. Also, if you use `gui/quickfort`, you will diff --git a/docs/guides/quickfort-user-guide.rst b/docs/guides/quickfort-user-guide.rst index e92b7d3e8..9c7d3ed44 100644 --- a/docs/guides/quickfort-user-guide.rst +++ b/docs/guides/quickfort-user-guide.rst @@ -29,9 +29,8 @@ For those just looking to apply existing 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 -:source:`online `, or run ``quickfort list -l`` at the -``[DFHack]#`` prompt to list them, and then ``quickfort run`` to apply them to -your fort! +:source:`online `, or run `gui/quickfort` to browse +and apply them to your fort! Before you become an expert at writing blueprints, though, you should know that the easiest way to make a quickfort blueprint is to build your plan "for real" diff --git a/docs/images/stonesense-roadtruss.jpg b/docs/images/stonesense-roadtruss.jpg new file mode 100644 index 000000000..19e71dd70 Binary files /dev/null and b/docs/images/stonesense-roadtruss.jpg differ diff --git a/docs/plugins/3dveins.rst b/docs/plugins/3dveins.rst new file mode 100644 index 000000000..f71a14343 --- /dev/null +++ b/docs/plugins/3dveins.rst @@ -0,0 +1,37 @@ +3dveins +======= + +.. dfhack-tool:: + :summary: Rewrite layer veins to expand in 3D space. + :tags: fort gameplay map + +Existing, flat veins are removed and new 3D veins that naturally span z-levels +are generated in their place. The transformation preserves the mineral counts +reported by `prospect`. + +Usage +----- + +:: + + 3dveins [verbose] + +The ``verbose`` option prints out extra information to the console. + +Example +------- + +:: + + 3dveins + +New veins are generated using 3D Perlin noise in order to produce a layout that +flows smoothly between z-levels. The vein distribution is based on the world +seed, so running the command for the second time should produce no change. It is +best to run it just once immediately after embark. + +This command is intended as only a cosmetic change, so it takes care to exactly +preserve the mineral counts reported by ``prospect all``. The amounts of layer +stones may slightly change in some cases if vein mass shifts between z layers. + +The only undo option is to restore your save from backup. diff --git a/docs/plugins/RemoteFortressReader.rst b/docs/plugins/RemoteFortressReader.rst new file mode 100644 index 000000000..c70adc608 --- /dev/null +++ b/docs/plugins/RemoteFortressReader.rst @@ -0,0 +1,24 @@ +RemoteFortressReader +==================== + +.. dfhack-tool:: + :summary: Backend for Armok Vision. + :tags: dev graphics + :no-command: + +.. dfhack-command:: RemoteFortressReader_version + :summary: Print the loaded RemoteFortressReader version. + +.. dfhack-command:: load-art-image-chunk + :summary: Gets an art image chunk by index. + +This plugin provides an API for realtime remote fortress visualization. See +:forums:`Armok Vision <146473>`. + +Usage +----- + +``RemoteFortressReader_version`` + Print the loaded RemoteFortressReader version. +``load-art-image-chunk `` + Gets an art image chunk by index, loading from disk if necessary. diff --git a/docs/plugins/add-spatter.rst b/docs/plugins/add-spatter.rst new file mode 100644 index 000000000..873bd761f --- /dev/null +++ b/docs/plugins/add-spatter.rst @@ -0,0 +1,14 @@ +add-spatter +=========== + +.. dfhack-tool:: + :summary: Make tagged reactions produce contaminants. + :tags: adventure fort gameplay items + :no-command: + +Give some use to all those poisons that can be bought from caravans! The plugin +automatically enables itself when you load a world with reactions that include +names starting with ``SPATTER_ADD_``, so there are no commands to run to use it. +These reactions will then produce contaminants on items instead of improvements. +The contaminants are immune to being washed away by water or destroyed by +`clean`. diff --git a/docs/plugins/autobutcher.rst b/docs/plugins/autobutcher.rst new file mode 100644 index 000000000..83c99271a --- /dev/null +++ b/docs/plugins/autobutcher.rst @@ -0,0 +1,111 @@ +autobutcher +=========== + +.. dfhack-tool:: + :summary: Automatically butcher excess livestock. + :tags: fort auto fps animals + +This plugin monitors how many pets you have of each gender and age and assigns +excess lifestock for slaughter. It requires that you add the target race(s) to a +watch list. Units will be ignored if they are: + +* Untamed +* Nicknamed (for custom protection; you can use the `rename` ``unit`` tool + individually, or `zone` ``nick`` for groups) +* Caged, if and only if the cage is defined as a room (to protect zoos) +* Trained for war or hunting + +Creatures who will not reproduce (because they're not interested in the +opposite sex or have been gelded) will be butchered before those who will. +Older adults and younger children will be butchered first if the population +is above the target (defaults are: 1 male kid, 5 female kids, 1 male adult, +5 female adults). Note that you may need to set a target above 1 to have a +reliable breeding population due to asexuality etc. See `fix-ster` if this is a +problem. + +Usage +----- + +``enable autobutcher`` + Start processing livestock according to the configuration. Note that + no races are watched by default. You have to add the ones you want to + monitor with ``autobutcher watch``, ``autobutcher target`` or + ``autobutcher autowatch``. +``autobutcher autowatch`` + Automatically add all new races (animals you buy from merchants, tame + yourself, or get from migrants) to the watch list using the default target + counts. +``autobutcher noautowatch`` + Stop auto-adding new races to the watch list. +``autobutcher target all|new| [ ...]`` + Set target counts for the specified races: + - fk = number of female kids + - mk = number of male kids + - fa = number of female adults + - ma = number of female adults + If you specify ``all``, then this command will set the counts for all races + on your current watchlist (including the races which are currenly set to + 'unwatched') and sets the new default for future watch commands. If you + specify ``new``, then this command just sets the new default counts for + future watch commands without changing your current watchlist. Otherwise, + all space separated races listed will be modified (or added to the watchlist + if they aren't there already). +``autobutcher ticks `` + Change the number of ticks between scanning cycles when the plugin is + enabled. By default, a cycle happens every 6000 ticks (about 8 game days). +``autobutcher watch all| [ ...]`` + Start watching the listed races. If they aren't already in your watchlist, + then they will be added with the default target counts. If you specify the + keyword ``all``, then all races in your watchlist that are currently marked + as unwatched will become watched. +``autobutcher unwatch all| [ ...]`` + Stop watching the specified race(s) (or all races on your watchlist if + ``all`` is given). The current target settings will be remembered. +``autobutcher forget all| [ ...]`` + Unwatch the specified race(s) (or all races on your watchlist if ``all`` is + given) and forget target settings for it/them. +``autobutcher [list]`` + Print status and current settings, including the watchlist. This is the + default command if autobutcher is run without parameters. +``autobutcher list_export`` + Print commands required to set the current settings in another fort. + +To see a list of all races, run this command: + + devel/query --table df.global.world.raws.creatures.all --search ^creature_id --maxdepth 1 + +Though not all the races listed there are tameable/butcherable. + +.. note:: + + Settings and watchlist are stored in the savegame, so you can have different + settings for each save. If you want to copy your watchlist to another, + savegame, you can export the commands required to recreate your settings. + + To export, open an external terminal in the DF directory, and run + ``dfhack-run autobutcher list_export > filename.txt``. To import, load your + new save and run ``script filename.txt`` in the DFHack terminal. + +Examples +-------- + +Keep at most 7 kids (4 female, 3 male) and at most 3 adults (2 female, 1 male) +for turkeys. Once the kids grow up, the oldest adults will get slaughtered. +Excess kids will get slaughtered starting the the youngest to allow that the +older ones grow into adults:: + + autobutcher target 4 3 2 1 BIRD_TURKEY + +Configure useful limits for dogs, cats, geese (for eggs, leather, and bones), +alpacas, sheep, and llamas (for wool), and pigs (for milk and meat). All other +unnamed tame units will be marked for slaughter as soon as they arrive in your +fortress:: + + enable autobutcher + autobutcher target 2 2 2 2 DOG + autobutcher target 1 1 2 2 CAT + autobutcher target 50 50 14 2 BIRD_GOOSE + autobutcher target 2 2 4 2 ALPACA SHEEP LLAMA + autobutcher target 5 5 6 2 PIG + autobutcher target 0 0 0 0 new + autobutcher autowatch diff --git a/docs/plugins/autochop.rst b/docs/plugins/autochop.rst new file mode 100644 index 000000000..6b51b85cb --- /dev/null +++ b/docs/plugins/autochop.rst @@ -0,0 +1,27 @@ +autochop +======== + +.. dfhack-tool:: + :summary: Auto-harvest trees when low on stockpiled logs. + :tags: fort auto plants + :no-command: + +This plugin can designate trees for chopping when your stocks are low on logs. + +Usage +----- + +:: + + enable autochop + +Then, open the settings menu with :kbd:`c` from the designations menu (the +option appears when you have "Chop Down Trees" selected with :kbd:`d`-:kbd:`t`). + +Set your desired thresholds and enable autochopping with :kbd:`a`. + +You can also restrict autochopping to specific burrows. Highlight a burrow name +with the Up/Down arrow keys and hit :kbd:`Enter` to mark it as the autochop +burrrow. + +Autochop checks your stock of logs and designates trees once every in game day. diff --git a/docs/plugins/autoclothing.rst b/docs/plugins/autoclothing.rst new file mode 100644 index 000000000..40fd4d996 --- /dev/null +++ b/docs/plugins/autoclothing.rst @@ -0,0 +1,32 @@ +autoclothing +============ + +.. dfhack-tool:: + :summary: Automatically manage clothing work orders. + :tags: fort auto workorders + +This command allows you to set how many of each clothing type every citizen +should have. + +Usage +----- + +:: + + autoclothing + autoclothing [quantity] + +``material`` can be "cloth", "silk", "yarn", or "leather". The ``item`` can be +anything your civilization can produce, such as "dress" or "mitten". + +When invoked without parameters, it shows a summary of all managed clothing +orders. When invoked with a material and item, but without a quantity, it shows +the current configuration for that material and item. + +Examples +-------- + +``autoclothing cloth "short skirt" 10`` + Sets the desired number of cloth short skirts available per citizen to 10. +``autoclothing cloth dress`` + Displays the currently set number of cloth dresses chosen per citizen. diff --git a/docs/plugins/autodump.rst b/docs/plugins/autodump.rst new file mode 100644 index 000000000..03e10db9c --- /dev/null +++ b/docs/plugins/autodump.rst @@ -0,0 +1,71 @@ +autodump +======== + +.. dfhack-tool:: + :summary: Automatically set items in a stockpile to be dumped. + :tags: fort armok fps productivity items stockpiles + :no-command: + +.. dfhack-command:: autodump + :summary: Teleports items marked for dumping to the cursor position. + +.. dfhack-command:: autodump-destroy-here + :summary: Destroy items marked for dumping under the cursor. + +.. dfhack-command:: autodump-destroy-item + :summary: Destroys the selected item. + +When `enabled `, this plugin adds an option to the :kbd:`q` menu for +stockpiles. When the ``autodump`` option is selected for the stockpile, any +items placed in the stockpile will automatically be designated to be dumped. + +When invoked as a command, it can instantly move all unforbidden items marked +for dumping to the tile under the cursor. After moving the items, the dump flag +is unset and the forbid flag is set, just as if it had been dumped normally. Be +aware that dwarves that are en route to pick up the item for dumping may still +come and move the item to your dump zone. + +The cursor must be placed on a floor tile so the items can be dumped there. + +Usage +----- + +:: + + enable autodump + autodump [] + autodump-destroy-here + autodump-destroy-item + +``autodump-destroy-here`` is an alias for ``autodump destroy-here`` and is +intended for use as a keybinding. + +``autodump-destroy-item`` destroys only the selected item. The item may be +selected in the :kbd:`k` list or in the container item list. If called again +before the game is resumed, cancels destruction of the item. + +Options +------- + +``destroy`` + Destroy instead of dumping. Doesn't require a cursor. If ``autodump`` is + called again with this option before the game is resumed, it cancels + pending destroy actions. +``destroy-here`` + Destroy items marked for dumping under the cursor. +``visible`` + Only process items that are not hidden. +``hidden`` + Only process hidden items. +``forbidden`` + Only process forbidden items (default: only unforbidden). + +Examples +-------- + +``autodump`` + Teleports items marked for dumping to the cursor position. +``autodump destroy`` + Destroys all unforbidden items marked for dumping +``autodump-destroy-item`` + Destroys the selected item. diff --git a/docs/plugins/autofarm.rst b/docs/plugins/autofarm.rst new file mode 100644 index 000000000..8896c3117 --- /dev/null +++ b/docs/plugins/autofarm.rst @@ -0,0 +1,37 @@ +autofarm +======== + +.. dfhack-tool:: + :summary: Automatically manage farm crop selection. + :tags: fort auto plants + +Periodically scan your plant stocks and assign crops to your farm plots based on +which plant stocks are low (as long as you have the appropriate seeds). The +target threshold for each crop type is configurable. + +Usage +----- + +``enable autofarm`` + Enable the plugin and start managing crop assignment. +``autofarm runonce`` + Updates all farm plots once, without enabling the plugin. +``autofarm status`` + Prints status information, including any defined thresholds. +``autofarm default `` + Sets the default threshold. +``autofarm threshold [ ...]`` + Sets thresholds of individual plant types. + +You can find the identifiers for the crop types in your world by running the +following command:: + + lua "for _,plant in ipairs(df.global.world.raws.plants.all) do if plant.flags.SEED then print(plant.id) end end" + +Examples +-------- + +``autofarm default 30`` + Set the default threshold to 30. +``autofarm threshold 150 MUSHROOM_HELMET_PLUMP GRASS_TAIL_PIG`` + Set the threshold for Plump Helmets and Pig Tails to 150 diff --git a/docs/plugins/autogems.rst b/docs/plugins/autogems.rst new file mode 100644 index 000000000..d4112c6c0 --- /dev/null +++ b/docs/plugins/autogems.rst @@ -0,0 +1,26 @@ +autogems +======== + +.. dfhack-tool:: + :summary: Automatically cut rough gems. + :tags: fort auto workorders + :no-command: + +.. dfhack-command:: autogems-reload + :summary: Reloads the autogems configuration file. + +Automatically cut rough gems. This plugin periodically scans your stocks of +rough gems and creates manager orders for cutting them at a Jeweler's Workshop. + +Usage +----- + +``enable autogems`` + Enables the plugin and starts autocutting gems according to its + configuration. +``autogems-reload`` + Reloads the autogems configuration file. You might need to do this if you + have manually modified the contents while the game is running. + +Run `gui/autogems` for a configuration UI, or access the ``Auto Cut Gems`` +option from the Current Workshop Orders screen (:kbd:`o`-:kbd:`W`). diff --git a/docs/plugins/autohauler.rst b/docs/plugins/autohauler.rst new file mode 100644 index 000000000..a71d3ed02 --- /dev/null +++ b/docs/plugins/autohauler.rst @@ -0,0 +1,57 @@ +autohauler +========== + +.. dfhack-tool:: + :summary: Automatically manage hauling labors. + :tags: fort auto labors + +Similar to `autolabor`, but instead of managing all labors, ``autohauler`` only +addresses hauling labors, leaving the assignment of skilled labors entirely up +to you. You can use the in-game `manipulator` UI or an external tool like Dwarf +Therapist to do so. + +Idle dwarves who are not on active military duty will be assigned the hauling +labors; everyone else (including those currently hauling) will have the hauling +labors removed. This is to encourage every dwarf to do their assigned skilled +labors whenever possible, but resort to hauling when those jobs are not +available. This also implies that the user will have a very tight skill +assignment, with most skilled labors only being assigned to just a few dwarves +and almost every non-military dwarf having at least one skilled labor assigned. + +Autohauler allows a skill to be used as a flag to exempt a dwarf from +``autohauler``'s effects. By default, this is the unused ALCHEMIST labor, but it +can be changed by the user. + +Usage +----- + +``enable autohauler`` + Start managing hauling labors. This is normally all you need to do. + Autohauler works well on default settings. +``autohauler status`` + Show autohauler status and status of fort dwarves. +``autohauler haulers`` + Set whether a particular labor should be assigned to haulers. +``autohauler allow|forbid`` + Set whether a particular labor should mark a dwarf as exempt from hauling. + By default, only the ``ALCHEMIST`` labor is set to ``forbid``. +``autohauler reset-all| reset`` + Reset a particular labor (or all labors) to their default + haulers/allow/forbid state. +``autohauler list`` + Show the active configuration for all labors. +``autohauler frameskip `` + Set the number of frames between runs of autohauler. +``autohauler debug`` + In the next cycle, output the state of every dwarf. + +Examples +-------- + +``autohauler HAUL_STONE haulers`` + Set stone hauling as a hauling labor (this is already the default). +``autohauler RECOVER_WOUNDED allow`` + Allow the "Recover wounded" labor to be manually assigned by the player. By + default it is automatically given to haulers. +``autohauler MINE forbid`` + Don't assign hauling labors to dwarves with the Mining labor enabled. diff --git a/docs/plugins/autolabor.rst b/docs/plugins/autolabor.rst new file mode 100644 index 000000000..ed39c2666 --- /dev/null +++ b/docs/plugins/autolabor.rst @@ -0,0 +1,92 @@ +autolabor +========= + +.. dfhack-tool:: + :summary: Automatically manage dwarf labors. + :tags: fort auto labors + +Autolabor attempts to keep as many dwarves as possible busy while allowing +dwarves to specialize in specific skills. + +Autolabor frequently checks how many jobs of each type are available and sets +labors proportionally in order to get them all done quickly. Labors with +equipment -- mining, hunting, and woodcutting -- which are abandoned if labors +change mid-job, are handled slightly differently to minimise churn. + +Dwarves on active military duty or dwarves assigned to burrows are left +untouched by autolabor. + +.. warning:: + + autolabor will override any manual changes you make to labors while it is + enabled, including through other tools such as Dwarf Therapist. + +Usage +----- + +:: + + enable autolabor + +Anything beyond this is optional - autolabor works well with the default +settings. Once you have enabled it in a fortress, it stays enabled until you +explicitly disable it, even if you save and reload your game. + +By default, each labor is assigned to between 1 and 200 dwarves (2-200 for +mining). 33% of the workforce become haulers, who handle all hauling jobs as +well as cleaning, pulling levers, recovering wounded, removing constructions, +and filling ponds. Other jobs are automatically assigned as described above. +Each of these settings can be adjusted. + +Jobs are rarely assigned to nobles with responsibilities for meeting diplomats +or merchants, never to the chief medical dwarf, and less often to the bookeeper +and manager. + +Hunting is never assigned without a butchery, and fishing is never assigned +without a fishery. + +For each labor, a preference order is calculated based on skill, biased against +masters of other trades and excluding those who can't do the job. The labor is +then added to the best dwarves for that labor, then to additional +dwarfs that meet any of these conditions: + +* The dwarf is idle and there are no idle dwarves assigned to this labor +* The dwarf has non-zero skill associated with the labor +* The labor is mining, hunting, or woodcutting and the dwarf currently has it enabled. + +We stop assigning dwarves when we reach the maximum allowed. + +Examples +-------- + +``autolabor MINE 5`` + Keep at least 5 dwarves with mining enabled. +``autolabor CUT_GEM 1 1`` + Keep exactly 1 dwarf with gemcutting enabled. +``autolabor COOK 1 1 3`` + Keep 1 dwarf with cooking enabled, selected only from the top 3. +``autolabor FEED_WATER_CIVILIANS haulers`` + Have haulers feed and water wounded dwarves. +``autolabor CUTWOOD disable`` + Turn off autolabor for wood cutting. + +Advanced usage +-------------- + +``autolabor list`` + List current status of all labors. Use this command to see the IDs for all + labors. +``autolabor status`` + Show basic status information. +``autolabor [] []`` + Set range of dwarves assigned to a labor, optionally specifying the size of + the pool of most skilled dwarves that will ever be considered for this + labor. +``autolabor haulers`` + Set a labor to be handled by hauler dwarves. +``autolabor disable`` + Turn off autolabor for a specific labor. +``autolabor reset-all| reset`` + Return a labor (or all labors) to the default handling. + +See `autolabor-artisans` for a differently-tuned setup. diff --git a/docs/plugins/automaterial.rst b/docs/plugins/automaterial.rst new file mode 100644 index 000000000..068664638 --- /dev/null +++ b/docs/plugins/automaterial.rst @@ -0,0 +1,53 @@ +automaterial +============ + +.. dfhack-tool:: + :summary: Sorts building materials by recent usage. + :tags: fort design productivity buildings map + :no-command: + +This plugin makes building constructions (walls, floors, fortifications, etc) +much easier by saving you from having to trawl through long lists of materials +each time you place one. + +It moves the last used material for a given construction type to the top of the +list, if there are any left. So if you build a wall with chalk blocks, the next +time you place a wall the chalk blocks will be at the top of the list, +regardless of distance (it only does this in "grouped" mode, as individual item +lists could be huge). This means you can place most constructions without having +to search for your preferred material type. + +Usage +----- + +:: + + enable automaterial + +.. image:: ../images/automaterial-mat.png + +Pressing :kbd:`a` while highlighting any material will enable that material for +"auto select" for this construction type. You can enable multiple materials. Now +the next time you place this type of construction, the plugin will automatically +choose materials for you from the kinds you enabled. If there is enough to +satisfy the whole placement, you won't be prompted with the material screen at +all -- the construction will be placed and you will be back in the construction +menu. + +When choosing the construction placement, you will see a couple of options: + +.. image:: ../images/automaterial-pos.png + +Use :kbd:`a` here to temporarily disable the material autoselection, e.g. if you +need to go to the material selection screen so you can toggle some materials on +or off. + +The other option (auto type selection, off by default) can be toggled on with +:kbd:`t`. If you toggle this option on, instead of returning you to the main +construction menu after selecting materials, it returns you back to this screen. +If you use this along with several autoselect enabled materials, you should be +able to place complex constructions more conveniently. + +The ``automaterial`` plugin also enables extra contruction placement modes, such +as designating areas larger than 10x10 and allowing you to designate hollow +rectangles instead of the default filled ones. diff --git a/docs/plugins/automelt.rst b/docs/plugins/automelt.rst new file mode 100644 index 000000000..12e3412e2 --- /dev/null +++ b/docs/plugins/automelt.rst @@ -0,0 +1,18 @@ +automelt +======== + +.. dfhack-tool:: + :summary: Quickly designate items to be melted. + :tags: fort productivity items stockpiles + :no-command: + +When `enabled `, this plugin adds an option to the :kbd:`q` menu for +stockpiles. When the ``automelt`` option is selected for the stockpile, any +items placed in the stockpile will automatically be designated to be melted. + +Usage +----- + +:: + + enable automelt diff --git a/docs/plugins/autonestbox.rst b/docs/plugins/autonestbox.rst new file mode 100644 index 000000000..9d5683f2b --- /dev/null +++ b/docs/plugins/autonestbox.rst @@ -0,0 +1,33 @@ +autonestbox +=========== + +.. dfhack-tool:: + :summary: Auto-assign egg-laying female pets to nestbox zones. + :tags: fort auto animals + +To use this feature, you must create pen/pasture zones above nestboxes. If the +pen is bigger than 1x1, the nestbox must be in the top left corner. Only 1 unit +will be assigned per pen, regardless of the size. Egg layers who are also +grazers will be ignored, since confining them to a 1x1 pasture is not a good +idea. Only tame and domesticated own units are processed since pasturing +half-trained wild egg layers could destroy your neat nestbox zones when they +revert to wild. + +Note that the age of the units is not checked, so you might get some egg-laying +kids assigned to the nestbox zones. Most birds grow up quite fast, though, so +they should be adults and laying eggs soon enough. + +Usage +----- + +``enable autonestbox`` + Start checking for unpastured egg-layers and assigning them to nestbox + zones. +``autonestbox`` + Print current status. +``autonestbox now`` + Run a scan and assignment cycle right now. Does not require that the plugin + is enabled. +``autonestbox ticks `` + Change the number of ticks between scan and assignment cycles when the + plugin is enabled. The default is 6000 (about 8 days). diff --git a/docs/plugins/autotrade.rst b/docs/plugins/autotrade.rst new file mode 100644 index 000000000..f355d40ef --- /dev/null +++ b/docs/plugins/autotrade.rst @@ -0,0 +1,18 @@ +autotrade +========= + +.. dfhack-tool:: + :summary: Quickly designate items to be traded. + :tags: fort productivity items stockpiles + :no-command: + +When `enabled `, this plugin adds an option to the :kbd:`q` menu for +stockpiles. When the ``autotrade`` option is selected for the stockpile, any +items placed in the stockpile will automatically be designated to be traded. + +Usage +----- + +:: + + enable autotrade diff --git a/docs/plugins/blueprint.rst b/docs/plugins/blueprint.rst new file mode 100644 index 000000000..9d7d7ef8d --- /dev/null +++ b/docs/plugins/blueprint.rst @@ -0,0 +1,133 @@ +blueprint +========= + +.. dfhack-tool:: + :summary: Record a live game map in a quickfort blueprint. + :tags: fort design buildings map stockpiles + +With ``blueprint``, you can export the structure of a portion of your fortress +in a blueprint file that you (or anyone else) can later play back with +`quickfort`. + +Blueprints are ``.csv`` or ``.xlsx`` files created in the ``blueprints`` +subdirectory of your DF folder. The map area to turn into a blueprint is either +selected interactively with the ``blueprint gui`` command or, if the GUI is not +used, starts at the active cursor location and extends right and down for the +requested width and height. + +Usage +----- + +:: + + blueprint [] [ []] [] + blueprint gui [ []] [] + +Examples +-------- + +``blueprint gui`` + Runs `gui/blueprint`, the interactive frontend, where all configuration for + a ``blueprint`` command can be set visually and interactively. +``blueprint 30 40 bedrooms`` + Generates blueprints for an area 30 tiles wide by 40 tiles tall, starting + from the active cursor on the current z-level. Blueprints are written to + ``bedrooms.csv`` in the ``blueprints`` directory. +``blueprint 30 40 bedrooms dig --cursor 108,100,150`` + Generates only the ``#dig`` blueprint in the ``bedrooms.csv`` file, and + the start of the blueprint area is set to a specific value instead of using + the in-game cursor position. + +Positional parameters +--------------------- + +``width`` + Width of the area (in tiles) to translate. +``height`` + Height of the area (in tiles) to translate. +``depth`` + Number of z-levels to translate. Positive numbers go *up* from the cursor + and negative numbers go *down*. Defaults to 1 if not specified, indicating + that the blueprint should only include the current z-level. +``name`` + Base name for blueprint files created in the ``blueprints`` directory. If no + name is specified, "blueprint" is used by default. The string must contain + some characters other than numbers so the name won't be confused with the + optional ``depth`` parameter. + +Phases +------ + +If you want to generate blueprints only for specific phases, add their names to +the commandline, anywhere after the blueprint base name. You can list multiple +phases; just separate them with a space. + +``dig`` + Generate quickfort ``#dig`` blueprints for digging natural stone. +``carve`` + Generate quickfort ``#dig`` blueprints for smoothing and carving. +``build`` + Generate quickfort ``#build`` blueprints for constructions and buildings. +``place`` + Generate quickfort ``#place`` blueprints for placing stockpiles. +``zone`` + Generate quickfort ``#zone`` blueprints for designating zones. +``query`` + Generate quickfort ``#query`` blueprints for configuring rooms. + +If no phases are specified, phases are autodetected. For example, a ``#place`` +blueprint will be created only if there are stockpiles in the blueprint area. + +Options +------- + +``-c``, ``--cursor ,,`` + Use the specified map coordinates instead of the current cursor position for + the upper left corner of the blueprint range. If this option is specified, + then an active game map cursor is not necessary. +``-e``, ``--engrave`` + Record engravings in the ``carve`` phase. If this option is not specified, + engravings are ignored. +``-f``, ``--format `` + Select the output format of the generated files. See the `Output formats`_ + section below for options. If not specified, the output format defaults to + "minimal", which will produce a small, fast ``.csv`` file. +``-h``, ``--help`` + Show command help text. +``-s``, ``--playback-start ,,`` + Specify the column and row offsets (relative to the upper-left corner of the + blueprint, which is ``1,1``) where the player should put the cursor when the + blueprint is played back with `quickfort`, in + `quickfort start marker ` format, for example: + ``10,10,central stairs``. If there is a space in the comment, you will need + to surround the parameter string in double quotes: + ``"-s10,10,central stairs"`` or ``--playback-start "10,10,central stairs"`` + or ``"--playback-start=10,10,central stairs"``. +``-t``, ``--splitby `` + Split blueprints into multiple files. See the `Splitting output into + multiple files`_ section below for details. If not specified, defaults to + "none", which will create a standard quickfort + `multi-blueprint ` file. + +Output formats +-------------- + +Here are the values that can be passed to the ``--format`` flag: + +``minimal`` + Creates ``.csv`` files with minimal file size that are fast to read and + write. This is the default. +``pretty`` + Makes the blueprints in the ``.csv`` files easier to read and edit with a + text editor by adding extra spacing and alignment markers. + +Splitting output into multiple files +------------------------------------ + +The ``--splitby`` flag can take any of the following values: + +``none`` + Writes all blueprints into a single file. This is the standard format for + quickfort fortress blueprint bundles and is the default. +``phase`` + Creates a separate file for each phase. diff --git a/docs/plugins/building-hacks.rst b/docs/plugins/building-hacks.rst new file mode 100644 index 000000000..12f49fbbe --- /dev/null +++ b/docs/plugins/building-hacks.rst @@ -0,0 +1,9 @@ +building-hacks +============== + +.. dfhack-tool:: + :summary: Provides a Lua API for creating powered workshops. + :tags: fort gameplay buildings + :no-command: + +See `building-hacks-api` for more details. diff --git a/docs/plugins/buildingplan.rst b/docs/plugins/buildingplan.rst new file mode 100644 index 000000000..ef159443d --- /dev/null +++ b/docs/plugins/buildingplan.rst @@ -0,0 +1,92 @@ +buildingplan +============ + +.. dfhack-tool:: + :summary: Plan building construction before you have materials. + :tags: fort design buildings + +This plugin adds a planning mode for building placement. You can then place +furniture, constructions, and other buildings before the required materials are +available, and they will be created in a suspended state. Buildingplan will +periodically scan for appropriate items, and the jobs will be unsuspended when +the items are available. + +This is very useful when combined with manager work orders or `workflow` -- you +can set a constraint to always have one or two doors/beds/tables/chairs/etc. +available, and place as many as you like. Materials are used to build the +planned buildings as they are produced, with minimal space dedicated to +stockpiles. + +Usage +----- + +:: + + enable buildingplan + buildingplan set + buildingplan set true|false + +Running ``buildingplan set`` without parameters displays the current settings. + +.. _buildingplan-settings: + +Global settings +--------------- + +The buildingplan plugin has global settings that can be set from the UI +(:kbd:`G` from any building placement screen, for example: +:kbd:`b`:kbd:`a`:kbd:`G`). These settings can also be set via the +``buildingplan set`` command. The available settings are: + +``all_enabled`` (default: false) + Enable planning mode for all building types. +``blocks``, ``boulders``, ``logs``, ``bars`` (defaults: true, true, true, false) + Allow blocks, boulders, logs, or bars to be matched for generic "building + material" items. +``quickfort_mode`` (default: false) + Enable compatibility mode for the legacy Python Quickfort (this setting is + not required for DFHack `quickfort`) + +The settings for ``blocks``, ``boulders``, ``logs``, and ``bars`` are saved with +your fort, so you only have to set them once and they will be persisted in your +save. + +If you normally embark with some blocks on hand for early workshops, you might +want to add this line to your ``dfhack-config/init/onMapLoad.init`` file to +always configure buildingplan to just use blocks for buildings and +constructions:: + + on-new-fortress buildingplan set boulders false; buildingplan set logs false + +.. _buildingplan-filters: + +Item filtering +-------------- + +While placing a building, you can set filters for what materials you want the +building made out of, what quality you want the component items to be, and +whether you want the items to be decorated. + +If a building type takes more than one item to construct, use +:kbd:`Ctrl`:kbd:`Left` and :kbd:`Ctrl`:kbd:`Right` to select the item that you +want to set filters for. Any filters that you set will be used for all buildings +of the selected type placed from that point onward (until you set a new filter +or clear the current one). Buildings placed before the filters were changed will +keep the filter values that were set when the building was placed. + +For example, you can be sure that all your constructed walls are the same color +by setting a filter to accept only certain types of stone. + +Quickfort mode +-------------- + +If you use the external Python Quickfort to apply building blueprints instead of +the native DFHack `quickfort` script, you must enable Quickfort mode. This +temporarily enables buildingplan for all building types and adds an extra blank +screen after every building placement. This "dummy" screen is needed for Python +Quickfort to interact successfully with Dwarf Fortress. + +Note that Quickfort mode is only for compatibility with the legacy Python +Quickfort. The DFHack `quickfort` script does not need this Quickfort mode to be +enabled. The `quickfort` script will successfully integrate with buildingplan as +long as the buildingplan plugin itself is enabled. diff --git a/docs/plugins/burrows.rst b/docs/plugins/burrows.rst new file mode 100644 index 000000000..50d736b95 --- /dev/null +++ b/docs/plugins/burrows.rst @@ -0,0 +1,54 @@ +burrows +======= + +.. dfhack-tool:: + :summary: Auto-expand burrows as you dig. + :tags: fort auto design productivity map units + :no-command: + +.. dfhack-command:: burrow + :summary: Quickly add units/tiles to burrows. + +When a wall inside a burrow with a name ending in ``+`` is dug out, the burrow +will be extended to newly-revealed adjacent walls. + +Usage +----- + +``burrow enable auto-grow`` + When a wall inside a burrow with a name ending in '+' is dug out, the burrow + will be extended to newly-revealed adjacent walls. This final '+' may be + omitted in burrow name args of other ``burrow`` commands. Note that digging + 1-wide corridors with the miner inside the burrow is SLOW. +``burrow disable auto-grow`` + Disables auto-grow processing. +``burrow clear-unit [ ...]`` + Remove all units from the named burrows. +``burrow clear-tiles [ ...]`` + Remove all tiles from the named burrows. +``burrow set-units target-burrow [ ...]`` + Clear all units from the target burrow, then add units from the named source + burrows. +``burrow add-units target-burrow [ ...]`` + Add units from the source burrows to the target. +``burrow remove-units target-burrow [ ...]`` + Remove units in source burrows from the target. +``burrow set-tiles target-burrow [ ...]`` + Clear target burrow tiles and adds tiles from the names source burrows. +``burrow add-tiles target-burrow [ ...]`` + Add tiles from the source burrows to the target. +``burrow remove-tiles target-burrow [ ...]`` + Remove tiles in source burrows from the target. + +In place of a source burrow, you can use one of the following keywords: + +- ``ABOVE_GROUND`` +- ``SUBTERRANEAN`` +- ``INSIDE`` +- ``OUTSIDE`` +- ``LIGHT`` +- ``DARK`` +- ``HIDDEN`` +- ``REVEALED`` + +to add tiles with the given properties. diff --git a/docs/plugins/changeitem.rst b/docs/plugins/changeitem.rst new file mode 100644 index 000000000..f7418238a --- /dev/null +++ b/docs/plugins/changeitem.rst @@ -0,0 +1,44 @@ +changeitem +========== + +.. dfhack-tool:: + :summary: Change item material or base quality. + :tags: adventure fort armok items + +By default, a change is only allowed if the existing and desired item materials +are of the same subtype (for example wood -> wood, stone -> stone, etc). But +since some transformations work pretty well and may be desired you can override +this with ``force``. Note that forced changes can possibly result in items that +crafters and haulers refuse to touch. + +Usage +----- + +``changeitem info`` + Show details about the selected item. Does not change the item. You can use + this command to discover RAW ids for existing items. +``changeitem []`` + Change the item selected in the ``k`` list or inside a container/inventory. +``changeitem here []`` + Change all items at the cursor position. Requires in-game cursor. + +Examples +-------- + +``changeitem here m INORGANIC:GRANITE`` + Change material of all stone items under the cursor to granite. +``changeitem q 5`` + Change currently selected item to masterpiece quality. + +Options +------- + +``m``, ``material `` + Change material. Must be followed by valid material RAW id. +``s``, ``subtype `` + Change subtype. Must be followed by a valid subtype RAW id." +``q``, ``quality `` + Change base quality. Must be followed by number (0-5) with 0 being no quality + and 5 being masterpiece quality. +``force`` + Ignore subtypes and force the change to the new material. diff --git a/docs/plugins/changelayer.rst b/docs/plugins/changelayer.rst new file mode 100644 index 000000000..f9467315f --- /dev/null +++ b/docs/plugins/changelayer.rst @@ -0,0 +1,76 @@ +changelayer +=========== + +.. dfhack-tool:: + :summary: Change the material of an entire geology layer. + :tags: fort armok map + +Note that one layer can stretch across many z-levels, and changes to the geology +layer will affect all surrounding regions, not just your embark! Mineral veins +and gem clusters will not be affected. Use `changevein` if you want to modify +those. + +tl;dr: You will end up with changing large areas in one go, especially if you +use it in lower z levels. Use this command with care! + +Usage +----- + +:: + + changelayer [] + +When run without options, ``changelayer`` will: + +- only affect the geology layer at the current cursor position +- only affect the biome that covers the current cursor position +- not allow changing stone to soil and vice versa + +You can use the `probe` command on various tiles around your map to find valid +material RAW ids and to get an idea how layers and biomes are distributed. + +Examples +-------- + +``changelayer GRANITE`` + Convert the layer at the cursor position into granite. +``changelayer SILTY_CLAY force`` + Convert teh layer at the cursor position into clay, even if it's stone. +``changelayer MARBLE all_biomes all_layers`` + Convert all layers of all biomes which are not soil into marble. + +.. note:: + + * If you use changelayer and nothing happens, try to pause/unpause the game + for a while and move the cursor to another tile. Then try again. If that + doesn't help, then try to temporarily change some other layer, undo your + changes, and try again for the layer you want to change. Saving and + reloading your map also sometimes helps. + * You should be fine if you only change single layers without the use + of 'force'. Still, it's advisable to save your game before messing with + the map. + * When you force changelayer to convert soil to stone, you might see some + weird stuff (flashing tiles, tiles changed all over place etc). Try + reverting the changes manually or even better use an older savegame. You + did save your game, right? + +Options +------- + +``all_biomes`` + Change the corresponding geology layer for all biomes on your map. Be aware + that the same geology layer can AND WILL be on different z-levels for + different biomes. +``all_layers`` + Change all geology layers on your map (only for the selected biome unless + ``all_biomes`` is also specified). Candy mountain, anyone? Will make your map + quite boring, but tidy. +``force`` + Allow changing stone to soil and vice versa. **THIS CAN HAVE WEIRD EFFECTS, + USE WITH CARE AND SAVE FIRST**. Note that soil will not be magically replaced + with stone. You will, however, get a stone floor after digging, so it will + allow the floor to be engraved. Similarly, stone will not be magically + replaced with soil, but you will get a soil floor after digging, so it could + be helpful for creating farm plots on maps with no soil. +``verbose`` + Output details about what is being changed. diff --git a/docs/plugins/changevein.rst b/docs/plugins/changevein.rst new file mode 100644 index 000000000..f033a4a6a --- /dev/null +++ b/docs/plugins/changevein.rst @@ -0,0 +1,26 @@ +changevein +========== + +.. dfhack-tool:: + :summary: Change the material of a mineral inclusion. + :tags: fort armok map + +You can change a vein to any incorganic material RAW id. Note that this command +only affects tiles within the current 16x16 block - for large veins and +clusters, you will need to use this command multiple times. + +You can use the `probe` command to discover the material RAW ids for existing +veins that you want to duplicate. + +Usage +----- + +:: + + changevein + +Example +------- + +``changevein NATIVE_PLATINUM`` + Convert vein at cursor position into platinum ore. diff --git a/docs/plugins/cleanconst.rst b/docs/plugins/cleanconst.rst new file mode 100644 index 000000000..12b1db0e5 --- /dev/null +++ b/docs/plugins/cleanconst.rst @@ -0,0 +1,18 @@ +cleanconst +========== + +.. dfhack-tool:: + :summary: Cleans up construction materials. + :tags: fort fps buildings + +This tool alters all constructions on the map so that they spawn their building +component when they are disassembled, allowing their actual build items to be +safely deleted. This can improve FPS when you have many constructions on the +map. + +Usage +----- + +:: + + cleanconst diff --git a/docs/plugins/cleaners.rst b/docs/plugins/cleaners.rst new file mode 100644 index 000000000..14a25d62f --- /dev/null +++ b/docs/plugins/cleaners.rst @@ -0,0 +1,57 @@ +.. _clean: +.. _spotclean: + +cleaners +======== + +.. dfhack-tool:: + :summary: Provides commands for cleaning spatter from the map. + :tags: adventure fort armok fps items map units + :no-command: + +.. dfhack-command:: clean + :summary: Removes contaminants. + +.. dfhack-command:: spotclean + :summary: Remove all contaminants from the tile under the cursor. + +This plugin provides commands that clean the splatter that get scattered all +over the map and that clings to your items and units. In an old fortress, +cleaning with this tool can significantly reduce FPS lag! It can also spoil your +!!FUN!!, so think before you use it. + +Usage +----- + +:: + + clean all|map|items|units|plants [] + spotclean + +By default, cleaning the map leaves mud and snow alone. Note that cleaning units +includes hostiles, and that cleaning items removes poisons from weapons. + +``spotclean`` works like ``clean map snow mud``, removing all contaminants from +the tile under the cursor. This is ideal if you just want to clean a specific +tile but don't want the `clean` command to remove all the glorious blood from +your entranceway. + +Examples +-------- + +``clean all`` + Clean everything that can be cleaned (except mud and snow). +``clean all mud item snow`` + Removes all spatter, including mud, leaves, and snow from map tiles. + +Options +------- + +When cleaning the map, you can specify extra options for extra cleaning: + +``mud`` + Also remove mud. +``item`` + Also remove item spatter, like fallen leaves and flowers. +``snow`` + Also remove snow coverings. diff --git a/docs/plugins/cleanowned.rst b/docs/plugins/cleanowned.rst new file mode 100644 index 000000000..57094d14b --- /dev/null +++ b/docs/plugins/cleanowned.rst @@ -0,0 +1,41 @@ +cleanowned +========== + +.. dfhack-tool:: + :summary: Confiscates and dumps garbage owned by dwarves. + :tags: fort productivity items + +This tool gets dwarves to give up ownership of scattered items and items with +heavy wear and then marks those items for dumping. Now you can finally get your +dwarves to give up their rotten food and tattered loincloths and go get new +ones! + +Usage +----- + +:: + + cleanowned [] [dryrun] + +When run without parameters, ``cleanowned`` will confiscate and dump rotten +items and owned food that is left behind on the floor. Specify the ``dryrun`` +parameter to just print out what would be done, but don't actually confiscate +anything. + +You can confiscate additional types of items by adding them to the commandline: + +``scattered`` + Confiscate/dump all items scattered on the floor. +``x`` + Confiscate/dump items with wear level 'x' (lightly worn) and more. +``X`` + Confiscate/dump items with wear level 'X' (heavily worn) and more. + +Or you can confiscate all owned items by specifying ``all``. + +Example +------- + +``cleanowned scattered X`` + Confiscate and dump rotten and dropped food, garbage on the floors, and any + worn items with 'X' damage and above. diff --git a/docs/plugins/command-prompt.rst b/docs/plugins/command-prompt.rst new file mode 100644 index 000000000..7ccad6c71 --- /dev/null +++ b/docs/plugins/command-prompt.rst @@ -0,0 +1,22 @@ +command-prompt +============== + +.. dfhack-tool:: + :summary: An in-game DFHack terminal where you can run other commands. + :tags: dfhack + +Usage +----- + +:: + + command-prompt [entry] + +If called with parameters, it starts with that text in the command edit area. +This is most useful for developers, who can set a keybinding to open a laungage +interpreter for lua or Ruby by starting with the `:lua ` or `:rb ` +portions of the command already filled in. + +Also see `gui/quickcmd` for a different take on running commands from the UI. + +.. image:: ../images/command-prompt.png diff --git a/docs/plugins/confirm.rst b/docs/plugins/confirm.rst new file mode 100644 index 000000000..6679cf4e3 --- /dev/null +++ b/docs/plugins/confirm.rst @@ -0,0 +1,20 @@ +confirm +======= + +.. dfhack-tool:: + :summary: Adds confirmation dialogs for destructive actions. + :tags: fort interface + +Now you can get the chance to avoid seizing goods from traders or deleting a +hauling route in case you hit the key accidentally. + +Usage +----- + +``enable confirm``, ``confirm enable all`` + Enable all confirmation options. Replace with ``disable`` to disable all. +``confirm enable option1 [option2...]`` + Enable (or ``disable``) specific confirmation dialogs. + +When run without parameters, ``confirm`` will report which confirmation dialogs +are currently enabled. diff --git a/docs/plugins/createitem.rst b/docs/plugins/createitem.rst new file mode 100644 index 000000000..b29e41521 --- /dev/null +++ b/docs/plugins/createitem.rst @@ -0,0 +1,54 @@ +createitem +========== + +.. dfhack-tool:: + :summary: Create arbitrary items. + :tags: adventure fort armok items + +You can create new items of any type and made of any material. A unit must be +selected in-game to use this command. By default, items created are spawned at +the feet of the selected unit. + +Specify the item and material information as you would indicate them in custom +reaction raws, with the following differences: + +* Separate the item and material with a space rather than a colon +* If the item has no subtype, the ``:NONE`` can be omitted +* If the item is ``REMAINS``, ``FISH``, ``FISH_RAW``, ``VERMIN``, ``PET``, or + ``EGG``, then specify a ``CREATURE:CASTE`` pair instead of a material token. +* If the item is a ``PLANT_GROWTH``, specify a ``PLANT_ID:GROWTH_ID`` pair + instead of a material token. + +Corpses, body parts, and prepared meals cannot be created using this tool. + +Usage +----- + +``createitem []`` + Create copies (default is 1) of the specified item made out of the + specified material. +``createitem inspect`` + Obtain the item and material tokens of an existing item. Its output can be + used directly as arguments to ``createitem`` to create new matching items + (as long as the item type is supported). +``createitem floor|item|building`` + Subsequently created items will be placed on the floor beneath the selected + unit's, inside the selected item, or as part of the selected building. + +.. note:: + + ``createitem building`` is good for loading traps, but if you use it with + workshops, you will have to deconstruct the workshop to access the item. + +Examples +-------- + +``createitem GLOVES:ITEM_GLOVES_GAUNTLETS INORGANIC:STEEL 2`` + Create 2 pairs of steel gauntlets (that is, 2 left gauntlets and 2 right + gauntlets). +``createitem WOOD PLANT_MAT:TOWER_CAP:WOOD 100`` + Create 100 tower-cap logs. +``createitem PLANT_GROWTH BILBERRY:FRUIT`` + Create a single bilberry. + +For more examples, :wiki:`the wiki `. diff --git a/docs/plugins/cursecheck.rst b/docs/plugins/cursecheck.rst new file mode 100644 index 000000000..2d623241c --- /dev/null +++ b/docs/plugins/cursecheck.rst @@ -0,0 +1,61 @@ +cursecheck +========== + +.. dfhack-tool:: + :summary: Check for cursed creatures. + :tags: fort armok inspection units + +This command checks a single map tile (or the whole map/world) for cursed +creatures (ghosts, vampires, necromancers, werebeasts, zombies, etc.). + +With an active in-game cursor, only the selected tile will be checked. Without a +cursor, the whole map will be checked. + +By default, you will just see the count of cursed creatures in case you just +want to find out if you have any of them running around in your fort. Dead and +passive creatures (ghosts who were put to rest, killed vampires, etc.) are +ignored. Undead skeletons, corpses, bodyparts and the like are all thrown into +the curse category "zombie". Anonymous zombies and resurrected body parts will +show as "unnamed creature". + +Usage +----- + +:: + + cursecheck [] + +Examples +-------- + +- ``cursecheck`` + Display a count of cursed creatures on the map (or under the cursor). +- ``cursecheck detail all`` + Give detailed info about all cursed creatures including deceased ones. +- ``cursecheck nick`` + Give a nickname all living/active cursed creatures. + +.. note:: + + If you do a full search (with the option "all") former ghosts will show up + with the cursetype "unknown" because their ghostly flag is not set. + + If you see any living/active creatures with a cursetype of "unknown", then + it is most likely a new type of curse introduced by a mod. + +Options +------- + +``detail`` + Print full name, date of birth, date of curse, and some status info (some + vampires might use fake identities in-game, though). +``nick`` + Set the type of curse as nickname (does not always show up in-game; some + vamps don't like nicknames). +``ids`` + Print the creature and race IDs. +``all`` + Include dead and passive cursed creatures (this can result in quite a long + list after having !!FUN!! with necromancers). +``verbose`` + Print all curse tags (if you really want to know it all). diff --git a/docs/plugins/cxxrandom.rst b/docs/plugins/cxxrandom.rst new file mode 100644 index 000000000..19788e4a4 --- /dev/null +++ b/docs/plugins/cxxrandom.rst @@ -0,0 +1,9 @@ +cxxrandom +========= + +.. dfhack-tool:: + :summary: Provides a Lua API for random distributions. + :tags: dev + :no-command: + +See `cxxrandom-api` for details. diff --git a/docs/plugins/debug.rst b/docs/plugins/debug.rst new file mode 100644 index 000000000..0e184595f --- /dev/null +++ b/docs/plugins/debug.rst @@ -0,0 +1,77 @@ +debug +===== + +.. dfhack-tool:: + :summary: Provides commands for controlling debug log verbosity. + :tags: dev + :no-command: + +.. dfhack-command:: debugfilter + :summary: Configure verbosity of DFHack debug output. + +Debug output is grouped by plugin name, category name, and verbosity level. + +The verbosity levels are: + +- ``Trace`` + Possibly very noisy messages which can be printed many times per second. +- ``Debug`` + Messages that happen often but they should happen only a couple of times per + second. +- ``Info`` + Important state changes that happen rarely during normal execution. +- ``Warning`` + Enabled by default. Shows warnings about unexpected events which code + managed to handle correctly. +- ``Error`` + Enabled by default. Shows errors which code can't handle without user + intervention. + +The runtime message printing is controlled using filters. Filters set the +visible messages of all matching categories. Matching uses regular expression +syntax, which allows listing multiple alternative matches or partial name +matches. This syntax is a C++ version of the ECMA-262 grammar (Javascript +regular expressions). Details of differences can be found at +https://en.cppreference.com/w/cpp/regex/ecmascript + +Persistent filters are stored in ``dfhack-config/runtime-debug.json``. Oldest +filters are applied first. That means a newer filter can override the older +printing level selection. + +Usage +----- + +``debugfilter category [] []`` + List available debug plugin and category names. If filters aren't givenm + then all plugins/categories are matched. This command is a good way to test + regex parameters before you pass them to ``set``. +``debugfilter filter []`` + List active and passive debug print level changes. The optional ``id`` + parameter is the id listed as first column in the filter list. If ``id`` is + given, then the command shows extended information for the given filter + only. +``debugfilter set [] [] []`` + Create a new debug filter to set category verbosity levels. This filter + will not be saved when the DF process exists or the plugin is unloaded. +``debugfilter set persistent [] [] []`` + Store the filter in the configuration file to until ``unset`` is used to + remove it. +``debugfilter unset [ ...]`` + Delete a space separated list of filters. +``debugfilter disable [ ...]`` + Disable a space separated list of filters but keep it in the filter list. +``debugfilter enable [ ...]`` + Enable a space sperate list of filters. +``debugfilter header [enable] | [disable] [ ...]`` + Control which header metadata is shown along with each log message. Run it + without parameters to see the list of configurable elements. Include an + ``enable`` or ``disable`` keyword to change whether specific elements are + shown. + +Example +------- + +``debugfilter set Warning core script`` + Hide script execution log messages (e.g. "Loading script: + dfhack-config/dfhack.init"), which are normally output at Info verbosity + in the "core" plugin with the "script" category. diff --git a/docs/plugins/deramp.rst b/docs/plugins/deramp.rst new file mode 100644 index 000000000..fdc0f7619 --- /dev/null +++ b/docs/plugins/deramp.rst @@ -0,0 +1,15 @@ +deramp +====== + +.. dfhack-tool:: + :summary: Removes all ramps designated for removal from the map. + :tags: fort armok map + +It also removes any "floating" down ramps that can remain after a cave-in. + +Usage +----- + +:: + + deramp diff --git a/docs/plugins/dig-now.rst b/docs/plugins/dig-now.rst new file mode 100644 index 000000000..43ed6ce8f --- /dev/null +++ b/docs/plugins/dig-now.rst @@ -0,0 +1,67 @@ +dig-now +======= + +.. dfhack-tool:: + :summary: Instantly complete dig designations. + :tags: fort armok map + +This tool will magically complete non-marker dig designations, modifying tile +shapes and creating boulders, ores, and gems as if a miner were doing the mining +or engraving. By default, the entire map is processed and boulder generation +follows standard game rules, but the behavior is configurable. + +Note that no units will get mining or engraving experience for the dug/engraved +tiles. + +Trees and roots are not currently handled by this plugin and will be skipped. +Requests for engravings are also skipped since they would depend on the skill +and creative choices of individual engravers. Other types of engraving (i.e. +smoothing and track carving) are handled. + +Usage +----- + +:: + + dig-now [ []] [] + +Where the optional ```` pair can be used to specify the coordinate bounds +within which ``dig-now`` will operate. If they are not specified, ``dig-now`` +will scan the entire map. If only one ```` is specified, only the tile at +that coordinate is processed. + +Any ```` parameters can either be an ``,,`` triple (e.g. +``35,12,150``) or the string ``here``, which means the position of the active +game cursor should be used. You can use the `position` command to get the +current cursor position if you need it. + +Examples +-------- + +``dig-now`` + Dig designated tiles according to standard game rules. +``dig-now --clean`` + Dig all designated tiles, but don't generate any boulders, ores, or gems. +``dig-now --dump here`` + Dig tiles and teleport all generated boulders, ores, and gems to the tile + under the game cursor. + +Options +------- + +``-c``, ``--clean`` + Don't generate any boulders, ores, or gems. Equivalent to + ``--percentages 0,0,0,0``. +``-d``, ``--dump `` + Dump any generated items at the specified coordinates. If the tile at those + coordinates is open space or is a wall, items will be generated on the + closest walkable tile below. +``-e``, ``--everywhere`` + Generate a boulder, ore, or gem for every tile that can produce one. + Equivalent to ``--percentages 100,100,100,100``. +``-p``, ``--percentages ,,,`` + Set item generation percentages for each of the tile categories. The + ``vein`` category includes both the large oval clusters and the long stringy + mineral veins. Default is ``25,33,100,100``. +``-z``, ``--cur-zlevel`` + Restricts the bounds to the currently visible z-level. diff --git a/docs/plugins/dig.rst b/docs/plugins/dig.rst new file mode 100644 index 000000000..4384ade65 --- /dev/null +++ b/docs/plugins/dig.rst @@ -0,0 +1,177 @@ +.. _digv: +.. _digtype: + +dig +=== + +.. dfhack-tool:: + :summary: Provides commands for designating tiles for digging. + :tags: fort design productivity map + :no-command: + +.. dfhack-command:: digv + :summary: Designate all of the selected vein for digging. + +.. dfhack-command:: digvx + :summary: Dig a vein across z-levels, digging stairs as needed. + +.. dfhack-command:: digl + :summary: Dig all of the selected layer stone. + +.. dfhack-command:: diglx + :summary: Dig layer stone across z-levels, digging stairs as needed. + +.. dfhack-command:: digcircle + :summary: Designate circles. + +.. dfhack-command:: digtype + :summary: Designate all vein tiles of the selected type. + +.. dfhack-command:: digexp + :summary: Designate dig patterns for exploratory mining. + +This plugin provides commands to make complicated dig patterns easy. + +Usage +----- + +``digv [x] [-p]`` + Designate all of the selected vein for digging. +``digvx [-p]`` + Dig a vein across z-levels, digging stairs as needed. This is an alias for + ``digv x``. +``digl [x] [undo] [-p]`` + Dig all of the selected layer stone. If ``undo`` is specified, removes the + designation instead (for if you accidentally set 50 levels at once). +``diglx [-p]`` + Dig layer stone across z-levels, digging stairs as needed. This is an alias + for ``digl x``. +``digcircle [] [] [] [] [-p]`` + Designate circles. The diameter is the number of tiles across the center of + the circle that you want to dig. See the `digcircle`_ section below for + options. +``digtype [] [-p]`` + Designate all vein tiles of the selected type. See the `digtype`_ section + below for options. +``digexp [] [] [-p]`` + Designate dig patterns for exploratory mining. See the `digexp`_ section + below for options. + +All commands support specifying the priority of the dig designations with +``-p``, where the number is from 1 to 7. If a priority is not specified, +the priority selected in-game is used as the default. + +Examples +-------- + +``digcircle filled 3 -p2`` + Dig a filled circle with a diameter of 3 tiles at dig priority 2. +``digcircle`` + Do it again (previous parameters are reused). +``expdig diag5 hidden`` + Designate the diagonal 5 pattern over all hidden tiles on the current + z-level. +``expdig ladder designated`` + Take existing designations on the current z-level and replace them with the + ladder pattern. +``expdig`` + Do it again (previous parameters are reused). + +digcircle +--------- + +The ``digcircle`` command can accept up to one option of each type below. + +Solidity options: + +``hollow`` + Designates hollow circles (default). +``filled`` + Designates filled circles. + +Action options: + +``set`` + Set designation (default). +``unset`` + Unset current designation. +``invert`` + Invert designations already present. + +Designation options: + +``dig`` + Normal digging designation (default). +``ramp`` + Dig ramps. +``ustair`` + Dig up staircases. +``dstair`` + Dig down staircases. +``xstair`` + Dig up/down staircases. +``chan`` + Dig channels. + +After you have set the options, the command called with no options repeats with +the last selected parameters. + +digtype +------- + +For every tile on the map of the same vein type as the selected tile, this +command designates it to have the same designation as the selected tile. If the +selected tile has no designation, they will be dig designated. + +If an argument is given, the designation of the selected tile is ignored, and +all appropriate tiles are set to the specified designation. + +Designation options: + +``dig`` + Normal digging designation. +``channel`` + Dig channels. +``ramp`` + Dig ramps. +``updown`` + Dig up/down staircases. +``up`` + Dig up staircases. +``down`` + Dig down staircases. +``clear`` + Clear any designations. + +digexp +------ + +This command is for :wiki:`exploratory mining `. + +There are two variables that can be set: pattern and filter. + +Patterns: + +``diag5`` + Diagonals separated by 5 tiles. +``diag5r`` + The diag5 pattern rotated 90 degrees. +``ladder`` + A 'ladder' pattern. +``ladderr`` + The ladder pattern rotated 90 degrees. +``cross`` + A cross, exactly in the middle of the map. +``clear`` + Just remove all dig designations. + +Filters: + +``hidden`` + Designate only hidden tiles of z-level (default) +``all`` + Designate the whole z-level. +``designated`` + Take current designation and apply the selected pattern to it. + +After you have a pattern set, you can use ``expdig`` to apply it again. diff --git a/docs/plugins/digFlood.rst b/docs/plugins/digFlood.rst new file mode 100644 index 000000000..57d4584a8 --- /dev/null +++ b/docs/plugins/digFlood.rst @@ -0,0 +1,42 @@ +digFlood +======== + +.. dfhack-tool:: + :summary: Digs out veins as they are discovered. + :tags: fort auto map + +Once you register specific vein types, this tool will automatically designate +tiles of those types of veins for digging as your miners complete adjacent +mining jobs. Note that it will *only* dig out tiles that are adjacent to a +just-finished dig job, so if you want to autodig a vein that has already been +discovered, you may need to manually designate one tile of the tile for digging +to get started. + +Usage +----- + +``enable digflood`` + Enable the plugin. +``digflood 1 [ ...]`` + Start monitoring for the specified vein types. +``digFlood 0 [ ...] 1`` + Stop monitoring for the specified vein types. Note the required ``1`` at the + end. +``digFlood CLEAR`` + Remove all inorganics from monitoring. +``digFlood digAll1`` + Ignore the monitor list and dig any vein. +``digFlood digAll0`` + Disable digAll mode. + +You can get the list of valid vein types with this command:: + + lua "for i,mat in ipairs(df.global.world.raws.inorganics) do if mat.material.flags.IS_STONE and not mat.material.flags.NO_STONE_STOCKPILE then print(i, mat.id) end end" + +Examples +-------- + +``digFlood 1 MICROCLINE COAL_BITUMINOUS`` + Automatically dig microcline and bituminous coal veins. +``digFlood 0 MICROCLINE 1`` + Stop automatically digging microcline. diff --git a/docs/plugins/diggingInvaders.rst b/docs/plugins/diggingInvaders.rst new file mode 100644 index 000000000..ace04e9fc --- /dev/null +++ b/docs/plugins/diggingInvaders.rst @@ -0,0 +1,60 @@ +diggingInvaders +=============== + +.. dfhack-tool:: + :summary: Invaders dig and destroy to get to your dwarves. + :tags: fort gameplay military units + +Usage +----- + +``enable diggingInvaders`` + Enable the plugin. +``diggingInvaders add `` + Register the specified race as a digging invader. +``diggingInvaders remove `` + Unregisters the specified race as a digging invader. +``diggingInvaders now`` + Makes invaders try to dig now (if the plugin is enabled). +``diggingInvaders clear`` + Clears the registry of digging invader races. +``diggingInvaders edgesPerTick `` + Makes the pathfinding algorithm work on at most n edges per tick. Set to 0 + or lower to make it unlimited. +``diggingInvaders setCost `` + Set the pathing cost per tile for a particular action. This determines what + invaders consider to be the shortest path to their target. +``diggingInvaders setDelay `` + Set the time cost (in ticks) for performing a particular action. This + determines how long it takes for invaders to get to their target. + +Note that the race is case-sensitive. You can get a list of races for your world +with this command:: + + devel/query --table df.global.world.raws.creatures.all --search creature_id --maxdepth 1 --maxlength 5000 + +but in general, the race is what you'd expect, just capitalized (e.g. ``GOBLIN`` +or ``ELF``). + +Actions: + +``walk`` + Default cost: 1, default delay: 0. This is the base cost for the pathing + algorithm. +``destroyBuilding`` + Default cost: 2, default delay: 1,000, +``dig`` + Default cost: 10,000, default delay: 1,000. This is for digging soil or + natural stone. +``destroyRoughConstruction`` + Default cost: 1,000, default delay: 1,000. This is for destroying + constructions made from boulders. +``destroySmoothConstruction`` + Default cost: 100, default delay: 100. This is for destroying constructions + made from blocks or bars. + +Example +------- + +``diggingInvaders add GOBLIN`` + Registers members of the GOBLIN race as a digging invader. diff --git a/docs/plugins/dwarfmonitor.rst b/docs/plugins/dwarfmonitor.rst new file mode 100644 index 000000000..bfdbd13b5 --- /dev/null +++ b/docs/plugins/dwarfmonitor.rst @@ -0,0 +1,94 @@ +dwarfmonitor +============ + +.. dfhack-tool:: + :summary: Measure fort happiness and efficiency. + :tags: fort inspection jobs units + +It can also show heads-up display widgets with live fort statistics. + +Usage +----- + +``enable dwarfmonitor`` + Enable the plugin. +``dwarfmonitor enable `` + Start tracking a specific facet of fortress life. The ``mode`` can be + "work", "misery", "date", "weather", or "all". This will show the + corresponding on-screen widgets, if applicable. +``dwarfmonitor disable `` + Stop monitoring ``mode`` and disable corresponding widgets. +``dwarfmonitor stats`` + Show statistics summary. +``dwarfmonitor prefs`` + Show summary of dwarf preferences. +``dwarfmonitor reload`` + Reload the widget configuration file (``dfhack-config/dwarfmonitor.json``). + +Widget configuration +-------------------- + +The following types of widgets (defined in +:file:`hack/lua/plugins/dwarfmonitor.lua`) can be displayed on the main fortress +mode screen: + +``misery`` + Show overall happiness levels of all dwarves. +``date`` + Show the in-game date. +``weather`` + Show current weather (e.g. rain/snow). +``cursor`` + Show the current mouse cursor position. + +The file :file:`dfhack-config/dwarfmonitor.json` can be edited to control the +positions and settings of all widgets. This file should contain a JSON object +with the key ``widgets`` containing an array of objects: + +.. code-block:: lua + + { + "widgets": [ + { + "type": "widget type (weather, misery, etc.)", + "x": X coordinate, + "y": Y coordinate + <...additional options...> + } + ] + } + +X and Y coordinates begin at zero (in the upper left corner of the screen). +Negative coordinates will be treated as distances from the lower right corner, +beginning at 1 - e.g. an x coordinate of 0 is the leftmost column, while an x +coordinate of -1 is the rightmost column. + +By default, the x and y coordinates given correspond to the leftmost tile of +the widget. Including an ``anchor`` option set to ``right`` will cause the +rightmost tile of the widget to be located at this position instead. + +Some widgets support additional options: + +* ``date`` widget: + + * ``format``: specifies the format of the date. The following characters + are replaced (all others, such as punctuation, are not modified) + + * ``Y`` or ``y``: The current year + * ``M``: The current month, zero-padded if necessary + * ``m``: The current month, *not* zero-padded + * ``D``: The current day, zero-padded if necessary + * ``d``: The current day, *not* zero-padded + + The default date format is ``Y-M-D``, per the ISO8601_ standard. + + .. _ISO8601: https://en.wikipedia.org/wiki/ISO_8601 + +* ``cursor`` widget: + + * ``format``: Specifies the format. ``X``, ``x``, ``Y``, and ``y`` are + replaced with the corresponding cursor cordinates, while all other + characters are unmodified. + * ``show_invalid``: If set to ``true``, the mouse coordinates will both be + displayed as ``-1`` when the cursor is outside of the DF window; otherwise, + nothing will be displayed. diff --git a/docs/plugins/dwarfvet.rst b/docs/plugins/dwarfvet.rst new file mode 100644 index 000000000..e7ddf73d6 --- /dev/null +++ b/docs/plugins/dwarfvet.rst @@ -0,0 +1,23 @@ +dwarfvet +======== + +.. dfhack-tool:: + :summary: Allows animals to be treated at animal hospitals. + :tags: fort gameplay animals + +Annoyed your dragons become useless after a minor injury? Well, with dwarfvet, +injured animals will be treated at an animal hospital, which is simply a hospital +that is also an animal training zone. Dwarfs with the Animal Caretaker labor +enabled will come to the hospital to treat animals. Normal medical skills are +used (and trained), but no experience is given to the Animal Caretaker skill +itself. + +Usage +----- + +``enable dwarfvet`` + Enables the plugin. +``dwarfvet report`` + Reports all zones that the game considers animal hospitals. +``dwarfvet report-usage`` + Reports on animals currently being treated. diff --git a/docs/plugins/embark-assistant.rst b/docs/plugins/embark-assistant.rst new file mode 100644 index 000000000..c7a3f778e --- /dev/null +++ b/docs/plugins/embark-assistant.rst @@ -0,0 +1,26 @@ +embark-assistant +================ + +.. dfhack-tool:: + :summary: Embark site selection support. + :tags: embark fort interface + +Run this command while the pre-embark screen is displayed to show extended (and +reasonably correct) resource information for the embark rectangle as well as +normally undisplayed sites in the current embark region. You will also have +access to a site selection tool with far more options than DF's vanilla search +tool. + +If you enable the plugin, you'll also be able to invoke ``embark-assistant`` +with the :kbd:`A` key on the pre-embark screen. + +Usage +----- + +:: + + enable embark-assistant + embark-assistant + +Note the site selection tool requires a display height of at least 46 lines to +display properly. diff --git a/docs/plugins/embark-tools.rst b/docs/plugins/embark-tools.rst new file mode 100644 index 000000000..64db27953 --- /dev/null +++ b/docs/plugins/embark-tools.rst @@ -0,0 +1,34 @@ +embark-tools +============ + +.. dfhack-tool:: + :summary: Extend the embark screen functionality. + :tags: embark fort interface + +Usage +----- + +:: + + enable embark-tools + embark-tools enable|disable all + embark-tools enable|disable [ ...] + +Avaliable tools are: + +``anywhere`` + Allows embarking anywhere (including sites, mountain-only biomes, and + oceans). Use with caution. +``mouse`` + Implements mouse controls (currently in the local embark region only). +``sand`` + Displays an indicator when sand is present in the currently-selected area, + similar to the default clay/stone indicators. +``sticky`` + Maintains the selected local area while navigating the world map. + +Example +------- + +``embark-tools enable all`` + Enable all embark screen extensions. diff --git a/docs/plugins/eventful.rst b/docs/plugins/eventful.rst new file mode 100644 index 000000000..e89480413 --- /dev/null +++ b/docs/plugins/eventful.rst @@ -0,0 +1,9 @@ +eventful +======== + +.. dfhack-tool:: + :summary: Provides a Lua API for reacting to in-game events. + :tags: dev gameplay + :no-command: + +See `eventful-api` for details. diff --git a/docs/plugins/fastdwarf.rst b/docs/plugins/fastdwarf.rst new file mode 100644 index 000000000..fb0524c3b --- /dev/null +++ b/docs/plugins/fastdwarf.rst @@ -0,0 +1,38 @@ +fastdwarf +========= + +.. dfhack-tool:: + :summary: Dwarves teleport and/or finish jobs instantly. + :tags: fort armok units + +Usage +----- + +:: + + enable fastdwarf + fastdwarf [] + +Examples +-------- + +``fastdwarf 1`` + Make all your dwarves move and work at maximum speed. +``fastdwarf 1 1`` + In addition to working at maximum speed, dwarves also teleport to their + destinations. + +Options +------- + +Speed modes: + +:0: Dwarves move and work at normal rates. +:1: Dwarves move and work at maximum speed. +:2: ALL units move (and work) at maximum speed, including creatures and + hostiles. + +Tele modes: + +:0: No teleportation. +:1: Dwarves teleport to their destinations. diff --git a/docs/plugins/filltraffic.rst b/docs/plugins/filltraffic.rst new file mode 100644 index 000000000..beb57dccd --- /dev/null +++ b/docs/plugins/filltraffic.rst @@ -0,0 +1,53 @@ +.. _restrictice: +.. _restrictliquids: + +filltraffic +=========== + +.. dfhack-tool:: + :summary: Set traffic designations using flood-fill starting at the cursor. + :tags: fort design productivity map + +.. dfhack-command:: alltraffic + :summary: Set traffic designations for every single tile of the map. + +.. dfhack-command:: restrictice + :summary: Restrict traffic on all tiles on top of visible ice. + +.. dfhack-command:: restrictliquids + :summary: Restrict traffic on all visible tiles with liquid. + +Usage +----- + +:: + + filltraffic [] + alltraffic + restrictice + restrictliquids + +For ``filltraffic``, flood filling stops at walls and doors. + +Examples +-------- + +``filltraffic H`` + When used in a room with doors, it will set traffic to HIGH in just that + room. + +Options +------- + +Traffic designations: + +:H: High Traffic. +:N: Normal Traffic. +:L: Low Traffic. +:R: Restricted Traffic. + +Filltraffic extra options: + +:X: Fill across z-levels. +:B: Include buildings and stockpiles. +:P: Include empty space. diff --git a/docs/plugins/fix-unit-occupancy.rst b/docs/plugins/fix-unit-occupancy.rst new file mode 100644 index 000000000..991c77314 --- /dev/null +++ b/docs/plugins/fix-unit-occupancy.rst @@ -0,0 +1,41 @@ +fix-unit-occupancy +================== + +.. dfhack-tool:: + :summary: Fix phantom unit occupancy issues. + :tags: fort bugfix map + +If you see "unit blocking tile" messages that you can't account for +(:bug:`3499`), this tool can help. + +Usage +----- + +:: + + enable fix-unit-occupancy + fix-unit-occupancy [here] [-n] + fix-unit-occupancy interval + +When run without arguments (or with just the ``here`` or ``-n`` parameters), +the fix just runs once. You can also have it run periodically by enbling the +plugin. + +Examples +-------- + +``fix-unit-occupancy`` + Run once and fix all occupancy issues on the map. +``fix-unit-occupancy -n`` + Report on, but do not fix, all occupancy issues on the map. + +Options +------- + +``here`` + Only operate on the tile at the cursor. +``-n`` + Report issues, but do not any write changes to the map. +``interval `` + Set how often the plugin will check for and fix issues when it is enabled. + The default is 1200 ticks, or 1 game day. diff --git a/docs/plugins/fixveins.rst b/docs/plugins/fixveins.rst new file mode 100644 index 000000000..616f84fae --- /dev/null +++ b/docs/plugins/fixveins.rst @@ -0,0 +1,16 @@ +fixveins +======== + +.. dfhack-tool:: + :summary: Restore missing mineral inclusions. + :tags: fort bugfix map + +This tool can also remove invalid references to mineral inclusions if you broke +your embark with tools like `tiletypes`. + +Usage +----- + +:: + + fixveins diff --git a/docs/plugins/flows.rst b/docs/plugins/flows.rst new file mode 100644 index 000000000..bbb2c6661 --- /dev/null +++ b/docs/plugins/flows.rst @@ -0,0 +1,16 @@ +flows +===== + +.. dfhack-tool:: + :summary: Counts map blocks with flowing liquids. + :tags: fort inspection map + +If you suspect that your magma sea leaks into HFS, you can use this tool to be +sure without revealing the map. + +Usage +----- + +:: + + flows diff --git a/docs/plugins/follow.rst b/docs/plugins/follow.rst new file mode 100644 index 000000000..0bf1e4d0f --- /dev/null +++ b/docs/plugins/follow.rst @@ -0,0 +1,17 @@ +follow +====== + +.. dfhack-tool:: + :summary: Make the screen follow the selected unit. + :tags: fort interface units + +Once you exit from the current menu or cursor mode, the screen will stay +centered on the unit. Handy for watching dwarves running around. Deactivated by +moving the cursor manually. + +Usage +----- + +:: + + follow diff --git a/docs/plugins/forceequip.rst b/docs/plugins/forceequip.rst new file mode 100644 index 000000000..a32af524b --- /dev/null +++ b/docs/plugins/forceequip.rst @@ -0,0 +1,104 @@ +forceequip +========== + +.. dfhack-tool:: + :summary: Move items into a unit's inventory. + :tags: adventure fort animals items military units + +This tool is typically used to equip specific clothing/armor items onto a dwarf, +but can also be used to put armor onto a war animal or to add unusual items +(such as crowns) to any unit. Make sure the unit you want to equip is standing +on the target items, which must be on the ground and be unforbidden. If multiple +units are standing on the same tile, the first one will be equipped. + +The most reliable way to set up the environment for this command is to pile +target items on a tile of floor with a garbage dump activity zone or the +`autodump` command, then walk/pasture a unit (or use `gui/teleport`) on top of +the items. Be sure to unforbid the items that you want to work with! + +.. note:: + + Weapons are not currently supported. + +Usage +----- + +:: + + forceequip [] + +As mentioned above, this plugin can be used to equip items onto units (such as +animals) who cannot normally equip gear. There's an important caveat here: such +creatures will automatically drop inappropriate gear almost immediately (within +10 game ticks). If you want them to retain their equipment, you must forbid it +AFTER using forceequip to get it into their inventory. This technique can also +be used to clothe dwarven infants, but only if you're able to separate them from +their mothers. + +By default, the ``forceequip`` command will attempt to abide by game rules as +closely as possible. For instance, it will skip any item which is flagged for +use in a job, and will not equip more than one piece of clothing/armor onto any +given body part. These restrictions can be overridden via options, but doing so +puts you at greater risk of unexpected consequences. For instance, a dwarf who +is wearing three breastplates will not be able to move very quickly. + +Items equipped by this plugin DO NOT become owned by the recipient. Adult +dwarves are free to adjust their own wardrobe, and may promptly decide to doff +your gear in favour of their owned items. Animals, as described above, will tend +to discard ALL clothing immediately unless it is manually forbidden. Armor items +seem to be an exception: an animal will tend to retain an equipped suit of mail +even if you neglect to forbid it. + +Please note that armored animals are quite vulnerable to ranged attacks. Unlike +dwarves, animals cannot block, dodge, or deflect arrows, and they are slowed by +the weight of their armor. + +Examples +-------- + +``forceequip`` + Attempts to equip all of the clothing and armor under the cursor onto the + unit under the cursor, following game rules regarding which item can be + equipped on which body part and only equipping 1 item onto each body part. + Items owned by other dwarves are ignored. +``forceequip v bp QQQ`` + List the bodyparts of the selected unit. +``forceequip bp LH`` + Equips an appopriate item onto the unit's left hand. +``forceequip m bp LH`` + Equips ALL appropriate items onto the unit's left hand. The unit may end up + wearing a dozen left-handed mittens. Use with caution, and remember that + dwarves tend to drop extra items ASAP. +``forceequip i bp NECK`` + Equips an item around the unit's neck, ignoring appropriateness + restrictions. If there's a millstone or an albatross carcass sitting on the + same square as the targeted unit, then there's a good chance that it will + end up around his neck. For precise control, remember that you can + selectively forbid some of the items that are piled on the ground. +``forceequip s`` + Equips the item currently selected in the k menu, if possible. +``forceequip s m i bp HD`` + Equips the selected item onto the unit's head. Ignores all restrictions and + conflicts. If you know exactly what you want to equip, and exactly where you + want it to go, then this is the most straightforward and reliable option. + +Options +------- + +``i``, ``ignore`` + Bypasses the usual item eligibility checks (such as "Never equip gear + belonging to another dwarf" and "Nobody is allowed to equip a Hive". +``m``, ``multi`` + Bypasses the 1-item-per-bodypart limit. Useful for equipping both a mitten + and a gauntlet on the same hand (or twelve breastplates on the upper body). +``m2``, ``m3``, ``m4`` + Modifies the 1-item-per-bodypart limit, allowing each part to receive 2, 3, + or 4 pieces of gear. +``s``, ``selected`` + Equip only the item currently selected in the k menu and ignore all other + items in the tile. +``bp``, ``bodypart `` + Specify which body part should be equipped. +``v``, ``verbose`` + Provide detailed narration and error messages, including listing available + body parts when an invalid ``bodypart`` code is specified. diff --git a/docs/plugins/generated-creature-renamer.rst b/docs/plugins/generated-creature-renamer.rst new file mode 100644 index 000000000..68302dbf5 --- /dev/null +++ b/docs/plugins/generated-creature-renamer.rst @@ -0,0 +1,32 @@ +generated-creature-renamer +========================== + +.. dfhack-tool:: + :summary: Automatically renames generated creatures. + :tags: adventure fort legends units + :no-command: + +.. dfhack-command:: list-generated + :summary: List the token names of all generated creatures. + +.. dfhack-command:: save-generated-raws + :summary: Export a creature graphics file for modding. + +Now, forgotten beasts, titans, necromancer experiments, etc. will have raw token +names that match the description given in-game instead of unreadable generated +strings. + +Usage +----- + +``enable generated-creature-renamer`` + Rename generated creatures when a world is loaded. +``list-generated [detailed]`` + List the token names of all generated creatures in the loaded save. If + ``detailed`` is specified, then also show the accompanying description. +``save-generated-raws`` + Save a sample creature graphics file in the Dwarf Fortress root directory to + use as a start for making a graphics set for generated creatures using the + new names that they get with this plugin. + +The new names are saved with the world. diff --git a/docs/plugins/getplants.rst b/docs/plugins/getplants.rst new file mode 100644 index 000000000..05bac71c9 --- /dev/null +++ b/docs/plugins/getplants.rst @@ -0,0 +1,57 @@ +getplants +========= + +.. dfhack-tool:: + :summary: Designate trees for chopping and shrubs for gathering. + :tags: fort productivity plants + +Specify the types of trees to cut down and/or shrubs to gather by their plant +names. + +Usage +----- + +``getplants [-t|-s|-f]`` + List valid tree/shrub ids, optionally restricted to the specified type. +``getplants [ ...] []`` + Designate trees/shrubs of the specified types for chopping/gathering. + +Examples +-------- + +``getplants`` + List all valid IDs. +``getplants -f -a`` + Gather all plants on the map that yield seeds for farming. +``getplants NETHER_CAP -n 10`` + Designate 10 nether cap trees for chopping. + +Options +------- + +``-t`` + Tree: Select trees only (exclude shrubs). +``-s`` + Shrub: Select shrubs only (exclude trees). +``-f`` + Farming: Designate only shrubs that yield seeds for farming. +``-a`` + All: Select every type of plant (obeys ``-t``/``-s``/``-f``). +``-c`` + Clear: Clear designations instead of setting them. +``-x`` + eXcept: Apply selected action to all plants except those specified (invert + selection). +``-v`` + Verbose: Lists the number of (un)designations per plant. +``-n `` + Number: Designate up to the specified number of plants of each species. + +.. note:: + + DF is capable of determining that a shrub has already been picked, leaving + an unusable structure part behind. This plugin does not perform such a check + (as the location of the required information has not yet been identified). + This leads to some shrubs being designated when they shouldn't be, causing a + plant gatherer to walk there and do nothing (except clearing the + designation). See :issue:`1479` for details. diff --git a/docs/plugins/hotkeys.rst b/docs/plugins/hotkeys.rst new file mode 100644 index 000000000..6780efca1 --- /dev/null +++ b/docs/plugins/hotkeys.rst @@ -0,0 +1,18 @@ +hotkeys +======= + +.. dfhack-tool:: + :summary: Show all dfhack keybindings for the current context. + :tags: dfhack + +The command opens an in-game screen showing which DFHack keybindings are active +in the current context. See also `hotkey-notes`. + +Usage +----- + +:: + + hotkeys + +.. image:: ../images/hotkeys.png diff --git a/docs/plugins/infiniteSky.rst b/docs/plugins/infiniteSky.rst new file mode 100644 index 000000000..f9a68a05a --- /dev/null +++ b/docs/plugins/infiniteSky.rst @@ -0,0 +1,26 @@ +infiniteSky +=========== + +.. dfhack-tool:: + :summary: Automatically allocates new z-levels of sky + :tags: fort design map + +If enabled, this plugin will automatically allocate new z-levels of sky at the +top of the map as you build up. Or it can allocate one or many additional levels +at your command. + +Usage +----- + +``enable infiniteSky`` + Enables monitoring of constructions. If you build anything in the second + highest z-level, it will allocate one more sky level. You can build stairs + up as high as you like! +``infiniteSky []`` + Raise the sky by n z-levels. If run without parameters, raises the sky by + one z-level. + +.. warning:: + + :issue:`Sometimes <254>` new z-levels disappear and cause cave-ins. + Saving and loading after creating new z-levels should fix the problem. diff --git a/docs/plugins/isoworldremote.rst b/docs/plugins/isoworldremote.rst new file mode 100644 index 000000000..284794f96 --- /dev/null +++ b/docs/plugins/isoworldremote.rst @@ -0,0 +1,9 @@ +isoworldremote +============== + +.. dfhack-tool:: + :summary: Provides a remote API used by Isoworld. + :tags: dev graphics + :no-command: + +See `remote` for related remote APIs. diff --git a/docs/plugins/jobutils.rst b/docs/plugins/jobutils.rst new file mode 100644 index 000000000..9d083d92f --- /dev/null +++ b/docs/plugins/jobutils.rst @@ -0,0 +1,60 @@ +.. _job: + +jobutils +======== + +.. dfhack-tool:: + :summary: Provides commands for interacting with jobs. + :tags: fort inspection jobs + :no-command: + +.. dfhack-command:: job + :summary: Inspect or modify details of workshop jobs. + +.. dfhack-command:: job-duplicate + :summary: Duplicates the highlighted job. + +.. dfhack-command:: job-material + :summary: Alters the material of the selected job. + +Usage +----- + +``job`` + Print details of the current job. The job can be selected in a workshop or + the unit/jobs screen. +``job list`` + Print details of all jobs in the selected workshop. +``job item-material `` + Replace the exact material id in the job item. +``job item-type `` + Replace the exact item type id in the job item. +``job-duplicate`` + Duplicates the highlighted job. Must be in :kbd:`q` mode and have a workshop + or furnace building selected. +``job-material `` + Alters the material of the selected job (in :kbd:`q` mode) or jumps to the + selected material when choosing the building component of a planned building + (in :kbd:`b` mode). Note that this form of the command can only handle + inorganic materials. + +Use the ``job`` and ``job list`` commands to discover the type and material ids +for existing jobs, or use the following commands to see the full lists:: + + lua @df.item_type + lua "for i,mat in ipairs(df.global.world.raws.inorganics) do if mat.material.flags.IS_STONE and not mat.material.flags.NO_STONE_STOCKPILE then print(i, mat.id) end end" + +Examples +-------- + +``job-material GNEISS`` + Change the selected "Construct rock Coffin" job at a Mason's workshop to + "Construct gneiss coffin". +``job item-material 2 MARBLE`` + Change the selected "Construct Traction Bench" job (which has three source + items: a table, a mechanism, and a chain) to specifically use a marble + mechanism. +``job item-type 2 TABLE`` + Change the selected "Encrust furniture with blue jade" job (which has two + source items: a cut gem and a piece of improvable furniture) to specifically + use a table instead of just any furniture. diff --git a/docs/plugins/labormanager.rst b/docs/plugins/labormanager.rst new file mode 100644 index 000000000..5c3632b6a --- /dev/null +++ b/docs/plugins/labormanager.rst @@ -0,0 +1,132 @@ +labormanager +============ + +.. dfhack-tool:: + :summary: Automatically manage dwarf labors. + :tags: fort auto labors + +Labormanager is derived from `autolabor` but uses a completely different +approach to assigning jobs to dwarves. While autolabor tries to keep as many +dwarves busy as possible, labormanager instead strives to get jobs done as +quickly as possible. + +Labormanager frequently scans the current job list, current list of dwarves, and +the map to determine how many dwarves need to be assigned to what labors in +order to meet all current labor needs without starving any particular type of +job. + +Dwarves on active military duty or dwarves assigned to burrows are left +untouched. + +.. warning:: + + As with autolabor, labormanager will override any manual changes you make to + labors while it is enabled, including through other tools such as Dwarf + Therapist. Do not run both autolabor and labormanager at the same time! + +Usage +----- + +:: + + enable labormanager + +Anything beyond this is optional - labormanager works well with the default +settings. Once you have enabled it in a fortress, it stays enabled until you +explicitly disable it, even if you save and reload your game. + +The default priorities for each labor vary (some labors are higher priority by +default than others). The way the plugin works is that, once it determines how +many jobs of each labor is needed, it then sorts them by adjusted priority. +(Labors other than hauling have a bias added to them based on how long it's been +since they were last used to prevent job starvation.) The labor with the highest +priority is selected, the "best fit" dwarf for that labor is assigned to that +labor, and then its priority is *halved*. This process is repeated until either +dwarves or labors run out. + +Because there is no easy way to detect how many haulers are actually needed at +any moment, the plugin always ensures that at least one dwarf is assigned to +each of the hauling labors, even if no hauling jobs are detected. At least one +dwarf is always assigned to construction removing and cleaning because these +jobs also cannot be easily detected. Lever pulling is always assigned to +everyone. Any dwarves for which there are no jobs will be assigned hauling, +lever pulling, and cleaning labors. If you use animal trainers, note that +labormanager will misbehave if you assign specific trainers to specific animals; +results are only guaranteed if you use "any trainer". + +Labormanager also sometimes assigns extra labors to currently busy dwarfs so +that when they finish their current job, they will go off and do something +useful instead of standing around waiting for a job. + +There is special handling to ensure that at least one dwarf is assigned to haul +food whenever food is detected left in a place where it will rot if not stored. +This will cause a dwarf to go idle if you have no stockpiles to haul food to. + +Dwarves who are unable to work (child, in the military, wounded, handless, +asleep, in a meeting) are entirely excluded from labor assignment. Any dwarf +explicitly assigned to a burrow will also be completely ignored by labormanager. + +The fitness algorithm for assigning jobs to dwarves generally attempts to favor +dwarves who are more skilled over those who are less skilled. It also tries to +avoid assigning female dwarfs with children to jobs that are "outside", favors +assigning "outside" jobs to dwarfs who are carrying a tool that could be used as +a weapon, and tries to minimize how often dwarves have to reequip. + +Labormanager automatically determines medical needs and reserves health care +providers as needed. Note that this may cause idling if you have injured dwarves +but no or inadequate hospital facilities. + +Hunting is never assigned without a butchery, and fishing is never assigned +without a fishery, and neither of these labors is assigned unless specifically +enabled (see below). + +The method by which labormanager determines what labor is needed for a +particular job is complicated and, in places, incomplete. In some situations, +labormanager will detect that it cannot determine what labor is required. It +will, by default, pause and print an error message on the dfhack console, +followed by the message "LABORMANAGER: Game paused so you can investigate the +above message.". If this happens, please open an :issue:`` on GitHub, +reporting the lines that immediately preceded this message. You can tell +labormanager to ignore this error and carry on by running +``labormanager pause-on-error no``, but be warned that some job may go undone in +this situation. + +Examples +-------- + +``labormanager priority BREWER 500`` + Boost the priority of brewing jobs. +``labormanager max FISH 1`` + Only assign fishing to one dwarf at a time. Note that you also have to run + ``labormanager allow-fishing`` for any dwarves to be assigned fishing at + all. + +Advanced usage +-------------- + +``labormanager list`` + Show current priorities and current allocation stats. Use this command to + see the IDs for all labors. +``labormanager status`` + Show basic status information. +``labormanager priority `` + Set the priority value for labor to . +``labormanager max `` + Set maximum number of dwarves that can be assigned to a labor. +``labormanager max none`` + Unrestrict the number of dwarves that can be assigned to a labor. +``labormanager max disable`` + Don't manage the specified labor. Dwarves who you have manually enabled this + labor on will be less likely to have managed labors assigned to them. +``labormanager reset-all|reset `` + Return a labor (or all labors) to the default priority. +``labormanager allow-fishing|forbid-fishing`` + Allow/disallow fisherdwarves. *Warning* Allowing fishing tends to result in + most of the fort going fishing. Fishing is forbidden by default. +``labormanager allow-hunting|forbid-hunting`` + Allow/disallow hunterdwarves. *Warning* Allowing hunting tends to result in + as many dwarves going hunting as you have crossbows. Hunting is forbidden by + default. +``labormanager pause-on-error yes|no`` + Make labormanager pause/continue if the labor inference engine fails. See + the above section for details. diff --git a/docs/plugins/lair.rst b/docs/plugins/lair.rst new file mode 100644 index 000000000..ed2816818 --- /dev/null +++ b/docs/plugins/lair.rst @@ -0,0 +1,19 @@ +lair +==== + +.. dfhack-tool:: + :summary: Mark the map as a monster lair. + :tags: fort armok map + +This avoids item scatter when the fortress is abandoned. + +Usage +----- + +``lair`` + Mark the map as monster lair. +``lair reset`` + Mark the map as ordinary (not lair). + +This command doesn't save the information about tiles - you won't be able to +restore the state of a real monster lairs using ``lair reset``. diff --git a/docs/plugins/liquids.rst b/docs/plugins/liquids.rst new file mode 100644 index 000000000..5bc24d04f --- /dev/null +++ b/docs/plugins/liquids.rst @@ -0,0 +1,84 @@ +.. _liquids-here: + +liquids +======= + +.. dfhack-tool:: + :summary: Place magma, water or obsidian. + :tags: adventure fort armok map + +.. dfhack-command:: liquids-here + :summary: Spawn liquids on the selected tile. + +Place magma, water or obsidian. See `gui/liquids` for an in-game interface for +this functionality. + +Also, if you only want to add or remove water or magma from a single tile, the +`source` script may be easier to use. + +Usage +----- + +``liquids`` + Start the interactive terminal settings interpreter. This command must be + called from the DFHack terminal and not from any in-game interface. +``liquids-here`` + Run the liquid spawner with the current/last settings made in ``liquids`` + (if no settings in ``liquids`` were made, then it paints a point of 7/7 + magma by default). This command is intended to be used as keybinding, and it + requires an active in-game cursor. + +.. warning:: + + Spawning and deleting liquids can mess up pathing data and temperatures + (creating heat traps). You've been warned. + +Interactive interpreter +----------------------- + +The interpreter replaces the normal dfhack command line and can't be used from a +hotkey. Settings will be remembered as long as dfhack runs. It is intended for +use in combination with the command ``liquids-here`` (which *can* be bound to a +hotkey). + +You can enter the following commands at the prompt. + +Misc commands: + +:q: quit +:help, ?: print this list of commands +:: put liquid + +Modes: + +:m: switch to magma +:w: switch to water +:o: make obsidian wall instead +:of: make obsidian floors +:rs: make a river source +:f: flow bits only +:wclean: remove salt and stagnant flags from tiles + +Set-Modes and flow properties (only for magma/water): + +:s+: only add mode +:s.: set mode +:s-: only remove mode +:f+: make the spawned liquid flow +:f.: don't change flow state (read state in flow mode) +:f-: make the spawned liquid static + +Permaflow (only for water): + +:pf.: don't change permaflow state +:pf-: make the spawned liquid static +:pf[NS][EW]: make the spawned liquid permanently flow +:0-7: set liquid amount + +Brush size and shape: + +:p, point: Single tile +:r, range: Block with cursor at bottom north-west (any place, any size) +:block: DF map block with cursor in it (regular spaced 16x16x1 blocks) +:column: Column from cursor, up through free space +:flood: Flood-fill water tiles from cursor (only makes sense with wclean) diff --git a/docs/plugins/luasocket.rst b/docs/plugins/luasocket.rst new file mode 100644 index 000000000..4b5b18540 --- /dev/null +++ b/docs/plugins/luasocket.rst @@ -0,0 +1,9 @@ +luasocket +========= + +.. dfhack-tool:: + :summary: Provides a Lua API for accessing network sockets. + :tags: dev + :no-command: + +See `luasocket-api` for details. diff --git a/docs/plugins/manipulator.rst b/docs/plugins/manipulator.rst new file mode 100644 index 000000000..3dc7f35b7 --- /dev/null +++ b/docs/plugins/manipulator.rst @@ -0,0 +1,181 @@ +manipulator +=========== + +.. dfhack-tool:: + :summary: An in-game labor management interface. + :tags: fort productivity labors + :no-command: + +It is equivalent to the popular Dwarf Therapist utility. + +To activate, open the unit screen and press :kbd:`l`. + +Usage +----- + +:: + + enable manipulator + +.. image:: ../images/manipulator.png + +The far left column displays the unit's name, happiness (color-coded based on +its value), profession, or squad, and the right half of the screen displays each +dwarf's labor settings and skill levels (0-9 for Dabbling through Professional, +A-E for Great through Grand Master, and U-Z for Legendary through Legendary+5). + +Cells with teal backgrounds denote skills not controlled by labors, e.g. +military and social skills. + +.. image:: ../images/manipulator2.png + +Press :kbd:`t` to toggle between Profession, Squad, and Job views. + +.. image:: ../images/manipulator3.png + +Use the arrow keys or number pad to move the cursor around, holding :kbd:`Shift` to +move 10 tiles at a time. + +Press the Z-Up (:kbd:`<`) and Z-Down (:kbd:`>`) keys to move quickly between labor/skill +categories. The numpad Z-Up and Z-Down keys seek to the first or last unit +in the list. :kbd:`Backspace` seeks to the top left corner. + +Press Enter to toggle the selected labor for the selected unit, or Shift+Enter +to toggle all labors within the selected category. + +Press the :kbd:`+`:kbd:`-` keys to sort the unit list according to the currently selected +skill/labor, and press the :kbd:`*`:kbd:`/` keys to sort the unit list by Name, Profession/Squad, +Happiness, or Arrival order (using :kbd:`Tab` to select which sort method to use here). + +With a unit selected, you can press the :kbd:`v` key to view its properties (and +possibly set a custom nickname or profession) or the :kbd:`c` key to exit +Manipulator and zoom to its position within your fortress. + +The following mouse shortcuts are also available: + +* Click on a column header to sort the unit list. Left-click to sort it in one + direction (descending for happiness or labors/skills, ascending for name, + profession or squad) and right-click to sort it in the opposite direction. +* Left-click on a labor cell to toggle that labor. Right-click to move the + cursor onto that cell instead of toggling it. +* Left-click on a unit's name, profession or squad to view its properties. +* Right-click on a unit's name, profession or squad to zoom to it. + +Pressing :kbd:`Esc` normally returns to the unit screen, but :kbd:`Shift`:kbd:`Esc` would exit +directly to the main dwarf mode screen. + +Professions +----------- + +The manipulator plugin supports saving professions: a named set of labors that can be +quickly applied to one or multiple dwarves. + +To save a profession, highlight a dwarf and press :kbd:`P`. The profession will be saved using +the custom profession name of the dwarf, or the default profession name for that dwarf if no +custom profession name has been set. + +To apply a profession, either highlight a single dwarf or select multiple with +:kbd:`x`, and press :kbd:`p` to select the profession to apply. All labors for +the selected dwarves will be reset to the labors of the chosen profession and +the custom profession names for those dwarves will be set to the applied +profession. + +Professions are saved as human-readable text files in the +``dfhack-config/professions`` folder within the DF folder, and can be edited or +deleted there. + +The professions library +~~~~~~~~~~~~~~~~~~~~~~~ + +The manipulator plugin comes with a library of professions that you can assign +to your dwarves. + +If you'd rather use Dwarf Therapist to manage your labors, it is easy to import +these professions to DT and use them there. Simply assign the professions you +want to import to a dwarf. Once you have assigned a profession to at least one +dwarf, you can select "Import Professions from DF" in the DT "File" menu. The +professions will then be available for use in DT. + +In the list below, the "needed" range indicates the approximate number of +dwarves of each profession that you are likely to need at the start of the game +and how many you are likely to need in a mature fort. These are just +approximations. Your playstyle may demand more or fewer of each profession. + +- ``Chef`` (needed: 0, 3) + Buchery, Tanning, and Cooking. It is important to focus just a few dwarves + on cooking since well-crafted meals make dwarves very happy. They are also + an excellent trade good. +- ``Craftsdwarf`` (needed: 0, 4-6) + All labors used at Craftsdwarf's workshops, Glassmaker's workshops, and + kilns. +- ``Doctor`` (needed: 0, 2-4) + The full suite of medical labors, plus Animal Caretaking for those using + the `dwarfvet` plugin. +- ``Farmer`` (needed 1, 4) + Food- and animal product-related labors. +- ``Fisherdwarf`` (needed 0, 0-1) + Fishing and fish cleaning. If you assign this profession to any dwarf, be + prepared to be inundated with fish. Fisherdwarves *never stop fishing*. Be + sure to also run ``prioritize -a PrepareRawFish ExtractFromRawFish`` or else + caught fish will just be left to rot. +- ``Hauler`` (needed 0, >20) + All hauling labors plus Siege Operating, Mechanic (so haulers can assist in + reloading traps) and Architecture (so haulers can help build massive + windmill farms and pump stacks). As you accumulate enough Haulers, you can + turn off hauling labors for other dwarves so they can focus on their skilled + tasks. You may also want to restrict your Mechanic's workshops to only + skilled mechanics so your unskilled haulers don't make low-quality + mechanisms. +- ``Laborer`` (needed 0, 10-12) + All labors that don't improve quality with skill, such as Soapmaking and + furnace labors. +- ``Marksdwarf`` (needed 0, 10-30) + Similar to ``Hauler``. See the description for ``Meleedwarf`` below for more + details. +- ``Mason`` (needed 2, 2-4) + Masonry and Gem Cutting/Encrusting. +- ``Meleedwarf`` (needed 0, 20-50) + Similar to ``Hauler``, but without most civilian labors. This profession is + separate from ``Hauler`` so you can find your military dwarves easily. + ``Meleedwarves`` and ``Marksdwarves`` have Mechanics and hauling labors + enabled so you can temporarily deactivate your military after sieges and + allow your military dwarves to help clean up and reset traps. +- ``Migrant`` (needed 0, 0) + You can assign this profession to new migrants temporarily while you sort + them into professions. Like ``Marksdwarf`` and ``Meleedwarf``, the purpose + of this profession is so you can find your new dwarves more easily. +- ``Miner`` (needed 2, 2-10) + Mining and Engraving. This profession also has the ``Alchemist`` labor + enabled, which disables hauling for those using the `autohauler` plugin. + Once the need for Miners tapers off in the late game, dwarves with this + profession make good military dwarves, wielding their picks as weapons. +- ``Outdoorsdwarf`` (needed 1, 2-4) + Carpentry, Bowyery, Woodcutting, Animal Training, Trapping, Plant Gathering, + Beekeeping, and Siege Engineering. +- ``Smith`` (needed 0, 2-4) + Smithing labors. You may want to specialize your Smiths to focus on a single + smithing skill to maximize equipment quality. +- ``StartManager`` (needed 1, 0) + All skills not covered by the other starting professions (``Miner``, + ``Mason``, ``Outdoorsdwarf``, and ``Farmer``), plus a few overlapping skills + to assist in critical tasks at the beginning of the game. Individual labors + should be turned off as migrants are assigned more specialized professions + that cover them, and the StartManager dwarf can eventually convert to some + other profession. +- ``Tailor`` (needed 0, 2) + Textile industry labors: Dying, Leatherworking, Weaving, and Clothesmaking. + +A note on autohauler +~~~~~~~~~~~~~~~~~~~~ + +These profession definitions are designed to work well with or without the +`autohauler` plugin (which helps to keep your dwarves focused on skilled labors +instead of constantly being distracted by hauling). If you do want to use +autohauler, adding the following lines to your ``onMapLoad.init`` file will +configure it to let the professions manage the "Feed water to civilians" and +"Recover wounded" labors instead of enabling those labors for all hauling +dwarves:: + + on-new-fortress enable autohauler + on-new-fortress autohauler FEED_WATER_CIVILIANS allow + on-new-fortress autohauler RECOVER_WOUNDED allow diff --git a/docs/plugins/map-render.rst b/docs/plugins/map-render.rst new file mode 100644 index 000000000..efe3ed0c6 --- /dev/null +++ b/docs/plugins/map-render.rst @@ -0,0 +1,9 @@ +map-render +========== + +.. dfhack-tool:: + :summary: Provides a Lua API for rerendering portions of the map. + :tags: dev graphics + :no-command: + +See `map-render-api` for details. diff --git a/docs/plugins/misery.rst b/docs/plugins/misery.rst new file mode 100644 index 000000000..b3634d2ac --- /dev/null +++ b/docs/plugins/misery.rst @@ -0,0 +1,19 @@ +misery +====== + +.. dfhack-tool:: + :summary: Increase the intensity of negative dwarven thoughts. + :tags: fort armok units + +When enabled, negative thoughts that your dwarves have will multiply by the +specified factor. + +Usage +----- + +``enable misery`` + Start multiplying negative thoughts. +``misery `` + Change the multiplicative factor of bad thoughts. The default is ``2``. +``misery clear`` + Clear away negative thoughts added by ``misery``. diff --git a/docs/plugins/mode.rst b/docs/plugins/mode.rst new file mode 100644 index 000000000..33173a5d3 --- /dev/null +++ b/docs/plugins/mode.rst @@ -0,0 +1,39 @@ +mode +==== + +.. dfhack-tool:: + :summary: See and change the game mode. + :tags: armok dev gameplay + +.. warning:: + + Only use ``mode`` after making a backup of your save! + + Not all combinations are good for every situation and most of them will + produce undesirable results. There are a few good ones though. + +Usage +----- + +``mode`` + Print the current game mode. +``mode set`` + Enter an interactive commandline menu where you can set the game mode. + +Examples +-------- + +Scenario 1: + +* You are in fort game mode, managing your fortress and paused. +* You switch to the arena game mode, *assume control of a creature* and then +* switch to adventure game mode. + +You just lost a fortress and gained an adventurer. + +Scenario 2: + +* You are in fort game mode, managing your fortress and paused at the Esc menu. +* You switch to the adventure game mode, assume control of a creature, then save or retire. + +You just created a returnable mountain home and gained an adventurer. diff --git a/docs/plugins/mousequery.rst b/docs/plugins/mousequery.rst new file mode 100644 index 000000000..12f4092bd --- /dev/null +++ b/docs/plugins/mousequery.rst @@ -0,0 +1,41 @@ +mousequery +========== + +.. dfhack-tool:: + :summary: Adds mouse controls to the DF interface. + :tags: fort productivity interface + +Adds mouse controls to the DF interface. For example, with ``mousequery`` you +can click on buildings to configure them, hold the mouse button to draw dig +designations, or click and drag to move the map around. + +Usage +----- + +:: + + enable mousequery + mousequery [rbutton|track|edge|live] [enable|disable] + mousequery drag [left|right|disable] + mousequery delay [] + +:rbutton: When the right mouse button is clicked, cancel out of menus or + scroll the main map if you r-click near an edge. +:track: Move the cursor with the mouse instead of the cursor keys when you + are in build or designation modes. +:edge: Scroll the map when you move the cursor to a map edge. See ``delay`` + below. If enabled also enables ``track``. +:delay: Set delay in milliseconds for map edge scrolling. Omit the amount to + display the current setting. +:live: Display information in the lower right corner of the screen about + the items/building/tile under the cursor, even while unpaused. + +Examples +-------- + +``mousequery rbutton enable`` + Enable using the right mouse button to cancel out of menus and scroll the + map. +``mousequery delay 300`` + When run after ``mousequery edge enable``, sets the edge scrolling delay to + 300ms. diff --git a/docs/plugins/nestboxes.rst b/docs/plugins/nestboxes.rst new file mode 100644 index 000000000..3c07cc30c --- /dev/null +++ b/docs/plugins/nestboxes.rst @@ -0,0 +1,18 @@ +nestboxes +========= + +.. dfhack-tool:: + :summary: Protect fertile eggs incubating in a nestbox. + :tags: fort auto animals + :no-command: + +This plugin will automatically scan for and forbid fertile eggs incubating in a +nestbox so that dwarves won't come to collect them for eating. The eggs will +hatch normally, even when forbidden. + +Usage +----- + +:: + + enable nestboxes diff --git a/docs/plugins/orders.rst b/docs/plugins/orders.rst new file mode 100644 index 000000000..298800c96 --- /dev/null +++ b/docs/plugins/orders.rst @@ -0,0 +1,140 @@ +orders +====== + +.. dfhack-tool:: + :summary: Manage manager orders. + :tags: fort productivity workorders + +Usage +----- + +``orders orders list`` + Shows the list of previously exported orders, including the orders library. +``orders export `` + Saves all the current manager orders in a file. +``orders import `` + Imports the specified manager orders. Note this adds to your current set of + manager orders. It will not clear the orders that already exist. +``orders clear`` + Deletes all manager orders in the current embark. +``orders sort`` + Sorts current manager orders by repeat frequency so repeating orders don't + prevent one-time orders from ever being completed. The sorting order is: + one-time orders first, then yearly, seasonally, monthly, and finally, daily. + +You can keep your orders automatically sorted by adding the following command to +your ``onMapLoad.init`` file:: + + repeat -name orders-sort -time 1 -timeUnits days -command [ orders sort ] + +Exported orders are saved in the ``dfhack-config/orders`` directory, where you +can view, edit, and delete them, if desired. + +Examples +-------- + +``orders export myorders`` + Export the current manager orders to a file named + ``dfhack-config/orders/myorders.json``. +``orders import library/basic`` + Import manager orders from the library that keep your fort stocked with + basic essentials. + +The orders library +------------------ + +DFHack comes with a library of useful manager orders that are ready for import: + +:source:`library/basic ` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This collection of orders handles basic fort necessities: + +- prepared meals and food products (and by-products like oil) +- booze/mead +- thread/cloth/dye +- pots/jugs/buckets/mugs +- bags of leather, cloth, silk, and yarn +- crafts and totems from otherwise unusable by-products +- mechanisms/cages +- splints/crutches +- lye/soap +- ash/potash +- beds/wheelbarrows/minecarts +- scrolls + +You should import it as soon as you have enough dwarves to perform the tasks. +Right after the first migration wave is usually a good time. + +:source:`library/furnace ` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This collection creates basic items that require heat. It is separated out from +``library/basic`` to give players the opportunity to set up magma furnaces first +in order to save resources. It handles: + +- charcoal (including smelting of bituminous coal and lignite) +- pearlash +- sand +- green/clear/crystal glass +- adamantine processing +- item melting + +Orders are missing for plaster powder until DF :bug:`11803` is fixed. + +:source:`library/military ` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This collection adds high-volume smelting jobs for military-grade metal ores and +produces weapons and armor: + +- leather backpacks/waterskins/cloaks/quivers/armor +- bone/wooden bolts +- smelting for platinum, silver, steel, bronze, bismuth bronze, and copper (and + their dependencies) +- bronze/bismuth bronze/copper bolts +- platinum/silver/steel/iron/bismuth bronze/bronze/copper weapons and armor, + with checks to ensure only the best available materials are being used + +If you set a stockpile to take weapons and armor of less than masterwork quality +and turn on `automelt` (like what `dreamfort` provides on its industry level), +these orders will automatically upgrade your military equipment to masterwork. +Make sure you have a lot of fuel (or magma forges and furnaces) before you turn +``automelt`` on, though! + +This file should only be imported, of course, if you need to equip a military. + +:source:`library/smelting ` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This collection adds smelting jobs for all ores. It includes handling the ores +already managed by ``library/military``, but has lower limits. This ensures all +ores will be covered if a player imports ``library/smelting`` but not +``library/military``, but the higher-volume ``library/military`` orders will +take priority if both are imported. + +:source:`library/rockstock ` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This collection of orders keeps a small stock of all types of rock furniture. +This allows you to do ad-hoc furnishings of guildhalls, libraries, temples, or +other rooms with `buildingplan` and your masons will make sure there is always +stock on hand to fulfill the plans. + +:source:`library/glassstock ` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Similar to ``library/rockstock`` above, this collection keeps a small stock of +all types of glass furniture. If you have a functioning glass industry, this is +more sustainable than ``library/rockstock`` since you can never run out of sand. +If you have plenty of rock and just want the variety, you can import both +``library/rockstock`` and ``library/glassstock`` to get a mixture of rock and +glass furnishings in your fort. + +There are a few items that ``library/glassstock`` produces that +``library/rockstock`` does not, since there are some items that can not be made +out of rock, for example: + +- tubes and corkscrews for building magma-safe screw pumps +- windows +- terrariums (as an alternative to wooden cages) diff --git a/docs/plugins/pathable.rst b/docs/plugins/pathable.rst new file mode 100644 index 000000000..f4b89683b --- /dev/null +++ b/docs/plugins/pathable.rst @@ -0,0 +1,10 @@ +pathable +======== + +.. dfhack-tool:: + :summary: Marks tiles that are reachable from the cursor. + :tags: dev inspection map + :no-command: + +This plugin provides a Lua API, but no direct commands. See `pathable-api` for +details. diff --git a/docs/plugins/petcapRemover.rst b/docs/plugins/petcapRemover.rst new file mode 100644 index 000000000..62959e731 --- /dev/null +++ b/docs/plugins/petcapRemover.rst @@ -0,0 +1,33 @@ +petcapRemover +============= + +.. dfhack-tool:: + :summary: Modify the pet population cap. + :tags: fort animals + +In vanilla DF, pets will not reproduce unless the population is below 50 and the +number of children of that species is below a certain percentage. This plugin +allows removing these restrictions and setting your own thresholds. Pets still +require PET or PET_EXOTIC tags in order to reproduce. In order to make +population more stable and avoid sudden population booms as you go below the +raised population cap, this plugin counts pregnancies toward the new population +cap. It can still go over, but only in the case of multiple births. + +Usage +----- + +``enable petcapRemover`` + Enables the plugin and starts running with default settings. +``petcapRemover cap `` + Set the new population cap per species to the specified value. If set to 0, + then there is no cap (good luck with all those animals!). The default cap + is 100. +``petcapRemover`` + Impregnate female pets that have access to a compatible male, up to the + population cap. +``petcapRemover every `` + Set how often the plugin will cause pregnancies. The default frequency is + every 10,000 ticks (a little over 8 game days). +``petcapRemover pregtime `` + Sets the pregnancy duration to the specified number of ticks. The default + value is 200,000 ticks, which is the natural pet pregnancy duration. diff --git a/docs/plugins/plants.rst b/docs/plugins/plants.rst new file mode 100644 index 000000000..f0a4f4af5 --- /dev/null +++ b/docs/plugins/plants.rst @@ -0,0 +1,33 @@ +.. _plant: + +plants +====== + +.. dfhack-tool:: + :summary: Provides commands that interact with plants. + :tags: adventure fort armok map plants + :no-command: + +.. dfhack-command:: plant + :summary: Create a plant or make an existing plant grow up. + +Usage +----- + +``plant create `` + Creates a new plant of the specified type at the active cursor position. + The cursor must be on a dirt or grass floor tile. +``plant grow`` + Grows saplings into trees. If the cursor is active, it only affects the + sapling under the cursor. If no cursor is active, it affect all saplings + on the map. + +To see the full list of plant ids, run the following command:: + + devel/query --table df.global.world.raws.plants.all --search ^id --maxdepth 1 + +Example +------- + +``plant create TOWER_CAP`` + Create a Tower Cap sapling at the cursor position. diff --git a/docs/plugins/power-meter.rst b/docs/plugins/power-meter.rst new file mode 100644 index 000000000..5e608ca46 --- /dev/null +++ b/docs/plugins/power-meter.rst @@ -0,0 +1,11 @@ +power-meter +=========== + +.. dfhack-tool:: + :summary: Allow presure plates to measure power. + :tags: fort gameplay buildings + :no-command: + +If you run `gui/power-meter` while building a pressure plate, the pressure +plate can be modified to detect power being supplied to gear boxes built in the +four adjacent N/S/W/E tiles. diff --git a/docs/plugins/probe.rst b/docs/plugins/probe.rst new file mode 100644 index 000000000..f9941bc48 --- /dev/null +++ b/docs/plugins/probe.rst @@ -0,0 +1,26 @@ +probe +===== + +.. dfhack-tool:: + :summary: Display low-level properties of the selected tile. + :tags: adventure fort inspection buildings map units + +.. dfhack-command:: bprobe + :summary: Display low-level properties of the selected building. + +.. dfhack-command:: cprobe + :summary: Display low-level properties of the selected unit. + +Usage +----- + +``probe`` + Displays properties of the tile selected with :kbd:`k`. Some of these + properties can be passed into `tiletypes`. +``bprobe`` + Displays properties of the building selected with :kbd:`q` or :kbd:`t`. + For deeper inspection of the building, see `gui/gm-editor`. +``cprobe`` + Displays properties of the unit selected with :kbd:`v`. It also displays the + IDs of any worn items. For deeper inspection of the unit and inventory items, + see `gui/gm-unit` and `gui/gm-editor`. diff --git a/docs/plugins/prospector.rst b/docs/plugins/prospector.rst new file mode 100644 index 000000000..4628d11c8 --- /dev/null +++ b/docs/plugins/prospector.rst @@ -0,0 +1,69 @@ +.. _prospect: + +prospector +========== + +.. dfhack-tool:: + :summary: Provides commands that help you analyze natural resources. + :tags: embark fort armok inspection map + :no-command: + +.. dfhack-command:: prospect + :summary: Shows a summary of resources that exist on the map. + +It can also calculate an estimate of resources available in the selected embark +area. + +Usage +----- + +:: + + prospect [all|hell] [] + +By default, only the visible part of the map is scanned. Include the ``all`` +keyword if you want ``prospect`` to scan the whole map as if it were revealed. +Use ``hell`` instead of ``all`` if you also want to see the Z range of HFS +tubes in the 'features' report section. + +Examples +-------- + +``prospect all`` + Shows the entire report for the entire map. + +``prospect hell --show layers,ores,veins`` + Shows only the layers, ores, and other vein stone report sections, and + includes information on HFS tubes (if run on a fortress map and not the + pre-embark screen). + +``prospect all -sores`` + Show only information about ores for the pre-embark or fortress map report. + +Options +------- + +``-s``, ``--show `` + Shows only the named comma-separated list of report sections. Report section + names are: summary, liquids, layers, features, ores, gems, veins, shrubs, + and trees. If run during pre-embark, only the layers, ores, gems, and veins + report sections are available. +``-v``, ``--values`` + Includes material value in the output. Most useful for the 'gems' report + section. + +Pre-embark estimate +------------------- + +If prospect is called during the embark selection screen, it displays an +estimate of layer stone availability. If the ``all`` keyword is specified, it +also estimates ores, gems, and vein material. The estimate covers all tiles of +the embark rectangle. + +.. note:: + + The results of pre-embark prospect are an *estimate*, and can at best be + expected to be somewhere within +/- 30% of the true amount; sometimes it + does a lot worse. In particular, it is not clear how to precisely compute + how many soil layers there will be in a given embark tile, so it can report + a whole extra layer, or omit one that is actually present. diff --git a/docs/plugins/regrass.rst b/docs/plugins/regrass.rst new file mode 100644 index 000000000..1a3fc7ed9 --- /dev/null +++ b/docs/plugins/regrass.rst @@ -0,0 +1,18 @@ +regrass +======= + +.. dfhack-tool:: + :summary: Regrows all the grass. + :tags: adventure fort armok animals map + +Use this command if your grazers have eaten everything down to the dirt. + +Usage +----- + +:: + + regrass [max] + +Specify the 'max' keyword to pack more grass onto a tile than what the game +normally allows to give your grazers extra chewing time. diff --git a/docs/plugins/rename.rst b/docs/plugins/rename.rst new file mode 100644 index 000000000..137cf56a4 --- /dev/null +++ b/docs/plugins/rename.rst @@ -0,0 +1,33 @@ +rename +====== + +.. dfhack-tool:: + :summary: Easily rename things. + :tags: adventure fort productivity buildings stockpiles units + +Use `gui/rename` for an in-game interface. + +Usage +----- + +``rename squad ""`` + Rename the indicated squad. The ordinal is the number that corresponds to + the list of squads in the squads menu (:kbd:`s`). The first squad is ordinal + ``1``. +``rename hotkey ""`` + Rename the indicated hotkey. The ordinal the the number that corresponds to + the list of hotkeys in the hotkeys menu (:kbd:`H`). The first hotkey is + ordinal ``1``. +``rename unit ""`` + Give the selected unit the given nickname. +``rename unit-profession ""`` + Give the selected unit the given profession name. +``rename building ""`` + Set a custom name to the selected building. The building must be a + stockpile, workshop, furnace, trap, siege engine, or activity zone. + +Example +------- + +``rename squad 1 "The Whiz Bonkers"`` + Rename the first squad to The Whiz Bonkers. diff --git a/docs/plugins/rendermax.rst b/docs/plugins/rendermax.rst new file mode 100644 index 000000000..747b74642 --- /dev/null +++ b/docs/plugins/rendermax.rst @@ -0,0 +1,35 @@ +rendermax +========= + +.. dfhack-tool:: + :summary: Modify the map lighting. + :tags: adventure fort gameplay graphics + +This plugin provides a collection of OpenGL lighting filters that affect how the +map is drawn to the screen. + +Usage +----- + +``rendermax light`` + Light the map tiles realisitically. Outside tiles are light during the day + and dark at night. Inside tiles are always dark unless a nearby unit is + lighting it up, as if they were carrying torches. +``rendermax light sun |cycle`` + Set the outside lighting to correspond with the specified day hour (1-24), + or specify ``cycle`` to have the lighting follow the sun (which is the + default). +``rendermax light reload`` + Reload the lighting settings file. +``rendermax trippy`` + Randomize the color of each tile. Used for fun, or testing. +``rendermax disable`` + Disable any ``rendermax`` lighting filters that are currently active. + +An image showing lava and dragon breath. Not pictured here: sunlight, shining +items/plants, materials that color the light etc. + +.. image:: ../images/rendermax.png + +For better visibility, try changing the black color in palette to non totally +black. See :forums:`128487` for more info. diff --git a/docs/plugins/resume.rst b/docs/plugins/resume.rst new file mode 100644 index 000000000..d6e0b81cb --- /dev/null +++ b/docs/plugins/resume.rst @@ -0,0 +1,23 @@ +resume +====== + +.. dfhack-tool:: + :summary: Color planned buildings based on their suspend status. + :tags: fort productivity interface jobs + :no-command: + +.. dfhack-command:: resume + :summary: Resume all suspended building jobs. + +When enabled, this plugin will display a colored 'X' over suspended buildings. +When run as a command, it can resume all suspended building jobs, allowing you +to quickly recover if a bunch of jobs were suspended due to the workers getting +scared off by wildlife or items temporarily blocking buildling sites. + +Usage +----- + +:: + + enable resume + resume all diff --git a/docs/plugins/reveal.rst b/docs/plugins/reveal.rst new file mode 100644 index 000000000..19066076b --- /dev/null +++ b/docs/plugins/reveal.rst @@ -0,0 +1,55 @@ +.. _revflood: + +reveal +====== + +.. dfhack-tool:: + :summary: Reveals the map. + :tags: adventure fort armok inspection map + +.. dfhack-tool:: unreveal + :summary: Hides previously hidden tiles again. + +.. dfhack-tool:: revforget + :summary: Discard records about what was visible before revealing the map. + +.. dfhack-tool:: revtoggle + :summary: Switch between reveal and unreveal. + +.. dfhack-tool:: revflood + :summary: Hide everything, then reveal tiles with a path to the cursor. + +.. dfhack-tool:: nopause + :summary: Disable pausing. + +This reveals all z-layers in fort mode. It also works in adventure mode, but any +of its effects are negated once you move. When you use it this way, you don't +need to run ``unreveal`` to hide the map again. + +Usage +----- + +``reveal [hell|demon]`` + Reveal the whole map. If ``hell`` is specified, also reveal HFS areas, but + you are required to run ``unreveal`` before unpausing is allowed in order + to prevent the demons from spawning. If you really want to unpause with hell + revealed, specify ``demon`` instead of ``hell``. +``unreveal`` + Reverts the effects of ``reveal``. +``revtoggle`` + Switches between ``reveal`` and ``unreveal``. Convenient to bind to a + hotkey. +``revforget`` + Discard info about what was visible before revealing the map. Only useful + where (for example) you abandoned with the fort revealed and no longer need + the saved map data when you load a new fort. +``revflood`` + Hide everything, then reveal tiles with a path to the cursor. This allows + reparing maps that you accidentally saved while they were revealed. Note + that tiles behind constructed walls are also revealed as a workaround for + :bug:`1871`. +``nopause 1|0`` + Disables pausing (both manual and automatic) with the exception of the pause + forced by `reveal` ``hell``. This is nice for digging under rivers. Use + ``nopause 1`` to prevent pausing and ``nopause 0`` to allow pausing like + normal. diff --git a/docs/plugins/ruby.rst b/docs/plugins/ruby.rst new file mode 100644 index 000000000..f1fafbb36 --- /dev/null +++ b/docs/plugins/ruby.rst @@ -0,0 +1,31 @@ +.. _rb: + +ruby +==== + +.. dfhack-tool:: + :summary: Allow Ruby scripts to be executed as DFHack commands. + :tags: dev + :no-command: + +.. dfhack-command:: rb + :summary: Eval() a ruby string. + +.. dfhack-command:: rb_eval + :summary: Eval() a ruby string. + +Usage +----- + +:: + + enable ruby + rb "ruby expression" + rb_eval "ruby expression" + :rb ruby expression + +Example +------- + +``:rb puts df.unit_find(:selected).name`` + Print the name of the selected unit. diff --git a/docs/plugins/search.rst b/docs/plugins/search.rst new file mode 100644 index 000000000..c489b4c40 --- /dev/null +++ b/docs/plugins/search.rst @@ -0,0 +1,52 @@ +.. _search-plugin: + +search +====== + +.. dfhack-tool:: + :summary: Adds search capabilities to the UI. + :tags: fort productivity interface + :no-command: + +Search options are added to the Stocks, Animals, Trading, Stockpile, Noble +aassignment candidates), Military (position candidates), Burrows (unit list), +Rooms, Announcements, Job List, and Unit List screens all get hotkeys that allow +you to dynamically filter the displayed lists. + +Usage +----- + +:: + + enable search + +.. image:: ../images/search.png + +Searching works the same way as the search option in :guilabel:`Move to Depot`. +You will see the Search option displayed on screen with a hotkey +(usually :kbd:`s`). Pressing it lets you start typing a query and the relevant +list will start filtering automatically. + +Pressing :kbd:`Enter`, :kbd:`Esc` or the arrow keys will return you to browsing +the now filtered list, which still functions as normal. You can clear the filter +by either going back into search mode and backspacing to delete it, or pressing +the "shifted" version of the search hotkey while browsing the list (e.g. if the +hotkey is :kbd:`s`, then hitting :kbd:`Shift`:kbd:`s` will clear any filter). + +Leaving any screen automatically clears the filter. + +In the Trade screen, the actual trade will always only act on items that are +actually visible in the list; the same effect applies to the Trade Value numbers +displayed by the screen. Because of this, the :kbd:`t` key is blocked while +search is active, so you have to reset the filters first. Pressing +:kbd:`Alt`:kbd:`C` will clear both search strings. + +In the stockpile screen the option only appears if the cursor is in the +rightmost list: + +.. image:: ../images/search-stockpile.png + +Note that the 'Permit XXX'/'Forbid XXX' keys conveniently operate only on items +actually shown in the rightmost list, so it is possible to select only fat or +tallow by forbidding fats, then searching for fat/tallow, and using Permit Fats +again while the list is filtered. diff --git a/docs/plugins/seedwatch.rst b/docs/plugins/seedwatch.rst new file mode 100644 index 000000000..c471f467d --- /dev/null +++ b/docs/plugins/seedwatch.rst @@ -0,0 +1,46 @@ +seedwatch +========= + +.. dfhack-tool:: + :summary: Manages seed and plant cooking based on seed stock levels. + :tags: fort auto plants + +Each seed type can be assigned a target. If the number of seeds of that type +falls below that target, then the plants and seeds of that type will be excluded +from cookery. If the number rises above the target + 20, then cooking will be +allowed. + +The plugin needs a fortress to be loaded and will deactivate automatically +otherwise. You have to reactivate with ``enable seedwatch`` after you load a +fort. + +Usage +----- + +``enable seedwatch`` + Start managing seed and plant cooking. By default, no types are watched. + You have to add them with further ``seedwatch`` commands. +``seedwatch `` + Adds the specifiied type to the watchlist (if it's not already there) and + sets the target number of seeds to the specified number. You can pass the + keyword ``all`` instead of a specific type to set the target for all types. +``seedwatch `` + Removes the specified type from the watch list. +``seedwatch clear`` + Clears all types from the watch list. +``seedwatch info`` + Display whether seedwatch is enabled and prints out the watch list. + +To print out a list of all plant types, you can run this command:: + + devel/query --table df.global.world.raws.plants.all --search ^id --maxdepth 1 + +Examples +-------- + +``seedwatch all 30`` + Adds all seeds to the watch list and sets the targets to 30. +``seedwatch MUSHROOM_HELMET_PLUMP 50`` + Add Plump Helmets to the watch list and sets the target to 50. +``seedwatch MUSHROOM_HELMET_PLUMP`` + removes Plump Helmets from the watch list. diff --git a/docs/plugins/showmood.rst b/docs/plugins/showmood.rst new file mode 100644 index 000000000..e12770341 --- /dev/null +++ b/docs/plugins/showmood.rst @@ -0,0 +1,13 @@ +showmood +======== + +.. dfhack-tool:: + :summary: Shows all items needed for the active strange mood. + :tags: fort armok inspection jobs units + +Usage +----- + +:: + + showmood diff --git a/docs/plugins/siege-engine.rst b/docs/plugins/siege-engine.rst new file mode 100644 index 000000000..d01fc524c --- /dev/null +++ b/docs/plugins/siege-engine.rst @@ -0,0 +1,25 @@ +siege-engine +============ + +.. dfhack-tool:: + :summary: Extend the functionality and usability of siege engines. + :tags: fort gameplay buildings + :no-command: + +Siege engines in DF haven't been updated since the game was 2D, and can only aim +in four directions. To make them useful above-ground, this plugin allows you to: + +* link siege engines to stockpiles +* restrict operator skill levels (like workshops) +* load any object into a catapult, not just stones +* aim at a rectangular area in any direction, and across Z-levels + +Usage +----- + +:: + + enable siege-engine + +You can use the new features by selecting a built siege engine and running +`gui/siege-engine`. diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst new file mode 100644 index 000000000..f5bce9bae --- /dev/null +++ b/docs/plugins/sort.rst @@ -0,0 +1,60 @@ +sort +==== + +.. dfhack-tool:: + :summary: Sort lists shown in the DF interface. + :tags: fort productivity interface + :no-command: + +.. dfhack-command:: sort-items + :summary: Sort the visible item list. + +.. dfhack-command:: sort-units + :summary: Sort the visible unit list. + +Usage +----- + +:: + + sort-items [ ...] + sort-units [ ...] + +Both commands sort the visible list using the given sequence of comparisons. +Each property can be prefixed with a ``<`` or ``>`` character to indicate +whether elements that don't have the given property defined go first or last +(respectively) in the sorted list. + +Examples +-------- + +``sort-items material type quality`` + Sort a list of items by material, then by type, then by quality +``sort-units profession name`` + Sort a list of units by profession, then by name + +Properties +---------- + +Items can be sorted by the following properties: + +- ``type`` +- ``description`` +- ``base_quality`` +- ``quality`` +- ``improvement`` +- ``wear`` +- ``material`` + +Units can be sorted by the following properties: + +- ``name`` +- ``age`` +- ``arrival`` +- ``noble`` +- ``profession`` +- ``profession_class`` +- ``race`` +- ``squad`` +- ``squad_position`` +- ``happiness`` diff --git a/docs/plugins/spectate.rst b/docs/plugins/spectate.rst new file mode 100644 index 000000000..d9e9d3929 --- /dev/null +++ b/docs/plugins/spectate.rst @@ -0,0 +1,17 @@ +spectate +======== + +.. dfhack-tool:: + :summary: Automatically follow exciting dwarves. + :tags: fort interface + :no-command: + +Usage +----- + +:: + + enable spectate + +The plugin will automatically switch which dwarf is being followed periodically, +preferring dwarves on z-levels with the highest job activity. diff --git a/docs/plugins/steam-engine.rst b/docs/plugins/steam-engine.rst new file mode 100644 index 000000000..6560ae714 --- /dev/null +++ b/docs/plugins/steam-engine.rst @@ -0,0 +1,89 @@ +steam-engine +============ + +.. dfhack-tool:: + :summary: Allow modded steam engine buildings to function. + :tags: fort gameplay buildings + :no-command: + +The steam-engine plugin detects custom workshops with the string +``STEAM_ENGINE`` in their token, and turns them into real steam engines! + +The plugin auto-enables itself when it detects the relevant tags in the world +raws. It does not need to be enabled with the `enable` command. + +Rationale +--------- +The vanilla game contains only water wheels and windmills as sources of power, +but windmills give relatively little power, and water wheels require flowing +water, which must either be a real river and thus immovable and +limited in supply, or actually flowing and thus laggy. + +Compared to the +:wiki:`dwarven water reactor ` exploit, +steam engines make a lot of sense! + +Construction +------------ +The workshop needs water as its input, which it takes via a passable floor tile +below it, like usual magma workshops do. The magma version also needs magma. + +Due to DF game limits, the workshop will collapse over true open space. However, +down stairs are passable but support machines, so you can use them. + +After constructing the building itself, machines can be connected to the edge +tiles that look like gear boxes. Their exact position is extracted from the +workshop raws. + +Like with collapse above, due to DF game limits the workshop can only +immediately connect to machine components built AFTER it. This also means that +engines cannot be chained without intermediate axles built after both engines. + +Operation +--------- +In order to operate the engine, queue the Stoke Boiler job (optionally on +repeat). A furnace operator will come, possibly bringing a bar of fuel, and +perform it. As a result, a "boiling water" item will appear in the :kbd:`t` +view of the workshop. + +.. note:: + + The completion of the job will actually consume one unit + of the appropriate liquids from below the workshop. This means + that you cannot just raise 7 units of magma with a piston and + have infinite power. However, liquid consumption should be slow + enough that water can be supplied by a pond zone bucket chain. + +Every such item gives 100 power, up to a limit of 300 for coal, or 500 for a +magma engine. The building can host twice that amount of items to provide longer +autonomous running. When the boiler gets filled to capacity, all queued jobs are +suspended. Once it drops back to 3+1 or 5+1 items, they are re-enabled. + +While the engine is providing power, steam is being consumed. The consumption +speed includes a fixed 10% waste rate, and the remaining 90% is applied +proportionally to the actual load in the machine. With the engine at nominal 300 +power with 150 load in the system, it will consume steam for actual +300*(10% + 90%*150/300) = 165 power. + +A masterpiece mechanism and chain will decrease the mechanical power drawn by +the engine itself from 10 to 5. A masterpiece barrel decreases waste rate by 4%. +A masterpiece piston and pipe decrease it by further 4%, and also decrease the +whole steam use rate by 10%. + +Explosions +---------- +The engine must be constructed using barrel, pipe, and piston from fire-safe, +or, in the magma version, magma-safe metals. + +During operation, weak parts gradually wear out, and eventually the engine +explodes. It should also explode if toppled during operation by a building +destroyer or a tantruming dwarf. + +Save files +---------- +It should be safe to load and view engine-using fortresses from a DF version +without DFHack installed, except that in such case the engines, of course, won't +work. However actually making modifications to them or machines they connect to +(including by pulling levers) can easily result in inconsistent state once this +plugin is available again. The effects may be as weird as negative power being +generated. diff --git a/docs/plugins/stockflow.rst b/docs/plugins/stockflow.rst new file mode 100644 index 000000000..9ce91eaca --- /dev/null +++ b/docs/plugins/stockflow.rst @@ -0,0 +1,35 @@ +stockflow +========= + +.. dfhack-tool:: + :summary: Queue manager jobs based on free space in stockpiles. + :tags: fort auto stockpiles workorders + +With this plugin, the fortress bookkeeper can tally up free space in specific +stockpiles and queue jobs through the manager to produce items to fill the free +space. + +When the plugin is enabled, the :kbd:`q` menu of each stockpile will have two +new options: + +* :kbd:`j`: Select a job to order, from an interface like the manager's screen. +* :kbd:`J`: Cycle between several options for how many such jobs to order. + +Whenever the bookkeeper updates stockpile records, new work orders will +be placed on the manager's queue for each such selection, reduced by the +number of identical orders already in the queue. + +This plugin is similar to `workflow`, but uses stockpiles to manage job triggers +instead of abstract stock quantities. + +Usage +----- + +``enable stockflow`` + Enable the plugin. +``stockflow status`` + Display whether the plugin is enabled. +``stockflow list`` + List any work order settings for your stockpiles. +``stockflow fast`` + Enqueue orders once per day instead of waiting for the bookkeeper. diff --git a/docs/plugins/stockpiles.rst b/docs/plugins/stockpiles.rst new file mode 100644 index 000000000..e7f02f970 --- /dev/null +++ b/docs/plugins/stockpiles.rst @@ -0,0 +1,53 @@ +.. _stocksettings: + +stockpiles +========== + +.. dfhack-tool:: + :summary: Import and export stockpile settings. + :tags: fort design productivity stockpiles + :no-command: + +.. dfhack-command:: copystock + :summary: Copies the configuration of the selected stockpile. + +.. dfhack-command:: savestock + :summary: Exports the configuration of the selected stockpile. + +.. dfhack-command:: loadstock + :summary: Imports the configuration of the selected stockpile. + +When the plugin is enabled, the :kbd:`q` menu of each stockpile will have an +option for saving or loading the stockpile settings. See `gui/stockpiles` for +an in-game interface. + +Usage +----- + +``enable stockpiles`` + Add a hotkey that you can hit to easily save and load settings from + stockpiles selected in :kbd:`q` mode. +``copystock`` + Copies the parameters of the currently highlighted stockpile to the custom + stockpile settings and switches to custom stockpile placement mode, + effectively allowing you to copy/paste stockpiles easily. +``savestock `` + Saves the currently highlighted stockpile's settings to a file in your + Dwarf Fortress folder. This file can be used to copy settings between game + saves or players. +``loadstock `` + Loads a saved stockpile settings file and applies it to the currently + selected stockpile. + +Filenames with spaces are not supported. Generated materials, divine metals, +etc. are not saved as they are different in every world. + +Examples +-------- + +``savestock food_settings.dfstock`` + Export the stockpile settings for the stockpile currently selected in + :kbd:`q` mode to a file named ``food_settings.dfstock``. +``loadstock food_settings.dfstock`` + Set the selected stockpile settings to those saved in the + ``food_settings.dfstock`` file. diff --git a/docs/plugins/stocks.rst b/docs/plugins/stocks.rst new file mode 100644 index 000000000..d8fae9579 --- /dev/null +++ b/docs/plugins/stocks.rst @@ -0,0 +1,24 @@ +stocks +====== + +.. dfhack-tool:: + :summary: Enhanced fortress stock management interface. + :tags: fort productivity items + +When the plugin is enabled, two new hotkeys become available: + +* :kbd:`e` on the vanilla DF stocks screen (:kbd:`z` and then select Stocks) + will launch the fortress-wide stock management screen. +* :kbd:`i` when a stockpile is selected in :kbd:`q` mode will launch the + stockpile inventory management screen. + +Usage +----- + +:: + + enable stocks + stocks show + +Running ``stocks show`` will bring you to the fortress-wide stock management +screen from whereever you are. diff --git a/docs/plugins/stonesense.rst b/docs/plugins/stonesense.rst new file mode 100644 index 000000000..23c20ef0a --- /dev/null +++ b/docs/plugins/stonesense.rst @@ -0,0 +1,82 @@ +stonesense +========== + +.. dfhack-tool:: + :summary: A 3D isometric visualizer. + :tags: adventure fort graphics map + +.. dfhack-command:: ssense + :summary: An alias for stonesense. + +Usage +----- + +``stonesense`` or ``ssense`` + Open the visualiser in a new window. +``ssense overlay`` + Overlay DF window, replacing the map area. + +The viewer window has read-only access to the game, and can follow the game view +or be moved independently. Configuration for stonesense can be set in the +``stonesense/init.txt`` file in your DF game directory. If the window refresh +rate is too low, change ``SEGMENTSIZE_Z`` to ``2`` in this file, and if you are +unable to see the edges of the map with the overlay active, try decreasing the +value for ``SEGMENTSIZE_XY`` -- normal values are ``50`` to ``80``, depending +on your screen resolution. + +If you replace the map section of your DF window with ``ssense overlay``, be +aware that it's not (yet) suitable for use as your only interface. Use DF's +``[PRINT_MODE:2D]`` init option (in ``data/init/init.txt``) for stability. + +.. figure:: ../images/stonesense-roadtruss.jpg + :align: center + :target: http://www.bay12forums.com/smf/index.php?topic=48172.msg3198664#msg3198664 + + The above-ground part of the fortress *Roadtruss*. + +Controls +-------- +Mouse controls are hard-coded and cannot be changed. + +:Left click: Move debug cursor (if available) +:Right click: Recenter screen +:Scrollwheel: Move up and down +:Ctrl-Scroll: Increase/decrease Z depth shown + +Follow mode makes the Stonesense view follow the location of the DF +window. The offset can be adjusted by holding :kbd:`Ctrl` while using the +keyboard window movement keys. When you turn on cursor follow mode, the +Stonesense debug cursor will follow the DF cursor when the latter exists. + +You can take screenshots with :kbd:`F5`, larger screenshots with +:kbd:`Ctrl`:kbd:`F5`, and screenshot the whole map at full resolution with +:kbd:`Ctrl`:kbd:`Shift`:kbd:`F5`. Screenshots are saved to the DF directory. +Note that feedback is printed to the DFHack console, and you may need +to zoom out before taking very large screenshots. + +See ``stonesense/keybinds.txt`` to learn or set keybindings, including +zooming, changing the dimensions of the rendered area, toggling various +views, fog, and rotation. Here's the important section: + +.. include:: ../../plugins/stonesense/resources/keybinds.txt + :literal: + :end-before: VALID ACTIONS: + +Known Issues +------------ +If Stonesense gives an error saying that it can't load +:file:`creatures/large_256/*.png`, your video card cannot handle the high +detail sprites used. Either open :file:`creatures/init.txt` and remove the +line containing that folder, or :dffd:`use these smaller sprites <6096>`. + +Stonesense requires working graphics acceleration, and we recommend +at least a dual core CPU to avoid slowing down your game of DF. + +Useful links +------------ +- :forums:`Official Stonesense thread <106497>` for feedback, + questions, requests or bug reports +- :forums:`Screenshots thread <48172>` +- :wiki:`Main wiki page ` +- :wiki:`How to add content ` +- `Stonesense on Github `_ diff --git a/docs/plugins/strangemood.rst b/docs/plugins/strangemood.rst new file mode 100644 index 000000000..7aabda93d --- /dev/null +++ b/docs/plugins/strangemood.rst @@ -0,0 +1,44 @@ +strangemood +=========== + +.. dfhack-tool:: + :summary: Trigger a strange mood. + :tags: fort armok units + +Usage +----- + +:: + + stangemood [] + +Examples +-------- + +``strangemood -force -unit -type secretive -skill armorsmith`` + Trigger a strange mood for the selected unit that will cause them to become + a legendary armorsmith. + +Options +------- + +``-force`` + Ignore normal strange mood preconditions (no recent mood, minimum moodable + population, artifact limit not reached, etc.). +``-unit`` + Make the strange mood strike the selected unit instead of picking one + randomly. Unit eligibility is still enforced (unless ``-force`` is also + specified). +``-type `` + Force the mood to be of a particular type instead of choosing randomly based + on happiness. Valid values are "fey", "secretive", "possessed", "fell", and + "macabre". +``-skill `` + Force the mood to use a specific skill instead of choosing the highest + moodable skill. Valid values are "miner", "carpenter", "engraver", "mason", + "tanner", "weaver", "clothier", "weaponsmith", "armorsmith", "metalsmith", + "gemcutter", "gemsetter", "woodcrafter", "stonecrafter", "metalcrafter", + "glassmaker", "leatherworker", "bonecarver", "bowyer", and "mechanic". + +Known limitations: if the selected unit is currently performing a job, the mood +will not be triggered. diff --git a/docs/plugins/tailor.rst b/docs/plugins/tailor.rst new file mode 100644 index 000000000..af7d253b2 --- /dev/null +++ b/docs/plugins/tailor.rst @@ -0,0 +1,41 @@ +tailor +====== + +.. dfhack-tool:: + :summary: Automatically keep your dwarves in fresh clothing. + :tags: fort auto workorders + +Whenever the bookkeeper updates stockpile records, this plugin will scan the +fort. If there are fresh cloths available, dwarves who are wearing tattered +clothing will have their rags confiscated (in the same manner as the +`cleanowned` tool) so that they'll reequip with replacement clothes. + +If there are not enough clothes available, manager orders will be generated +to manufacture some more. ``tailor`` will intelligently create orders using +raw materials that you have on hand in the fort. For example, if you have +lots of silk, but no cloth, then ``tailor`` will order only silk clothing to +be made. + +Usage +----- + +:: + + enable tailor + tailor status + tailor materials [ ...] + +By default, ``tailor`` will prefer using materials in this order:: + + silk cloth yarn leather + +but you can use the ``tailor materials`` command to restrict which materials +are used, and in what order. + +Example +------- + +``tailor materials silk cloth yarn`` + Restrict the materials used for automatically manufacturing clothing to + silk, cloth, and yarn, preferred in that order. This saves leather for + other uses, like making armor. diff --git a/docs/plugins/tiletypes.rst b/docs/plugins/tiletypes.rst new file mode 100644 index 000000000..44fba00df --- /dev/null +++ b/docs/plugins/tiletypes.rst @@ -0,0 +1,160 @@ +.. _tiletypes-here: +.. _tiletypes-here-point: + +tiletypes +========= + +.. dfhack-tool:: + :summary: Paints tiles of specified types onto the map. + :tags: adventure fort armok map + +.. dfhack-command:: tiletypes-command + :summary: Run tiletypes commands. + +.. dfhack-command:: tiletypes-here + :summary: Paint map tiles starting from the cursor. + +.. dfhack-command:: tiletypes-here-point + :summary: Paint the map tile under the cursor. + +You can use the `probe` command to discover properties of existing tiles that +you'd like to copy. If you accidentally paint over a vein that you want back, +`fixveins` may help. + +The tool works with a brush, a filter, and a paint specification. The brush +determines the shape of the area to affect, the filter selects which tiles to +affect, and the paint specification determines how to affect those tiles. + +Both paint and filter can have many different properties, like general shape +(WALL, FLOOR, etc.), general material (SOIL, STONE, MINERAL, etc.), specific +materials (MICROCLINE, MARBLE, etc.), state of 'designated', 'hidden', and +'light' flags, and many others. + +Usage +----- + +``tiletypes`` + Start the interactive terminal prompt where you can iteratively modify + the brush, filter, and paint specification and get help on syntax + elements. When in the interactive prompt, type ``quit`` to get out. +``tiletypes-command [; ...]`` + Run ``tiletypes`` commands from outside the interactive prompt. You can + use this form from hotkeys or `dfhack-run` to set specific tiletypes + properties. You can run multiple commands on one line by separating them + with :literal:`\ ; \ ` -- that's a semicolon with a space on either side. + See the Commands_ section below for an overview of commands you can run. +``tiletypes-here []`` + Apply the current options set in ``tiletypes`` and/or ``tiletypes-command`` + at the in-game cursor position, including the brush. Can be used from a + hotkey. +``tiletypes-here-point []`` + Apply the current options set in ``tiletypes`` and/or ``tiletypes-command`` + at the in-game cursor position to a single tile (ignoring brush settings). + Can be used from a hotkey. + +Examples +-------- + +``tiletypes-command filter material STONE ; f shape WALL ; paint shape FLOOR`` + Turn all stone walls into floors, preserving the material. +``tiletypes-command p any ; p s wall ; p sp normal`` + Clear the paint specificaiton and set it to unsmoothed walls. +``tiletypes-command f any ; p stone marble ; p sh wall ; p sp normal ; r 10 10`` + Prepare to paint a 10x10 area of marble walls, ready for harvesting for + flux. +``tiletypes-command f any ; f designated 1 ; p any ; p hidden 0 ; block ; run`` + Set the filter to match designated tiles, the paint specification to unhide + them, and the brush to cover all tiles in the current block. Then run itThis is useful + for unhiding tiles you wish to dig out of an aquifer so the game doesn't + pause and undesignate adjacent tiles every time a new damp tile is + "discovered". + +Options +------- + +``-c``, ``--cursor ,,`` + Use the specified map coordinates instead of the current cursor position. If + this option is specified, then an active game map cursor is not necessary. +``-q``, ``--quiet`` + Suppress non-error status output. + +Commands +-------- + +Commands can set the brush or modify the filter or paint options. When at the +interactive ``tiletypes>`` prompt, the command ``run`` (or hitting enter on an +empty line) will apply the current filter and paint specification with the +current brush at the current cursor position. The command ``quit`` will exit. + +Brush commands +`````````````` + +``p``, ``point`` + Use the point brush. +``r``, ``range []`` + Use the range brush with the specified width, height, and depth. If not + specified, depth is 1, meaning just the current z-level. The range starts at + the position of the cursor and goes to the east, south and up (towards the + sky). +``block`` + Use the block brush, which includes all tiles in the 16x16 block that + includes the cursor. +``column`` + Use the column brush, which ranges from the current cursor position to the + first solid tile above it. This is useful for filling the empty space in a + cavern. + +Filter and paint commands +````````````````````````` + +The general forms for modifying the filter or paint specification are: + +``f``, ``filter `` + Modify the filter. +``p``, ``paint `` + Modify the paint specification. + +The options identify the property of the tile and the value of that property: + +``any`` + Reset to default (no filter/paint). +``s``, ``sh``, ``shape `` + Tile shape information. Run ``:lua @df.tiletype_shape`` to see valid shapes, + or use a shape of ``any`` to clear the current setting. +``m``, ``mat``, ``material `` + Tile material information. Run ``:lua @df.tiletype_material`` to see valid + materials, or use a material of ``any`` to clear the current setting. +``sp``, ``special `` + Tile special information. Run ``:lua @df.tiletype_special`` to see valid + special values, or use a special value of ``any`` to clear the current + setting. +``v``, ``var``, ``variant `` + Tile variant information. Run ``:lua @df.tiletype_variant`` to see valid + variant values, or use a variant value of ``any`` to clear the current + setting. +``a``, ``all [] [] [] []`` + Set values for any or all of shape, material, special, and/or variant, in + any order. +``d``, ``designated 0|1`` + Only useful for the filter, since you can't "paint" designations. +``h``, ``hidden 0|1`` + Whether a tile is hidden. A value of ``0`` means "revealed". +``l``, ``light 0|1`` + Whether a tile is marked as "Light". A value of ``0`` means "dark". +``st``, ``subterranean 0|1`` + Whether a tile is marked as "Subterranean". +``sv``, ``skyview 0|1`` + Whether a tile is marked as "Outside". A value of ``0`` means "inside". +``aqua``, ``aquifer 0|1`` + Whether a tile is marked as an aquifer. +``stone `` + Set a particular type of stone, creating veins as required. To see a list of + valid stone types, run: ``:lua for _,mat in ipairs(df.global.world.raws.inorganics) do if mat.material.flags.IS_STONE and not mat.material.flags.NO_STONE_STOCKPILE then print(mat.id) end end`` + Note that this command paints under ice and constructions, instead of + overwriting them. Also note that specifying a specific ``stone`` will cancel + out anything you have specified for ``material``, and vice-versa. +``veintype `` + Set a particular vein type for the ``stone`` option to take advantage of the + different boulder drop rates. To see valid vein types, run + ``:lua @df.inclusion_type``, or use vein type ``CLUSTER`` to reset to the + default. diff --git a/docs/plugins/title-folder.rst b/docs/plugins/title-folder.rst new file mode 100644 index 000000000..a6c7ee63c --- /dev/null +++ b/docs/plugins/title-folder.rst @@ -0,0 +1,14 @@ +title-folder +============= + +.. dfhack-tool:: + :summary: Displays the DF folder name in the window title bar. + :tags: interface + :no-command: + +Usage +----- + +:: + + enable title-folder diff --git a/docs/plugins/title-version.rst b/docs/plugins/title-version.rst new file mode 100644 index 000000000..307a4da18 --- /dev/null +++ b/docs/plugins/title-version.rst @@ -0,0 +1,14 @@ +title-version +============= + +.. dfhack-tool:: + :summary: Displays the DFHack version on DF's title screen. + :tags: interface + :no-command: + +Usage +----- + +:: + + enable title-version diff --git a/docs/plugins/trackstop.rst b/docs/plugins/trackstop.rst new file mode 100644 index 000000000..3ca47f465 --- /dev/null +++ b/docs/plugins/trackstop.rst @@ -0,0 +1,19 @@ +trackstop +========= + +.. dfhack-tool:: + :summary: Add dynamic configuration options for track stops. + :tags: fort gameplay buildings + :no-command: + +When enabled, this plugin adds a :kbd:`q` menu for track stops, which is +completely blank in vanilla DF. This allows you to view and/or change the track +stop's friction and dump direction settings, using the keybindings from the +track stop building interface. + +Usage +----- + +:: + + enable trackstop diff --git a/docs/plugins/tubefill.rst b/docs/plugins/tubefill.rst new file mode 100644 index 000000000..1085897c8 --- /dev/null +++ b/docs/plugins/tubefill.rst @@ -0,0 +1,19 @@ +tubefill +======== + +.. dfhack-tool:: + :summary: Replentishes mined-out adamantine. + :tags: fort armok map + +Veins that were originally hollow will be left alone. + +Usage +----- + +:: + + tubefill [hollow] + +Specify ``hollow`` to fill in naturally hollow veins too, but be aware that this +will trigger a demon invasion on top of your miner when you dig into the region +that used to be hollow. You have been warned! diff --git a/docs/plugins/tweak.rst b/docs/plugins/tweak.rst new file mode 100644 index 000000000..bb125fc0d --- /dev/null +++ b/docs/plugins/tweak.rst @@ -0,0 +1,140 @@ +tweak +===== + +.. dfhack-tool:: + :summary: A collection of tweaks and bugfixes. + :tags: adventure fort armok bugfix fps interface + +Usage +----- + +:: + + tweak [disable] + +Run the ``tweak`` command to run the tweak or enable its effects. For tweaks +that have persistent effects, append the ``disable`` keyword to disable them. + +One-shot commands: + +``clear-missing`` + Remove the missing status from the selected unit. This allows engraving + slabs for ghostly, but not yet found, creatures. +``clear-ghostly`` + Remove the ghostly status from the selected unit and mark it as dead. This + allows getting rid of bugged ghosts which do not show up in the engraving + slab menu at all, even after using ``clear-missing``. It works, but is + potentially very dangerous - so use with care. Probably (almost certainly) + it does not have the same effects like a proper burial. You've been warned. +``fixmigrant`` + Remove the resident/merchant flag from the selected unit. Intended to fix + bugged migrants/traders who stay at the map edge and don't enter your fort. + Only works for dwarves (or generally the player's race in modded games). + Do NOT abuse this for 'real' caravan merchants (if you really want to kidnap + them, use ``tweak makeown`` instead, otherwise they will have their clothes + set to forbidden). +``makeown`` + Force selected unit to become a member of your fort. Can be abused to grab + caravan merchants and escorts, even if they don't belong to the player's + race. Foreign sentients (humans, elves) can be put to work, but you can't + assign rooms to them and they don't show up in labor management programs + (like `manipulator` or Dwarf Therapist) because the game treats them like + pets. Grabbing draft animals from a caravan can result in weirdness + (animals go insane or berserk and are not flagged as tame), but you are + allowed to mark them for slaughter. Grabbing wagons results in some funny + spam, then they are scuttled. + +Commands that persist until disabled or DF quits: + +.. comment: please sort these alphabetically + +``adamantine-cloth-wear`` + Prevents adamantine clothing from wearing out while being worn + (:bug:`6481`). +``advmode-contained`` + Fixes custom reactions with container inputs in advmode + (:bug:`6202`) in advmode. The issue is that the screen tries to force you to + select the contents separately from the container. This forcefully skips + child reagents. +``block-labors`` + Prevents labors that can't be used from being toggled. +``burrow-name-cancel`` + Implements the "back" option when renaming a burrow, which currently does + nothing in vanilla DF (:bug:`1518`). +``cage-butcher`` + Adds an option to butcher units when viewing cages with :kbd:`q`. +``civ-view-agreement`` + Fixes overlapping text on the "view agreement" screen. +``condition-material`` + Fixes a crash in the work order contition material list (:bug:`9905`). +``craft-age-wear`` + Fixes crafted items not wearing out over time (:bug:`6003`). With this + tweak, items made from cloth and leather will gain a level of wear every 20 + years. +``do-job-now`` + Adds a job priority toggle to the jobs list. +``embark-profile-name`` + Allows the use of lowercase letters when saving embark profiles. +``eggs-fertile`` + Displays a fertility indicator on nestboxes. +``farm-plot-select`` + Adds "Select all" and "Deselect all" options to farm plot menus. +``fast-heat`` + Improves temperature update performance by ensuring that 1 degree of item + temperature is crossed in no more than specified number of frames when + updating from the environment temperature. This reduces the time it takes + for ``tweak stable-temp`` to stop updates again when equilibrium is + disturbed. +``fast-trade`` + Makes Shift-Down in the Move Goods to Depot and Trade screens toggle the + current item (fully, in case of a stack), and scroll down one line. Shift-Up + undoes the last Shift-Down by scrolling up one line and then toggle the item. +``fps-min`` + Fixes the in-game minimum FPS setting (:bug:`6277`). +``hide-priority`` + Adds an option to hide designation priority indicators. +``hotkey-clear`` + Adds an option to clear currently-bound hotkeys (in the :kbd:`H` menu). +``import-priority-category`` + When meeting with a liaison, makes Shift+Left/Right arrow adjust all items + in category when discussing an import agreement with the liaison. +``kitchen-prefs-all`` + Adds an option to toggle cook/brew for all visible items in kitchen + preferences. +``kitchen-prefs-color`` + Changes color of enabled items to green in kitchen preferences. +``kitchen-prefs-empty`` + Fixes a layout issue with empty kitchen tabs (:bug:`9000`). +``max-wheelbarrow`` + Allows assigning more than 3 wheelbarrows to a stockpile. +``military-color-assigned`` + Color squad candidates already assigned to other squads in yellow/green to + make them stand out more in the list. + + .. image:``../images/tweak-mil-color.png + +``military-stable-assign`` + Preserve list order and cursor position when assigning to squad, i.e. stop + the rightmost list of the Positions page of the military screen from + constantly resetting to the top. +``nestbox-color`` + Makes built nestboxes use the color of their material. +``partial-items`` + Displays percentages on partially-consumed items such as hospital cloth. +``pausing-fps-counter`` + Replace fortress mode FPS counter with one that stops counting when paused. +``reaction-gloves`` + Fixes reactions to produce gloves in sets with correct handedness + (:bug:`6273`). +``shift-8-scroll`` + Gives Shift-8 (or :kbd:`*`) priority when scrolling menus, instead of + scrolling the map. +``stable-cursor`` + Saves the exact cursor position between t/q/k/d/b/etc menus of fortress + mode, if the map view is near enough to its previous position. +``stone-status-all`` + Adds an option to toggle the economic status of all stones. +``title-start-rename`` + Adds a safe rename option to the title screen "Start Playing" menu. +``tradereq-pet-gender`` + Displays pet genders on the trade request screen. diff --git a/docs/plugins/workNow.rst b/docs/plugins/workNow.rst new file mode 100644 index 000000000..55004bca2 --- /dev/null +++ b/docs/plugins/workNow.rst @@ -0,0 +1,22 @@ +workNow +======= + +.. dfhack-tool:: + :summary: Reduce the time that dwarves idle after completing a job. + :tags: fort auto labors + +After finishing a job, dwarves will wander away for a while before picking up a +new job. This plugin will automatically poke the game to assign dwarves to new +tasks. + +Usage +----- + +``workNow`` + Print current plugin status. +``workNow 0`` + Stop monitoring and poking. +``workNow 1`` + Poke the game to assign dwarves to tasks whenever the game is paused. +``workNow 2`` + Poke the game to assign dwarves to tasks whenever a dwarf finishes a job. diff --git a/docs/plugins/workflow.rst b/docs/plugins/workflow.rst new file mode 100644 index 000000000..9013ba189 --- /dev/null +++ b/docs/plugins/workflow.rst @@ -0,0 +1,143 @@ +workflow +======== + +.. dfhack-tool:: + :summary: Manage automated item production rules. + :tags: fort auto jobs + +.. dfhack-command:: fix-job-postings + :summary: Fixes crashes caused by old versions of workflow. + +Manage repeat jobs according to stock levels. `gui/workflow` provides a simple +front-end integrated in the game UI. + +When the plugin is enabled, it protects all repeat jobs from removal. If they do +disappear due to any cause (raw materials not available, manual removal by the +player, etc.), they are immediately re-added to their workshop and suspended. + +If any constraints on item amounts are set, repeat jobs that produce that kind +of item are automatically suspended and resumed as the item amount goes above or +below the limit. + +There is a good amount of overlap between this plugin and the vanilla manager +workorders, and both systems have their advantages. Vanilla manager workorders +can be more expressive about when to enqueue jobs. For example, you can gate the +activation of a vanilla workorder based on availability of raw materials, which +you cannot do in ``workflow``. However, ``workflow`` is often more convenient +for quickly keeping a small stock of various items on hand without having to +configure all the vanilla manager options. Also see the `orders` plugin for +a library of manager orders that may make managing your stocks even more +convenient than ``workflow`` can. + +Usage +----- + +``enable workflow`` + Start monitoring for and managing workshop jobs that are set to repeat. +``workflow enable|disable drybuckets`` + Enables/disables automatic emptying of abandoned water buckets. +``workflow enable|disable auto-melt`` + Enables/disables automatic resumption of repeat melt jobs when there are + objects to melt. +``workflow count [gap]`` + Set a constraint, counting every stack as 1 item. If a gap is specified, + stocks are allowed to dip that many items below the target before relevant + jobs are resumed. +``workflow amount [gap]`` + Set a constraint, counting all items within stacks. If a gap is specified, + stocks are allowed to dip that many items below the target before relevant + jobs are resumed. +``workflow unlimit `` + Delete a constraint. +``workflow unlimit-all`` + Delete all constraints. +``workflow jobs`` + List workflow-controlled jobs (if in a workshop, filtered by it). +``workflow list`` + List active constraints, and their job counts. +``workflow list-commands`` + List active constraints as workflow commands that re-create them; this list + can be copied to a file, and then reloaded using the `script` built-in + command. +``fix-job-postings [dry-run]`` + Fixes crashes caused by the version of workflow released with DFHack + 0.40.24-r4. It will be run automatically if needed. If your save has never + been run with this version, you will never need this command. Specify the + ``dry-run`` keyword to see what this command would do without making any + changes to game state. + +Examples +-------- + +Keep metal bolts within 900-1000, and wood/bone within 150-200:: + + workflow amount AMMO:ITEM_AMMO_BOLTS/METAL 1000 100 + workflow amount AMMO:ITEM_AMMO_BOLTS/WOOD,BONE 200 50 + +Keep the number of prepared food & drink stacks between 90 and 120:: + + workflow count FOOD 120 30 + workflow count DRINK 120 30 + +Make sure there are always 25-30 empty bins/barrels/bags:: + + workflow count BIN 30 + workflow count BARREL 30 + workflow count BOX/CLOTH,SILK,YARN 30 + +Make sure there are always 15-20 coal and 25-30 copper bars:: + + workflow count BAR//COAL 20 + workflow count BAR//COPPER 30 + +Produce 15-20 gold crafts:: + + workflow count CRAFTS//GOLD 20 + +Collect 15-20 sand bags and clay boulders:: + + workflow count POWDER_MISC/SAND 20 + workflow count BOULDER/CLAY 20 + +Make sure there are always 80-100 units of dimple dye:: + + workflow amount POWDER_MISC//MUSHROOM_CUP_DIMPLE:MILL 100 20 + +.. note:: + + In order for this to work, you have to set the material of the PLANT input + on the Mill Plants job to MUSHROOM_CUP_DIMPLE using the + `job item-material ` command. Otherwise the plugin won't be able to + deduce the output material. + +Maintain 10-100 locally-made crafts of exceptional quality:: + + workflow count CRAFTS///LOCAL,EXCEPTIONAL 100 90 + +Constraint format +----------------- + +The constraint spec consists of 4 parts, separated with ``/`` characters:: + + ITEM[:SUBTYPE]/[GENERIC_MAT,...]/[SPECIFIC_MAT:...]/[LOCAL,] + +The first part is mandatory and specifies the item type and subtype, using the +raw tokens for items (the same syntax used custom reaction inputs). For more +information, see :wiki:`this wiki page `. + +The subsequent parts are optional: + +- A generic material spec constrains the item material to one of the hard-coded + generic classes, which currently include:: + + PLANT WOOD CLOTH SILK LEATHER BONE SHELL SOAP TOOTH HORN PEARL YARN + METAL STONE SAND GLASS CLAY MILK + +- A specific material spec chooses the material exactly, using the raw syntax + for reaction input materials, e.g. ``INORGANIC:IRON``, although for + convenience it also allows just ``IRON``, or ``ACACIA:WOOD`` etc. See the + link above for more details on the unabbreviated raw syntax. + +- A comma-separated list of miscellaneous flags, which currently can be used to + ignore imported items (``LOCAL``) or items below a certain quality (1-5, with + 5 being masterwork). diff --git a/docs/plugins/xlsxreader.rst b/docs/plugins/xlsxreader.rst new file mode 100644 index 000000000..3d6cc0ac8 --- /dev/null +++ b/docs/plugins/xlsxreader.rst @@ -0,0 +1,9 @@ +xlsxreader +========== + +.. dfhack-tool:: + :summary: Provides a Lua API for reading xlsx files. + :tags: dev + :no-command: + +See `xlsxreader-api` for details. diff --git a/docs/plugins/zone.rst b/docs/plugins/zone.rst new file mode 100644 index 000000000..93b244399 --- /dev/null +++ b/docs/plugins/zone.rst @@ -0,0 +1,159 @@ +zone +==== + +.. dfhack-tool:: + :summary: Manage activity zones, cages, and the animals therein. + :tags: fort productivity animals buildings + +Usage +----- + +``enable zone`` + Add helpful filters to the pen/pasture sidebar menu (e.g. show only caged + grazers). +``zone set`` + Set zone or cage under cursor as default for future ``assign`` or ``tocages`` + commands. +``zone assign [] []`` + Assign unit(s) to the zone with the given ID, or to the most recent pen or + pit marked with the ``set`` command. If no filters are set, then a unit must + be selected in the in-game ui. +``zone unassign []`` + Unassign selected creature from its zone. +``zone nick []`` + Assign the given nickname to the selected animal or the animals matched by + the given filter. +``zone remnick []`` + Remove nicknames from the selected animal or the animals matched by the + given filter. +``zone enumnick []`` + Assign enumerated nicknames (e.g. "Hen 1", "Hen 2"...). +``zone tocages []`` + Assign unit(s) to cages that have been built inside the pasture selected + with the ``set`` command. +``zone uinfo []`` + Print info about unit(s). If no filters are set, then a unit must be + selected in the in-game ui. +``zone zinfo`` + Print info about the zone(s) and any buildings under the cursor. + +Examples +-------- + +Before any ``assign`` or ``tocages`` examples can be used, you must first move +the cursor over a pen/pasture or pit zone and run ``zone set`` to select the +zone. + +``zone assign all own ALPACA minage 3 maxage 10`` + Assign all of your alpacas who are between 3 and 10 years old to the + selected pasture. +``zone assign all own caged grazer nick ineedgrass`` + Assign all of your grazers who are sitting in cages on stockpiles (e.g. + after buying them from merchants) to the selected pasture and give them the + nickname 'ineedgrass'. +``zone assign all own not grazer not race CAT`` + Assign all of your animals who are not grazers (excluding cats) to the + selected pasture. + " zone assign all own milkable not grazer\n" +``zone assign all own female milkable not grazer`` + Assign all of your non-grazing milkable creatures to the selected pasture or + cage. +``zone assign all own race DWARF maxage 2`` + Throw all useless kids into a pit :) They'll be fine I'm sure. +``zone nick donttouchme`` + Nicknames all units in the current default zone or cage to 'donttouchme'. + This is especially useful for protecting a group of animals assigned to a + pasture or cage from being "processed" by `autobutcher`. +``zone tocages count 50 own tame male not grazer`` + Stuff up to 50 of your tame male animals who are not grazers into cages + built on the current default zone. + +Filters +------- + +:all: Process all units. +:count : Process only up to n units. +:unassigned: Not assigned to zone, chain or built cage. +:minage : Minimum age. Must be followed by number. +:maxage : Maximum age. Must be followed by number. +:not: Negates the next filter keyword. All of the keywords documented + below are negatable. +:race: Must be followed by a race RAW ID (e.g. BIRD_TURKEY, ALPACA, + etc). +:caged: In a built cage. +:own: From own civilization. You'll usually want to include this + filter. +:war: Trained war creature. +:hunting: Trained hunting creature. +:tamed: Creature is tame. +:trained: Creature is trained. Finds war/hunting creatures as well as + creatures who have a training level greater than 'domesticated'. + If you want to specifically search for war/hunting creatures + use ``war`` or ``hunting``. +:trainablewar: Creature can be trained for war (and is not already trained for + war/hunt). +:trainablehunt: Creature can be trained for hunting (and is not already trained + for war/hunt). +:male: Creature is male. +:female: Creature is female. +:egglayer: Race lays eggs. If you want units who actually lay eggs, also + specify ``female``. +:grazer: Race is a grazer. +:milkable: Race is milkable. If you want units who actually can be milked, + also specify ``female``. +:merchant: Is a merchant / belongs to a merchant. Should only be used for + pitting or slaughtering, not for stealing animals. + +Usage with single units +----------------------- +One convenient way to use the zone tool is to bind the commands ``zone assign`` +and ``zone set`` to hotkeys. Place the in-game cursor over a pen/pasture or pit +and use the ``zone set`` hotkey to mark it. Then you can select units on the map +(in 'v' or 'k' mode), in the unit list or from inside cages and use the +``zone assign`` hotkey to assign them to their new home. Allows pitting your own +dwarves, by the way. + +Matching with filters +--------------------- +All filters can be used together with the ``assign`` and ``tocages`` commands. + +Note that it's not possible to reassign units who are inside built cages or +chained, though this likely won't matter because if you have gone to the trouble +of creating a zoo or chaining a creature, you probably wouldn't want them +reassigned anyways. Also, ``zone`` will avoid caging owned pets because the owner +uncages them after a while which results in infinite hauling back and forth. + +Most filters should include an ``own`` element (which implies ``tame``) unless +you want to use ``zone assign`` for pitting hostiles. The ``own`` filter ignores +dwarves unless you explicitly specify ``race DWARF`` (so it's safe to use +``assign all own`` to one big pasture if you want to have all your animals in +the same place). + +The ``egglayer`` and ``milkable`` filters should be used together with +``female`` unless you want the males of the race included. Merchants and their +animals are ignored unless you specify ``merchant`` (pitting them should be no +problem, but stealing and pasturing their animals is not a good idea since +currently they are not properly added to your own stocks; slaughtering them +should work). + +Most filters can be negated (e.g. ``not grazer`` -> race is not a grazer). + +Mass-renaming +------------- + +Using the ``nick`` command, you can set the same nickname for multiple units. +If used without ``assign``, ``all``, or ``count``, it will rename all units in +the current default target zone. Combined with ``assign``, ``all``, or ``count`` +(and likely further optional filters) it will rename units matching the filter +conditions. + +Cage zones +---------- + +The ``tocages`` command assigns units to a set of cages, for example a room next +to your butcher shop(s). Units will be spread evenly among available cages to +optimize hauling to and butchering from them. For this to work you need to build +cages and then place one pen/pasture activity zone above them, covering all +cages you want to use. Then use ``zone set`` (like with ``assign``) and run +``zone tocages ``. ``tocages`` can be used together with ``nick`` or +``remnick`` to adjust nicknames while assigning to cages. diff --git a/docs/sphinx_extensions/dfhack/changelog.py b/docs/sphinx_extensions/dfhack/changelog.py index f7405d8b1..0cd732988 100644 --- a/docs/sphinx_extensions/dfhack/changelog.py +++ b/docs/sphinx_extensions/dfhack/changelog.py @@ -6,7 +6,7 @@ import sys from sphinx.errors import ExtensionError, SphinxError, SphinxWarning -from dfhack.util import DFHACK_ROOT, DOCS_ROOT +from dfhack.util import DFHACK_ROOT, DOCS_ROOT, write_file_if_changed CHANGELOG_PATHS = ( 'docs/changelog.txt', @@ -172,7 +172,7 @@ def consolidate_changelog(all_entries): def print_changelog(versions, all_entries, path, replace=True, prefix=''): # all_entries: version -> section -> entry - with open(path, 'w') as f: + with write_file_if_changed(path) as f: def write(line): if replace: line = replace_text(line, REPLACEMENTS) @@ -238,8 +238,10 @@ def generate_changelog(all=False): consolidate_changelog(stable_entries) consolidate_changelog(dev_entries) - print_changelog(versions, stable_entries, os.path.join(DOCS_ROOT, '_auto/news.rst')) - print_changelog(versions, dev_entries, os.path.join(DOCS_ROOT, '_auto/news-dev.rst')) + os.makedirs(os.path.join(DOCS_ROOT, 'changelogs'), mode=0o755, exist_ok=True) + + print_changelog(versions, stable_entries, os.path.join(DOCS_ROOT, 'changelogs/news.rst')) + print_changelog(versions, dev_entries, os.path.join(DOCS_ROOT, 'changelogs/news-dev.rst')) if all: for version in versions: @@ -251,10 +253,10 @@ def generate_changelog(all=False): else: version_entries = {version: dev_entries[version]} print_changelog([version], version_entries, - os.path.join(DOCS_ROOT, '_changelogs/%s-github.txt' % version), + os.path.join(DOCS_ROOT, 'changelogs/%s-github.txt' % version), replace=False) print_changelog([version], version_entries, - os.path.join(DOCS_ROOT, '_changelogs/%s-reddit.txt' % version), + os.path.join(DOCS_ROOT, 'changelogs/%s-reddit.txt' % version), replace=False, prefix='> ') @@ -264,7 +266,7 @@ def cli_entrypoint(): import argparse parser = argparse.ArgumentParser() parser.add_argument('-a', '--all', action='store_true', - help='Print changelogs for all versions to docs/_changelogs') + help='Print changelogs for all versions to docs/changelogs') parser.add_argument('-c', '--check', action='store_true', help='Check that all entries are printed') args = parser.parse_args() @@ -272,9 +274,9 @@ def cli_entrypoint(): entries = generate_changelog(all=args.all) if args.check: - with open(os.path.join(DOCS_ROOT, '_auto/news.rst')) as f: + with open(os.path.join(DOCS_ROOT, 'changelogs/news.rst')) as f: content_stable = f.read() - with open(os.path.join(DOCS_ROOT, '_auto/news-dev.rst')) as f: + with open(os.path.join(DOCS_ROOT, 'changelogs/news-dev.rst')) as f: content_dev = f.read() for entry in entries: for description in entry.children: diff --git a/docs/sphinx_extensions/dfhack/tool_docs.py b/docs/sphinx_extensions/dfhack/tool_docs.py new file mode 100644 index 000000000..178303744 --- /dev/null +++ b/docs/sphinx_extensions/dfhack/tool_docs.py @@ -0,0 +1,200 @@ +# useful references: +# https://www.sphinx-doc.org/en/master/extdev/appapi.html +# https://www.sphinx-doc.org/en/master/development/tutorials/recipe.html +# https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#rst-directives + +import logging +import os +from typing import List, Optional, Type + +import docutils.nodes as nodes +import docutils.parsers.rst.directives as rst_directives +import sphinx +import sphinx.addnodes as addnodes +import sphinx.directives + +import dfhack.util + + +logger = sphinx.util.logging.getLogger(__name__) + + +def get_label_class(builder: sphinx.builders.Builder) -> Type[nodes.Inline]: + if builder.format == 'text': + return nodes.inline + else: + return nodes.strong + +def make_labeled_paragraph(label: Optional[str]=None, content: Optional[str]=None, + label_class=nodes.strong, content_class=nodes.inline) -> nodes.paragraph: + p = nodes.paragraph('', '') + if label is not None: + p += [ + label_class('', '{}:'.format(label)), + nodes.inline('', ' '), + ] + if content is not None: + p += content_class('', content) + return p + +def make_summary(builder: sphinx.builders.Builder, summary: str) -> nodes.paragraph: + para = nodes.paragraph('', '') + if builder.format == 'text': + # It might be clearer to block indent instead of just indenting the + # first line, but this is clearer than nothing. + para += nodes.inline(text=' ') + para += nodes.inline(text=summary) + return para + + +_KEYBINDS = {} +_KEYBINDS_RENDERED = set() # commands whose keybindings have been rendered + +def scan_keybinds(root, files, keybindings): + """Add keybindings in the specified files to the + given keybindings dict. + """ + for file in files: + with open(os.path.join(root, file)) as f: + lines = [l.replace('keybinding add', '').strip() for l in f.readlines() + if l.startswith('keybinding add')] + for k in lines: + first, command = k.split(' ', 1) + bind, context = (first.split('@') + [''])[:2] + if ' ' not in command: + command = command.replace('"', '') + tool = command.split(' ')[0].replace('"', '') + keybindings[tool] = keybindings.get(tool, []) + [ + (command, bind.split('-'), context)] + +def scan_all_keybinds(root_dir): + """Get the implemented keybinds, and return a dict of + {tool: [(full_command, keybinding, context), ...]}. + """ + keybindings = dict() + for root, _, files in os.walk(root_dir): + scan_keybinds(root, files, keybindings) + return keybindings + + +def render_dfhack_keybind(command, builder: sphinx.builders.Builder) -> List[nodes.paragraph]: + _KEYBINDS_RENDERED.add(command) + out = [] + if command not in _KEYBINDS: + return out + for keycmd, key, ctx in _KEYBINDS[command]: + n = make_labeled_paragraph('Keybinding', label_class=get_label_class(builder)) + for k in key: + if builder.format == 'text': + k = '[{}]'.format(k) + n += nodes.inline(k, k, classes=['kbd']) + if keycmd != command: + n += nodes.inline(' -> ', ' -> ') + n += nodes.literal(keycmd, keycmd, classes=['guilabel']) + if ctx: + n += nodes.inline(' in ', ' in ') + n += nodes.literal(ctx, ctx) + out.append(n) + return out + + +def check_missing_keybinds(): + # FIXME: _KEYBINDS_RENDERED is empty in the parent process under parallel builds + # consider moving to a sphinx Domain to solve this properly + for missing_command in sorted(set(_KEYBINDS.keys()) - _KEYBINDS_RENDERED): + logger.warning('Undocumented keybindings for command: %s', missing_command) + + +class DFHackToolDirectiveBase(sphinx.directives.ObjectDescription): + has_content = False + required_arguments = 0 + optional_arguments = 1 + + def get_name_or_docname(self): + if self.arguments: + return self.arguments[0] + else: + return self.env.docname.split('/')[-1] + + @staticmethod + def wrap_box(*children: List[nodes.Node]) -> nodes.Admonition: + return nodes.topic('', *children, classes=['dfhack-tool-summary']) + + def make_labeled_paragraph(self, *args, **kwargs): + # convenience wrapper to set label_class to the desired builder-specific node type + kwargs.setdefault('label_class', get_label_class(self.env.app.builder)) + return make_labeled_paragraph(*args, **kwargs) + + def render_content(self) -> List[nodes.Node]: + raise NotImplementedError + + def run(self): + return [self.wrap_box(*self.render_content())] + + +class DFHackToolDirective(DFHackToolDirectiveBase): + option_spec = { + 'tags': dfhack.util.directive_arg_str_list, + 'no-command': rst_directives.flag, + 'summary': rst_directives.unchanged, + } + + def render_content(self) -> List[nodes.Node]: + tag_paragraph = self.make_labeled_paragraph('Tags') + for tag in self.options.get('tags', []): + tag_paragraph += [ + addnodes.pending_xref(tag, nodes.inline(text=tag), **{ + 'reftype': 'ref', + 'refdomain': 'std', + 'reftarget': 'tag/' + tag, + 'refexplicit': False, + 'refwarn': True, + }), + nodes.inline(text=' | '), + ] + tag_paragraph.pop() + + ret_nodes = [tag_paragraph] + if 'no-command' in self.options: + ret_nodes += [make_summary(self.env.app.builder, self.options.get('summary', ''))] + return ret_nodes + + def run(self): + out = DFHackToolDirectiveBase.run(self) + if 'no-command' not in self.options: + out += [self.wrap_box(*DFHackCommandDirective.render_content(self))] + return out + + +class DFHackCommandDirective(DFHackToolDirectiveBase): + option_spec = { + 'summary': rst_directives.unchanged_required, + } + + def render_content(self) -> List[nodes.Node]: + command = self.get_name_or_docname() + return [ + self.make_labeled_paragraph('Command', command, content_class=nodes.literal), + make_summary(self.env.app.builder, self.options.get('summary', '')), + *render_dfhack_keybind(command, builder=self.env.app.builder), + ] + + +def register(app): + app.add_directive('dfhack-tool', DFHackToolDirective) + app.add_directive('dfhack-command', DFHackCommandDirective) + + _KEYBINDS.update(scan_all_keybinds(os.path.join(dfhack.util.DFHACK_ROOT, 'data', 'init'))) + + +def setup(app): + app.connect('builder-inited', register) + + # TODO: re-enable once detection is corrected + # app.connect('build-finished', lambda *_: check_missing_keybinds()) + + return { + 'version': '0.1', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/docs/sphinx_extensions/dfhack/util.py b/docs/sphinx_extensions/dfhack/util.py index 71a432da4..91f0accbe 100644 --- a/docs/sphinx_extensions/dfhack/util.py +++ b/docs/sphinx_extensions/dfhack/util.py @@ -1,3 +1,5 @@ +import contextlib +import io import os DFHACK_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) @@ -5,3 +7,34 @@ DOCS_ROOT = os.path.join(DFHACK_ROOT, 'docs') if not os.path.isdir(DOCS_ROOT): raise ReferenceError('docs root not found: %s' % DOCS_ROOT) + + +@contextlib.contextmanager +def write_file_if_changed(path): + with io.StringIO() as buffer: + yield buffer + new_contents = buffer.getvalue() + + try: + with open(path, 'r') as infile: + old_contents = infile.read() + except IOError: + old_contents = None + + if old_contents != new_contents: + with open(path, 'w') as outfile: + outfile.write(new_contents) + + +# directive argument helpers (supplementing docutils.parsers.rst.directives) +def directive_arg_str_list(argument): + """ + Converts a space- or comma-separated list of values into a Python list + of strings. + (Directive option conversion function.) + """ + if ',' in argument: + entries = argument.split(',') + else: + entries = argument.split() + return [entry.strip() for entry in entries] diff --git a/docs/styles/dfhack.css b/docs/styles/dfhack.css index 9b6e523ef..c1a00ed90 100644 --- a/docs/styles/dfhack.css +++ b/docs/styles/dfhack.css @@ -60,3 +60,22 @@ div.body { span.pre { overflow-wrap: break-word; } + +div.dfhack-tool-summary, +aside.dfhack-tool-summary { + margin: 10px 0; + padding: 10px 15px; + background-color: #EEE; +} + +div.dfhack-tool-summary p, +aside.dfhack-tool-summary p { + margin-top: 0; + margin-bottom: 0.5em; + line-height: 1em; +} + +div.dfhack-tool-summary p:last-child, +aside.dfhack-tool-summary p:last-child { + margin-bottom: 0; +} diff --git a/index.rst b/index.rst index 2e5454f40..a54ea87f5 100644 --- a/index.rst +++ b/index.rst @@ -15,10 +15,9 @@ Quick Links * `Downloads `_ * `Installation guide ` -* `Source code `_ - (**important:** read `compile` before attempting to build from source) -* `Bay 12 forums thread `_ -* `Bug tracker `_ +* `Getting help ` +* :source:`Source code <>` + (**important:** read `compile` before attempting to build from source.) User Manual =========== @@ -28,10 +27,8 @@ User Manual /docs/Introduction /docs/Installing - /docs/Support /docs/Core - /docs/Plugins - /docs/Scripts + /docs/Tools /docs/guides/index - /docs/index-about /docs/index-dev + /docs/index-about diff --git a/library/Core.cpp b/library/Core.cpp index 1cd00d3aa..1b3f1409f 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -275,65 +275,6 @@ static string dfhack_version_desc() return s.str(); } -static std::string getScriptHelp(std::string path, std::string helpprefix) -{ - ifstream script(path.c_str()); - - if (script.good()) - { - std::string help; - if (getline(script, help) && - help.substr(0,helpprefix.length()) == helpprefix) - { - help = help.substr(helpprefix.length()); - while (help.size() && help[0] == ' ') - help = help.substr(1); - return help; - } - } - - return "No help available."; -} - -static void listScripts(PluginManager *plug_mgr, std::map &pset, std::string path, bool all, std::string prefix = "") -{ - std::vector files; - Filesystem::listdir(path, files); - - path += '/'; - for (size_t i = 0; i < files.size(); i++) - { - if (hasEnding(files[i], ".lua")) - { - string help = getScriptHelp(path + files[i], "--"); - string key = prefix + files[i].substr(0, files[i].size()-4); - if (pset.find(key) == pset.end()) { - pset[key] = help; - } - } - else if (plug_mgr->ruby && plug_mgr->ruby->is_enabled() && hasEnding(files[i], ".rb")) - { - string help = getScriptHelp(path + files[i], "#"); - string key = prefix + files[i].substr(0, files[i].size()-3); - if (pset.find(key) == pset.end()) { - pset[key] = help; - } - } - else if (all && !files[i].empty() && files[i][0] != '.' && files[i] != "internal" && files[i] != "test") - { - listScripts(plug_mgr, pset, path+files[i]+"/", all, prefix+files[i]+"/"); - } - } -} - -static void listAllScripts(map &pset, bool all) -{ - vector paths; - Core::getInstance().getScriptPaths(&paths); - for (string path : paths) - listScripts(Core::getInstance().getPluginManager(), pset, path, all); -} - namespace { struct ScriptArgs { const string *pcmd; @@ -440,59 +381,52 @@ command_result Core::runCommand(color_ostream &out, const std::string &command) return CR_NOT_IMPLEMENTED; } -// List of built in commands -static const std::set built_in_commands = { - "ls" , - "help" , - "type" , - "load" , - "unload" , - "reload" , - "enable" , - "disable" , - "plug" , - "keybinding" , - "alias" , - "fpause" , - "cls" , - "die" , - "kill-lua" , - "script" , - "hide" , - "show" , - "sc-script" -}; +bool is_builtin(color_ostream &con, const string &command) { + CoreSuspender suspend; + auto L = Lua::Core::State; + Lua::StackUnwinder top(L); -static bool try_autocomplete(color_ostream &con, const std::string &first, std::string &completed) -{ - std::vector possible; + if (!lua_checkstack(L, 1) || + !Lua::PushModulePublic(con, L, "helpdb", "is_builtin")) { + con.printerr("Failed to load helpdb Lua code\n"); + return false; + } - // Check for possible built in commands to autocomplete first - for (auto const &command : built_in_commands) - if (command.substr(0, first.size()) == first) - possible.push_back(command); + Lua::Push(L, command); - auto plug_mgr = Core::getInstance().getPluginManager(); - for (auto it = plug_mgr->begin(); it != plug_mgr->end(); ++it) - { - const Plugin * plug = it->second; - for (size_t j = 0; j < plug->size(); j++) - { - const PluginCommand &pcmd = (*plug)[j]; - if (pcmd.isHotkeyCommand()) - continue; - if (pcmd.name.substr(0, first.size()) == first) - possible.push_back(pcmd.name); - } + if (!Lua::SafeCall(con, L, 1, 1)) { + con.printerr("Failed Lua call to helpdb.is_builtin.\n"); + return false; + } + + return lua_toboolean(L, -1); +} + +void get_commands(color_ostream &con, vector &commands) { + CoreSuspender suspend; + auto L = Lua::Core::State; + Lua::StackUnwinder top(L); + + if (!lua_checkstack(L, 1) || + !Lua::PushModulePublic(con, L, "helpdb", "get_commands")) { + con.printerr("Failed to load helpdb Lua code\n"); + return; + } + + if (!Lua::SafeCall(con, L, 0, 1)) { + con.printerr("Failed Lua call to helpdb.get_commands.\n"); } - bool all = (first.find('/') != std::string::npos); + Lua::GetVector(L, commands); +} - std::map scripts; - listAllScripts(scripts, all); - for (auto iter = scripts.begin(); iter != scripts.end(); ++iter) - if (iter->first.substr(0, first.size()) == first) - possible.push_back(iter->first); +static bool try_autocomplete(color_ostream &con, const std::string &first, std::string &completed) +{ + std::vector commands, possible; + + for (auto &command : commands) + if (command.substr(0, first.size()) == first) + possible.push_back(command); if (possible.size() == 1) { @@ -648,49 +582,71 @@ static std::string sc_event_name (state_change_event id) { return "SC_UNKNOWN"; } -string getBuiltinCommand(std::string cmd) -{ - std::string builtin = ""; +void help_helper(color_ostream &con, const string &entry_name) { + CoreSuspender suspend; + auto L = Lua::Core::State; + Lua::StackUnwinder top(L); - // Check our list of builtin commands from the header - if (built_in_commands.count(cmd)) - builtin = cmd; + if (!lua_checkstack(L, 2) || + !Lua::PushModulePublic(con, L, "helpdb", "help")) { + con.printerr("Failed to load helpdb Lua code\n"); + return; + } - // Check for some common aliases for built in commands - else if (cmd == "?" || cmd == "man") - builtin = "help"; + Lua::Push(L, entry_name); - else if (cmd == "dir") - builtin = "ls"; + if (!Lua::SafeCall(con, L, 1, 0)) { + con.printerr("Failed Lua call to helpdb.help.\n"); + } +} - else if (cmd == "clear") - builtin = "cls"; +void tags_helper(color_ostream &con) { + CoreSuspender suspend; + auto L = Lua::Core::State; + Lua::StackUnwinder top(L); - else if (cmd == "devel/dump-rpc") - builtin = "devel/dump-rpc"; + if (!lua_checkstack(L, 1) || + !Lua::PushModulePublic(con, L, "helpdb", "tags")) { + con.printerr("Failed to load helpdb Lua code\n"); + return; + } - return builtin; + if (!Lua::SafeCall(con, L, 0, 0)) { + con.printerr("Failed Lua call to helpdb.tags.\n"); + } } -void ls_helper(color_ostream &con, const string &name, const string &desc) -{ - const size_t help_line_length = 80 - 22 - 5; - const string padding = string(80 - help_line_length, ' '); - vector lines; - con.print(" %-22s - ", name.c_str()); - word_wrap(&lines, desc, help_line_length); +void ls_helper(color_ostream &con, const vector ¶ms) { + vector filter; + bool skip_tags = false; + bool show_dev_commands = false; - // print first line, then any additional lines preceded by padding - for (size_t i = 0; i < lines.size(); i++) - con.print("%s%s\n", i ? padding.c_str() : "", lines[i].c_str()); -} + for (auto str : params) { + if (str == "--notags") + skip_tags = true; + else if (str == "--dev") + show_dev_commands = true; + else + filter.push_back(str); + } -void ls_helper(color_ostream &con, const PluginCommand &pcmd) -{ - if (pcmd.isHotkeyCommand()) - con.color(COLOR_CYAN); - ls_helper(con, pcmd.name, pcmd.description); - con.reset_color(); + CoreSuspender suspend; + auto L = Lua::Core::State; + Lua::StackUnwinder top(L); + + if (!lua_checkstack(L, 4) || + !Lua::PushModulePublic(con, L, "helpdb", "ls")) { + con.printerr("Failed to load helpdb Lua code\n"); + return; + } + + Lua::PushVector(L, filter); + Lua::Push(L, skip_tags); + Lua::Push(L, show_dev_commands); + + if (!Lua::SafeCall(con, L, 3, 0)) { + con.printerr("Failed Lua call to helpdb.ls.\n"); + } } command_result Core::runCommand(color_ostream &con, const std::string &first_, vector &parts) @@ -704,700 +660,587 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v return CR_FAILURE; } + if (first.empty()) + return CR_NOT_IMPLEMENTED; + + if (first.find('\\') != std::string::npos) + { + con.printerr("Replacing backslashes with forward slashes in \"%s\"\n", first.c_str()); + for (size_t i = 0; i < first.size(); i++) + { + if (first[i] == '\\') + first[i] = '/'; + } + } + + // let's see what we actually got command_result res; - if (!first.empty()) + if (first == "help" || first == "man" || first == "?") { - if(first.find('\\') != std::string::npos) + if(!parts.size()) { - con.printerr("Replacing backslashes with forward slashes in \"%s\"\n", first.c_str()); - for (size_t i = 0; i < first.size(); i++) + if (con.is_console()) { - if (first[i] == '\\') - first[i] = '/'; - } + con.print("This is the DFHack console. You can type commands in and manage DFHack plugins from it.\n" + "Some basic editing capabilities are included (single-line text editing).\n" + "The console also has a command history - you can navigate it with Up and Down keys.\n" + "On Windows, you may have to resize your console window. The appropriate menu is accessible\n" + "by clicking on the program icon in the top bar of the window.\n\n"); + } + con.print("Here are some basic commands to get you started:\n" + " help|?|man - This text.\n" + " help - Usage help for the given plugin, command, or script.\n" + " tags - List the tags that the DFHack tools are grouped by.\n" + " ls|dir [] - List commands, optionally filtered by a tag or substring.\n" + " Optional parameters:\n" + " --notags: skip printing tags for each command.\n" + " --dev: include commands intended for developers and modders.\n" + " cls|clear - Clear the console.\n" + " fpause - Force DF to pause.\n" + " die - Force DF to close immediately, without saving.\n" + " keybinding - Modify bindings of commands to in-game key shortcuts.\n" + "\n" + "See more commands by running 'ls'.\n\n" + ); + + con.print("DFHack version %s\n", dfhack_version_desc().c_str()); } - - // let's see what we actually got - string builtin = getBuiltinCommand(first); - if (builtin == "help") + else + { + help_helper(con, parts[0]); + } + } + else if (first == "tags") + { + tags_helper(con); + } + else if (first == "load" || first == "unload" || first == "reload") + { + bool all = false; + bool load = (first == "load"); + bool unload = (first == "unload"); + if (parts.size()) { - if(!parts.size()) + for (auto p = parts.begin(); p != parts.end(); p++) { - if (con.is_console()) + if (p->size() && (*p)[0] == '-') { - con.print("This is the DFHack console. You can type commands in and manage DFHack plugins from it.\n" - "Some basic editing capabilities are included (single-line text editing).\n" - "The console also has a command history - you can navigate it with Up and Down keys.\n" - "On Windows, you may have to resize your console window. The appropriate menu is accessible\n" - "by clicking on the program icon in the top bar of the window.\n\n"); + if (p->find('a') != string::npos) + all = true; } - con.print("Basic commands:\n" - " help|?|man - This text.\n" - " help COMMAND - Usage help for the given command.\n" - " ls|dir [-a] [PLUGIN] - List available commands. Optionally for single plugin.\n" - " cls|clear - Clear the console.\n" - " fpause - Force DF to pause.\n" - " die - Force DF to close immediately\n" - " keybinding - Modify bindings of commands to keys\n" - "Plugin management (useful for developers):\n" - " plug [PLUGIN|v] - List plugin state and description.\n" - " load PLUGIN|-all - Load a plugin by name or load all possible plugins.\n" - " unload PLUGIN|-all - Unload a plugin or all loaded plugins.\n" - " reload PLUGIN|-all - Reload a plugin or all loaded plugins.\n" - ); - - con.print("\nDFHack version %s\n", dfhack_version_desc().c_str()); } - else if (parts.size() == 1) + if (all) { - if (getBuiltinCommand(parts[0]).size()) - { - con << parts[0] << ": built-in command; Use `ls`, `help`, or check hack/Readme.html for more information" << std::endl; - return CR_NOT_IMPLEMENTED; - } - Plugin *plug = plug_mgr->getPluginByCommand(parts[0]); - if (plug) { - for (size_t j = 0; j < plug->size();j++) - { - const PluginCommand & pcmd = (plug->operator[](j)); - if (pcmd.name != parts[0]) - continue; - - if (pcmd.isHotkeyCommand()) - con.color(COLOR_CYAN); - con.print("%s: %s\n",pcmd.name.c_str(), pcmd.description.c_str()); - con.reset_color(); - if (!pcmd.usage.empty()) - con << "Usage:\n" << pcmd.usage << flush; - return CR_OK; - } - } - string file = findScript(parts[0] + ".lua"); - if ( file != "" ) { - string help = getScriptHelp(file, "--"); - con.print("%s: %s\n", parts[0].c_str(), help.c_str()); - return CR_OK; - } - if (plug_mgr->ruby && plug_mgr->ruby->is_enabled() ) { - file = findScript(parts[0] + ".rb"); - if ( file != "" ) { - string help = getScriptHelp(file, "#"); - con.print("%s: %s\n", parts[0].c_str(), help.c_str()); - return CR_OK; - } - } - con.printerr("Unknown command: %s\n", parts[0].c_str()); - return CR_FAILURE; + if (load) + plug_mgr->loadAll(); + else if (unload) + plug_mgr->unloadAll(); + else + plug_mgr->reloadAll(); + return CR_OK; } - else + for (auto p = parts.begin(); p != parts.end(); p++) { - con.printerr("not implemented yet\n"); - return CR_NOT_IMPLEMENTED; + if (!p->size() || (*p)[0] == '-') + continue; + if (load) + plug_mgr->load(*p); + else if (unload) + plug_mgr->unload(*p); + else + plug_mgr->reload(*p); } } - else if (builtin == "load" || builtin == "unload" || builtin == "reload") + else + con.printerr("%s: no arguments\n", first.c_str()); + } + else if( first == "enable" || first == "disable" ) + { + CoreSuspender suspend; + bool enable = (first == "enable"); + + if(parts.size()) { - bool all = false; - bool load = (builtin == "load"); - bool unload = (builtin == "unload"); - if (parts.size()) + for (size_t i = 0; i < parts.size(); i++) { - for (auto p = parts.begin(); p != parts.end(); p++) + std::string part = parts[i]; + if (part.find('\\') != std::string::npos) { - if (p->size() && (*p)[0] == '-') + con.printerr("Replacing backslashes with forward slashes in \"%s\"\n", part.c_str()); + for (size_t j = 0; j < part.size(); j++) { - if (p->find('a') != string::npos) - all = true; + if (part[j] == '\\') + part[j] = '/'; } } - if (all) - { - if (load) - plug_mgr->loadAll(); - else if (unload) - plug_mgr->unloadAll(); - else - plug_mgr->reloadAll(); - return CR_OK; - } - for (auto p = parts.begin(); p != parts.end(); p++) - { - if (!p->size() || (*p)[0] == '-') - continue; - if (load) - plug_mgr->load(*p); - else if (unload) - plug_mgr->unload(*p); - else - plug_mgr->reload(*p); - } - } - else - con.printerr("%s: no arguments\n", builtin.c_str()); - } - else if( builtin == "enable" || builtin == "disable" ) - { - CoreSuspender suspend; - bool enable = (builtin == "enable"); - - if(parts.size()) - { - for (size_t i = 0; i < parts.size(); i++) - { - std::string part = parts[i]; - if (part.find('\\') != std::string::npos) - { - con.printerr("Replacing backslashes with forward slashes in \"%s\"\n", part.c_str()); - for (size_t j = 0; j < part.size(); j++) - { - if (part[j] == '\\') - part[j] = '/'; - } - } - Plugin * plug = (*plug_mgr)[part]; + Plugin * plug = (*plug_mgr)[part]; - if(!plug) - { - std::string lua = findScript(part + ".lua"); - if (lua.size()) - { - res = enableLuaScript(con, part, enable); - } - else - { - res = CR_NOT_FOUND; - con.printerr("No such plugin or Lua script: %s\n", part.c_str()); - } - } - else if (!plug->can_set_enabled()) + if(!plug) + { + std::string lua = findScript(part + ".lua"); + if (lua.size()) { - res = CR_NOT_IMPLEMENTED; - con.printerr("Cannot %s plugin: %s\n", builtin.c_str(), part.c_str()); + res = enableLuaScript(con, part, enable); } else { - res = plug->set_enabled(con, enable); - - if (res != CR_OK || plug->is_enabled() != enable) - con.printerr("Could not %s plugin: %s\n", builtin.c_str(), part.c_str()); - } - } - - return res; - } - else - { - for (auto it = plug_mgr->begin(); it != plug_mgr->end(); ++it) - { - Plugin * plug = it->second; - if (!plug->can_be_enabled()) continue; - - con.print( - "%20s\t%-3s%s\n", - (plug->getName()+":").c_str(), - plug->is_enabled() ? "on" : "off", - plug->can_set_enabled() ? "" : " (controlled elsewhere)" - ); - } - } - } - else if (builtin == "ls" || builtin == "dir") - { - bool all = false; - if (parts.size() && parts[0] == "-a") - { - all = true; - vector_erase_at(parts, 0); - } - if(parts.size()) - { - string & plugname = parts[0]; - const Plugin * plug = (*plug_mgr)[plugname]; - if(!plug) - { - con.printerr("There's no plugin called %s!\n", plugname.c_str()); - } - else if (plug->getState() != Plugin::PS_LOADED) - { - con.printerr("Plugin %s is not loaded.\n", plugname.c_str()); - } - else if (!plug->size()) - { - con.printerr("Plugin %s is loaded but does not implement any commands.\n", plugname.c_str()); - } - else for (size_t j = 0; j < plug->size();j++) - { - ls_helper(con, plug->operator[](j)); - } - } - else - { - con.print( - "builtin:\n" - " help|?|man - This text or help specific to a plugin.\n" - " ls|dir [-a] [PLUGIN] - List available commands. Optionally for single plugin.\n" - " cls|clear - Clear the console.\n" - " fpause - Force DF to pause.\n" - " die - Force DF to close immediately\n" - " kill-lua - Stop an active Lua script\n" - " keybinding - Modify bindings of commands to keys\n" - " script FILENAME - Run the commands specified in a file.\n" - " sc-script - Automatically run specified scripts on state change events\n" - " plug [PLUGIN|v] - List plugin state and detailed description.\n" - " load PLUGIN|-all [...] - Load a plugin by name or load all possible plugins.\n" - " unload PLUGIN|-all [...] - Unload a plugin or all loaded plugins.\n" - " reload PLUGIN|-all [...] - Reload a plugin or all loaded plugins.\n" - " enable/disable PLUGIN [...] - Enable or disable a plugin if supported.\n" - " type COMMAND - Display information about where a command is implemented\n" - "\n" - "plugins:\n" - ); - std::set out; - for (auto it = plug_mgr->begin(); it != plug_mgr->end(); ++it) - { - const Plugin * plug = it->second; - if(!plug->size()) - continue; - for (size_t j = 0; j < plug->size();j++) - { - const PluginCommand & pcmd = (plug->operator[](j)); - out.insert(sortable(pcmd.isHotkeyCommand(),pcmd.name,pcmd.description)); + res = CR_NOT_FOUND; + con.printerr("No such plugin or Lua script: %s\n", part.c_str()); } } - for(auto iter = out.begin();iter != out.end();iter++) + else if (!plug->can_set_enabled()) { - if ((*iter).recolor) - con.color(COLOR_CYAN); - ls_helper(con, iter->name, iter->description); - con.reset_color(); + res = CR_NOT_IMPLEMENTED; + con.printerr("Cannot %s plugin: %s\n", first.c_str(), part.c_str()); } - std::map scripts; - listAllScripts(scripts, all); - if (!scripts.empty()) + else { - con.print("\nscripts:\n"); - for (auto iter = scripts.begin(); iter != scripts.end(); ++iter) - ls_helper(con, iter->first, iter->second); + res = plug->set_enabled(con, enable); + + if (res != CR_OK || plug->is_enabled() != enable) + con.printerr("Could not %s plugin: %s\n", first.c_str(), part.c_str()); } } + + return res; } - else if (builtin == "plug") + else { - const char *header_format = "%30s %10s %4s %8s\n"; - const char *row_format = "%30s %10s %4i %8s\n"; - con.print(header_format, "Name", "State", "Cmds", "Enabled"); - - plug_mgr->refresh(); for (auto it = plug_mgr->begin(); it != plug_mgr->end(); ++it) { Plugin * plug = it->second; - if (!plug) - continue; - if (parts.size() && std::find(parts.begin(), parts.end(), plug->getName()) == parts.end()) - continue; - color_value color; - switch (plug->getState()) - { - case Plugin::PS_LOADED: - color = COLOR_RESET; - break; - case Plugin::PS_UNLOADED: - case Plugin::PS_UNLOADING: - color = COLOR_YELLOW; - break; - case Plugin::PS_LOADING: - color = COLOR_LIGHTBLUE; - break; - case Plugin::PS_BROKEN: - color = COLOR_LIGHTRED; - break; - default: - color = COLOR_LIGHTMAGENTA; - break; - } - con.color(color); - con.print(row_format, - plug->getName().c_str(), - Plugin::getStateDescription(plug->getState()), - plug->size(), - (plug->can_be_enabled() - ? (plug->is_enabled() ? "enabled" : "disabled") - : "n/a") + if (!plug->can_be_enabled()) continue; + + con.print( + "%20s\t%-3s%s\n", + (plug->getName()+":").c_str(), + plug->is_enabled() ? "on" : "off", + plug->can_set_enabled() ? "" : " (controlled elsewhere)" ); - con.color(COLOR_RESET); } } - else if (builtin == "type") + } + else if (first == "ls" || first == "dir") + { + ls_helper(con, parts); + } + else if (first == "plug") + { + const char *header_format = "%30s %10s %4s %8s\n"; + const char *row_format = "%30s %10s %4i %8s\n"; + con.print(header_format, "Name", "State", "Cmds", "Enabled"); + + plug_mgr->refresh(); + for (auto it = plug_mgr->begin(); it != plug_mgr->end(); ++it) { - if (!parts.size()) - { - con.printerr("type: no argument\n"); - return CR_WRONG_USAGE; - } - con << parts[0]; - string builtin_cmd = getBuiltinCommand(parts[0]); - string lua_path = findScript(parts[0] + ".lua"); - string ruby_path = findScript(parts[0] + ".rb"); - Plugin *plug = plug_mgr->getPluginByCommand(parts[0]); - if (builtin_cmd.size()) - { - con << " is a built-in command"; - if (builtin_cmd != parts[0]) - con << " (aliased to " << builtin_cmd << ")"; - con << std::endl; - } - else if (IsAlias(parts[0])) - { - con << " is an alias: " << GetAliasCommand(parts[0]) << std::endl; - } - else if (plug) - { - con << " is a command implemented by the plugin " << plug->getName() << std::endl; - } - else if (lua_path.size()) - { - con << " is a Lua script: " << lua_path << std::endl; - } - else if (ruby_path.size()) - { - con << " is a Ruby script: " << ruby_path << std::endl; - } - else + Plugin * plug = it->second; + if (!plug) + continue; + if (parts.size() && std::find(parts.begin(), parts.end(), plug->getName()) == parts.end()) + continue; + color_value color; + switch (plug->getState()) { - con << " is not a recognized command." << std::endl; - plug = plug_mgr->getPluginByName(parts[0]); - if (plug) - con << "Plugin " << parts[0] << " exists and implements " << plug->size() << " commands." << std::endl; - return CR_FAILURE; + case Plugin::PS_LOADED: + color = COLOR_RESET; + break; + case Plugin::PS_UNLOADED: + case Plugin::PS_UNLOADING: + color = COLOR_YELLOW; + break; + case Plugin::PS_LOADING: + color = COLOR_LIGHTBLUE; + break; + case Plugin::PS_BROKEN: + color = COLOR_LIGHTRED; + break; + default: + color = COLOR_LIGHTMAGENTA; + break; } + con.color(color); + con.print(row_format, + plug->getName().c_str(), + Plugin::getStateDescription(plug->getState()), + plug->size(), + (plug->can_be_enabled() + ? (plug->is_enabled() ? "enabled" : "disabled") + : "n/a") + ); + con.color(COLOR_RESET); } - else if (builtin == "keybinding") + } + else if (first == "type") + { + if (!parts.size()) { - if (parts.size() >= 3 && (parts[0] == "set" || parts[0] == "add")) - { - std::string keystr = parts[1]; - if (parts[0] == "set") - ClearKeyBindings(keystr); - for (int i = parts.size()-1; i >= 2; i--) - { - if (!AddKeyBinding(keystr, parts[i])) { - con.printerr("Invalid key spec: %s\n", keystr.c_str()); - break; - } - } - } - else if (parts.size() >= 2 && parts[0] == "clear") - { - for (size_t i = 1; i < parts.size(); i++) - { - if (!ClearKeyBindings(parts[i])) { - con.printerr("Invalid key spec: %s\n", parts[i].c_str()); - break; - } - } - } - else if (parts.size() == 2 && parts[0] == "list") - { - std::vector list = ListKeyBindings(parts[1]); - if (list.empty()) - con << "No bindings." << endl; - for (size_t i = 0; i < list.size(); i++) - con << " " << list[i] << endl; - } - else - { - con << "Usage:" << endl - << " keybinding list " << endl - << " keybinding clear [@context]..." << endl - << " keybinding set [@context] \"cmdline\" \"cmdline\"..." << endl - << " keybinding add [@context] \"cmdline\" \"cmdline\"..." << endl - << "Later adds, and earlier items within one command have priority." << endl - << "Supported keys: [Ctrl-][Alt-][Shift-](A-Z, 0-9, F1-F12, or Enter)." << endl - << "Context may be used to limit the scope of the binding, by" << endl - << "requiring the current context to have a certain prefix." << endl - << "Current UI context is: " - << Gui::getFocusString(Core::getTopViewscreen()) << endl; - } + con.printerr("type: no argument\n"); + return CR_WRONG_USAGE; } - else if (builtin == "alias") + con << parts[0]; + bool builtin = is_builtin(con, parts[0]); + string lua_path = findScript(parts[0] + ".lua"); + string ruby_path = findScript(parts[0] + ".rb"); + Plugin *plug = plug_mgr->getPluginByCommand(parts[0]); + if (builtin) { - if (parts.size() >= 3 && (parts[0] == "add" || parts[0] == "replace")) - { - const string &name = parts[1]; - vector cmd(parts.begin() + 2, parts.end()); - if (!AddAlias(name, cmd, parts[0] == "replace")) - { - con.printerr("Could not add alias %s - already exists\n", name.c_str()); - return CR_FAILURE; - } - } - else if (parts.size() >= 2 && (parts[0] == "delete" || parts[0] == "clear")) + con << " is a built-in command"; + con << std::endl; + } + else if (IsAlias(parts[0])) + { + con << " is an alias: " << GetAliasCommand(parts[0]) << std::endl; + } + else if (plug) + { + con << " is a command implemented by the plugin " << plug->getName() << std::endl; + } + else if (lua_path.size()) + { + con << " is a Lua script: " << lua_path << std::endl; + } + else if (ruby_path.size()) + { + con << " is a Ruby script: " << ruby_path << std::endl; + } + else + { + con << " is not a recognized command." << std::endl; + plug = plug_mgr->getPluginByName(parts[0]); + if (plug) + con << "Plugin " << parts[0] << " exists and implements " << plug->size() << " commands." << std::endl; + return CR_FAILURE; + } + } + else if (first == "keybinding") + { + if (parts.size() >= 3 && (parts[0] == "set" || parts[0] == "add")) + { + std::string keystr = parts[1]; + if (parts[0] == "set") + ClearKeyBindings(keystr); + for (int i = parts.size()-1; i >= 2; i--) { - if (!RemoveAlias(parts[1])) - { - con.printerr("Could not remove alias %s\n", parts[1].c_str()); - return CR_FAILURE; + if (!AddKeyBinding(keystr, parts[i])) { + con.printerr("Invalid key spec: %s\n", keystr.c_str()); + break; } } - else if (parts.size() >= 1 && (parts[0] == "list")) + } + else if (parts.size() >= 2 && parts[0] == "clear") + { + for (size_t i = 1; i < parts.size(); i++) { - auto aliases = ListAliases(); - for (auto p : aliases) - { - con << p.first << ": " << join_strings(" ", p.second) << endl; + if (!ClearKeyBindings(parts[i])) { + con.printerr("Invalid key spec: %s\n", parts[i].c_str()); + break; } } - else + } + else if (parts.size() == 2 && parts[0] == "list") + { + std::vector list = ListKeyBindings(parts[1]); + if (list.empty()) + con << "No bindings." << endl; + for (size_t i = 0; i < list.size(); i++) + con << " " << list[i] << endl; + } + else + { + con << "Usage:" << endl + << " keybinding list " << endl + << " keybinding clear [@context]..." << endl + << " keybinding set [@context] \"cmdline\" \"cmdline\"..." << endl + << " keybinding add [@context] \"cmdline\" \"cmdline\"..." << endl + << "Later adds, and earlier items within one command have priority." << endl + << "Supported keys: [Ctrl-][Alt-][Shift-](A-Z, 0-9, F1-F12, or Enter)." << endl + << "Context may be used to limit the scope of the binding, by" << endl + << "requiring the current context to have a certain prefix." << endl + << "Current UI context is: " + << Gui::getFocusString(Core::getTopViewscreen()) << endl; + } + } + else if (first == "alias") + { + if (parts.size() >= 3 && (parts[0] == "add" || parts[0] == "replace")) + { + const string &name = parts[1]; + vector cmd(parts.begin() + 2, parts.end()); + if (!AddAlias(name, cmd, parts[0] == "replace")) { - con << "Usage: " << endl - << " alias add|replace " << endl - << " alias delete|clear " << endl - << " alias list" << endl; + con.printerr("Could not add alias %s - already exists\n", name.c_str()); + return CR_FAILURE; } } - else if (builtin == "fpause") + else if (parts.size() >= 2 && (parts[0] == "delete" || parts[0] == "clear")) { - World::SetPauseState(true); - if (auto scr = Gui::getViewscreenByType()) + if (!RemoveAlias(parts[1])) { - scr->worldgen_paused = true; + con.printerr("Could not remove alias %s\n", parts[1].c_str()); + return CR_FAILURE; } - con.print("The game was forced to pause!\n"); } - else if (builtin == "cls") + else if (parts.size() >= 1 && (parts[0] == "list")) { - if (con.is_console()) - ((Console&)con).clear(); - else + auto aliases = ListAliases(); + for (auto p : aliases) { - con.printerr("No console to clear.\n"); - return CR_NEEDS_CONSOLE; + con << p.first << ": " << join_strings(" ", p.second) << endl; } } - else if (builtin == "die") + else { - std::_Exit(666); + con << "Usage: " << endl + << " alias add|replace " << endl + << " alias delete|clear " << endl + << " alias list" << endl; } - else if (builtin == "kill-lua") + } + else if (first == "fpause") + { + World::SetPauseState(true); + if (auto scr = Gui::getViewscreenByType()) { - bool force = false; - for (auto it = parts.begin(); it != parts.end(); ++it) - { - if (*it == "force") - force = true; - } - if (!Lua::Interrupt(force)) - { - con.printerr( - "Failed to register hook. This can happen if you have" - " lua profiling or coverage monitoring enabled. Use" - " 'kill-lua force' to force, but this may disable" - " profiling and coverage monitoring.\n"); - } + scr->worldgen_paused = true; } - else if (builtin == "script") + con.print("The game was forced to pause!\n"); + } + else if (first == "cls" || first == "clear") + { + if (con.is_console()) + ((Console&)con).clear(); + else { - if(parts.size() == 1) - { - loadScriptFile(con, parts[0], false); - } - else - { - con << "Usage:" << endl - << " script " << endl; - return CR_WRONG_USAGE; - } + con.printerr("No console to clear.\n"); + return CR_NEEDS_CONSOLE; + } + } + else if (first == "die") + { + std::_Exit(666); + } + else if (first == "kill-lua") + { + bool force = false; + for (auto it = parts.begin(); it != parts.end(); ++it) + { + if (*it == "force") + force = true; + } + if (!Lua::Interrupt(force)) + { + con.printerr( + "Failed to register hook. This can happen if you have" + " lua profiling or coverage monitoring enabled. Use" + " 'kill-lua force' to force, but this may disable" + " profiling and coverage monitoring.\n"); + } + } + else if (first == "script") + { + if(parts.size() == 1) + { + loadScriptFile(con, parts[0], false); + } + else + { + con << "Usage:" << endl + << " script " << endl; + return CR_WRONG_USAGE; } - else if (builtin=="hide") + } + else if (first == "hide") + { + if (!getConsole().hide()) + { + con.printerr("Could not hide console\n"); + return CR_FAILURE; + } + return CR_OK; + } + else if (first == "show") + { + if (!getConsole().show()) + { + con.printerr("Could not show console\n"); + return CR_FAILURE; + } + return CR_OK; + } + else if (first == "sc-script") + { + if (parts.empty() || parts[0] == "help" || parts[0] == "?") { - if (!getConsole().hide()) + con << "Usage: sc-script add|remove|list|help SC_EVENT [path-to-script] [...]" << endl; + con << "Valid event names (SC_ prefix is optional):" << endl; + for (int i = SC_WORLD_LOADED; i <= SC_UNPAUSED; i++) { - con.printerr("Could not hide console\n"); - return CR_FAILURE; + std::string name = sc_event_name((state_change_event)i); + if (name != "SC_UNKNOWN") + con << " " << name << endl; } return CR_OK; } - else if (builtin=="show") + else if (parts[0] == "list") { - if (!getConsole().show()) + if(parts.size() < 2) + parts.push_back(""); + if (parts[1].size() && sc_event_id(parts[1]) == SC_UNKNOWN) { - con.printerr("Could not show console\n"); - return CR_FAILURE; + con << "Unrecognized event name: " << parts[1] << endl; + return CR_WRONG_USAGE; + } + for (auto it = state_change_scripts.begin(); it != state_change_scripts.end(); ++it) + { + if (!parts[1].size() || (it->event == sc_event_id(parts[1]))) + { + con.print("%s (%s): %s%s\n", sc_event_name(it->event).c_str(), + it->save_specific ? "save-specific" : "global", + it->save_specific ? "/raw/" : "/", + it->path.c_str()); + } } return CR_OK; } - else if (builtin == "sc-script") + else if (parts[0] == "add") { - if (parts.empty() || parts[0] == "help" || parts[0] == "?") + if (parts.size() < 3 || (parts.size() >= 4 && parts[3] != "-save")) { - con << "Usage: sc-script add|remove|list|help SC_EVENT [path-to-script] [...]" << endl; - con << "Valid event names (SC_ prefix is optional):" << endl; - for (int i = SC_WORLD_LOADED; i <= SC_UNPAUSED; i++) - { - std::string name = sc_event_name((state_change_event)i); - if (name != "SC_UNKNOWN") - con << " " << name << endl; - } - return CR_OK; + con << "Usage: sc-script add EVENT path-to-script [-save]" << endl; + return CR_WRONG_USAGE; } - else if (parts[0] == "list") + state_change_event evt = sc_event_id(parts[1]); + if (evt == SC_UNKNOWN) { - if(parts.size() < 2) - parts.push_back(""); - if (parts[1].size() && sc_event_id(parts[1]) == SC_UNKNOWN) - { - con << "Unrecognized event name: " << parts[1] << endl; - return CR_WRONG_USAGE; - } - for (auto it = state_change_scripts.begin(); it != state_change_scripts.end(); ++it) - { - if (!parts[1].size() || (it->event == sc_event_id(parts[1]))) - { - con.print("%s (%s): %s%s\n", sc_event_name(it->event).c_str(), - it->save_specific ? "save-specific" : "global", - it->save_specific ? "/raw/" : "/", - it->path.c_str()); - } - } - return CR_OK; + con << "Unrecognized event: " << parts[1] << endl; + return CR_FAILURE; } - else if (parts[0] == "add") + bool save_specific = (parts.size() >= 4 && parts[3] == "-save"); + StateChangeScript script(evt, parts[2], save_specific); + for (auto it = state_change_scripts.begin(); it != state_change_scripts.end(); ++it) { - if (parts.size() < 3 || (parts.size() >= 4 && parts[3] != "-save")) - { - con << "Usage: sc-script add EVENT path-to-script [-save]" << endl; - return CR_WRONG_USAGE; - } - state_change_event evt = sc_event_id(parts[1]); - if (evt == SC_UNKNOWN) + if (script == *it) { - con << "Unrecognized event: " << parts[1] << endl; + con << "Script already registered" << endl; return CR_FAILURE; } - bool save_specific = (parts.size() >= 4 && parts[3] == "-save"); - StateChangeScript script(evt, parts[2], save_specific); - for (auto it = state_change_scripts.begin(); it != state_change_scripts.end(); ++it) - { - if (script == *it) - { - con << "Script already registered" << endl; - return CR_FAILURE; - } - } - state_change_scripts.push_back(script); - return CR_OK; } - else if (parts[0] == "remove") + state_change_scripts.push_back(script); + return CR_OK; + } + else if (parts[0] == "remove") + { + if (parts.size() < 3 || (parts.size() >= 4 && parts[3] != "-save")) { - if (parts.size() < 3 || (parts.size() >= 4 && parts[3] != "-save")) - { - con << "Usage: sc-script remove EVENT path-to-script [-save]" << endl; - return CR_WRONG_USAGE; - } - state_change_event evt = sc_event_id(parts[1]); - if (evt == SC_UNKNOWN) - { - con << "Unrecognized event: " << parts[1] << endl; - return CR_FAILURE; - } - bool save_specific = (parts.size() >= 4 && parts[3] == "-save"); - StateChangeScript tmp(evt, parts[2], save_specific); - auto it = std::find(state_change_scripts.begin(), state_change_scripts.end(), tmp); - if (it != state_change_scripts.end()) - { - state_change_scripts.erase(it); - return CR_OK; - } - else - { - con << "Unrecognized script" << endl; - return CR_FAILURE; - } + con << "Usage: sc-script remove EVENT path-to-script [-save]" << endl; + return CR_WRONG_USAGE; + } + state_change_event evt = sc_event_id(parts[1]); + if (evt == SC_UNKNOWN) + { + con << "Unrecognized event: " << parts[1] << endl; + return CR_FAILURE; + } + bool save_specific = (parts.size() >= 4 && parts[3] == "-save"); + StateChangeScript tmp(evt, parts[2], save_specific); + auto it = std::find(state_change_scripts.begin(), state_change_scripts.end(), tmp); + if (it != state_change_scripts.end()) + { + state_change_scripts.erase(it); + return CR_OK; } else { - con << "Usage: sc-script add|remove|list|help SC_EVENT [path-to-script] [...]" << endl; - return CR_WRONG_USAGE; + con << "Unrecognized script" << endl; + return CR_FAILURE; } } - else if (builtin == "devel/dump-rpc") + else { - if (parts.size() == 1) - { - std::ofstream file(parts[0]); - CoreService core; - core.dumpMethods(file); + con << "Usage: sc-script add|remove|list|help SC_EVENT [path-to-script] [...]" << endl; + return CR_WRONG_USAGE; + } + } + else if (first == "devel/dump-rpc") + { + if (parts.size() == 1) + { + std::ofstream file(parts[0]); + CoreService core; + core.dumpMethods(file); - for (auto & it : *plug_mgr) - { - Plugin * plug = it.second; - if (!plug) - continue; + for (auto & it : *plug_mgr) + { + Plugin * plug = it.second; + if (!plug) + continue; - std::unique_ptr svc(plug->rpc_connect(con)); - if (!svc) - continue; + std::unique_ptr svc(plug->rpc_connect(con)); + if (!svc) + continue; - file << "// Plugin: " << plug->getName() << endl; - svc->dumpMethods(file); - } - } - else - { - con << "Usage: devel/dump-rpc \"filename\"" << endl; - return CR_WRONG_USAGE; + file << "// Plugin: " << plug->getName() << endl; + svc->dumpMethods(file); } } - else if (RunAlias(con, first, parts, res)) + else { - return res; + con << "Usage: devel/dump-rpc \"filename\"" << endl; + return CR_WRONG_USAGE; } - else + } + else if (RunAlias(con, first, parts, res)) + { + return res; + } + else + { + res = plug_mgr->InvokeCommand(con, first, parts); + if (res == CR_WRONG_USAGE) { - res = plug_mgr->InvokeCommand(con, first, parts); - if(res == CR_NOT_IMPLEMENTED) + help_helper(con, first); + } + else if (res == CR_NOT_IMPLEMENTED) + { + string completed; + string filename = findScript(first + ".lua"); + bool lua = filename != ""; + if ( !lua ) { + filename = findScript(first + ".rb"); + } + if ( lua ) + res = runLuaScript(con, first, parts); + else if ( filename != "" && plug_mgr->ruby && plug_mgr->ruby->is_enabled() ) + res = runRubyScript(con, plug_mgr, filename, parts); + else if ( try_autocomplete(con, first, completed) ) + res = CR_NOT_IMPLEMENTED; + else + con.printerr("%s is not a recognized command.\n", first.c_str()); + if (res == CR_NOT_IMPLEMENTED) { - string completed; - string filename = findScript(first + ".lua"); - bool lua = filename != ""; - if ( !lua ) { - filename = findScript(first + ".rb"); - } - if ( lua ) - res = runLuaScript(con, first, parts); - else if ( filename != "" && plug_mgr->ruby && plug_mgr->ruby->is_enabled() ) - res = runRubyScript(con, plug_mgr, filename, parts); - else if ( try_autocomplete(con, first, completed) ) - res = CR_NOT_IMPLEMENTED; - else - con.printerr("%s is not a recognized command.\n", first.c_str()); - if (res == CR_NOT_IMPLEMENTED) + Plugin *p = plug_mgr->getPluginByName(first); + if (p) { - Plugin *p = plug_mgr->getPluginByName(first); - if (p) - { - con.printerr("%s is a plugin ", first.c_str()); - if (p->getState() == Plugin::PS_UNLOADED) - con.printerr("that is not loaded - try \"load %s\" or check stderr.log\n", - first.c_str()); - else if (p->size()) - con.printerr("that implements %zi commands - see \"ls %s\" for details\n", - p->size(), first.c_str()); - else - con.printerr("but does not implement any commands\n"); - } + con.printerr("%s is a plugin ", first.c_str()); + if (p->getState() == Plugin::PS_UNLOADED) + con.printerr("that is not loaded - try \"load %s\" or check stderr.log\n", + first.c_str()); + else if (p->size()) + con.printerr("that implements %zi commands - see \"help %s\" for details\n", + p->size(), first.c_str()); + else + con.printerr("but does not implement any commands\n"); } } - else if (res == CR_NEEDS_CONSOLE) - con.printerr("%s needs interactive console to work.\n", first.c_str()); - return res; } - - return CR_OK; + else if (res == CR_NEEDS_CONSOLE) + con.printerr("%s needs an interactive console to work.\n" + "Please run this command from the DFHack terminal.\n", first.c_str()); + return res; } - return CR_NOT_IMPLEMENTED; + return CR_OK; } bool Core::loadScriptFile(color_ostream &out, string fname, bool silent) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index aaf780f74..70cb01dfc 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2370,6 +2370,21 @@ static int screen_findGraphicsTile(lua_State *L) } } +static int screen_hideGuard(lua_State *L) { + df::viewscreen *screen = dfhack_lua_viewscreen::get_pointer(L, 1, false); + luaL_checktype(L, 2, LUA_TFUNCTION); + + // remove screen from the stack so it doesn't get returned as an output + lua_remove(L, 1); + + Screen::Hide hideGuard(screen, Screen::Hide::RESTORE_AT_TOP); + + int nargs = lua_gettop(L) - 1; + lua_call(L, nargs, LUA_MULTRET); + + return lua_gettop(L); +} + namespace { int screen_show(lua_State *L) @@ -2472,6 +2487,7 @@ static const luaL_Reg dfhack_screen_funcs[] = { { "paintString", screen_paintString }, { "fillRect", screen_fillRect }, { "findGraphicsTile", screen_findGraphicsTile }, + CWRAP(hideGuard, screen_hideGuard), CWRAP(show, screen_show), CWRAP(dismiss, screen_dismiss), CWRAP(isDismissed, screen_isDismissed), @@ -3220,6 +3236,7 @@ static const luaL_Reg dfhack_internal_funcs[] = { { "getAddress", internal_getAddress }, { "setAddress", internal_setAddress }, { "getVTable", internal_getVTable }, + { "adjustOffset", internal_adjustOffset }, { "getMemRanges", internal_getMemRanges }, { "patchMemory", internal_patchMemory }, diff --git a/library/PluginManager.cpp b/library/PluginManager.cpp index a1b1bd293..223abfeac 100644 --- a/library/PluginManager.cpp +++ b/library/PluginManager.cpp @@ -503,8 +503,6 @@ command_result Plugin::invoke(color_ostream &out, const std::string & command, s { cr = cmd.function(out, parameters); } - if (cr == CR_WRONG_USAGE && !cmd.usage.empty()) - out << "Usage:\n" << cmd.usage << flush; break; } } diff --git a/library/include/PluginManager.h b/library/include/PluginManager.h index f168d7e47..79b7e0492 100644 --- a/library/include/PluginManager.h +++ b/library/include/PluginManager.h @@ -97,6 +97,10 @@ namespace DFHack /// create a command with a name, description, function pointer to its code /// and saying if it needs an interactive terminal /// Most commands shouldn't require an interactive terminal! + /// Note that the description and usage fields are only used for + /// out-of-tree plugins that do not have rendered help installed in + /// the hack/docs directory. Help for all internal plugins comes from + /// the rendered .rst files. PluginCommand(const char * _name, const char * _description, command_function function_, diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index e476ffa11..4a46040af 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -1,4 +1,4 @@ --- Common startup file for all dfhack plugins with lua support +-- Common startup file for all dfhack scripts and plugins with lua support -- The global dfhack table is already created by C++ init code. -- Setup the global environment. @@ -652,8 +652,9 @@ function Script:needs_update() return (not self.env) or self.mtime ~= dfhack.filesystem.mtime(self.path) end function Script:get_flags() - if self.flags_mtime ~= dfhack.filesystem.mtime(self.path) then - self.flags_mtime = dfhack.filesystem.mtime(self.path) + local mtime = dfhack.filesystem.mtime(self.path) + if self.flags_mtime ~= mtime then + self.flags_mtime = mtime self._flags = {} local f = io.open(self.path) local contents = f:read('*all') @@ -788,7 +789,11 @@ function dfhack.run_script_with_env(envVars, name, flags, ...) end scripts[file].env = env scripts[file].run = script_code - return script_code(...), env + local args = {...} + for i,v in ipairs(args) do + args[i] = tostring(v) -- ensure passed parameters are strings + end + return script_code(table.unpack(args)), env end function dfhack.current_script_name() @@ -814,36 +819,7 @@ end function dfhack.script_help(script_name, extension) script_name = script_name or dfhack.current_script_name() - extension = extension or 'lua' - local full_name = script_name .. '.' .. extension - local path = dfhack.internal.findScript(script_name .. '.' .. extension) - or error("Could not find script: " .. full_name) - local begin_seq, end_seq - if extension == 'rb' then - begin_seq = '=begin' - end_seq = '=end' - else - begin_seq = '[====[' - end_seq = ']====]' - end - local f = io.open(path) or error("Could not open " .. path) - local in_help = false - local help = '' - for line in f:lines() do - if line:endswith(begin_seq) then - in_help = true - elseif in_help then - if line:endswith(end_seq) then - break - end - if line ~= script_name and line ~= ('='):rep(#script_name) then - help = help .. line .. '\n' - end - end - end - f:close() - help = help:gsub('^\n+', ''):gsub('\n+$', '') - return help + return require('helpdb').get_entry_long_help(script_name) end local function _run_command(args, use_console) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 788e16c4f..d81fbf6b9 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -188,6 +188,7 @@ EditField.ATTRS{ key = DEFAULT_NIL, key_sep = DEFAULT_NIL, modal = false, + ignore_keys = DEFAULT_NIL, } function EditField:preinit(init_table) @@ -270,6 +271,12 @@ function EditField:onInput(keys) return self:inputToSubviews(keys) end + if self.ignore_keys then + for _,ignore_key in ipairs(self.ignore_keys) do + if keys[ignore_key] then return false end + end + end + if self.key and keys.LEAVESCREEN then local old = self.text self:setText(self.saved_text) @@ -537,12 +544,10 @@ Label.ATTRS{ auto_width = false, on_click = DEFAULT_NIL, on_rclick = DEFAULT_NIL, - -- scroll_keys = STANDARDSCROLL, - show_scroll_icons = DEFAULT_NIL, -- DEFAULT_NIL, 'right', 'left', false - up_arrow_icon = string.char(24), - down_arrow_icon = string.char(25), - scroll_icon_pen = COLOR_LIGHTCYAN, + show_scrollbar = DEFAULT_NIL, -- DEFAULT_NIL, 'right', 'left', false + scrollbar_fg = COLOR_LIGHTGREEN, + scrollbar_bg = COLOR_CYAN } function Label:init(args) @@ -566,16 +571,16 @@ function Label:setText(text) end function Label:update_scroll_inset() - if self.show_scroll_icons == nil then - self._show_scroll_icons = self:getTextHeight() > self.frame_body.height and 'right' or false + if self.show_scrollbar == nil then + self._show_scrollbar = self:getTextHeight() > self.frame_body.height and 'right' or false else - self._show_scroll_icons = self.show_scroll_icons + self._show_scrollbar = self.show_scrollbar end - if self._show_scroll_icons then - -- here self._show_scroll_icons can only be either + if self._show_scrollbar then + -- here self._show_scrollbar can only be either -- 'left' or any true value which we interpret as right local l,t,r,b = gui.parse_inset(self.frame_inset) - if self._show_scroll_icons == 'left' and l <= 0 then + if self._show_scrollbar == 'left' and l <= 0 then l = 1 elseif r <= 0 then r = 1 @@ -584,14 +589,54 @@ function Label:update_scroll_inset() end end -function Label:render_scroll_icons(dc, x, y1, y2) - if self.start_line_num ~= 1 then - dc:seek(x, y1):char(self.up_arrow_icon, self.scroll_icon_pen) +-- the position is the number of tiles of empty space above the top of the +-- scrollbar, and the height is the number of tiles the scrollbar should occupy +-- to represent the percentage of text that is on the screen. +local function get_scrollbar_pos_and_height(label) + local first_visible_line = label.start_line_num + local text_height = label:getTextHeight() + local last_visible_line = first_visible_line + label.frame_body.height - 1 + local scrollbar_body_height = label.frame_body.height - 2 + local displayed_lines = last_visible_line - first_visible_line + + local height = math.floor(((displayed_lines-1) * scrollbar_body_height) / + text_height) + + local max_pos = scrollbar_body_height - height + local pos = math.ceil(((first_visible_line-1) * max_pos) / + (text_height - label.frame_body.height)) + + return pos, height +end + +local UP_ARROW_CHAR = string.char(24) +local DOWN_ARROW_CHAR = string.char(25) +local NO_ARROW_CHAR = string.char(32) +local BAR_CHAR = string.char(7) +local BAR_BG_CHAR = string.char(179) + +function Label:render_scrollbar(dc, x, y1, y2) + -- render up arrow if we're not at the top + dc:seek(x, y1):char( + self.start_line_num == 1 and NO_ARROW_CHAR or UP_ARROW_CHAR, + self.scrollbar_fg, self.scrollbar_bg) + -- render scrollbar body + local pos, height = get_scrollbar_pos_and_height(self) + local starty = y1 + pos + 1 + local endy = y1 + pos + height + for y=y1+1,y2-1 do + if y >= starty and y <= endy then + dc:seek(x, y):char(BAR_CHAR, self.scrollbar_fg) + else + dc:seek(x, y):char(BAR_BG_CHAR, self.scrollbar_bg) + end end + -- render down arrow if we're not at the bottom local last_visible_line = self.start_line_num + self.frame_body.height - 1 - if last_visible_line < self:getTextHeight() then - dc:seek(x, y2):char(self.down_arrow_icon, self.scroll_icon_pen) - end + dc:seek(x, y2):char( + last_visible_line >= self:getTextHeight() and + NO_ARROW_CHAR or DOWN_ARROW_CHAR, + self.scrollbar_fg, self.scrollbar_bg) end function Label:computeFrame(parent_rect) @@ -637,13 +682,11 @@ function Label:onRenderBody(dc) end function Label:onRenderFrame(dc, rect) - if self._show_scroll_icons - and self:getTextHeight() > self.frame_body.height - then - local x = self._show_scroll_icons == 'left' + if self._show_scrollbar then + local x = self._show_scrollbar == 'left' and self.frame_body.x1-dc.x1-1 or self.frame_body.x2-dc.x1+1 - self:render_scroll_icons(dc, + self:render_scrollbar(dc, x, self.frame_body.y1-dc.y1, self.frame_body.y2-dc.y1 @@ -651,7 +694,35 @@ function Label:onRenderFrame(dc, rect) end end +function Label:click_scrollbar() + if not self._show_scrollbar then return end + local rect = self.frame_body + local x, y = dscreen.getMousePos() + + if self._show_scrollbar == 'left' and x ~= rect.x1-1 or x ~= rect.x2+1 then + return + end + if y < rect.y1 or y > rect.y2 then + return + end + + if y == rect.y1 then + return -1 + elseif y == rect.y2 then + return 1 + else + local pos, height = get_scrollbar_pos_and_height(self) + if y < rect.y1 + pos then + return '-halfpage' + elseif y > rect.y1 + pos + height then + return '+halfpage' + end + end + return nil +end + function Label:scroll(nlines) + if not nlines then return end if type(nlines) == 'string' then if nlines == '+page' then nlines = self.frame_body.height @@ -669,12 +740,16 @@ function Label:scroll(nlines) n = math.min(n, self:getTextHeight() - self.frame_body.height + 1) n = math.max(n, 1) self.start_line_num = n + return nlines end function Label:onInput(keys) if is_disabled(self) then return false end - if keys._MOUSE_L_DOWN and self:getMousePos() and self.on_click then - self:on_click() + if keys._MOUSE_L_DOWN then + if not self:scroll(self:click_scrollbar()) and + self:getMousePos() and self.on_click then + self:on_click() + end end if keys._MOUSE_R_DOWN and self:getMousePos() and self.on_rclick then self:on_rclick() @@ -1099,6 +1174,7 @@ FilteredList = defclass(FilteredList, Widget) FilteredList.ATTRS { edit_below = false, edit_key = DEFAULT_NIL, + edit_ignore_keys = DEFAULT_NIL, } function FilteredList:init(info) @@ -1108,6 +1184,7 @@ function FilteredList:init(info) on_change = self:callback('onFilterChange'), on_char = self:callback('onFilterChar'), key = self.edit_key, + ignore_keys = self.edit_ignore_keys, } self.list = List{ frame = { t = 2 }, @@ -1204,7 +1281,9 @@ function FilteredList:setFilter(filter, pos) local cidx = nil filter = filter or '' - self.edit:setText(filter) + if filter ~= self.edit.text then + self.edit:setText(filter) + end if filter ~= '' then local tokens = filter:split() diff --git a/library/lua/helpdb.lua b/library/lua/helpdb.lua index e6bd9133b..805b56db9 100644 --- a/library/lua/helpdb.lua +++ b/library/lua/helpdb.lua @@ -191,11 +191,11 @@ local function update_entry(entry, iterator, opts) _,_,tags = line:trim():find('[*]*Tags:[*]* *(.*)') in_tags, tags_found = true, true elseif not short_help_found and - line:find('^%w') then + line:find('^%s*%w') and not line:find('^%w+:') then if in_short_help then entry.short_help = entry.short_help .. ' ' .. line else - entry.short_help = line + entry.short_help = line:trim() end local sentence_end = entry.short_help:find('.', 1, true) if sentence_end then @@ -432,6 +432,37 @@ local function ensure_db() index_tags() end +local function parse_blocks(text) + local blocks = {} + for line in text:gmatch('[^\n]*') do + local _,indent = line:find('^ *') + table.insert(blocks, {line=line:trim(), indent=indent}) + end + return blocks +end + +local function format_block(line, indent, width) + local wrapped = line:wrap(width - indent) + if indent == 0 then return wrapped end + local padding = (' '):rep(indent) + local indented_lines = {} + for line in wrapped:gmatch('[^\n]*') do + table.insert(indented_lines, padding .. line) + end + return table.concat(indented_lines, '\n') +end + +-- wraps the unwrapped source help at the specified width, preserving block +-- indents +local function rewrap(text, width) + local formatted_blocks = {} + for _,block in ipairs(parse_blocks(text)) do + table.insert(formatted_blocks, + format_block(block.line, block.indent, width)) + end + return table.concat(formatted_blocks, '\n') +end + --------------------------------------------------------------------------- -- get API --------------------------------------------------------------------------- @@ -482,9 +513,10 @@ function get_entry_short_help(entry) return get_db_property(entry, 'short_help') end --- returns the full help documentation associated with the entry -function get_entry_long_help(entry) - return get_db_property(entry, 'long_help') +-- returns the full help documentation associated with the entry, optionally +-- wrapped to the specified width (80 if not specified). +function get_entry_long_help(entry, width) + return rewrap(get_db_property(entry, 'long_help'), width or 80) end -- returns the set of tags associated with the entry diff --git a/library/lua/utils.lua b/library/lua/utils.lua index 99ca87c6e..00e31929f 100644 --- a/library/lua/utils.lua +++ b/library/lua/utils.lua @@ -608,18 +608,20 @@ df_env = df_shortcut_env() function df_expr_to_ref(expr) expr = expr:gsub('%["(.-)"%]', function(field) return '.' .. field end) :gsub('%[\'(.-)\'%]', function(field) return '.' .. field end) - :gsub('%[(%d+)]', function(field) return '.' .. field end) + :gsub('%[(%-?%d+)%]', function(field) return '.' .. field end) local parts = expr:split('.', true) local obj = df_env[parts[1]] for i = 2, #parts do local key = tonumber(parts[i]) or parts[i] - local cur = obj[key] - if i == #parts and ((type(cur) ~= 'userdata') or - type(cur) == 'userdata' and getmetatable(cur) == nil) then - obj = obj:_field(key) - else - obj = obj[key] + if i == #parts then + local ok, ret = pcall(function() + return obj:_field(key) + end) + if ok then + return ret + end end + obj = obj[key] end return obj end diff --git a/plugins/3dveins.cpp b/plugins/3dveins.cpp index 929ee24f6..eaf741caf 100644 --- a/plugins/3dveins.cpp +++ b/plugins/3dveins.cpp @@ -52,12 +52,9 @@ command_result cmd_3dveins(color_ostream &out, std::vector & param DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "3dveins", "Rewrites the veins to make them extend in 3D space.", - cmd_3dveins, false, - " Run this after embark to change all veins on the map to a shape\n" - " that consistently spans Z levels. The operation preserves the\n" - " mineral counts reported by prospect.\n" - )); + "3dveins", + "Rewrites the veins to make them extend in 3D space.", + cmd_3dveins)); return CR_OK; } diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 969d3774a..49e704b75 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -82,7 +82,6 @@ if(BUILD_SUPPORTED) dfhack_plugin(3dveins 3dveins.cpp) dfhack_plugin(add-spatter add-spatter.cpp) - # dfhack_plugin(advtools advtools.cpp) dfhack_plugin(autobutcher autobutcher.cpp LINK_LIBRARIES lua) dfhack_plugin(autochop autochop.cpp) dfhack_plugin(autoclothing autoclothing.cpp) @@ -123,7 +122,6 @@ if(BUILD_SUPPORTED) dfhack_plugin(eventful eventful.cpp LINK_LIBRARIES lua) dfhack_plugin(fastdwarf fastdwarf.cpp) dfhack_plugin(filltraffic filltraffic.cpp) - dfhack_plugin(fix-armory fix-armory.cpp) dfhack_plugin(fix-unit-occupancy fix-unit-occupancy.cpp) dfhack_plugin(fixveins fixveins.cpp) dfhack_plugin(flows flows.cpp) @@ -131,7 +129,7 @@ if(BUILD_SUPPORTED) dfhack_plugin(forceequip forceequip.cpp) dfhack_plugin(generated-creature-renamer generated-creature-renamer.cpp) dfhack_plugin(getplants getplants.cpp) - dfhack_plugin(hotkeys hotkeys.cpp) + dfhack_plugin(hotkeys hotkeys.cpp LINK_LIBRARIES lua) dfhack_plugin(infiniteSky infiniteSky.cpp) dfhack_plugin(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote) dfhack_plugin(jobutils jobutils.cpp) diff --git a/plugins/advtools.cpp b/plugins/advtools.cpp deleted file mode 100644 index a1965cba0..000000000 --- a/plugins/advtools.cpp +++ /dev/null @@ -1,827 +0,0 @@ -#include "Core.h" -#include "Console.h" -#include "Export.h" -#include "PluginManager.h" -#include "MiscUtils.h" -#include "modules/World.h" -#include "modules/Translation.h" -#include "modules/Materials.h" -#include "modules/Maps.h" -#include "modules/Items.h" -#include "modules/Gui.h" -#include "modules/Units.h" - -#include "DataDefs.h" -#include "df/world.h" -#include "df/ui_advmode.h" -#include "df/item.h" -#include "df/unit.h" -#include "df/unit_inventory_item.h" -#include "df/unit_relationship_type.h" -#include "df/map_block.h" -#include "df/nemesis_record.h" -#include "df/historical_figure.h" -#include "df/general_ref_is_nemesisst.h" -#include "df/general_ref_contains_itemst.h" -#include "df/general_ref_contained_in_itemst.h" -#include "df/general_ref_unit_holderst.h" -#include "df/general_ref_building_civzone_assignedst.h" -#include "df/material.h" -#include "df/craft_material_class.h" -#include "df/viewscreen_optionst.h" -#include "df/viewscreen_dungeonmodest.h" -#include "df/viewscreen_dungeon_monsterstatusst.h" -#include "df/nemesis_flags.h" - -#include - -using namespace DFHack; -using namespace df::enums; - -using df::nemesis_record; -using df::historical_figure; - -using namespace DFHack::Translation; -/* -advtools -======== -A package of different adventure mode tools. Usage: - -:list-equipped [all]: List armor and weapons equipped by your companions. - If all is specified, also lists non-metal clothing. -:metal-detector [all-types] [non-trader]: - Reveal metal armor and weapons in shops. The options - disable the checks on item type and being in shop. -*/ - -DFHACK_PLUGIN("advtools"); -REQUIRE_GLOBAL(world); -REQUIRE_GLOBAL(ui_advmode); - -/********************* - * PLUGIN INTERFACE * - *********************/ - -static bool bodyswap_hotkey(df::viewscreen *top); - -command_result adv_bodyswap (color_ostream &out, std::vector & parameters); -command_result adv_tools (color_ostream &out, std::vector & parameters); - -DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) -{ - if (!ui_advmode) - return CR_OK; - - commands.push_back(PluginCommand( - "advtools", "Adventure mode tools.", - adv_tools, false, - " list-equipped [all]\n" - " List armor and weapons equipped by your companions.\n" - " If all is specified, also lists non-metal clothing.\n" - " metal-detector [all-types] [non-trader]\n" - " Reveal metal armor and weapons in shops. The options\n" - " disable the checks on item type and being in shop.\n" - )); - - commands.push_back(PluginCommand( - "adv-bodyswap", "Change the adventurer unit.", - adv_bodyswap, bodyswap_hotkey, - " - When viewing unit details, body-swaps into that unit.\n" - " - In the main adventure mode screen, reverts transient swap.\n" - "Options:\n" - " force\n" - " Allow swapping into non-companion units.\n" - " permanent\n" - " Permanently change the unit to be the adventurer.\n" - " Otherwise it will revert if adv-bodyswap is called\n" - " in the main screen, or if the main menu, Fast Travel\n" - " or Sleep/Wait screen is opened.\n" - " noinherit\n" - " In permanent mode, don't reassign companions to the new unit.\n" - )); - - return CR_OK; -} - -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ - return CR_OK; -} - -df::nemesis_record *getPlayerNemesis(color_ostream &out, bool restore_swap); - -DFHACK_PLUGIN_IS_ENABLED(in_transient_swap); - -DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) -{ - switch (event) { - case SC_WORLD_LOADED: - case SC_WORLD_UNLOADED: - in_transient_swap = false; - break; - default: - break; - } - return CR_OK; -} - -DFhackCExport command_result plugin_onupdate ( color_ostream &out ) -{ - // Revert transient swaps before trouble happens - if (in_transient_swap) - { - auto screen = Core::getTopViewscreen(); - bool revert = false; - - if (strict_virtual_cast(screen)) - { - using namespace df::enums::ui_advmode_menu; - - switch (ui_advmode->menu) - { - case Travel: - // was also Sleep, now equivalent - revert = true; - break; - default: - break; - } - } - else if (strict_virtual_cast(screen)) - { - // Options may mean save game - revert = true; - } - - if (revert) - { - getPlayerNemesis(out, true); - in_transient_swap = false; - } - } - - return CR_OK; -} - -/********************* - * UTILITY FUNCTIONS * - *********************/ - -static bool bodyswap_hotkey(df::viewscreen *top) -{ - return !!virtual_cast(top) || - !!virtual_cast(top); -} - -bool bodySwap(color_ostream &out, df::unit *player) -{ - if (!player) - { - out.printerr("Unit to swap is NULL\n"); - return false; - } - - auto &vec = world->units.active; - - int idx = linear_index(vec, player); - if (idx < 0) - { - out.printerr("Unit to swap not found: %d\n", player->id); - return false; - } - - if (idx != 0) - std::swap(vec[0], vec[idx]); - - return true; -} - -df::nemesis_record *getPlayerNemesis(color_ostream &out, bool restore_swap) -{ - auto real_nemesis = vector_get(world->nemesis.all, ui_advmode->player_id); - if (!real_nemesis || !real_nemesis->unit) - { - out.printerr("Invalid player nemesis id: %d\n", ui_advmode->player_id); - return NULL; - } - - if (restore_swap) - { - df::unit *ctl = world->units.active[0]; - auto ctl_nemesis = Units::getNemesis(ctl); - - if (ctl_nemesis != real_nemesis) - { - if (!bodySwap(out, real_nemesis->unit)) - return NULL; - - auto name = TranslateName(&real_nemesis->unit->name, false); - out.print("Returned into the body of %s.\n", name.c_str()); - } - - real_nemesis->unit->relationship_ids[df::unit_relationship_type::GroupLeader] = -1; - in_transient_swap = false; - } - - return real_nemesis; -} - -void changeGroupLeader(df::nemesis_record *new_nemesis, df::nemesis_record *old_nemesis) -{ - auto &cvec = new_nemesis->companions; - - // Swap companions - cvec.swap(old_nemesis->companions); - - vector_erase_at(cvec, linear_index(cvec, new_nemesis->id)); - insert_into_vector(cvec, old_nemesis->id); - - // Update follow - new_nemesis->group_leader_id = -1; - new_nemesis->unit->relationship_ids[df::unit_relationship_type::GroupLeader] = -1; - - for (unsigned i = 0; i < cvec.size(); i++) - { - auto nm = df::nemesis_record::find(cvec[i]); - if (!nm) - continue; - - nm->group_leader_id = new_nemesis->id; - if (nm->unit) - nm->unit->relationship_ids[df::unit_relationship_type::GroupLeader] = new_nemesis->unit_id; - } -} - -void copyAcquaintances(df::nemesis_record *new_nemesis, df::nemesis_record *old_nemesis) -{ - auto &svec = old_nemesis->unit->adventurer_knows; - auto &tvec = new_nemesis->unit->adventurer_knows; - - for (unsigned i = 0; i < svec.size(); i++) - insert_into_vector(tvec, svec[i]); - - insert_into_vector(tvec, old_nemesis->unit_id); -} - -void sortCompanionNemesis(std::vector *list, int player_id = -1) -{ - std::map table; - std::vector output; - - output.reserve(list->size()); - - if (player_id < 0) - { - auto real_nemesis = vector_get(world->nemesis.all, ui_advmode->player_id); - if (real_nemesis) - player_id = real_nemesis->id; - } - - // Index records; find the player - for (size_t i = 0; i < list->size(); i++) - { - auto item = (*list)[i]; - if (item->id == player_id) - output.push_back(item); - else - table[item->figure->id] = item; - } - - // Pull out the items by the persistent sort order - auto &order_vec = ui_advmode->companions.all_histfigs; - for (size_t i = 0; i < order_vec.size(); i++) - { - auto it = table.find(order_vec[i]); - if (it == table.end()) - continue; - output.push_back(it->second); - table.erase(it); - } - - // The remaining ones in reverse id order - for (auto it = table.rbegin(); it != table.rend(); ++it) - output.push_back(it->second); - - list->swap(output); -} - -void listCompanions(color_ostream &out, std::vector *list, bool units = true) -{ - nemesis_record *player = getPlayerNemesis(out, false); - if (!player) - return; - - list->push_back(player); - - for (size_t i = 0; i < player->companions.size(); i++) - { - auto item = nemesis_record::find(player->companions[i]); - if (item && (item->unit || !units)) - list->push_back(item); - } -} - -std::string getUnitNameProfession(df::unit *unit) -{ - std::string name = TranslateName(&unit->name, false) + ", "; - if (unit->custom_profession.empty()) - name += ENUM_ATTR_STR(profession, caption, unit->profession); - else - name += unit->custom_profession; - return name; -} - -enum InventoryMode { - INV_HAULED, - INV_WEAPON, - INV_WORN, - INV_IN_CONTAINER -}; - -typedef std::pair inv_item; - -static void listContainerInventory(std::vector *list, df::item *container) -{ - auto &refs = container->general_refs; - for (size_t i = 0; i < refs.size(); i++) - { - auto ref = refs[i]; - if (!strict_virtual_cast(ref)) - continue; - - df::item *child = ref->getItem(); - if (!child) continue; - - list->push_back(inv_item(child, INV_IN_CONTAINER)); - listContainerInventory(list, child); - } -} - -void listUnitInventory(std::vector *list, df::unit *unit) -{ - auto &items = unit->inventory; - for (size_t i = 0; i < items.size(); i++) - { - auto item = items[i]; - InventoryMode mode; - - switch (item->mode) { - case df::unit_inventory_item::Hauled: - mode = INV_HAULED; - break; - case df::unit_inventory_item::Weapon: - mode = INV_WEAPON; - break; - default: - mode = INV_WORN; - } - - list->push_back(inv_item(item->item, mode)); - listContainerInventory(list, item->item); - } -} - -bool isShopItem(df::item *item) -{ - for (size_t k = 0; k < item->general_refs.size(); k++) - { - auto ref = item->general_refs[k]; - if (virtual_cast(ref)) - return true; - } - - return false; -} - -bool isWeaponArmor(df::item *item) -{ - using namespace df::enums::item_type; - - switch (item->getType()) { - case HELM: - case ARMOR: - case WEAPON: - case AMMO: - case GLOVES: - case PANTS: - case SHOES: - return true; - default: - return false; - } -} - -int containsMetalItems(df::item *item, bool all, bool non_trader, bool rec = false) -{ - int cnt = 0; - - auto &refs = item->general_refs; - for (size_t i = 0; i < refs.size(); i++) - { - auto ref = refs[i]; - - if (strict_virtual_cast(ref)) - return 0; - if (!rec && strict_virtual_cast(ref)) - return 0; - - if (strict_virtual_cast(ref)) - { - df::item *child = ref->getItem(); - if (!child) continue; - - cnt += containsMetalItems(child, all, non_trader, true); - } - } - - if (!non_trader && !isShopItem(item)) - return cnt; - if (!all && !isWeaponArmor(item)) - return cnt; - - MaterialInfo minfo(item); - if (minfo.getCraftClass() != craft_material_class::Metal) - return cnt; - - return ++cnt; -} - -void joinCounts(std::map &counts) -{ - for (auto it = counts.begin(); it != counts.end(); it++) - { - df::coord pt = it->first; - while (pt.x > 0 && counts.count(pt - df::coord(1,0,0))) - pt.x--; - while (pt.y > 0 &&counts.count(pt - df::coord(0,1,0))) - pt.y--; - while (pt.x < 0 && counts.count(pt + df::coord(1,0,0))) - pt.x++; - while (pt.y < 0 &&counts.count(pt + df::coord(0,1,0))) - pt.y++; - - if (pt == it->first) - continue; - - counts[pt] += it->second; - it->second = 0; - } -} - -/********************* - * FORMATTING * - *********************/ - -static void printCompanionHeader(color_ostream &out, size_t i, df::unit *unit) -{ - out.color(COLOR_GREY); - - if (i < 28) - out << char('a'+i); - else - out << i; - - out << ": " << getUnitNameProfession(unit); - if (Units::isDead(unit)) - out << " (DEAD)"; - if (Units::isGhost(unit)) - out << " (GHOST)"; - out << endl; - - out.reset_color(); -} - -static size_t formatSize(std::vector *out, const std::map in, size_t *cnt) -{ - size_t len = 0; - - for (auto it = in.begin(); it != in.end(); ++it) - { - std::string line = it->first; - if (it->second != 1) - line += stl_sprintf(" [%d]", it->second); - len = std::max(len, line.size()); - out->push_back(line); - } - - if (out->empty()) - { - out->push_back("(none)"); - len = 6; - } - - if (cnt) - *cnt = std::max(*cnt, out->size()); - - return len; -} - -static std::string formatDirection(df::coord delta) -{ - std::string ns, ew, dir; - - if (delta.x > 0) - ew = "E"; - else if (delta.x < 0) - ew = "W"; - - if (delta.y > 0) - ns = "S"; - else if (delta.y < 0) - ns = "N"; - - if (abs(delta.x) > abs(delta.y)*5) - dir = ew; - else if (abs(delta.y) > abs(delta.x)*5) - dir = ns; - else if (abs(delta.x) > abs(delta.y)*2) - dir = ew + ns + ew; - else if (abs(delta.y) > abs(delta.x)*2) - dir = ns + ns + ew; - else if (delta.x || delta.y) - dir = ns + ew; - else - dir = "***"; - - int dist = (int)sqrt((double)(delta.x*delta.x + delta.y*delta.y)); - return stl_sprintf("%d away %s %+d", dist, dir.c_str(), delta.z); -} - -static void printEquipped(color_ostream &out, df::unit *unit, bool all) -{ - std::vector items; - listUnitInventory(&items, unit); - - std::map head, body, legs, weapons; - - for (auto it = items.begin(); it != items.end(); ++it) - { - df::item *item = it->first; - - // Skip non-worn non-weapons - ItemTypeInfo iinfo(item); - - bool is_weapon = (it->second == INV_WEAPON || iinfo.type == item_type::AMMO); - if (!(is_weapon || it->second == INV_WORN)) - continue; - - // Skip non-metal, unless all - MaterialInfo minfo(item); - df::craft_material_class mclass = minfo.getCraftClass(); - - bool is_metal = (mclass == craft_material_class::Metal); - if (!(is_weapon || all || is_metal)) - continue; - - // Format the name - std::string name; - if (is_metal) - name = minfo.toString() + " "; - else if (mclass != craft_material_class::None) - name = toLower(ENUM_KEY_STR(craft_material_class,mclass)) + " "; - name += iinfo.toString(); - - // Add to the right table - int count = item->getStackSize(); - - if (is_weapon) - { - weapons[name] += count; - continue; - } - - switch (iinfo.type) { - case item_type::HELM: - head[name] += count; - break; - case item_type::ARMOR: - case item_type::GLOVES: - case item_type::BACKPACK: - case item_type::QUIVER: - body[name] += count; - break; - case item_type::PANTS: - case item_type::SHOES: - legs[name] += count; - break; - default: - weapons[name] += count; - } - } - - std::vector cols[4]; - size_t sizes[4]; - size_t lines = 0; - - sizes[0] = formatSize(&cols[0], head, &lines); - sizes[1] = formatSize(&cols[1], body, &lines); - sizes[2] = formatSize(&cols[2], legs, &lines); - sizes[3] = formatSize(&cols[3], weapons, &lines); - - for (size_t i = 0; i < lines; i++) - { - for (int j = 0; j < 4; j++) - { - size_t sz = std::max(sizes[j], size_t(18)); - out << "| " << std::left << std::setw(sz) << vector_get(cols[j],i) << " "; - } - - out << "|" << std::endl; - } -} - -/********************* - * COMMANDS * - *********************/ - -command_result adv_bodyswap (color_ostream &out, std::vector & parameters) -{ - // HOTKEY COMMAND; CORE IS SUSPENDED - bool force = false; - bool permanent = false; - bool no_make_leader = false; - - for (unsigned i = 0; i < parameters.size(); i++) - { - auto &item = parameters[i]; - - if (item == "force") - force = true; - else if (item == "permanent") - permanent = true; - else if (item == "noinherit") - no_make_leader = true; - else - return CR_WRONG_USAGE; - } - - // Get the real player; undo previous transient swap - auto real_nemesis = getPlayerNemesis(out, true); - if (!real_nemesis) - return CR_FAILURE; - - // Get the unit to swap to - auto new_unit = Gui::getSelectedUnit(out, true); - auto new_nemesis = Units::getNemesis(new_unit); - - if (!new_nemesis) - { - if (new_unit) - { - out.printerr("Cannot swap into a non-historical unit.\n"); - return CR_FAILURE; - } - - return CR_OK; - } - - if (new_nemesis == real_nemesis) - return CR_OK; - - // Verify it's a companion - if (!force && linear_index(real_nemesis->companions, new_nemesis->id) < 0) - { - out.printerr("This is not your companion - use force to bodyswap.\n"); - return CR_FAILURE; - } - - // Swap - if (!bodySwap(out, new_nemesis->unit)) - return CR_FAILURE; - - auto name = TranslateName(&new_nemesis->unit->name, false); - out.print("Swapped into the body of %s.\n", name.c_str()); - - // Permanently re-link everything - if (permanent) - { - using namespace df::enums::nemesis_flags; - - ui_advmode->player_id = linear_index(world->nemesis.all, new_nemesis); - - // Flag 0 appears to be the 'active adventurer' flag, and - // the player_id field above seems to be computed using it - // when a savegame is loaded. - // Also, unless this is set, it is impossible to retire. - real_nemesis->flags.set(ACTIVE_ADVENTURER, false); - new_nemesis->flags.set(ACTIVE_ADVENTURER, true); - - real_nemesis->flags.set(RETIRED_ADVENTURER, true); // former retired adventurer - new_nemesis->flags.set(ADVENTURER, true); // blue color in legends - - // Reassign companions and acquaintances - if (!no_make_leader) - { - changeGroupLeader(new_nemesis, real_nemesis); - copyAcquaintances(new_nemesis, real_nemesis); - } - } - else - { - in_transient_swap = true; - - // Make the player unit follow around to avoid bad consequences - // if it is unloaded before the transient swap is reverted. - real_nemesis->unit->relationship_ids[df::unit_relationship_type::GroupLeader] = new_nemesis->unit_id; - } - - return CR_OK; -} - -command_result adv_tools (color_ostream &out, std::vector & parameters) -{ - if (parameters.empty()) - return CR_WRONG_USAGE; - - CoreSuspender suspend; - - const auto &command = parameters[0]; - if (command == "list-equipped") - { - bool all = false; - for (size_t i = 1; i < parameters.size(); i++) - { - if (parameters[i] == "all") - all = true; - else - return CR_WRONG_USAGE; - } - - std::vector list; - - listCompanions(out, &list); - sortCompanionNemesis(&list); - - for (size_t i = 0; i < list.size(); i++) - { - auto item = list[i]; - auto unit = item->unit; - - printCompanionHeader(out, i, unit); - printEquipped(out, unit, all); - } - - return CR_OK; - } - else if (command == "metal-detector") - { - bool all = false, non_trader = false; - for (size_t i = 1; i < parameters.size(); i++) - { - if (parameters[i] == "all-types") - all = true; - else if (parameters[i] == "non-trader") - non_trader = true; - else - return CR_WRONG_USAGE; - } - - auto *player = getPlayerNemesis(out, false); - if (!player) - return CR_FAILURE; - - df::coord player_pos = player->unit->pos; - - int total = 0; - std::map counts; - - auto &items = world->items.all; - for (size_t i = 0; i < items.size(); i++) - { - df::item *item = items[i]; - - int num = containsMetalItems(item, all, non_trader); - if (!num) - continue; - - df::map_block *block = Maps::getTileBlock(item->pos); - if (!block) - continue; - - total += num; - counts[(item->pos - player_pos)/10] += num; - - auto &designations = block->designation; - auto &dgn = designations[item->pos.x%16][item->pos.y%16]; - - dgn.bits.hidden = 0; // revealed - dgn.bits.pile = 1; // visible - } - - joinCounts(counts); - - out.print("%d items of metal merchandise found in the vicinity.\n", total); - for (auto it = counts.begin(); it != counts.end(); it++) - { - if (!it->second) - continue; - - df::coord delta = it->first * 10; - out.print(" %s: %d\n", formatDirection(delta).c_str(), it->second); - } - - return CR_OK; - } - else - return CR_WRONG_USAGE; -} diff --git a/plugins/autobutcher.cpp b/plugins/autobutcher.cpp index ee93d30e5..32c8b8764 100644 --- a/plugins/autobutcher.cpp +++ b/plugins/autobutcher.cpp @@ -86,95 +86,11 @@ static void cleanup_autobutcher(color_ostream &out); static command_result df_autobutcher(color_ostream &out, vector ¶meters); static void autobutcher_cycle(color_ostream &out); -const string autobutcher_help = - "Automatically butcher excess livestock. This plugin monitors how many pets\n" - "you have of each gender and age and assigns excess lifestock for slaughter\n" - "once they reach a specific count. Requires\n" - "that you add the target race(s) to a watch list. Only tame units will be\n" - "processed. Named units will be completely ignored (you can give animals\n" - "nicknames with the tool 'rename unit' to protect them from getting slaughtered\n" - "automatically). Trained war or hunting pets will be ignored.\n" - "Once you have too many adults, the oldest will be butchered first.\n" - "Once you have too many kids, the youngest will be butchered first.\n" - "If you don't set a target count the following default will be used:\n" - "1 male kid, 5 female kids, 1 male adult, 5 female adults.\n" - "\n" - "Usage:\n" - "\n" - "enable autobutcher\n" - " Start processing livestock according to the configuration. Note that\n" - " no races are watched by default. You have to add the ones you want to\n" - " monitor (or use autowatch)\n" - "autobutcher autowatch\n" - " Automatically add all new races (animals you buy\n" - " from merchants, tame yourself, or get from migrants)\n" - " to the watch list using the default target counts.\n" - "autobutcher noautowatch\n" - " Stop auto-adding new races to the watch list.\n" - "autobutcher target all|new| [ ...] \n" - " Set target counts for the specified races:\n" - " fk = number of female kids\n" - " mk = number of male kids\n" - " fa = number of female adults\n" - " ma = number of female adults\n" - " If you specify 'all', then this command will set the counts for all races\n" - " on your current watchlist (including the races which are currenly set to\n" - " 'unwatched') and sets the new default for future watch commands. If you\n" - " specify 'new', then this command just sets the new default counts for\n" - " future watch commands without changing your current watchlist. Otherwise,\n" - " all space separated races listed will be modified (or added to the watchlist\n" - " if they aren't there already).\n" - "autobutcher ticks \n" - " Change the number of ticks between scanning cycles when the plugin is\n" - " enabled. By default, a cycle happens every 6000 ticks (about 8 game days).\n" - "autobutcher watch all| [ ...]\n" - " Start watching the listed races. If they aren't already in your watchlist, then\n" - " they will be added with the default target counts. If you specify the keyword 'all',\n" - " then all races in your watchlist that are currently marked as unwatched will become\n" - " watched.\n" - "autobutcher unwatch all| [ ...]\n" - " Stop watching the specified race(s) (or all races on your watchlist if 'all' is\n" - " given). The current target settings will be remembered.\n" - "autobutcher forget all| [ ...]\n" - " Unwatch the specified race(s) (or all races on your watchlist if 'all' is given)\n" - " and forget target settings for it/them.\n" - "autobutcher [list]\n" - " Print status and current settings, including the watchlist.\n" - "autobutcher list_export\n" - " Print commands required to set the current settings in another fort.\n" - " Useful to run form dfhack-run like: 'dfhack-run autobutcher list_export > autobutcher.script'\n" - "\n" - "To see a list of all races, run this command:\n" - "\n" - " devel/query --table df.global.world.raws.creatures.all --search ^creature_id --maxdepth 1'\n" - "\n" - "Though not all the races listed there are tameable/butcherable\n" - "\n" - "Examples:\n" - "\n" - "autobutcher target 4 3 2 1 BIRD_TURKEY\n" - " This means you want to have at most 7 kids (4 female, 3 male) and at most 3 adults\n" - " (2 female, 1 male) for turkeys. Once the kids grow up, the\n" - " oldest adults will get slaughtered. Excess kids will get slaughtered starting\n" - " the the youngest to allow that the older ones grow into adults.\n" - "autobutcher target 2 2 2 2 DOG\n" - "autobutcher target 1 1 2 2 CAT\n" - "autobutcher target 50 50 14 2 BIRD_GOOSE\n" - "autobutcher target 2 2 4 2 ALPACA SHEEP LLAMA\n" - "autobutcher target 5 5 6 2 PIG\n" - "autobutcher target 0 0 0 0 new\n" - "autobutcher autowatch\n" - " Configure useful limits for dogs, cats, geese (for eggs, leather, and bones), alpacas, sheep,\n" - " and llamas (for wool), and pigs (for milk and meat). All other unnamed tame units will be marked\n" - " for slaughter as soon as they arrive in your fortress.\n"; - DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( plugin_name, "Automatically butcher excess livestock.", - df_autobutcher, - false, - autobutcher_help.c_str())); + df_autobutcher)); return CR_OK; } diff --git a/plugins/autochop.cpp b/plugins/autochop.cpp index 04ae8af71..82c40934c 100644 --- a/plugins/autochop.cpp +++ b/plugins/autochop.cpp @@ -313,7 +313,7 @@ static int do_chop_designation(bool chop, bool count_only, int *skipped = nullpt { int count = 0; int estimated_yield = get_log_count(); - multimap trees_by_size; + multimap> trees_by_size; if (skipped) { @@ -935,10 +935,9 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) { commands.push_back(PluginCommand( - "autochop", "Auto-harvest trees when low on stockpiled logs", - df_autochop, false, - "Opens the automated chopping control screen. Specify 'debug' to forcibly save settings.\n" - )); + "autochop", + "Auto-harvest trees when low on stockpiled logs.", + df_autochop)); initialize(); return CR_OK; diff --git a/plugins/autoclothing.cpp b/plugins/autoclothing.cpp index d19e647d5..83eb0398a 100644 --- a/plugins/autoclothing.cpp +++ b/plugins/autoclothing.cpp @@ -1,5 +1,3 @@ - -// some headers required for a plugin. Nothing special, just the basics. #include "Core.h" #include #include @@ -184,16 +182,9 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector [number]\n" - "Example:\n" - " autoclothing cloth \"short skirt\" 10\n" - " Sets the desired number of cloth short skirts available per citizen to 10.\n" - " autoclothing cloth dress\n" - " Displays the currently set number of cloth dresses chosen per citizen.\n" - )); + "autoclothing", + "Automatically manage clothing work orders", + autoclothing)); return CR_OK; } diff --git a/plugins/autodump.cpp b/plugins/autodump.cpp index 054d28f77..fb215c26b 100644 --- a/plugins/autodump.cpp +++ b/plugins/autodump.cpp @@ -275,31 +275,19 @@ command_result df_autodump_destroy_item(color_ostream &out, vector & pa DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) { commands.push_back(PluginCommand( - "autodump", "Teleport items marked for dumping to the cursor.", - df_autodump, false, - " This utility lets you quickly move all items designated to be dumped.\n" - " Items are instantly moved to the cursor position, the dump flag is unset,\n" - " and the forbid flag is set, as if it had been dumped normally.\n" - " Be aware that any active dump item tasks still point at the item.\n" - "Options:\n" - " destroy - instead of dumping, destroy the items instantly.\n" - " destroy-here - only affect the tile under cursor.\n" - " visible - only process items that are not hidden.\n" - " hidden - only process hidden items.\n" - " forbidden - only process forbidden items (default: only unforbidden).\n" - )); + "autodump", + "Teleport items marked for dumping to the cursor.", + df_autodump)); commands.push_back(PluginCommand( - "autodump-destroy-here", "Destroy items marked for dumping under cursor.", - df_autodump_destroy_here, Gui::cursor_hotkey, - " Identical to autodump destroy-here, but intended for use as keybinding.\n" - )); + "autodump-destroy-here", + "Destroy items marked for dumping under cursor.", + df_autodump_destroy_here, + Gui::cursor_hotkey)); commands.push_back(PluginCommand( - "autodump-destroy-item", "Destroy the selected item.", - df_autodump_destroy_item, Gui::any_item_hotkey, - " Destroy the selected item. The item may be selected\n" - " in the 'k' list, or inside a container. If called\n" - " again before the game is resumed, cancels destroy.\n" - )); + "autodump-destroy-item", + "Destroy the selected item.", + df_autodump_destroy_item, + Gui::any_item_hotkey)); return CR_OK; } diff --git a/plugins/autofarm.cpp b/plugins/autofarm.cpp index 2dafdee49..1a02b6a06 100644 --- a/plugins/autofarm.cpp +++ b/plugins/autofarm.cpp @@ -38,15 +38,6 @@ DFHACK_PLUGIN("autofarm"); DFHACK_PLUGIN_IS_ENABLED(enabled); -const char* tagline = "Automatically handle crop selection in farm plots based on current plant stocks."; -const char* usage = ( - "``enable autofarm``: Enables the plugin\n" - "``autofarm runonce``: Updates farm plots (one-time only)\n" - "``autofarm status``: Prints status information\n" - "``autofarm default 30``: Sets the default threshold\n" - "``autofarm threshold 150 helmet_plump tail_pig``: Sets thresholds\n" - ); - class AutoFarm { private: std::map thresholds; @@ -330,7 +321,7 @@ public: void status(color_ostream& out) { - out << (enabled ? "Running." : "Stopped.") << '\n'; + out << "Autofarm is " << (enabled ? "Active." : "Stopped.") << '\n'; for (auto& lc : lastCounts) { auto plant = world->raws.plants.all[lc.first]; @@ -355,10 +346,9 @@ DFhackCExport command_result plugin_init(color_ostream& out, std::vector ()); return CR_OK; diff --git a/plugins/autogems.cpp b/plugins/autogems.cpp index fcd8fcdc7..d296caf7f 100644 --- a/plugins/autogems.cpp +++ b/plugins/autogems.cpp @@ -41,19 +41,6 @@ typedef int32_t mat_index; typedef std::map gem_map; bool running = false; -const char *tagline = "Creates a new Workshop Order setting, automatically cutting rough gems."; -const char *usage = ( - " enable autogems\n" - " Enable the plugin.\n" - " disable autogems\n" - " Disable the plugin.\n" - "\n" - "While enabled, the Current Workshop Orders screen (o-W) have a new option:\n" - " g: Auto Cut Gems\n" - "\n" - "While this option is enabled, jobs will be created in Jeweler's Workshops\n" - "to cut any accessible rough gems.\n" -); std::set blacklist; void add_task(mat_index gem_type, df::building_workshopst *workshop) { @@ -385,11 +372,8 @@ DFhackCExport command_result plugin_enable(color_ostream& out, bool enable) { DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( "autogems-reload", - "Reload autogems config file", - cmd_reload_config, - false, - "Reload autogems config file" - )); + "Reload autogems config file.", + cmd_reload_config)); return CR_OK; } diff --git a/plugins/autohauler.cpp b/plugins/autohauler.cpp index 35bf90ca1..b52e9cfb5 100644 --- a/plugins/autohauler.cpp +++ b/plugins/autohauler.cpp @@ -712,45 +712,9 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector haulers\n" - " Set a labor to be handled by hauler dwarves.\n" - " autohauler allow\n" - " Allow hauling if a specific labor is enabled.\n" - " autohauler forbid\n" - " Forbid hauling if a specific labor is enabled.\n" - " autohauler reset\n" - " Return a labor to the default handling.\n" - " autohauler reset-all\n" - " Return all labors to the default handling.\n" - " autohauler frameskip \n" - " Set the number of frames between runs of autohauler.\n" - " autohauler list\n" - " List current status of all labors.\n" - " autohauler status\n" - " Show basic status information.\n" - " autohauler debug\n" - " In the next cycle, will output the state of every dwarf.\n" - "Function:\n" - " When enabled, autohauler periodically checks your dwarves and assigns\n" - " hauling jobs to idle dwarves while removing them from busy dwarves.\n" - " This plugin, in contrast to autolabor, is explicitly designed to be\n" - " used alongside Dwarf Therapist.\n" - " Warning: autohauler will override any manual changes you make to\n" - " hauling labors while it is enabled...but why would you make them?\n" - "Examples:\n" - " autohauler HAUL_STONE haulers\n" - " Set stone hauling as a hauling labor.\n" - " autohauler BOWYER allow\n" - " Allow hauling when the bowyer labor is enabled.\n" - " autohauler MINE forbid\n" - " Forbid hauling while the mining labor is disabled." - )); + "autohauler", + "Automatically manage hauling labors.", + autohauler)); // Initialize plugin labor lists init_state(out); diff --git a/plugins/autolabor.cpp b/plugins/autolabor.cpp index ba116c1c5..15c6903b4 100644 --- a/plugins/autolabor.cpp +++ b/plugins/autolabor.cpp @@ -686,48 +686,9 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector [] []\n" - " Set number of dwarves assigned to a labor.\n" - " autolabor haulers\n" - " Set a labor to be handled by hauler dwarves.\n" - " autolabor disable\n" - " Turn off autolabor for a specific labor.\n" - " autolabor reset\n" - " Return a labor to the default handling.\n" - " autolabor reset-all\n" - " Return all labors to the default handling.\n" - " autolabor list\n" - " List current status of all labors.\n" - " autolabor status\n" - " Show basic status information.\n" - "Function:\n" - " When enabled, autolabor periodically checks your dwarves and enables or\n" - " disables labors. It tries to keep as many dwarves as possible busy but\n" - " also tries to have dwarves specialize in specific skills.\n" - " Warning: autolabor will override any manual changes you make to labors\n" - " while it is enabled.\n" - " To prevent particular dwarves from being managed by autolabor, put them\n" - " in any burrow.\n" - " To restrict the assignment of a labor to only the top most skilled\n" - " dwarves, add a talent pool number .\n" - "Examples:\n" - " autolabor MINE 2\n" - " Keep at least 2 dwarves with mining enabled.\n" - " autolabor CUT_GEM 1 1\n" - " Keep exactly 1 dwarf with gemcutting enabled.\n" - " autolabor COOK 1 1 3\n" - " Keep 1 dwarf with cooking enabled, selected only from the top 3.\n" - " autolabor FEED_WATER_CIVILIANS haulers\n" - " Have haulers feed and water wounded dwarves.\n" - " autolabor CUTWOOD disable\n" - " Turn off autolabor for wood cutting.\n" - )); + "autolabor", + "Automatically manage dwarf labors.", + autolabor)); init_state(); diff --git a/plugins/autonestbox.cpp b/plugins/autonestbox.cpp index c47f4425f..dd052f234 100644 --- a/plugins/autonestbox.cpp +++ b/plugins/autonestbox.cpp @@ -33,24 +33,6 @@ DFHACK_PLUGIN_IS_ENABLED(is_enabled); REQUIRE_GLOBAL(world); -static const string autonestbox_help = - "Assigns unpastured female egg-layers to nestbox zones.\n" - "Requires that you create pen/pasture zones above nestboxes.\n" - "If the pen is bigger than 1x1 the nestbox must be in the top left corner.\n" - "Only 1 unit will be assigned per pen, regardless of the size.\n" - "The age of the units is currently not checked, most birds grow up quite fast.\n" - "Usage:\n" - "\n" - "enable autonestbox\n" - " Start checking for unpastured egg-layers and assigning them to nestbox zones.\n" - "autonestbox\n" - " Print current status." - "autonestbox now\n" - " Run a scan and assignment cycle right now. Does not require that the plugin is enabled.\n" - "autonestbox ticks \n" - " Change the number of ticks between scan and assignment cycles when the plugin is enabled.\n" - " The default is 6000 (about 8 days)\n"; - namespace DFHack { // for configuration-related logging DBG_DECLARE(autonestbox, status, DebugCategory::LINFO); @@ -90,9 +72,7 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector &); DFhackCExport command_result plugin_init(color_ostream &, vector &commands) { - commands.push_back(PluginCommand("blueprint", "Record the structure of a live game map in a quickfort blueprint file", blueprint, false)); + commands.push_back( + PluginCommand("blueprint", + "Record a live game map in a quickfort blueprint.", + blueprint)); return CR_OK; } diff --git a/plugins/buildingplan.cpp b/plugins/buildingplan.cpp index 594eaf48f..b13c8daa3 100644 --- a/plugins/buildingplan.cpp +++ b/plugins/buildingplan.cpp @@ -1058,9 +1058,9 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back( - PluginCommand( - "buildingplan", "Plan building construction before you have materials", - buildingplan_cmd, false, "Run 'buildingplan debug [on|off]' to toggle debugging, or 'buildingplan version' to query the plugin version.")); + PluginCommand("buildingplan", + "Plan building construction before you have materials.", + buildingplan_cmd)); return CR_OK; } diff --git a/plugins/burrows.cpp b/plugins/burrows.cpp index 3b1d3fe86..029b3c715 100644 --- a/plugins/burrows.cpp +++ b/plugins/burrows.cpp @@ -53,35 +53,10 @@ static void deinit_map(color_ostream &out); DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand( - "burrow", "Miscellaneous burrow control.", burrow, false, - " burrow enable options...\n" - " burrow disable options...\n" - " Enable or disable features of the plugin.\n" - " See below for a list and explanation.\n" - " burrow clear-units burrow burrow...\n" - " burrow clear-tiles burrow burrow...\n" - " Removes all units or tiles from the burrows.\n" - " burrow set-units target-burrow src-burrow...\n" - " burrow add-units target-burrow src-burrow...\n" - " burrow remove-units target-burrow src-burrow...\n" - " Adds or removes units in source burrows to/from the target\n" - " burrow. Set is equivalent to clear and add.\n" - " burrow set-tiles target-burrow src-burrow...\n" - " burrow add-tiles target-burrow src-burrow...\n" - " burrow remove-tiles target-burrow src-burrow...\n" - " Adds or removes tiles in source burrows to/from the target\n" - " burrow. In place of a source burrow it is possible to use\n" - " one of the following keywords:\n" - " ABOVE_GROUND, SUBTERRANEAN, INSIDE, OUTSIDE,\n" - " LIGHT, DARK, HIDDEN, REVEALED\n" - "Implemented features:\n" - " auto-grow\n" - " When a wall inside a burrow with a name ending in '+' is dug\n" - " out, the burrow is extended to newly-revealed adjacent walls.\n" - " This final '+' may be omitted in burrow name args of commands above.\n" - " Note: Digging 1-wide corridors with the miner inside the burrow is SLOW.\n" - )); + commands.push_back( + PluginCommand("burrow", + "Quick commands for burrow control.", + burrow)); if (Core::getInstance().isMapLoaded()) init_map(out); diff --git a/plugins/changeitem.cpp b/plugins/changeitem.cpp index 52d9e7ab9..49feaec79 100644 --- a/plugins/changeitem.cpp +++ b/plugins/changeitem.cpp @@ -37,37 +37,12 @@ REQUIRE_GLOBAL(world); command_result df_changeitem(color_ostream &out, vector & parameters); -const string changeitem_help = - "Changeitem allows to change some item attributes.\n" - "By default the item currently selected in the UI will be changed\n" - "(you can select items in the 'k' list or inside containers/inventory).\n" - "By default change is only allowed if materials is of the same subtype\n" - "(for example wood<->wood, stone<->stone etc). But since some transformations\n" - "work pretty well and may be desired you can override this with 'force'.\n" - "Note that some attributes will not be touched, possibly resulting in weirdness.\n" - "To get an idea how the RAW id should look like, check some items with 'info'.\n" - "Using 'force' might create items which are not touched by crafters/haulers.\n" - "Options:\n" - " info - don't change anything, print some item info instead\n" - " here - change all items at cursor position\n" - " material, m - change material. must be followed by material RAW id\n" - " subtype, s - change subtype. must be followed by correct RAW id\n" - " quality, q - change base quality. must be followed by number (0-5)\n" - " force - ignore subtypes, force change to new material.\n" - "Example:\n" - " changeitem m INORGANIC:GRANITE here\n" - " change material of all items under the cursor to granite\n" - " changeitem q 5\n" - " change currently selected item to masterpiece quality\n"; - - DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) { commands.push_back(PluginCommand( - "changeitem", "Change item attributes (material, quality).", - df_changeitem, false, - changeitem_help.c_str() - )); + "changeitem", + "Change item attributes (material, quality).", + df_changeitem)); return CR_OK; } @@ -130,8 +105,7 @@ command_result df_changeitem(color_ostream &out, vector & parameters) if (p == "help" || p == "?") { - out << changeitem_help << endl; - return CR_OK; + return CR_WRONG_USAGE; } else if (p == "here") { diff --git a/plugins/changelayer.cpp b/plugins/changelayer.cpp index 79081c040..7520ac932 100644 --- a/plugins/changelayer.cpp +++ b/plugins/changelayer.cpp @@ -31,66 +31,14 @@ DFHACK_PLUGIN("changelayer"); REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(cursor); -const string changelayer_help = - " Allows to change the material of whole geology layers.\n" - " Can have impact on all surrounding regions, not only your embark!\n" - " By default changing stone to soil and vice versa is not allowed.\n" - " By default changes only the layer at the cursor position.\n" - " Note that one layer can stretch across lots of z levels.\n" - " By default changes only the geology which is linked to the biome under the\n" - " cursor. That geology might be linked to other biomes as well, though.\n" - " Mineral veins and gem clusters will stay on the map.\n" - " Use 'changevein' for them.\n\n" - " tl;dr: You will end up with changing quite big areas in one go.\n\n" - "Options (first parameter MUST be the material id):\n" - " all_biomes - Change layer for all biomes on your map.\n" - " Result may be undesirable since the same layer\n" - " can AND WILL be on different z-levels for different biomes.\n" - " Use the tool 'probe' to get an idea how layers and biomes\n" - " are distributed on your map.\n" - " all_layers - Change all layers on your map.\n" - " Candy mountain, anyone?\n" - " Will make your map quite boring, but tidy.\n" - " force - Allow changing stone to soil and vice versa.\n" - " !!THIS CAN HAVE WEIRD EFFECTS, USE WITH CARE!!\n" - " Note that soil will not be magically replaced with stone.\n" - " You will, however, get a stone floor after digging so it\n" - " will allow the floor to be engraved.\n" - " Note that stone will not be magically replaced with soil.\n" - " You will, however, get a soil floor after digging so it\n" - " could be helpful for creating farm plots on maps with no soil.\n" - " verbose - Give some more details about what is being changed.\n" - " trouble - Give some advice for known problems.\n" - "Example:\n" - " changelayer GRANITE\n" - " Convert layer at cursor position into granite.\n" - " changelayer SILTY_CLAY force\n" - " Convert layer at cursor position into clay even if it's stone.\n" - " changelayer MARBLE allbiomes alllayers\n" - " Convert all layers of all biomes into marble.\n"; - -const string changelayer_trouble = - "Known problems with changelayer:\n\n" - " Nothing happens, the material stays the old.\n" - " Pause/unpause the game and/or move the cursor a bit. Then retry.\n" - " Try changing another layer, undo the changes and try again.\n" - " Try saving and loading the game.\n\n" - " Weird stuff happening after using the 'force' option.\n" - " Change former stone layers back to stone, soil back to soil.\n" - " If in doubt, use the 'probe' tool to find tiles with soil walls\n" - " and stone layer type or the other way round.\n"; - - command_result changelayer (color_ostream &out, std::vector & parameters); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "changelayer", "Change a whole geology layer.", - changelayer, false, /* true means that the command can't be used from non-interactive user interface */ - // Extended help string. Used by CR_WRONG_USAGE and the help command: - changelayer_help.c_str() - )); + "changelayer", + "Change the material of an entire geology layer.", + changelayer)); return CR_OK; } @@ -120,13 +68,7 @@ command_result changelayer (color_ostream &out, std::vector & para { if(parameters[i] == "help" || parameters[i] == "?") { - out.print("%s",changelayer_help.c_str()); - return CR_OK; - } - if(parameters[i] == "trouble") - { - out.print("%s",changelayer_trouble.c_str()); - return CR_OK; + return CR_WRONG_USAGE; } if(parameters[i] == "force") force = true; diff --git a/plugins/changevein.cpp b/plugins/changevein.cpp index 8612603fc..f531ca256 100644 --- a/plugins/changevein.cpp +++ b/plugins/changevein.cpp @@ -85,9 +85,8 @@ command_result df_changevein (color_ostream &out, vector & parameters) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand("changevein", - "Changes the material of a mineral inclusion.", - df_changevein, false, - "Syntax: changevein \n")); + "Change the material of a mineral inclusion.", + df_changevein)); return CR_OK; } diff --git a/plugins/cleanconst.cpp b/plugins/cleanconst.cpp index 84659c5d7..38149abd3 100644 --- a/plugins/cleanconst.cpp +++ b/plugins/cleanconst.cpp @@ -71,12 +71,9 @@ command_result df_cleanconst(color_ostream &out, vector & parameters) DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) { commands.push_back(PluginCommand( - "cleanconst", "Cleans up construction materials.", - df_cleanconst, false, - " This utility alters all constructions on the map so that they spawn their\n" - " building component when they are disassembled, allowing their actual\n" - " build items to be safely deleted.\n" - )); + "cleanconst", + "Cleans up construction materials.", + df_cleanconst)); return CR_OK; } diff --git a/plugins/cleaners.cpp b/plugins/cleaners.cpp index 24694c6a2..00075e9d7 100644 --- a/plugins/cleaners.cpp +++ b/plugins/cleaners.cpp @@ -241,27 +241,13 @@ command_result clean (color_ostream &out, vector & parameters) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "clean","Remove contaminants from tiles, items and creatures.", - clean, false, - " Removes contaminants from map tiles, items and creatures.\n" - "Options:\n" - " map - clean the map tiles\n" - " items - clean all items\n" - " units - clean all creatures\n" - " plants - clean all plants\n" - " all - clean everything.\n" - "More options for 'map':\n" - " snow - also remove snow\n" - " mud - also remove mud\n" - " item - also remove item spatters (e.g. leaves and flowers)\n" - "Example:\n" - " clean all mud snow item\n" - " Removes all spatter, including mud and snow from map tiles.\n" - )); + "clean", + "Remove contaminants from tiles, items, and creatures.", + clean)); commands.push_back(PluginCommand( - "spotclean","Cleans map tile under cursor.", - spotclean,Gui::cursor_hotkey - )); + "spotclean", + "Clean the map tile under the cursor.", + spotclean,Gui::cursor_hotkey)); return CR_OK; } diff --git a/plugins/cleanowned.cpp b/plugins/cleanowned.cpp index 90b0e743d..c1e5b31d4 100644 --- a/plugins/cleanowned.cpp +++ b/plugins/cleanowned.cpp @@ -31,22 +31,9 @@ command_result df_cleanowned (color_ostream &out, vector & parameters); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "cleanowned", "Confiscates and dumps garbage owned by dwarfs.", - df_cleanowned, false, - " This tool lets you confiscate and dump all the garbage\n" - " dwarves ultimately accumulate.\n" - " By default, only rotten and dropped food is confiscated.\n" - "Options:\n" - " dryrun - don't actually do anything, just print what would be done.\n" - " scattered - confiscate owned items on the ground\n" - " all - confiscate everything\n" - " x - confiscate & dump 'x' and worse damaged items\n" - " X - confiscate & dump 'X' and worse damaged items\n" - "Example:\n" - " cleanowned scattered X\n" - " This will confiscate rotten and dropped food, garbage on the floors\n" - " and any worn items with 'X' damage and above.\n" - )); + "cleanowned", + "Confiscates and dumps garbage owned by dwarves.", + df_cleanowned)); return CR_OK; } diff --git a/plugins/command-prompt.cpp b/plugins/command-prompt.cpp index ba2fe0e87..94398837a 100644 --- a/plugins/command-prompt.cpp +++ b/plugins/command-prompt.cpp @@ -344,11 +344,10 @@ bool hotkey_allow_all(df::viewscreen *top) DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "command-prompt", "Shows a command prompt on window.", - show_prompt, hotkey_allow_all, - "command-prompt [entry] - shows a cmd prompt in df window." - " Entry is used for default prefix (e.g. ':lua')" - )); + "command-prompt", + "Allows you to run a DFHack command from in-game.", + show_prompt, + hotkey_allow_all)); return CR_OK; } diff --git a/plugins/confirm.cpp b/plugins/confirm.cpp index 32da4e1f8..5cef6376f 100644 --- a/plugins/confirm.cpp +++ b/plugins/confirm.cpp @@ -547,13 +547,8 @@ DFhackCExport command_result plugin_init (color_ostream &out, vector & parameters); DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand("createitem", "Create arbitrary items.", df_createitem, false, - "Syntax: createitem [count]\n" - " - Item token for what you wish to create, as specified in custom\n" - " reactions. If the item has no subtype, omit the :NONE.\n" - " - 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" - "'createitem inspect' with that item selected in-game.\n" - "\n" - "To use this command, you must select which unit will create the items.\n" - "By default, items created will be placed at that unit's feet.\n" - "To change this, run 'createitem '.\n" - "Valid destinations:\n" - "* floor - Place items on floor beneath maker's feet.\n" - "* item - Place items inside selected container.\n" - "* building - Place items inside selected building.\n" - )); + commands.push_back( + PluginCommand("createitem", + "Create arbitrary items.", + df_createitem)); return CR_OK; } diff --git a/plugins/cursecheck.cpp b/plugins/cursecheck.cpp index d20c645ab..007c81228 100644 --- a/plugins/cursecheck.cpp +++ b/plugins/cursecheck.cpp @@ -79,9 +79,10 @@ command_result cursecheck (color_ostream &out, vector & parameters); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand("cursecheck", + commands.push_back(PluginCommand( + "cursecheck", "Check for cursed creatures (undead, necromancers...)", - cursecheck, false )); + cursecheck)); return CR_OK; } diff --git a/plugins/debug.cpp b/plugins/debug.cpp index 4fbc48759..f4a22b8d1 100644 --- a/plugins/debug.cpp +++ b/plugins/debug.cpp @@ -104,85 +104,13 @@ JsonArchive& operator>>(JsonArchive& ar, const serialization::nvp& target) static constexpr auto defaultRegex = std::regex::optimize | std::regex::nosubs | std::regex::collate; -static const char* const commandHelp = - " Manage runtime debug print filters.\n" - "\n" - " debugfilter category [ []]\n" - " List categories matching regular expressions.\n" - " debugfilter filter []\n" - " List active filters or show detailed information for a filter.\n" - " debugfilter set [persistent] [ []]\n" - " Set a filter level to categories matching regular expressions.\n" - " debugfilter unset [ ...]\n" - " Unset filters matching space separated list of ids from 'filter'.\n" - " debugfilter disable [ ...]\n" - " Disable filters matching space separated list of ids from 'filter'.\n" - " debugfilter enable [ ...]\n" - " Enable filters matching space separated list of ids from 'filter'.\n" - " debugfilter header [enable] | [disable] [ ...]\n" - " Control which header metadata is shown along with each log message.\n" - " debugfilter help []\n" - " Show detailed help for a command or this help.\n"; -static const char* const commandCategory = - " category [ []]\n" - " List categories with optional filters. Parameters are passed to\n" - " std::regex to limit which once are shown. The first regular\n" - " expression is used to match the category and the second is used\n" - " to match the plugin name.\n"; -static const char* const commandSet = - " set [persistent] [ []]\n" - " Set filtering level for matching categories. 'level' must be one of\n" - " trace, debug, info, warning and error. The 'level' parameter sets\n" - " the lowest message level that will be shown. The command doesn't\n" - " allow filters to disable any error messages.\n" - " Default filter life time is until Dwarf Fortress process exists or\n" - " plugin is unloaded. Passing 'persistent' as second parameter tells\n" - " the plugin to store the filter to dfhack-config. Stored filters\n" - " will be active until always when the plugin is loaded. 'unset'\n" - " command can be used to remove persistent filters.\n" - " Filters are applied FIFO order. The latest filter will override any\n" - " older filter that also matches.\n"; -static const char* const commandFilters = - " filter []\n" - " Show the list of active filters. The first column is 'id' which can\n" - " be used to deactivate filters using 'unset' command.\n" - " Filters are printed in same order as applied - the oldest first.\n"; -static const char* const commandUnset = - " unset [ ...]\n" - " 'unset' takes space separated list of filter ids from 'filter'.\n" - " It will reset any matching category back to the default 'warning'\n" - " level or any other still active matching filter level.\n"; -static const char* const commandDisable = - " disable [ ...]\n" - " 'disable' takes space separated list of filter ids from 'filter'.\n" - " It will reset any matching category back to the default 'warning'\n" - " level or any other still active matching filter level.\n" - " 'disable' will print red filters that were already disabled.\n"; -static const char* const commandEnable = - " enable [ ...]\n" - " 'enable' takes space separated list of filter ids from 'filter'.\n" - " It will reset any matching category back to the default 'warning'\n" - " level or any other still active matching filter level.\n" - " 'enable' will print red filters that were already enabled.\n"; -static const char* const commandHeader = - " header [enable] | [disable] [ ...]\n" - " 'header' allows you to customize what metadata is displayed with\n" - " each log message. Run it without parameters to see the list of\n" - " configurable elements. Include an 'enable' or 'disable' keyword to\n" - " change specific elements.\n"; -static const char* const commandHelpDetails = - " help []\n" - " Show help for any of subcommands. Without any parameters it shows\n" - " short help for all subcommands.\n"; - //! Helper type to hold static dispatch table for subcommands struct CommandDispatch { //! Store handler function pointer and help message for commands struct Command { using handler_t = command_result(*)(color_ostream&,std::vector&); - Command(handler_t handler, const char* help) : - handler_(handler), - help_(help) + Command(handler_t handler) : + handler_(handler) {} command_result operator()(color_ostream& out, @@ -193,12 +121,8 @@ struct CommandDispatch { handler_t handler() const noexcept { return handler_; } - - const char* help() const noexcept - { return help_; } private: handler_t handler_; - const char* help_; }; using dispatch_t = const std::map; //! Name to handler function and help message mapping @@ -1125,28 +1049,14 @@ static command_result configureHeader(color_ostream& out, using DFHack::debugPlugin::CommandDispatch; -static command_result printHelp(color_ostream& out, - std::vector& parameters) -{ - const char* help = commandHelp; - auto iter = CommandDispatch::dispatch.end(); - if (1u < parameters.size()) - iter = CommandDispatch::dispatch.find(parameters[1]); - if (iter != CommandDispatch::dispatch.end()) - help = iter->second.help(); - out << help << std::flush; - return CR_OK; -} - CommandDispatch::dispatch_t CommandDispatch::dispatch { - {"category", {listCategories,commandCategory}}, - {"filter", {listFilters,commandFilters}}, - {"set", {setFilter,commandSet}}, - {"unset", {unsetFilter,commandUnset}}, - {"enable", {enableFilter,commandEnable}}, - {"disable", {disableFilter,commandDisable}}, - {"header", {configureHeader,commandHeader}}, - {"help", {printHelp,commandHelpDetails}}, + {"category", {listCategories}}, + {"filter", {listFilters}}, + {"set", {setFilter}}, + {"unset", {unsetFilter}}, + {"enable", {enableFilter}}, + {"disable", {disableFilter}}, + {"header", {configureHeader}}, }; //! Dispatch command handling to the subcommand or help @@ -1156,13 +1066,14 @@ static command_result commandDebugFilter(color_ostream& out, DEBUG(command,out).print("debugfilter %s, parameter count %zu\n", parameters.size() > 0 ? parameters[0].c_str() : "", parameters.size()); - auto handler = printHelp; auto iter = CommandDispatch::dispatch.end(); if (0u < parameters.size()) iter = CommandDispatch::dispatch.find(parameters[0]); - if (iter != CommandDispatch::dispatch.end()) - handler = iter->second.handler(); - return (handler)(out, parameters); + if (iter != CommandDispatch::dispatch.end()) { + iter->second.handler()(out, parameters); + return CR_OK; + } + return CR_WRONG_USAGE; } } } /* namespace debug */ @@ -1173,9 +1084,7 @@ DFhackCExport DFHack::command_result plugin_init(DFHack::color_ostream& out, commands.emplace_back( "debugfilter", "Manage runtime debug print filters", - DFHack::debugPlugin::commandDebugFilter, - false, - DFHack::debugPlugin::commandHelp); + DFHack::debugPlugin::commandDebugFilter); auto& filMan = DFHack::debugPlugin::FilterManager::getInstance(); DFHack::command_result rv = DFHack::CR_OK; if ((rv = filMan.loadConfig(out)) != DFHack::CR_OK) diff --git a/plugins/deramp.cpp b/plugins/deramp.cpp index 62679cae0..1c397242b 100644 --- a/plugins/deramp.cpp +++ b/plugins/deramp.cpp @@ -109,13 +109,11 @@ command_result df_deramp (color_ostream &out, vector & parameters) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand( - "deramp", "Replace all ramps marked for removal with floors.", - df_deramp, false, - " If there are any ramps designated for removal, they will be instantly\n" - " removed. Any ramps that don't have their counterpart will also be removed\n" - " (fixes bugs with caveins)\n" - )); + commands.push_back( + PluginCommand( + "deramp", + "Removes all ramps designated for removal from the map.", + df_deramp)); return CR_OK; } diff --git a/plugins/dfstream.cpp b/plugins/dfstream.cpp deleted file mode 100644 index eb98c181b..000000000 --- a/plugins/dfstream.cpp +++ /dev/null @@ -1,316 +0,0 @@ -#include "Core.h" -#include "Console.h" -#include "Export.h" -#include "PluginManager.h" - -#include "DataDefs.h" -#include "df/graphic.h" -#include "df/enabler.h" -#include "df/renderer.h" - -#include -#include -#include "PassiveSocket.h" -#include "tinythread.h" - -using namespace DFHack; -using namespace df::enums; - -using std::string; -using std::vector; - -DFHACK_PLUGIN("dfstream"); -REQUIRE_GLOBAL(gps); -REQUIRE_GLOBAL(enabler); - -// Owns the thread that accepts TCP connections and forwards messages to clients; -// has a mutex -class client_pool { - typedef tthread::mutex mutex; - - mutex clients_lock; - std::vector clients; - - // TODO - delete this at some point - tthread::thread * accepter; - - static void accept_clients(void * client_pool_pointer) { - client_pool * p = reinterpret_cast(client_pool_pointer); - CPassiveSocket socket; - socket.Initialize(); - if (socket.Listen((const uint8_t *)"0.0.0.0", 8008)) { - std::cout << "Listening on a socket" << std::endl; - } else { - std::cout << "Not listening: " << socket.GetSocketError() << std::endl; - std::cout << socket.DescribeError() << std::endl; - } - while (true) { - CActiveSocket * client = socket.Accept(); - if (client != 0) { - lock l(*p); - p->clients.push_back(client); - } - } - } - -public: - class lock { - tthread::lock_guard l; - public: - lock(client_pool & p) - : l(p.clients_lock) - { - } - }; - friend class client_pool::lock; - - client_pool() { - accepter = new tthread::thread(accept_clients, this); - } - - // MUST have lock - bool has_clients() { - return !clients.empty(); - } - - // MUST have lock - void add_client(CActiveSocket * sock) { - clients.push_back(sock); - } - - // MUST have lock - void broadcast(const std::string & message) { - unsigned int sz = htonl(message.size()); - for (size_t i = 0; i < clients.size(); ++i) { - clients[i]->Send(reinterpret_cast(&sz), sizeof(sz)); - clients[i]->Send((const uint8_t *) message.c_str(), message.size()); - } - } -}; - -// A decorator (in the design pattern sense) of the DF renderer class. -// Sends the screen contents to a client_pool. -class renderer_decorator : public df::renderer { - // the renderer we're decorating - df::renderer * inner; - - // how many frames have passed since we last sent a frame - int framesNotPrinted; - - // set to false in the destructor - bool * alive; - - // clients to which we send the frame - client_pool clients; - - // The following three methods facilitate copying of state to the inner object - void set_to_null() { - screen = NULL; - screentexpos = NULL; - screentexpos_addcolor = NULL; - screentexpos_grayscale = NULL; - screentexpos_cf = NULL; - screentexpos_cbr = NULL; - screen_old = NULL; - screentexpos_old = NULL; - screentexpos_addcolor_old = NULL; - screentexpos_grayscale_old = NULL; - screentexpos_cf_old = NULL; - screentexpos_cbr_old = NULL; - } - - void copy_from_inner() { - screen = inner->screen; - screentexpos = inner->screentexpos; - screentexpos_addcolor = inner->screentexpos_addcolor; - screentexpos_grayscale = inner->screentexpos_grayscale; - screentexpos_cf = inner->screentexpos_cf; - screentexpos_cbr = inner->screentexpos_cbr; - screen_old = inner->screen_old; - screentexpos_old = inner->screentexpos_old; - screentexpos_addcolor_old = inner->screentexpos_addcolor_old; - screentexpos_grayscale_old = inner->screentexpos_grayscale_old; - screentexpos_cf_old = inner->screentexpos_cf_old; - screentexpos_cbr_old = inner->screentexpos_cbr_old; - } - - void copy_to_inner() { - inner->screen = screen; - inner->screentexpos = screentexpos; - inner->screentexpos_addcolor = screentexpos_addcolor; - inner->screentexpos_grayscale = screentexpos_grayscale; - inner->screentexpos_cf = screentexpos_cf; - inner->screentexpos_cbr = screentexpos_cbr; - inner->screen_old = screen_old; - inner->screentexpos_old = screentexpos_old; - inner->screentexpos_addcolor_old = screentexpos_addcolor_old; - inner->screentexpos_grayscale_old = screentexpos_grayscale_old; - inner->screentexpos_cf_old = screentexpos_cf_old; - inner->screentexpos_cbr_old = screentexpos_cbr_old; - } - -public: - renderer_decorator(df::renderer * inner, bool * alive) - : inner(inner) - , framesNotPrinted(0) - , alive(alive) - { - copy_from_inner(); - } - virtual void update_tile(int x, int y) { - copy_to_inner(); - inner->update_tile(x, y); - } - virtual void update_all() { - copy_to_inner(); - inner->update_all(); - } - virtual void render() { - copy_to_inner(); - inner->render(); - - ++framesNotPrinted; - int gfps = enabler->calculated_gfps; - if (gfps == 0) gfps = 1; - // send a frame roughly every 128 mibiseconds (1 second = 1024 mibiseconds) - if ((framesNotPrinted * 1024) / gfps <= 128) return; - - client_pool::lock lock(clients); - if (!clients.has_clients()) return; - framesNotPrinted = 0; - std::stringstream frame; - frame << gps->dimx << ' ' << gps->dimy << " 0 0 " << gps->dimx << ' ' << gps->dimy << '\n'; - unsigned char * sc_ = gps->screen; - for (int y = 0; y < gps->dimy; ++y) { - unsigned char * sc = sc_; - for (int x = 0; x < gps->dimx; ++x) { - unsigned char ch = sc[0]; - unsigned char bold = (sc[3] != 0) * 8; - unsigned char translate[] = - { 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15 }; - unsigned char fg = translate[(sc[1] + bold) % 16]; - unsigned char bg = translate[sc[2] % 16]*16; - frame.put(ch); - frame.put(fg+bg); - sc += 4*gps->dimy; - } - sc_ += 4; - } - clients.broadcast(frame.str()); - } - virtual void set_fullscreen() { inner->set_fullscreen(); } - virtual void zoom(df::zoom_commands cmd) { - copy_to_inner(); - inner->zoom(cmd); - } - virtual void resize(int w, int h) { - copy_to_inner(); - inner->resize(w, h); - copy_from_inner(); - } - virtual void grid_resize(int w, int h) { - copy_to_inner(); - inner->grid_resize(w, h); - copy_from_inner(); - } - virtual ~renderer_decorator() { - *alive = false; - if (inner) { - copy_to_inner(); - delete inner; - inner = 0; - } - set_to_null(); - } - virtual bool get_mouse_coords(int *x, int *y) { return inner->get_mouse_coords(x, y); } - virtual bool uses_opengl() { return inner->uses_opengl(); } - - static renderer_decorator * hook(df::renderer *& ptr, bool * alive) { - renderer_decorator * r = new renderer_decorator(ptr, alive); - ptr = r; - return r; - } - - static void unhook(df::renderer *& ptr, renderer_decorator * dec, color_ostream & out) { - dec->copy_to_inner(); - ptr = dec->inner; - dec->inner = 0; - delete dec; - } -}; - -inline df::renderer *& active_renderer() { - return enabler->renderer; -} - -// This class is a smart pointer around a renderer_decorator. -// It should only be assigned r_d pointers that use the alive-pointer of this -// instance. -// If the r_d has been deleted by an external force, this smart pointer doesn't -// redelete it. -class auto_renderer_decorator { - renderer_decorator * p; -public: - // pass this member to the ctor of renderer_decorator - bool alive; - - auto_renderer_decorator() - : p(0) - { - } - - ~auto_renderer_decorator() { - reset(); - } - - void reset() { - if (*this) { - delete p; - p = 0; - } - } - - operator bool() { - return (p != 0) && alive; - } - - auto_renderer_decorator & operator=(renderer_decorator *p) { - reset(); - this->p = p; - return *this; - } - - renderer_decorator * get() { - return p; - } - - renderer_decorator * operator->() { - return get(); - } -}; - -auto_renderer_decorator decorator; - -DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) -{ - if (!df::renderer::_identity.can_instantiate()) - { - out.printerr("Cannot allocate a renderer\n"); - return CR_OK; - } - if (!decorator) { - decorator = renderer_decorator::hook(active_renderer(), &decorator.alive); - } - return CR_OK; -} - -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ - if (decorator && active_renderer() == decorator.get()) - { - renderer_decorator::unhook(active_renderer(), decorator.get(), out); - } - decorator.reset(); - return CR_OK; -} -// vim:set sw=4 sts=4 et: diff --git a/plugins/dig-now.cpp b/plugins/dig-now.cpp index 78b2b1522..365be3313 100644 --- a/plugins/dig-now.cpp +++ b/plugins/dig-now.cpp @@ -424,26 +424,30 @@ static bool is_smooth_wall(MapExtras::MapCache &map, const DFCoord &pos) { && tileShape(tt) == df::tiletype_shape::WALL; } -static bool is_smooth_wall_or_door(MapExtras::MapCache &map, - const DFCoord &pos) { - if (is_smooth_wall(map, pos)) - return true; - +static bool is_connector(MapExtras::MapCache &map, const DFCoord &pos) { df::building *bld = Buildings::findAtTile(pos); - return bld && bld->getType() == df::building_type::Door; + + return bld && + (bld->getType() == df::building_type::Door || + bld->getType() == df::building_type::Floodgate); +} + +static bool is_smooth_wall_or_connector(MapExtras::MapCache &map, + const DFCoord &pos) { + return is_smooth_wall(map, pos) || is_connector(map, pos); } // adds adjacent smooth walls and doors to the given tdir static TileDirection get_adjacent_smooth_walls(MapExtras::MapCache &map, const DFCoord &pos, TileDirection tdir) { - if (is_smooth_wall_or_door(map, DFCoord(pos.x, pos.y-1, pos.z))) + if (is_smooth_wall_or_connector(map, DFCoord(pos.x, pos.y-1, pos.z))) tdir.north = 1; - if (is_smooth_wall_or_door(map, DFCoord(pos.x, pos.y+1, pos.z))) + if (is_smooth_wall_or_connector(map, DFCoord(pos.x, pos.y+1, pos.z))) tdir.south = 1; - if (is_smooth_wall_or_door(map, DFCoord(pos.x-1, pos.y, pos.z))) + if (is_smooth_wall_or_connector(map, DFCoord(pos.x-1, pos.y, pos.z))) tdir.west = 1; - if (is_smooth_wall_or_door(map, DFCoord(pos.x+1, pos.y, pos.z))) + if (is_smooth_wall_or_connector(map, DFCoord(pos.x+1, pos.y, pos.z))) tdir.east = 1; return tdir; } @@ -469,7 +473,7 @@ static bool adjust_smooth_wall_dir(MapExtras::MapCache &map, const DFCoord &pos, TileDirection tdir = BLANK_TILE_DIRECTION) { if (!is_smooth_wall(map, pos)) - return false; + return is_connector(map, pos); tdir = ensure_valid_tdir(get_adjacent_smooth_walls(map, pos, tdir)); @@ -838,17 +842,6 @@ static bool get_options(color_ostream &out, return true; } -static void print_help(color_ostream &out) { - auto L = Lua::Core::State; - Lua::StackUnwinder top(L); - - if (!lua_checkstack(L, 1) || - !Lua::PushModulePublic(out, L, "plugins.dig-now", "print_help") || - !Lua::SafeCall(out, L, 0, 0)) { - out.printerr("Failed to load dig-now Lua code\n"); - } -} - bool dig_now_impl(color_ostream &out, const dig_now_options &options) { if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); @@ -880,18 +873,18 @@ command_result dig_now(color_ostream &out, std::vector ¶ms) { dig_now_options options; if (!get_options(out, options, params) || options.help) - { - print_help(out); - return options.help ? CR_OK : CR_FAILURE; - } + return CR_WRONG_USAGE; return dig_now_impl(out, options) ? CR_OK : CR_FAILURE; } DFhackCExport command_result plugin_init(color_ostream &, std::vector &commands) { - commands.push_back(PluginCommand( - "dig-now", "Instantly complete dig designations", dig_now, false)); + commands.push_back( + PluginCommand( + "dig-now", + "Instantly complete dig designations.", + dig_now)); return CR_OK; } diff --git a/plugins/dig.cpp b/plugins/dig.cpp index 6c33f206a..ddc2cd97e 100644 --- a/plugins/dig.cpp +++ b/plugins/dig.cpp @@ -28,7 +28,6 @@ command_result digv (color_ostream &out, vector & parameters); command_result digvx (color_ostream &out, vector & parameters); command_result digl (color_ostream &out, vector & parameters); command_result diglx (color_ostream &out, vector & parameters); -command_result digauto (color_ostream &out, vector & parameters); command_result digexp (color_ostream &out, vector & parameters); command_result digcircle (color_ostream &out, vector & parameters); command_result digtype (color_ostream &out, vector & parameters); @@ -40,44 +39,37 @@ REQUIRE_GLOBAL(world); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "digv","Dig a whole vein.",digv,Gui::cursor_hotkey, - " Designates a whole vein under the cursor for digging.\n" - "Options:\n" - " x - follow veins through z-levels with stairs.\n" - )); + "digv", + "Dig a whole vein.", + digv, + Gui::cursor_hotkey)); commands.push_back(PluginCommand( - "digvx","Dig a whole vein, following through z-levels.",digvx,Gui::cursor_hotkey, - " Designates a whole vein under the cursor for digging.\n" - " Also follows the vein between z-levels with stairs, like 'digv x' would.\n" - )); + "digvx", + "Dig a whole vein, following through z-levels.", + digvx, + Gui::cursor_hotkey)); commands.push_back(PluginCommand( - "digl","Dig layerstone.",digl,Gui::cursor_hotkey, - " Designates layerstone under the cursor for digging.\n" - " Veins will not be touched.\n" - "Options:\n" - " x - follow layer through z-levels with stairs.\n" - " undo - clear designation (can be used together with 'x').\n" - )); + "digl", + "Dig layerstone.", + digl, + Gui::cursor_hotkey)); commands.push_back(PluginCommand( - "diglx","Dig layerstone, following through z-levels.",diglx,Gui::cursor_hotkey, - " Designates layerstone under the cursor for digging.\n" - " Also follows the stone between z-levels with stairs, like 'digl x' would.\n" - )); - commands.push_back(PluginCommand("digexp","Select or designate an exploratory pattern.",digexp)); - commands.push_back(PluginCommand("digcircle","Dig designate a circle (filled or hollow)",digcircle)); - //commands.push_back(PluginCommand("digauto","Mark a tile for continuous digging.",autodig)); - commands.push_back(PluginCommand("digtype", "Dig all veins of a given type.", digtype,Gui::cursor_hotkey, - "For every tile on the map of the same vein type as the selected tile, this command designates it to have the same designation as the selected tile. If the selected tile has no designation, they will be dig designated.\n" - "If an argument is given, the designation of the selected tile is ignored, and all appropriate tiles are set to the specified designation.\n" - "Options:\n" - " dig\n" - " channel\n" - " ramp\n" - " updown - up/down stairs\n" - " up - up stairs\n" - " down - down stairs\n" - " clear - clear designation\n" - )); + "diglx", + "Dig layerstone, following through z-levels.", + diglx, + Gui::cursor_hotkey)); + commands.push_back(PluginCommand( + "digexp", + "Select or designate an exploratory pattern.", + digexp)); + commands.push_back(PluginCommand( + "digcircle", + "Dig designate a circle (filled or hollow)", + digcircle)); + commands.push_back(PluginCommand( + "digtype", + "Dig all veins of a given type.", + digtype,Gui::cursor_hotkey)); return CR_OK; } @@ -1420,12 +1412,6 @@ command_result digl (color_ostream &out, vector & parameters) return CR_OK; } - -command_result digauto (color_ostream &out, vector & parameters) -{ - return CR_NOT_IMPLEMENTED; -} - command_result digtype (color_ostream &out, vector & parameters) { //mostly copy-pasted from digv diff --git a/plugins/digFlood.cpp b/plugins/digFlood.cpp index 459a12c11..7370d3fe5 100644 --- a/plugins/digFlood.cpp +++ b/plugins/digFlood.cpp @@ -51,26 +51,9 @@ DFhackCExport command_result plugin_enable(color_ostream& out, bool enable) { DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "digFlood", "Automatically dig out veins as you discover them.", - digFlood, false, - "Example:\n" - " digFlood 0\n" - " disable plugin\n" - " digFlood 1\n" - " enable plugin\n" - " digFlood 0 MICROCLINE COAL_BITUMINOUS 1\n" - " disable plugin and remove microcline and bituminous coal from being monitored, then re-enable plugin\n" - " digFlood 1 MICROCLINE 0 COAL_BITUMINOUS 1\n" - " do monitor microcline, don't monitor COAL_BITUMINOUS, then enable plugin\n" - " digFlood CLEAR\n" - " remove all inorganics from monitoring\n" - " digFlood digAll1\n" - " enable digAll mode: dig any vein, regardless of the monitor list\n" - " digFlood digAll0\n" - " disable digAll mode\n" - "\n" - "Note that while order matters, multiple commands can be sequenced in one line. It is recommended to alter your save-specific regionX/raw/onLoad.init or global onLoadWorld.init file so that you won't have to type in every mineral type you want to dig every time you start the game. Material names are case sensitive.\n" - )); + "digFlood", + "Automatically dig out veins as you discover them.", + digFlood)); return CR_OK; } diff --git a/plugins/diggingInvaders/diggingInvaders.cpp b/plugins/diggingInvaders/diggingInvaders.cpp index 573c85320..457a00e50 100644 --- a/plugins/diggingInvaders/diggingInvaders.cpp +++ b/plugins/diggingInvaders/diggingInvaders.cpp @@ -120,28 +120,9 @@ static int32_t jobDelayDefault[] = { DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "diggingInvaders", "Makes invaders dig to your dwarves.", - diggingInvadersCommand, false, /* true means that the command can't be used from non-interactive user interface */ - " diggingInvaders 0\n disables the plugin\n" - " diggingInvaders 1\n enables the plugin\n" - " diggingInvaders enable\n enables the plugin\n" - " diggingInvaders disable\n disables the plugin\n" - " diggingInvaders add GOBLIN\n registers the race GOBLIN as a digging invader. Case-sensitive.\n" - " diggingInvaders remove GOBLIN\n unregisters the race GOBLIN as a digging invader. Case-sensitive.\n" - " diggingInvaders setCost GOBLIN walk n\n sets the walk cost in the path algorithm for the race GOBLIN\n" - " diggingInvaders setCost GOBLIN destroyBuilding n\n" - " diggingInvaders setCost GOBLIN dig n\n" - " diggingInvaders setCost GOBLIN destroyRoughConstruction n\n rough constructions are made from boulders\n" - " diggingInvaders setCost GOBLIN destroySmoothConstruction n\n smooth constructions are made from blocks or bars instead of boulders\n" - " diggingInvaders setDelay GOBLIN destroyBuilding n\n adds to the job_completion_timer of destroy building jobs that are assigned to invaders\n" - " diggingInvaders setDelay GOBLIN dig n\n" - " diggingInvaders setDelay GOBLIN destroyRoughConstruction n\n" - " diggingInvaders setDelay GOBLIN destroySmoothConstruction n\n" - " diggingInvaders now\n makes invaders try to dig now, if plugin is enabled\n" - " diggingInvaders clear\n clears all digging invader races\n" - " diggingInvaders edgesPerTick n\n makes the pathfinding algorithm work on at most n edges per tick. Set to 0 or lower to make it unlimited." -// " diggingInvaders\n Makes invaders try to dig now.\n" - )); + "diggingInvaders", + "Makes invaders dig to your dwarves.", + diggingInvadersCommand)); //*df::global::debug_showambush = true; return CR_OK; diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index 84e9b9abe..1a453e0d5 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -2075,20 +2075,9 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector \n" - " Start monitoring \n" - " can be \"work\", \"misery\", \"weather\", or \"all\"\n" - "dwarfmonitor disable \n" - " as above\n\n" - "dwarfmonitor stats\n" - " Show statistics summary\n" - "dwarfmonitor prefs\n" - " Show dwarf preferences summary\n\n" - "dwarfmonitor reload\n" - " Reload configuration file (dfhack-config/dwarfmonitor.json)\n" - )); + "dwarfmonitor", + "Measure fort happiness and efficiency.", + dwarfmonitor_cmd)); dm_lua::state=Lua::Core::State; if (dm_lua::state == NULL) diff --git a/plugins/dwarfvet.cpp b/plugins/dwarfvet.cpp index 30308bc57..356fda238 100644 --- a/plugins/dwarfvet.cpp +++ b/plugins/dwarfvet.cpp @@ -370,14 +370,8 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "embark-assistant", "Embark site selection support.", - embark_assistant, false, /* false means that the command can be used from non-interactive user interface */ - // Extended help string. Used by CR_WRONG_USAGE and the help command: - " This command starts the embark-assist plugin that provides embark site\n" - " selection help. It has to be called while the pre-embark screen is\n" - " displayed and shows extended (and correct(?)) resource information for\n" - " the embark rectangle as well as normally undisplayed sites in the\n" - " current embark region. It also has a site selection tool with more\n" - " options than DF's vanilla search tool. For detailed help invoke the\n" - " in game info screen. Prefers 46 lines to display properly.\n" - )); + "embark-assistant", + "Embark site selection support.", + embark_assistant)); return CR_OK; } diff --git a/plugins/embark-tools.cpp b/plugins/embark-tools.cpp index b87295020..924def798 100644 --- a/plugins/embark-tools.cpp +++ b/plugins/embark-tools.cpp @@ -752,20 +752,10 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector second->getId() + ": " + iter->second->getDesc() + "\n"); - } commands.push_back(PluginCommand( "embark-tools", - "A collection of embark tools", - embark_tools_cmd, - false, - help.c_str() - )); + "Extend the embark screen functionality.", + embark_tools_cmd)); return CR_OK; } diff --git a/plugins/fastdwarf.cpp b/plugins/fastdwarf.cpp index 3948d8577..787f85c5d 100644 --- a/plugins/fastdwarf.cpp +++ b/plugins/fastdwarf.cpp @@ -224,20 +224,10 @@ DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable ) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand("fastdwarf", - "let dwarves teleport and/or finish jobs instantly", - fastdwarf, false, - "fastdwarf: make dwarves faster.\n" - "Usage:\n" - " fastdwarf (tele)\n" - "Valid values for speed:\n" - " * 0 - Make dwarves move and work at standard speed.\n" - " * 1 - Make dwarves move and work at maximum speed.\n" - " * 2 - Make ALL creatures move and work at maximum speed.\n" - "Valid values for (tele):\n" - " * 0 - Disable dwarf teleportation (default)\n" - " * 1 - Make dwarves teleport to their destinations instantly.\n" - )); + commands.push_back(PluginCommand( + "fastdwarf", + "Dwarves teleport and/or finish jobs instantly.", + fastdwarf)); return CR_OK; } diff --git a/plugins/filltraffic.cpp b/plugins/filltraffic.cpp index ddb5ef877..781fce0a8 100644 --- a/plugins/filltraffic.cpp +++ b/plugins/filltraffic.cpp @@ -44,41 +44,21 @@ DFHACK_PLUGIN("filltraffic"); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "filltraffic","Flood-fill selected traffic designation from cursor", - filltraffic, Gui::cursor_hotkey, - " Flood-fill selected traffic type from the cursor.\n" - "Traffic Type Codes:\n" - " H: High Traffic\n" - " N: Normal Traffic\n" - " L: Low Traffic\n" - " R: Restricted Traffic\n" - "Other Options:\n" - " X: Fill across z-levels.\n" - " B: Include buildings and stockpiles.\n" - " P: Include empty space.\n" - "Example:\n" - " filltraffic H\n" - " When used in a room with doors,\n" - " it will set traffic to HIGH in just that room.\n" - )); + "filltraffic", + "Flood-fill selected traffic designation from cursor.", + filltraffic, Gui::cursor_hotkey)); commands.push_back(PluginCommand( - "alltraffic","Set traffic for the entire map", - alltraffic, false, - " Set traffic types for all tiles on the map.\n" - "Traffic Type Codes:\n" - " H: High Traffic\n" - " N: Normal Traffic\n" - " L: Low Traffic\n" - " R: Restricted Traffic\n" - )); + "alltraffic", + "Set traffic designation for the entire map.", + alltraffic)); commands.push_back(PluginCommand( - "restrictliquids","Restrict on every visible square with liquid", - restrictLiquid, false, "" - )); + "restrictliquids", + "Restrict traffic on every visible square with liquid.", + restrictLiquid)); commands.push_back(PluginCommand( - "restrictice","Restrict traffic on squares above visible ice", - restrictIce, false, "" - )); + "restrictice", + "Restrict traffic on squares above visible ice.", + restrictIce)); return CR_OK; } diff --git a/plugins/fix-armory.cpp b/plugins/fix-armory.cpp deleted file mode 100644 index 0f63b4d93..000000000 --- a/plugins/fix-armory.cpp +++ /dev/null @@ -1,843 +0,0 @@ -// Fixes containers in barracks to actually work as intended. - -#include "Core.h" -#include "Console.h" -#include "Export.h" -#include "PluginManager.h" - -#include "modules/Gui.h" -#include "modules/Screen.h" -#include "modules/Units.h" -#include "modules/Items.h" -#include "modules/Job.h" -#include "modules/World.h" -#include "modules/Maps.h" - -#include "MiscUtils.h" - -#include "DataDefs.h" -#include -#include "df/ui.h" -#include "df/world.h" -#include "df/squad.h" -#include "df/unit.h" -#include "df/squad_position.h" -#include "df/squad_ammo_spec.h" -#include "df/items_other_id.h" -#include "df/item_weaponst.h" -#include "df/item_armorst.h" -#include "df/item_helmst.h" -#include "df/item_pantsst.h" -#include "df/item_shoesst.h" -#include "df/item_glovesst.h" -#include "df/item_shieldst.h" -#include "df/item_flaskst.h" -#include "df/item_backpackst.h" -#include "df/item_quiverst.h" -#include "df/item_ammost.h" -#include "df/building_weaponrackst.h" -#include "df/building_armorstandst.h" -#include "df/building_cabinetst.h" -#include "df/building_boxst.h" -#include "df/building_squad_use.h" -#include "df/job.h" -#include "df/general_ref_building_holderst.h" -#include "df/general_ref_building_destinationst.h" -#include "df/barrack_preference_category.h" - -#include - -using std::vector; -using std::string; -using std::endl; -using namespace DFHack; -using namespace df::enums; - -using df::global::ui; -using df::global::world; -using df::global::gamemode; -using df::global::ui_build_selector; - -using namespace DFHack::Gui; -using Screen::Pen; - -static command_result fix_armory(color_ostream &out, vector & parameters); - -DFHACK_PLUGIN("fix-armory"); - -DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event); - -DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) -{ - commands.push_back(PluginCommand( - "fix-armory", "Enables or disables the fix-armory plugin.", fix_armory, false, - " fix-armory enable\n" - " Enables the tweaks.\n" - " fix-armory disable\n" - " Disables the tweaks. All equipment will be hauled off to stockpiles.\n" - )); - - if (Core::getInstance().isMapLoaded()) - plugin_onstatechange(out, SC_MAP_LOADED); - - return CR_OK; -} - -DFhackCExport command_result plugin_shutdown (color_ostream &out) -{ - return CR_OK; -} - -/* - * PART 1 - Stop restockpiling of items stored in the armory. - * - * For everything other than ammo this is quite straightforward, - * since the uniform switch code already tries to store items - * in barracks containers, and it is thus known what the intention - * is. Moreover these containers know which squad and member they - * belong to. - * - * For ammo there is no such code (in fact, ammo is never removed - * from a quiver, except when it is dropped itself), so I had to - * apply some improvisation. There is one place where BOX containers - * with Squad Equipment set are used as an anchor location for a - * pathfinding check when assigning ammo, so presumably that's - * the correct place. I however wanted to also differentiate - * training ammo, so came up with the following rules: - * - * 1. Combat ammo and ammo without any allowed use can be stored - * in BOXes marked for Squad Equipment, either directly or via - * containing room. No-allowed-use ammo is assumed to be reserved - * for emergency combat use, or something like that; however if - * it is already stored in a training chest, it won't be moved. - * 1a. If assigned to a squad position, that box can be used _only_ - * for ammo assigned to that specific _squad_. Otherwise, if - * multiple squads can use this room, they will store their - * ammo all mixed up. - * 2. Training ammo can be stored in BOXes within archery ranges - * (designated from archery target) that are enabled for Training. - * Train-only ammo in particular can _only_ be stored in such - * boxes. The inspiration for this comes from some broken code - * for weapon racks in Training rooms. - * - * As an additional feature (partially needed due to the constraints - * of working from an external hack), this plugin also blocks instant - * queueing of stockpiling jobs for items blocked on the ground, if - * these items are assigned to any squad. - * - * Since there apparently still are bugs that cause uniform items to be - * momentarily dropped on ground, this delay is set not to the minimally - * necessary 50 ticks, but to 0.5 - 1.0 in-game days, so as to provide a - * grace period during which the items can be instantly picked up again. - */ - -// Completely block the use of stockpiles -#define NO_STOCKPILES - -// Check if the item is assigned to any use controlled by the military tab -static bool is_assigned_item(df::item *item) -{ - if (!ui) - return false; - - auto type = item->getType(); - int idx = binsearch_index(ui->equipment.items_assigned[type], item->id); - if (idx < 0) - return false; - - return true; -} - -// Check if this ammo item is assigned to this squad with one of the specified uses -static bool is_squad_ammo(df::item *item, df::squad *squad, bool combat, bool train) -{ - for (size_t i = 0; i < squad->ammunition.size(); i++) - { - auto spec = squad->ammunition[i]; - bool cs = spec->flags.bits.use_combat; - bool ts = spec->flags.bits.use_training; - - // no-use ammo assumed to fit any category - if (((cs || !ts) && combat) || ((ts || !cs) && train)) - { - if (binsearch_index(spec->assigned, item->id) >= 0) - return true; - } - } - - return false; -} - -// Recursively check room parents to find out if this ammo item is allowed here -static bool can_store_ammo_rec(df::item *item, df::building *holder, int squad_id) -{ - auto squads = holder->getSquads(); - - if (squads) - { - for (size_t i = 0; i < squads->size(); i++) - { - auto use = (*squads)[i]; - - // For containers assigned to a squad, only consider that squad - if (squad_id >= 0 && use->squad_id != squad_id) - continue; - - // Squad Equipment -> combat - bool combat = use->mode.bits.squad_eq; - bool train = false; - - if (combat || train) - { - auto squad = df::squad::find(use->squad_id); - - if (squad && is_squad_ammo(item, squad, combat, train)) - return true; - } - } - } - // Ugh, archery targets don't actually have a squad use vector - else if (holder->getType() == building_type::ArcheryTarget) - { - auto &squads = world->squads.all; - - for (size_t si = 0; si < squads.size(); si++) - { - auto squad = squads[si]; - - // For containers assigned to a squad, only consider that squad - if (squad_id >= 0 && squad->id != squad_id) - continue; - - for (size_t j = 0; j < squad->rooms.size(); j++) - { - auto use = squad->rooms[j]; - - if (use->building_id != holder->id) - continue; - - // Squad Equipment -> combat - bool combat = use->mode.bits.squad_eq; - // Archery target with Train -> training - bool train = use->mode.bits.train; - - if (combat || train) - { - if (is_squad_ammo(item, squad, combat, train)) - return true; - } - - break; - } - } - } - - for (size_t i = 0; i < holder->parents.size(); i++) - if (can_store_ammo_rec(item, holder->parents[i], squad_id)) - return true; - - return false; -} - -// Check if the ammo item can be stored in this container -static bool can_store_ammo(df::item *item, df::building *holder) -{ - // Only chests - if (holder->getType() != building_type::Box) - return false; - - // with appropriate flags set - return can_store_ammo_rec(item, holder, holder->getSpecificSquad()); -} - -// Check if the item is assigned to the squad member who owns this armory building -static bool belongs_to_position(df::item *item, df::building *holder) -{ - int sid = holder->getSpecificSquad(); - if (sid < 0) - return false; - - auto squad = df::squad::find(sid); - if (!squad) - return false; - - int position = holder->getSpecificPosition(); - - // Weapon racks belong to the whole squad, i.e. can be used by any position - if (position == -1 && holder->getType() == building_type::Weaponrack) - { - for (size_t i = 0; i < squad->positions.size(); i++) - { - if (binsearch_index(squad->positions[i]->assigned_items, item->id) >= 0) - return true; - } - } - else - { - auto cpos = vector_get(squad->positions, position); - if (cpos && binsearch_index(cpos->assigned_items, item->id) >= 0) - return true; - } - - return false; -} - -// Check if the item is appropriately stored in an armory building -static bool is_in_armory(df::item *item) -{ - if (item->flags.bits.in_inventory || item->flags.bits.on_ground) - return false; - - auto holder = Items::getHolderBuilding(item); - if (!holder) - return false; - - // If indeed in a building, check if it is the right one - if (item->getType() == item_type::AMMO) - return can_store_ammo(item, holder); - else - return belongs_to_position(item, holder); -} - -/* - * Hooks used to affect stockpiling code as it runs, and prevent it - * from doing unwanted stuff. - * - * Toady can simply add these checks directly to the stockpiling code; - * we have to abuse some handy item vmethods. - */ - -template struct armory_hook : Item { - typedef Item interpose_base; - - /* - * This vmethod is called by the actual stockpiling code before it - * tries to queue a job, and is normally used to prevent stockpiling - * of uncollected webs. - */ - DEFINE_VMETHOD_INTERPOSE(bool, isCollected, ()) - { -#ifdef NO_STOCKPILES - /* - * Completely block any items assigned to a squad from being stored - * in stockpiles. The reason is that I still observe haulers running - * around with bins to pick them up for some reason. There could be - * some unaccounted race conditions involved. - */ - if (is_assigned_item(this)) - return false; -#else - // Block stockpiling of items in the armory. - if (is_in_armory(this)) - return false; - - /* - * When an item is removed from inventory due to Pickup Equipment - * process, the unit code directly invokes the stockpiling code - * and thus creates the job even before the item is actually dropped - * on the ground. We don't want this at all, especially due to the - * grace period idea. - * - * With access to source, that code can just be changed to simply - * drop the item on ground, without running stockpiling code. - */ - if (this->flags.bits.in_inventory) - { - auto holder = Items::getHolderUnit(this); - - // When that call happens, the item is still in inventory - if (holder && is_assigned_item(this)) - { - // And its ID is is this vector - if (::binsearch_index(holder->military.uniform_drop, this->id) >= 0) - return false; - } - } -#endif - - // Call the original vmethod - return INTERPOSE_NEXT(isCollected)(); - } - - /* - * This vmethod is used to actually put the item on the ground. - * When it does that, it also adds it to a vector of items to be - * instanly restockpiled by a loop in another part of the code. - * - * We don't want this either, even more than when removing from - * uniform, because this can happen in lots of various situations, - * including deconstructed containers etc, and we want our own - * armory code below to have a chance to look at the item. - * - * The logical place for this code is in the loop that processes - * that vector, but that part is not virtual. - */ - DEFINE_VMETHOD_INTERPOSE(bool, moveToGround, (int16_t x, int16_t y, int16_t z)) - { - // First, let it do its work - bool rv = INTERPOSE_NEXT(moveToGround)(x, y, z); - - // Prevent instant restockpiling of dropped assigned items. - if (is_assigned_item(this)) - { - // The original vmethod adds the item to this vector to force instant check - auto &ovec = world->items.other[items_other_id::ANY_RECENTLY_DROPPED]; - - // If it is indeed there, remove it - if (erase_from_vector(ovec, &df::item::id, this->id)) - { - // and queue it to be checked normally in 0.5-1 in-game days - // (this is a grace period in case the uniform is dropped just - // for a moment due to a momentary glitch) - this->stockpile_countdown = 12 + random_int(12); - this->stockpile_delay = 0; - } - } - - return rv; - } -}; - -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, isCollected); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, isCollected); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, isCollected); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, isCollected); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, isCollected); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, isCollected); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, isCollected); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, isCollected); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, isCollected); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, isCollected); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, isCollected); - -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, moveToGround); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, moveToGround); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, moveToGround); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, moveToGround); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, moveToGround); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, moveToGround); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, moveToGround); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, moveToGround); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, moveToGround); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, moveToGround); -template<> IMPLEMENT_VMETHOD_INTERPOSE(armory_hook, moveToGround); - -/* - * PART 2 - Actively queue jobs to haul assigned items to the armory. - * - * The logical place for this of course is in the same code that decides - * to put stuff in stockpiles, alongside the checks to prevent moving - * stuff away from the armory. We just run it independently every 50 - * simulation frames. - */ - -// Check if this item is loose and can be moved to armory -static bool can_store_item(df::item *item) -{ - // bad id, or cooldown timer still counting - if (!item || item->stockpile_countdown > 0) - return false; - - // bad flags? - if (item->flags.bits.in_job || - item->flags.bits.removed || - item->flags.bits.in_building || - item->flags.bits.encased || - item->flags.bits.owned || - item->flags.bits.forbid || - item->flags.bits.on_fire) - return false; - - // in unit inventory? - auto top = item; - - while (top->flags.bits.in_inventory) - { - auto parent = Items::getContainer(top); - if (!parent) break; - top = parent; - } - - if (Items::getGeneralRef(top, general_ref_type::UNIT_HOLDER)) - return false; - - // already in armory? - if (is_in_armory(item)) - return false; - - return true; -} - -// Queue a job to store the item in the building, if possible -static bool try_store_item(df::building *target, df::item *item) -{ - // Check if the dwarves can path between the target and the item - df::coord tpos(target->centerx, target->centery, target->z); - df::coord ipos = Items::getPosition(item); - - if (!Maps::canWalkBetween(tpos, ipos)) - return false; - - // Check if the target has enough space left - if (!target->canStoreItem(item, true)) - return false; - - // Create the job - auto href = df::allocate(); - if (!href) - return false; - - auto job = new df::job(); - - job->pos = tpos; - - bool dest = false; - - // Choose the job type - correct matching is needed so that - // later canStoreItem calls would take the job into account. - switch (target->getType()) { - case building_type::Weaponrack: - job->job_type = job_type::StoreWeapon; - // Without this flag dwarves will pick up the item, and - // then dismiss the job and put it back into the stockpile: - job->flags.bits.specific_dropoff = true; - break; - case building_type::Armorstand: - job->job_type = job_type::StoreArmor; - job->flags.bits.specific_dropoff = true; - break; - case building_type::Cabinet: - job->job_type = job_type::StoreOwnedItem; - dest = true; - break; - default: - job->job_type = job_type::StoreItemInHospital; - dest = true; - break; - } - - // job <-> item link - if (!Job::attachJobItem(job, item, df::job_item_ref::Hauled)) - { - delete job; - delete href; - return false; - } - - // job <-> building link - href->building_id = target->id; - target->jobs.push_back(job); - job->general_refs.push_back(href); - - // Two of the jobs need this link to find the job in canStoreItem(). - // They also don't actually need BUILDING_HOLDER, but it doesn't hurt. - if (dest) - { - auto rdest = df::allocate(); - - if (rdest) - { - rdest->building_id = target->id; - job->general_refs.push_back(rdest); - } - } - - // add to job list - Job::linkIntoWorld(job); - return true; -} - -// Store the item into the first building in the list that would accept it. -static void try_store_item(std::vector &vec, df::item *item) -{ - for (size_t i = 0; i < vec.size(); i++) - { - auto target = df::building::find(vec[i]); - if (!target) - continue; - - if (try_store_item(target, item)) - return; - } -} - -// Store the items into appropriate armory buildings -static void try_store_item_set(std::vector &items, df::squad *squad, df::squad_position *pos) -{ - for (size_t j = 0; j < items.size(); j++) - { - auto item = df::item::find(items[j]); - - // not loose - if (!can_store_item(item)) - continue; - - // queue jobs to put it in the appropriate container - if (item->isWeapon()) - try_store_item(squad->rack_combat, item); - else if (item->isClothing()) - try_store_item(pos->preferences[barrack_preference_category::Cabinet], item); - else if (item->isArmorNotClothing()) - try_store_item(pos->preferences[barrack_preference_category::Armorstand], item); - else - try_store_item(pos->preferences[barrack_preference_category::Box], item); - } -} - -// For storing ammo, use a data structure sorted by free space, to even out the load -typedef std::map > ammo_box_set; - -// Enumerate boxes in the room, adding them to the set -static void index_boxes(df::building *root, ammo_box_set &group, int squad_id) -{ - if (root->getType() == building_type::Box) - { - int id = root->getSpecificSquad(); - - if (id < 0 || id == squad_id) - { - //color_ostream_proxy out(Core::getInstance().getConsole()); - //out.print("%08x %d\n", unsigned(root), root->getFreeCapacity(true)); - - group[root->getFreeCapacity(true)].insert(root); - } - } - - for (size_t i = 0; i < root->children.size(); i++) - index_boxes(root->children[i], group, squad_id); -} - -// Loop over the set from most empty to least empty -static bool try_store_ammo(df::item *item, ammo_box_set &group) -{ - int volume = item->getVolume(); - - for (auto it = group.rbegin(); it != group.rend(); ++it) - { - if (it->first < volume) - break; - - for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) - { - auto bld = *it2; - - if (try_store_item(bld, item)) - { - it->second.erase(bld); - group[bld->getFreeCapacity(true)].insert(bld); - return true; - } - } - } - - return false; -} - -// Collect chests for ammo storage -static void index_ammo_boxes(df::squad *squad, ammo_box_set &train_set, ammo_box_set &combat_set) -{ - for (size_t j = 0; j < squad->rooms.size(); j++) - { - auto room = squad->rooms[j]; - auto bld = df::building::find(room->building_id); - - // Chests in rooms marked for Squad Equipment used for combat ammo - if (room->mode.bits.squad_eq) - index_boxes(bld, combat_set, squad->id); - - // Chests in archery ranges used for training ammo - if (room->mode.bits.train && bld->getType() == building_type::ArcheryTarget) - index_boxes(bld, train_set, squad->id); - } -} - -// Store ammo into appropriate chests -static void try_store_ammo(df::squad *squad) -{ - bool indexed = false; - ammo_box_set train_set, combat_set; - - for (size_t i = 0; i < squad->ammunition.size(); i++) - { - auto spec = squad->ammunition[i]; - bool cs = spec->flags.bits.use_combat; - bool ts = spec->flags.bits.use_training; - - for (size_t j = 0; j < spec->assigned.size(); j++) - { - auto item = df::item::find(spec->assigned[j]); - - // not loose - if (!can_store_item(item)) - continue; - - // compute the maps lazily - if (!indexed) - { - indexed = true; - index_ammo_boxes(squad, train_set, combat_set); - } - - // BUG: if the same container is in both sets, - // when a job is queued, the free space in the other - // set will not be updated, which could lead to uneven - // loading - but not to overflowing the container! - - // As said above, combat goes into Squad Equipment - if (cs && try_store_ammo(item, combat_set)) - continue; - // Training goes into Archery Range with Train - if (ts && try_store_ammo(item, train_set)) - continue; - // No use goes into combat - if (!(ts || cs) && try_store_ammo(item, combat_set)) - continue; - } - } -} - -DFHACK_PLUGIN_IS_ENABLED(is_enabled); - -DFhackCExport command_result plugin_onupdate(color_ostream &out, state_change_event event) -{ - if (!is_enabled) - return CR_OK; - - // Process every 50th frame, sort of like regular stockpiling does - if (DF_GLOBAL_VALUE(cur_year_tick,1) % 50 != 0) - return CR_OK; - - // Loop over squads - auto &squads = world->squads.all; - - for (size_t si = 0; si < squads.size(); si++) - { - auto squad = squads[si]; - - for (size_t i = 0; i < squad->positions.size(); i++) - { - auto pos = squad->positions[i]; - - try_store_item_set(pos->assigned_items, squad, pos); - } - - try_store_ammo(squad); - } - - return CR_OK; -} - -static void enable_hook(color_ostream &out, VMethodInterposeLinkBase &hook, bool enable) -{ - if (!hook.apply(enable)) - out.printerr("Could not %s hook.\n", enable?"activate":"deactivate"); -} - -static void enable_hooks(color_ostream &out, bool enable) -{ - is_enabled = enable; - - enable_hook(out, INTERPOSE_HOOK(armory_hook, isCollected), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, isCollected), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, isCollected), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, isCollected), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, isCollected), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, isCollected), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, isCollected), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, isCollected), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, isCollected), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, isCollected), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, isCollected), enable); - - enable_hook(out, INTERPOSE_HOOK(armory_hook, moveToGround), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, moveToGround), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, moveToGround), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, moveToGround), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, moveToGround), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, moveToGround), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, moveToGround), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, moveToGround), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, moveToGround), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, moveToGround), enable); - enable_hook(out, INTERPOSE_HOOK(armory_hook, moveToGround), enable); -} - -static void enable_plugin(color_ostream &out) -{ - auto entry = World::GetPersistentData("fix-armory/enabled", NULL); - if (!entry.isValid()) - { - out.printerr("Could not save the status.\n"); - return; - } - - enable_hooks(out, true); -} - -static void disable_plugin(color_ostream &out) -{ - auto entry = World::GetPersistentData("fix-armory/enabled"); - World::DeletePersistentData(entry); - - enable_hooks(out, false); -} - -DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) -{ - switch (event) { - case SC_MAP_LOADED: - if (!gamemode || *gamemode == game_mode::DWARF) - { - bool enable = World::GetPersistentData("fix-armory/enabled").isValid(); - - if (enable) - { - out.print("Enabling the fix-armory plugin.\n"); - enable_hooks(out, true); - } - else - enable_hooks(out, false); - } - break; - case SC_MAP_UNLOADED: - enable_hooks(out, false); - default: - break; - } - - return CR_OK; -} - -DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) -{ - if (!Core::getInstance().isWorldLoaded()) { - out.printerr("World is not loaded: please load a game first.\n"); - return CR_FAILURE; - } - - if (enable) - enable_plugin(out); - else - disable_plugin(out); - - return CR_OK; -} - -static command_result fix_armory(color_ostream &out, vector ¶meters) -{ - CoreSuspender suspend; - - if (parameters.empty()) - return CR_WRONG_USAGE; - - string cmd = parameters[0]; - - if (cmd == "enable") - return plugin_enable(out, true); - else if (cmd == "disable") - return plugin_enable(out, false); - else - return CR_WRONG_USAGE; - - return CR_OK; -} diff --git a/plugins/fix-unit-occupancy.cpp b/plugins/fix-unit-occupancy.cpp index d602ae213..973c185a8 100644 --- a/plugins/fix-unit-occupancy.cpp +++ b/plugins/fix-unit-occupancy.cpp @@ -181,18 +181,8 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector & parameters) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand("fixveins", - "Remove invalid references to mineral inclusions and restore missing ones.", + commands.push_back(PluginCommand( + "fixveins", + "Restore missing mineral inclusions.", df_fixveins)); return CR_OK; } diff --git a/plugins/flows.cpp b/plugins/flows.cpp index 070776b10..a17554cb9 100644 --- a/plugins/flows.cpp +++ b/plugins/flows.cpp @@ -59,7 +59,8 @@ command_result df_flows (color_ostream &out, vector & parameters) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand("flows", + commands.push_back(PluginCommand( + "flows", "Counts map blocks with flowing liquids.", df_flows)); return CR_OK; diff --git a/plugins/follow.cpp b/plugins/follow.cpp index e9733d5da..53ff5c523 100644 --- a/plugins/follow.cpp +++ b/plugins/follow.cpp @@ -31,11 +31,10 @@ uint8_t prevMenuWidth; DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "follow", "Make the screen follow the selected unit", - follow, Gui::view_unit_hotkey, - " Select a unit and run this plugin to make the camera follow it.\n" - " Moving the camera yourself deactivates the plugin.\n" - )); + "follow", + "Make the screen follow the selected unit.", + follow, + Gui::view_unit_hotkey)); followedUnit = 0; prevX=prevY=prevZ = -1; prevMenuWidth = 0; diff --git a/plugins/forceequip.cpp b/plugins/forceequip.cpp index ab39bb0d6..2ee4e47a7 100644 --- a/plugins/forceequip.cpp +++ b/plugins/forceequip.cpp @@ -55,171 +55,12 @@ const int const_GloveLeftHandedness = 2; command_result df_forceequip(color_ostream &out, vector & parameters); -const string forceequip_help = - "ForceEquip moves local items into a unit's inventory. It is typically\n" - "used to equip specific clothing/armor items onto a dwarf, but can also\n" - "be used to put armor onto a war animal or to add unusual items (such\n" - "as crowns) to any unit.\n" - "This plugin can process multiple items in a single call, but will only\n" - "work with a single unit (the first one it finds under the cursor).\n" - "In order to minimize confusion, it is recommended that you use\n" - "forceequip only when you have a unit standing alone atop a pile of\n" - "gear that you would like it to wear. Items which are stored in bins\n" - "or other containers (e.g. chests, armor racks) may also work, but\n" - "piling items on the floor (via a garbage dump activity zone, of the\n" - "DFHack autodump command) is the most reliable way to do it.\n" - "The plugin will ignore any items that are forbidden. Hence, you\n" - "can setup a large pile of surplus gear, walk a unit onto it (or\n" - "pasture an animal on it), unforbid a few items and run forceequip.\n" - "The (forbidden) majority of your gear will remain in-place, ready\n" - "for the next passerby." - "\n" - "As mentioned above, this plugin can be used to equip items onto\n" - "units (such as animals) which cannot normally equip gear. There's\n" - "an important caveat here - such creatures will automatically drop\n" - "inappropriate gear almost immediately (within 10 game ticks).\n" - "If you want them to retain their equipment, you must forbid it\n" - "AFTER using forceequip to get it into their inventory.\n" - "This technique can also be used to clothe dwarven infants, but\n" - "only if you're able to separate them from their mothers.\n" - "\n" - "By default, the forceequip plugin will attempt to avoid\n" - "conflicts and outright cheating. For instance, it will skip\n" - "any item which is flagged for use in a job, and will not\n" - "equip more than one piece of clothing/armor onto any given\n" - "body part. These restrictions can be overridden via command\n" - "switches (see examples below) but doing so puts you at greater\n" - "risk of unexpected consequences. For instance, a dwarf who\n" - "is wearing three breastplates will not be able to move very\n" - "quickly.\n" - "\n" - "Items equipped by this plugin DO NOT become owned by the\n" - "recipient. Adult dwarves are free to adjust their own\n" - "wardrobe, and may promptly decide to doff your gear in\n" - "favour of their owned items. Animals, as described above,\n" - "will tend to discard ALL clothing immediately unless it is\n" - "manually forbidden. Armor items seem to be an exception;\n" - "an animal will tend to retain an equipped suit of mail\n" - "even if you neglect to Forbid it.\n" - "\n" - "Please note that armored animals are quite vulnerable to ranged\n" - "attacks. Unlike dwarves, animals cannot block, dodge, or deflect\n" - "arrows, and they are slowed by the weight of their armor.\n" - "\n" - "This plugin currently does not support weapons.\n" - "\n" - "Options:\n" - " here, h - process the unit and item(s) under the cursor.\n" - " - This option is enabled by default since the plugin\n" - " - does not currently support remote equpping.\n" - " ignore, i - bypasses the usual item eligibility checks (such as\n" - " - \"Never equip gear belonging to another dwarf\" and\n" - " - \"Nobody is allowed to equip a Hive\".)\n" - " multi, m - bypasses the 1-item-per-bodypart limit, allowing\n" - " - the unit to receive an unlimited amount of gear.\n" - " - Can be used legitimately (e.g. mitten + gauntlet)\n" - " - or for cheating (e.g. twelve breastplates).\n" - " m2, m3, m4 - alters the 1-item-per-bodypart limit, allowing\n" - " - each part to receive 2, 3, or 4 pieces of gear.\n" - " selected, s - rather than processing all items piled at a unit's\n" - " - feet, process only the one item currently selected.\n" - " bodypart, bp - must be followed by a bodypart code (e.g. LH).\n" - " - Instructs the plugin to equip all available items\n" - " - onto this body part only. Typically used in\n" - " - conjunction with the f switch (to over-armor\n" - " - a particular bodypart) or the i switch (to equip\n" - " - an unusual item onto a specific slot).\n" - " verbose, v - provides detailed narration and error messages.\n" - " - Can be helpful in resolving failures; not needed\n" - " - for casual use.\n" - "\n" - "Examples:\n" - " forceequip\n" - " attempts to equip all of the items under the cursor onto the unit\n" - " under the cursor. Uses only clothing/armor items; ignores all\n" - " other types. Equips a maximum of 1 item onto each bodypart,\n" - " and equips only \"appropriate\" items in each slot (e.g. glove\n" - " --> hand). Bypasses any item which might cause a conflict,\n" - " such as a Boot belonging to a different dwarf.\n" - " forceequip bp LH\n" - " attempts to equip all local items onto the left hand of the local\n" - " unit. If the hand is already equipped then nothing will happen,\n" - " and if it is not equipped then only one appropriate item (e.g. \n" - " a single mitten or gauntlet) will be equipped. This command can\n" - " be useful if you don't want to selectively forbid individual items\n" - " and simply want the unit to equip, say, a Helmet while leaving\n" - " the rest of the pile alone.\n" - " forceequip m bp LH\n" - " as above, but will equip ALL appropriate items onto the unit's\n" - " left hand. After running this command, it might end up wearing\n" - " a dozen left-handed mittens. Use with caution, and remember\n" - " that dwarves will tend to drop supernumary items ASAP.\n" - " forceequip m\n" - " as above, but will equip ALL appropriate items onto any\n" - " appropriate bodypart. Tends to put several boots onto the right\n" - " foot while leaving the left foot bare.\n" - " forceequip m2\n" - " as above, but will equip up to two appropriate items onto each\n" - " bodypart. Helps to balance footwear, but doesn't ensure proper\n" - " placement (e.g. left foot gets two socks, right foot gets two\n" - " shoes). For best results, use \"selected bp LH\" and\n" - " \"selected bp RH\" instead.\n" - " forceequip i\n" - " performs the standard \"equip appropriate items onto appropriate\n" - " bodyparts\" logic, but also includes items that would normally\n" - " be considered ineligible (such as a sock which is owned by\n" - " a different dwarf).\n" - " forceequip bp NECK\n" - " attempts to equip any appropriate gear onto the Neck of the\n" - " local unit. Since the plugin believes that no items are actually\n" - " appropriate for the Neck slot, this command does nothing.\n" - " forceequip i bp NECK\n" - " attempts to equip items from the local pile onto the Neck\n" - " of the local unit. Ignores appropriateness restrictions.\n" - " If there's a millstone or an albatross carcass sitting on\n" - " the same square as the targeted unit, then there's a good\n" - " chance that it will end up around his neck. For precise\n" - " control, remember that you can selectively forbid some of\n" - " the items that are piled on the ground.\n" - " forceequip i m bp NECK\n" - " as above, but equips an unlimited number of items onto the\n" - " targeted bodypart. Effectively, all unforbidden items\n" - " (including helms, millstones, boulders, etc) will be\n" - " moved from the local pile and placed in the dwarf's\n" - " inventory (specifically, on his neck). When used with\n" - " a large pile of goods, this will leave the dwarf heavily\n" - " encumbered and very slow to move.\n" - " forceequip s\n" - " requires that a single item be selected using the k menu.\n" - " This item must occupy the same square as the target unit,\n" - " and must be unforbidden. Attempts to equip this single\n" - " item onto an appropriate slot in the unit's inventory.\n" - " Can serve as a quicker alternative to the selective-\n" - " unforbidding approach described above.\n" - " forceequip s m i bp HD\n" - " equips the selected item onto the unit's head. Ignores\n" - " all possible restrictions and conflicts. If you know\n" - " exactly what you want to equip, and exactly where you\n" - " want it to go, then this is the most straightforward\n" - " and reliable option.\n" - " forceequip v bp QQQ\n" - " guaranteed to fail (and accomplish nothing) because\n" - " there are no bodyparts called QQQ. However, since the\n" - " verbose switch is used, the resulting error messages\n" - " will list every bodypart that the unit DOES possess.\n" - " May be useful if you're unfamiliar with the BP codes\n" - " used by Dwarf Fortress, or if you're experimenting\n" - " with an exotic creature.\n" - "\n" - ; - DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) { commands.push_back(PluginCommand( - "forceequip", "Move items from the ground into a unit's inventory", - df_forceequip, false, - forceequip_help.c_str() - )); + "forceequip", + "Move items into a unit's inventory.", + df_forceequip)); return CR_OK; } @@ -439,8 +280,7 @@ command_result df_forceequip(color_ostream &out, vector & parameters) if (p == "help" || p == "?" || p == "h" || p == "/?" || p == "info" || p == "man") { - out << forceequip_help << endl; - return CR_OK; + return CR_WRONG_USAGE; } else if (p == "here" || p == "h") { diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index 625c093cf..f6e9e41b6 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -27,17 +27,12 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector & parameters) DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) { commands.push_back(PluginCommand( - "getplants", "Cut down trees or gather shrubs by ID", - df_getplants, false, - " Specify the types of trees to cut down and/or shrubs to gather by their\n" - " plant IDs, separated by spaces.\n" - "Options:\n" - " -t - Tree: Select trees only (exclude shrubs)\n" - " -s - Shrub: Select shrubs only (exclude trees)\n" - " -f - Farming: Designate only shrubs that yield seeds for farming. Implies -s\n" - " -c - Clear: Clear designations instead of setting them\n" - " -x - eXcept: Apply selected action to all plants except those specified\n" - " -a - All: Select every type of plant (obeys -t/-s/-f)\n" - " -v - Verbose: List the number of (un)designations per plant\n" - " -n * - Number: Designate up to * (an integer number) plants of each species\n" - "Specifying both -t and -s or -f will have no effect.\n" - "If no plant IDs are specified, and the -a switch isn't given, all valid plant\n" - "IDs will be listed with -t, -s, and -f restricting the list to trees, shrubs,\n" - "and farmable shrubs, respectively.\n" - )); + "getplants", + "Designate trees for chopping and shrubs for gathering.", + df_getplants)); return CR_OK; } diff --git a/plugins/hotkeys.cpp b/plugins/hotkeys.cpp index ecf3b2969..e92bc61fe 100644 --- a/plugins/hotkeys.cpp +++ b/plugins/hotkeys.cpp @@ -8,6 +8,7 @@ #include "modules/World.h" #include "modules/Gui.h" +#include "LuaTools.h" #include "PluginManager.h" DFHACK_PLUGIN("hotkeys"); @@ -123,6 +124,29 @@ static void invoke_command(const size_t index) } } +static std::string get_help(const std::string &command, bool full_help) +{ + auto L = Lua::Core::State; + color_ostream_proxy out(Core::getInstance().getConsole()); + Lua::StackUnwinder top(L); + + if (!lua_checkstack(L, 2) || + !Lua::PushModulePublic(out, L, "helpdb", + full_help ? "get_entry_long_help" : "get_entry_short_help")) + return "Help text unavailable."; + + Lua::Push(L, command); + + if (!Lua::SafeCall(out, L, 1, 1)) + return "Help text unavailable."; + + const char *s = lua_tostring(L, -1); + if (!s) + return "Help text unavailable."; + + return s; +} + class ViewscreenHotkeys : public dfhack_viewscreen { public: @@ -222,31 +246,16 @@ public: if (first[0] == '#') return; - Plugin *plugin = Core::getInstance().getPluginManager()->getPluginByCommand(first); - if (plugin) + OutputString(COLOR_BROWN, x, y, "Help", true, help_start); + string help_text = get_help(first, show_usage); + vector lines; + split_string(&lines, help_text, "\n"); + for (auto it = lines.begin(); it != lines.end() && y < gps->dimy - 4; it++) { - for (size_t i = 0; i < plugin->size(); i++) + auto wrapped_lines = wrapString(*it, width); + for (auto wit = wrapped_lines.begin(); wit != wrapped_lines.end() && y < gps->dimy - 4; wit++) { - auto pc = plugin->operator[](i); - if (pc.name == first) - { - OutputString(COLOR_BROWN, x, y, "Help", true, help_start); - vector lines; - string help_text = pc.description; - if (show_usage) - help_text += "\n\n" + pc.usage; - - split_string(&lines, help_text, "\n"); - for (auto it = lines.begin(); it != lines.end() && y < gps->dimy - 4; it++) - { - auto wrapped_lines = wrapString(*it, width); - for (auto wit = wrapped_lines.begin(); wit != wrapped_lines.end() && y < gps->dimy - 4; wit++) - { - OutputString(COLOR_WHITE, x, y, *wit, true, help_start); - } - } - break; - } + OutputString(COLOR_WHITE, x, y, *wit, true, help_start); } } } @@ -348,8 +357,9 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector \n" - " Replace the exact material id in the job item.\n" - " job item-type \n" - " Replace the exact item type id in the job item.\n" - ) - ); + "job", + "Inspect and modify job item properties.", + job_cmd)); if (ui_workshop_job_cursor || ui_build_selector) { commands.push_back( PluginCommand( - "job-material", "Alter the material of the selected job.", - job_material, job_material_hotkey, - " job-material \n" - "Intended to be used as a keybinding:\n" - " - In 'q' mode, when a job is highlighted within a workshop\n" - " or furnace, changes the material of the job. Only inorganic\n" - " materials can be used in this mode.\n" - " - In 'b' mode, during selection of building components\n" - " positions the cursor over the first available choice\n" - " with the matching material.\n" - ) - ); + "job-material", + "Alter the material of the selected job or building.", + job_material, + job_material_hotkey)); } if (ui_workshop_job_cursor && job_next_id) { commands.push_back( PluginCommand( - "job-duplicate", "Duplicate the selected job in a workshop.", - job_duplicate, Gui::workshop_job_hotkey, - " - In 'q' mode, when a job is highlighted within a workshop\n" - " or furnace building, instantly duplicates the job.\n" - ) - ); + "job-duplicate", + "Duplicate the selected job in a workshop.", + job_duplicate, + Gui::workshop_job_hotkey)); } return CR_OK; diff --git a/plugins/labormanager/labormanager.cpp b/plugins/labormanager/labormanager.cpp index 02569fd8b..f508c9797 100644 --- a/plugins/labormanager/labormanager.cpp +++ b/plugins/labormanager/labormanager.cpp @@ -845,38 +845,9 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector \n" - " Set max number of dwarves assigned to a labor.\n" - " labormanager max unmanaged\n" - " labormanager max disable\n" - " Don't attempt to manage this labor.\n" - " Any dwarves with unmanaged labors assigned will be less\n" - " likely to have managed labors assigned to them.\n" - " labormanager max none\n" - " Unrestrict the number of dwarves assigned to a labor.\n" - " labormanager priority \n" - " Change the assignment priority of a labor (default is 100)\n" - " labormanager reset \n" - " Return a labor to the default handling.\n" - " labormanager reset-all\n" - " Return all labors to the default handling.\n" - " labormanager list\n" - " List current status of all labors.\n" - " labormanager status\n" - " Show basic status information.\n" - "Function:\n" - " When enabled, labormanager periodically checks your dwarves and enables or\n" - " disables labors. Generally, each dwarf will be assigned exactly one labor.\n" - " Warning: labormanager will override any manual changes you make to labors\n" - " while it is enabled, except where the labor is marked as unmanaged.\n" - " Do not try to run both autolabor and labormanager at the same time.\n" - )); + "labormanager", + "Automatically manage dwarf labors.", + labormanager)); generate_labor_to_skill_map(); diff --git a/plugins/lair.cpp b/plugins/lair.cpp index 6fb167988..7c3b1953f 100644 --- a/plugins/lair.cpp +++ b/plugins/lair.cpp @@ -61,7 +61,9 @@ command_result lair(color_ostream &out, std::vector & params) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand("lair","Mark the map as a monster lair (avoids item scatter)",lair, false, - "Usage: 'lair' to mark entire map as monster lair, 'lair reset' to undo the operation.\n")); + commands.push_back(PluginCommand( + "lair", + "Mark the map as a monster lair to avoid item scatter.", + lair)); return CR_OK; } diff --git a/plugins/liquids.cpp b/plugins/liquids.cpp index 76c098c8a..980deb747 100644 --- a/plugins/liquids.cpp +++ b/plugins/liquids.cpp @@ -65,17 +65,15 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector []] [] - -Examples: - -dig-now - Dig all designated tiles according to standard game rules. - -dig-now --clean - Dig designated tiles, but don't generate any boulders, ores, or gems. - -dig-now --dump here - Dig tiles and dump all generated boulders, ores, and gems at the tile under - the game cursor. - -See the online DFHack documentation for details on all options. -]=] - -function print_help() print(short_help_text) end - local function parse_coords(opts, configname, arg) local cursor = argparse.coords(arg, configname) utils.assign(opts[configname], cursor) diff --git a/plugins/misery.cpp b/plugins/misery.cpp index b8e11f5c0..224060c6b 100644 --- a/plugins/misery.cpp +++ b/plugins/misery.cpp @@ -128,21 +128,10 @@ DFhackCExport command_result plugin_onupdate(color_ostream& out) { } DFhackCExport command_result plugin_init(color_ostream& out, vector &commands) { - commands.push_back(PluginCommand("misery", "increase the intensity of negative dwarven thoughts", - &misery, false, - "misery: When enabled, every new negative dwarven thought will be multiplied by a factor (2 by default).\n" - "Usage:\n" - " misery enable n\n" - " enable misery with optional magnitude n. If specified, n must be positive.\n" - " misery n\n" - " same as \"misery enable n\"\n" - " misery enable\n" - " same as \"misery enable 2\"\n" - " misery disable\n" - " stop adding new negative thoughts. This will not remove existing duplicated thoughts. Equivalent to \"misery 1\"\n" - " misery clear\n" - " remove fake thoughts added in this session of DF. Saving makes them permanent! Does not change factor.\n\n" - )); + commands.push_back(PluginCommand( + "misery", + "Increase the intensity of negative dwarven thoughts.", + misery)); return CR_OK; } diff --git a/plugins/mode.cpp b/plugins/mode.cpp index 5e58c50a0..aeda6380b 100644 --- a/plugins/mode.cpp +++ b/plugins/mode.cpp @@ -19,12 +19,10 @@ DFHACK_PLUGIN("mode"); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "mode","View, change and track game mode.", - mode, true, - " Without any parameters, this command prints the current game mode\n" - " You can interactively set the game mode with 'mode set'.\n" - "!!Setting the game modes can be dangerous and break your game!!\n" - )); + "mode", + "View, change and track game mode.", + mode, + true)); return CR_OK; } diff --git a/plugins/mousequery.cpp b/plugins/mousequery.cpp index 618252ad3..cd85de2bc 100644 --- a/plugins/mousequery.cpp +++ b/plugins/mousequery.cpp @@ -916,19 +916,9 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector \n" - " Set delay when edge scrolling in tracking mode. Omit amount to display current setting.\n" - )); + "mousequery", + "Add mouse functionality to Dwarf Fortress.", + mousequery_cmd)); return CR_OK; } diff --git a/plugins/nestboxes.cpp b/plugins/nestboxes.cpp index 8b9a33289..403a8cb37 100644 --- a/plugins/nestboxes.cpp +++ b/plugins/nestboxes.cpp @@ -69,13 +69,10 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector params; + return petcapRemover(out, params); } } diff --git a/plugins/plants.cpp b/plugins/plants.cpp index 69e712ef8..2325c01e3 100644 --- a/plugins/plants.cpp +++ b/plugins/plants.cpp @@ -32,10 +32,7 @@ command_result df_grow (color_ostream &out, vector & parameters) { if(parameters[i] == "help" || parameters[i] == "?") { - out.print("Usage:\n" - "This command turns all living saplings on the map into full-grown trees.\n" - "With active cursor, work on the targetted one only.\n"); - return CR_OK; + return CR_WRONG_USAGE; } } @@ -91,11 +88,7 @@ command_result df_createplant (color_ostream &out, vector & parameters) { if ((parameters.size() != 1) || (parameters[0] == "help" || parameters[0] == "?")) { - out.print("Usage:\n" - "Create a new plant at the cursor.\n" - "Specify the type of plant to create by its raw ID (e.g. TOWER_CAP or MUSHROOM_HELMET_PLUMP).\n" - "Only shrubs and saplings can be placed, and they must be located on a dirt or grass floor.\n"); - return CR_OK; + return CR_WRONG_USAGE; } CoreSuspender suspend; @@ -201,10 +194,10 @@ command_result df_plant (color_ostream &out, vector & parameters) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand("plant", "Plant creation and removal.", df_plant, false, - "Command to create, grow or remove plants on the map. For more details, check the subcommand help :\n" - "plant grow help - Grows saplings into trees.\n" - "plant create help - Create a new plant.\n")); + commands.push_back(PluginCommand( + "plant", + "Grow shrubs or trees.", + df_plant)); return CR_OK; } diff --git a/plugins/probe.cpp b/plugins/probe.cpp index ba7c42ede..b9b98ee75 100644 --- a/plugins/probe.cpp +++ b/plugins/probe.cpp @@ -49,20 +49,14 @@ command_result df_bprobe (color_ostream &out, vector & parameters); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand("probe", - "A tile probe", - df_probe, - false, - "Hover the cursor over a tile to view its properties.\n")); + "Display information about the selected tile.", + df_probe)); commands.push_back(PluginCommand("cprobe", - "A creature probe", - df_cprobe, - false, - "Select a creature to view its properties.\n")); + "Display information about the selected creature.", + df_cprobe)); commands.push_back(PluginCommand("bprobe", - "A simple building probe", - df_bprobe, - false, - "Select a building to view its properties.\n")); + "Display information about the selected building.", + df_bprobe)); return CR_OK; } diff --git a/plugins/prospector.cpp b/plugins/prospector.cpp index 0516dd552..e75c967dc 100644 --- a/plugins/prospector.cpp +++ b/plugins/prospector.cpp @@ -260,46 +260,9 @@ command_result prospector (color_ostream &out, vector & parameters); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "prospect", "Show stats of available raw resources.", - prospector, false, - " prospect [all|hell] []\n" - "\n" - " Shows a summary of resources that exist on the map. By default,\n" - " only the visible part of the map is scanned. Include the 'all' keyword\n" - " if you want prospect to scan the whole map as if it were revealed.\n" - " Use 'hell' instead of 'all' if you also want to see the Z range of HFS\n" - " tubes in the 'features' report section.\n" - "\n" - "Options:\n" - " -h,--help\n" - " Shows this help text.\n" - " -s,--show \n" - " Shows only the named comma-separated list of report sections.\n" - " Report section names are: summary, liquids, layers, features, ores,\n" - " gems, veins, shrubs, and trees. If run during pre-embark, only the\n" - " layers, ores, gems, and veins report sections are available.\n" - " -v,--values\n" - " Includes material value in the output. Most useful for the 'gems'\n" - " report section.\n" - "\n" - "Examples:\n" - " prospect all\n" - " Shows the entire report for the entire map.\n" - "\n" - " prospect hell --show layers,ores,veins\n" - " Shows only the layers, ores, and other vein stone report sections,\n" - " and includes information on HFS tubes when a fort is loaded.\n" - "\n" - " prospect all -sores\n" - " Show only information about ores for the pre-embark or fortress map\n" - " report.\n" - "\n" - "Pre-embark estimate:\n" - " If called during the embark selection screen, displays a rough\n" - " estimate of layer stone availability. If the 'all' keyword is\n" - " specified, also estimates ores, gems, and other vein material. The\n" - " estimate covers all tiles of the embark rectangle.\n" - )); + "prospect", + "Show raw resources available on the map.", + prospector)); return CR_OK; } diff --git a/plugins/regrass.cpp b/plugins/regrass.cpp index 0cac5bd77..5d2a6450c 100644 --- a/plugins/regrass.cpp +++ b/plugins/regrass.cpp @@ -29,8 +29,10 @@ command_result df_regrass (color_ostream &out, vector & parameters); DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand("regrass", "Regrows surface grass.", df_regrass, false, - "Specify parameter 'max' to set all grass types to full density, otherwise only one type of grass will be restored per tile.\n")); + commands.push_back(PluginCommand( + "regrass", + "Regrows surface grass.", + df_regrass)); return CR_OK; } diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 9ab9a7502..643e92b21 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -221,12 +221,14 @@ DFHACK_PLUGIN_IS_ENABLED(enableUpdates); // Mandatory init function. If you have some global state, create it here. DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand("RemoteFortressReader_version", "List the loaded RemoteFortressReader version", RemoteFortressReader_version, false, "This is used for plugin version checking.")); + commands.push_back(PluginCommand( + "RemoteFortressReader_version", + "List the loaded RemoteFortressReader version", + RemoteFortressReader_version)); commands.push_back(PluginCommand( "load-art-image-chunk", "Gets an art image chunk by index, loading from disk if necessary", - loadArtImageChunk, false, - "Usage: load_art_image_chunk N, where N is the id of the chunk to get.")); + loadArtImageChunk)); enableUpdates = true; return CR_OK; } diff --git a/plugins/rename.cpp b/plugins/rename.cpp index 0ef3e02d5..7c46fc908 100644 --- a/plugins/rename.cpp +++ b/plugins/rename.cpp @@ -61,16 +61,9 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector \"name\"\n" - " rename hotkey \"name\"\n" - " (identified by ordinal index)\n" - " rename unit \"nickname\"\n" - " rename unit-profession \"custom profession\"\n" - " (a unit must be highlighted in the ui)\n" - " rename building \"nickname\"\n" - " (a building must be highlighted via 'q')\n" - )); + "rename", + "Easily rename things.", + rename)); if (Core::getInstance().isWorldLoaded()) plugin_onstatechange(out, SC_WORLD_LOADED); diff --git a/plugins/rendermax/rendermax.cpp b/plugins/rendermax/rendermax.cpp index d391bdb36..b7c703e09 100644 --- a/plugins/rendermax/rendermax.cpp +++ b/plugins/rendermax/rendermax.cpp @@ -49,16 +49,9 @@ static command_result rendermax(color_ostream &out, vector & parameters DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "rendermax", "switch rendering engine.", rendermax, false, - " rendermax trippy\n" - " rendermax truecolor red|green|blue|white\n" - " rendermax lua\n" - " rendermax light - lighting engine\n" - " rendermax light reload - reload the settings file\n" - " rendermax light sun |cycle - set time to x (in hours) or cycle (same effect if x<0)\n" - " rendermax light occlusionON|occlusionOFF - debug the occlusion map\n" - " rendermax disable\n" - )); + "rendermax", + "Modify the map lighting.", + rendermax)); return CR_OK; } @@ -331,7 +324,7 @@ static command_result rendermax(color_ostream &out, vector & parameters return CR_WRONG_USAGE; if(!enabler->renderer->uses_opengl()) { - out.printerr("Sorry, this plugin needs open gl enabled printmode. Try STANDARD or other non-2D\n"); + out.printerr("Sorry, this plugin needs open GL-enabled printmode. Try STANDARD or other non-2D.\n"); return CR_FAILURE; } string cmd=parameters[0]; diff --git a/plugins/resume.cpp b/plugins/resume.cpp index 6b8ad5e7d..21a4b521e 100644 --- a/plugins/resume.cpp +++ b/plugins/resume.cpp @@ -302,18 +302,9 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector & params); DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) { - commands.push_back(PluginCommand("reveal","Reveal the map.",reveal,false, - "Reveals the map, by default ignoring hell.\n" - "Options:\n" - "hell - also reveal hell, while forcing the game to pause.\n" - "demon - reveal hell, do not pause.\n")); - commands.push_back(PluginCommand("unreveal","Revert the map to its previous state.",unreveal,false, - "Reverts the previous reveal operation, hiding the map again.\n")); - commands.push_back(PluginCommand("revtoggle","Reveal/unreveal depending on state.",revtoggle,false, - "Toggles between reveal and unreveal.\n")); - commands.push_back(PluginCommand("revflood","Hide all, and reveal tiles reachable from the cursor.",revflood,false, - "This command hides the whole map. Then, starting from the cursor,\n" - "reveals all accessible tiles. Allows repairing perma-revealed maps.\n" - "Note that constructed walls are considered passable to work around DF bug 1871.\n")); - commands.push_back(PluginCommand("revforget", "Forget the current reveal data.",revforget,false, - "Forget the current reveal data, allowing to use reveal again.\n")); - commands.push_back(PluginCommand("nopause","Disable manual and automatic pausing.",nopause,false, - "Disable pausing (doesn't affect pause forced by reveal).\n" - "Activate with 'nopause 1', deactivate with 'nopause 0'.\n")); + commands.push_back(PluginCommand( + "reveal", + "Reveal the map.", + reveal)); + commands.push_back(PluginCommand( + "unreveal", + "Revert a revealed map to its unrevealed state.", + unreveal)); + commands.push_back(PluginCommand( + "revtoggle", + "Switch betwen reveal and unreveal.", + revtoggle)); + commands.push_back(PluginCommand( + "revflood", + "Hide all, then reveal tiles reachable from the cursor.", + revflood)); + commands.push_back(PluginCommand( + "revforget", + "Forget the current reveal data.", + revforget)); + commands.push_back(PluginCommand( + "nopause", + "Disable manual and automatic pausing.", + nopause)); return CR_OK; } diff --git a/plugins/seedwatch.cpp b/plugins/seedwatch.cpp index 65b89cfa1..13ed8e66e 100644 --- a/plugins/seedwatch.cpp +++ b/plugins/seedwatch.cpp @@ -49,47 +49,6 @@ bool ignoreSeeds(df::item_flags& f) // seeds with the following flags should not f.bits.in_job; }; -void printHelp(color_ostream &out) // prints help -{ - out.print( - "Watches the numbers of seeds available and enables/disables seed and plant cooking.\n" - "Each plant type can be assigned a limit. If their number falls below,\n" - "the plants and seeds of that type will be excluded from cookery.\n" - "If the number rises above the limit + %i, then cooking will be allowed.\n", buffer - ); - out.printerr( - "The plugin needs a fortress to be loaded and will deactivate automatically otherwise.\n" - "You have to reactivate with 'seedwatch start' after you load the game.\n" - ); - out.print( - "Options:\n" - "seedwatch all - Adds all plants from the abbreviation list to the watch list.\n" - "seedwatch start - Start watching.\n" - "seedwatch stop - Stop watching.\n" - "seedwatch info - Display whether seedwatch is watching, and the watch list.\n" - "seedwatch clear - Clears the watch list.\n\n" - ); - if(!abbreviations.empty()) - { - out.print("You can use these abbreviations for the plant tokens:\n"); - for(map::const_iterator i = abbreviations.begin(); i != abbreviations.end(); ++i) - { - out.print("%s -> %s\n", i->first.c_str(), i->second.c_str()); - } - } - out.print( - "Examples:\n" - "seedwatch MUSHROOM_HELMET_PLUMP 30\n" - " add MUSHROOM_HELMET_PLUMP to the watch list, limit = 30\n" - "seedwatch MUSHROOM_HELMET_PLUMP\n" - " removes MUSHROOM_HELMET_PLUMP from the watch list.\n" - "seedwatch ph 30\n" - " is the same as 'seedwatch MUSHROOM_HELMET_PLUMP 30'\n" - "seedwatch all 30\n" - " adds all plants from the abbreviation list to the watch list, the limit being 30.\n" - ); -}; - // searches abbreviations, returns expansion if so, returns original if not string searchAbbreviations(string in) { @@ -144,8 +103,7 @@ command_result df_seedwatch(color_ostream &out, vector& parameters) if(gm.g_mode != game_mode::DWARF || !World::isFortressMode(gm.g_type)) { // just print the help - printHelp(out); - return CR_OK; + return CR_WRONG_USAGE; } string par; @@ -153,14 +111,12 @@ command_result df_seedwatch(color_ostream &out, vector& parameters) switch(parameters.size()) { case 0: - printHelp(out); return CR_WRONG_USAGE; case 1: par = parameters[0]; if ((par == "help") || (par == "?")) { - printHelp(out); return CR_WRONG_USAGE; } else if(par == "start") @@ -182,11 +138,11 @@ command_result df_seedwatch(color_ostream &out, vector& parameters) out.print("seedwatch Info:\n"); if(running) { - out.print("seedwatch is supervising. Use 'seedwatch stop' to stop supervision.\n"); + out.print("seedwatch is supervising. Use 'disable seedwatch' to stop supervision.\n"); } else { - out.print("seedwatch is not supervising. Use 'seedwatch start' to start supervision.\n"); + out.print("seedwatch is not supervising. Use 'enable seedwatch' to start supervision.\n"); } map watchMap; Kitchen::fillWatchMap(watchMap); @@ -246,7 +202,6 @@ command_result df_seedwatch(color_ostream &out, vector& parameters) } break; default: - printHelp(out); return CR_WRONG_USAGE; break; } @@ -256,7 +211,10 @@ command_result df_seedwatch(color_ostream &out, vector& parameters) DFhackCExport command_result plugin_init(color_ostream &out, vector& commands) { - commands.push_back(PluginCommand("seedwatch", "Toggles seed cooking based on quantity available", df_seedwatch)); + commands.push_back(PluginCommand( + "seedwatch", + "Toggles seed cooking based on quantity available.", + df_seedwatch)); // fill in the abbreviations map, with abbreviations for the standard plants abbreviations["bs"] = "SLIVER_BARB"; abbreviations["bt"] = "TUBER_BLOATED"; diff --git a/plugins/showmood.cpp b/plugins/showmood.cpp index c7d620676..abeb2e98e 100644 --- a/plugins/showmood.cpp +++ b/plugins/showmood.cpp @@ -297,8 +297,10 @@ command_result df_showmood (color_ostream &out, vector & parameters) DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand("showmood", "Shows items needed for current strange mood.", df_showmood, false, - "Run this command without any parameters to display information on the currently active Strange Mood.")); + commands.push_back(PluginCommand( + "showmood", + "Shows all items needed for active strange mood.", + df_showmood)); return CR_OK; } diff --git a/plugins/sort.cpp b/plugins/sort.cpp index ab2829655..630ac9e53 100644 --- a/plugins/sort.cpp +++ b/plugins/sort.cpp @@ -56,25 +56,9 @@ static command_result sort_items(color_ostream &out, vector & parameter DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "sort-units", "Sort the visible unit list.", sort_units, unit_list_hotkey, - " sort-units order [order...]\n" - " Sort the unit list using the given sequence of comparisons.\n" - " The '<' prefix for an order makes undefined values sort first.\n" - " The '>' prefix reverses the sort order for defined values.\n" - " Unit order examples:\n" - " name, age, arrival, squad, squad_position, profession\n" - "The orderings are defined in hack/lua/plugins/sort/*.lua\n" - )); + "sort-units", "Sort the visible unit list.", sort_units, unit_list_hotkey)); commands.push_back(PluginCommand( - "sort-items", "Sort the visible item list.", sort_items, item_list_hotkey, - " sort-items order [order...]\n" - " Sort the item list using the given sequence of comparisons.\n" - " The '<' prefix for an order makes undefined values sort first.\n" - " The '>' prefix reverses the sort order for defined values.\n" - " Item order examples:\n" - " description, material, wear, type, quality\n" - "The orderings are defined in hack/lua/plugins/sort/*.lua\n" - )); + "sort-items", "Sort the visible item list.", sort_items, item_list_hotkey)); return CR_OK; } diff --git a/plugins/spectate.cpp b/plugins/spectate.cpp index aae48cf5a..1161c3f32 100644 --- a/plugins/spectate.cpp +++ b/plugins/spectate.cpp @@ -42,12 +42,7 @@ command_result spectate (color_ostream &out, std::vector & paramet DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand("spectate", "Automated spectator mode.", - spectate, - false, - "" - " spectate\n" - " toggles spectator mode\n" - "\n")); + spectate)); return CR_OK; } diff --git a/plugins/steam-engine.cpp b/plugins/steam-engine.cpp index fbc575e36..6e3c317d3 100644 --- a/plugins/steam-engine.cpp +++ b/plugins/steam-engine.cpp @@ -37,82 +37,6 @@ #include "df/workshop_type.h" #include "df/world.h" -/* - * This plugin implements a steam engine workshop. It activates - * if there are any workshops in the raws with STEAM_ENGINE in - * their token, and provides the necessary behavior. - * - * Construction: - * - * The workshop needs water as its input, which it takes via a - * passable floor tile below it, like usual magma workshops do. - * The magma version also needs magma. - * - * ISSUE: Since this building is a machine, and machine collapse - * code cannot be modified, it would collapse over true open space. - * As a loophole, down stair provides support to machines, while - * being passable, so use them. - * - * After constructing the building itself, machines can be connected - * to the edge tiles that look like gear boxes. Their exact position - * is extracted from the workshop raws. - * - * ISSUE: Like with collapse above, part of the code involved in - * machine connection cannot be modified. As a result, the workshop - * can only immediately connect to machine components built AFTER it. - * This also means that engines cannot be chained without intermediate - * short axles that can be built later. - * - * Operation: - * - * In order to operate the engine, queue the Stoke Boiler job. - * A furnace operator will come, possibly bringing a bar of fuel, - * and perform it. As a result, a "boiling water" item will appear - * in the 't' view of the workshop. - * - * Note: The completion of the job will actually consume one unit - * of appropriate liquids from below the workshop. - * - * Every such item gives 100 power, up to a limit of 300 for coal, - * and 500 for a magma engine. The building can host twice that - * amount of items to provide longer autonomous running. When the - * boiler gets filled to capacity, all queued jobs are suspended; - * once it drops back to 3+1 or 5+1 items, they are re-enabled. - * - * While the engine is providing power, steam is being consumed. - * The consumption speed includes a fixed 10% waste rate, and - * the remaining 90% are applied proportionally to the actual - * load in the machine. With the engine at nominal 300 power with - * 150 load in the system, it will consume steam for actual - * 300*(10% + 90%*150/300) = 165 power. - * - * Masterpiece mechanism and chain will decrease the mechanical - * power drawn by the engine itself from 10 to 5. Masterpiece - * barrel decreases waste rate by 4%. Masterpiece piston and pipe - * decrease it by further 4%, and also decrease the whole steam - * use rate by 10%. - * - * Explosions: - * - * The engine must be constructed using barrel, pipe and piston - * from fire-safe, or in the magma version magma-safe metals. - * - * During operation weak parts get gradually worn out, and - * eventually the engine explodes. It should also explode if - * toppled during operation by a building destroyer, or a - * tantruming dwarf. - * - * Save files: - * - * It should be safe to load and view fortresses using engines - * from a DF version without DFHack installed, except that in such - * case the engines won't work. However actually making modifications - * to them, or machines they connect to (including by pulling levers), - * can easily result in inconsistent state once this plugin is - * available again. The effects may be as weird as negative power - * being generated. - */ - using std::vector; using std::string; using std::stack; diff --git a/plugins/stockflow.cpp b/plugins/stockflow.cpp index aede089ad..65223f603 100644 --- a/plugins/stockflow.cpp +++ b/plugins/stockflow.cpp @@ -29,30 +29,6 @@ REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(ui); bool fast = false; -const char *tagline = "Allow the bookkeeper to queue manager jobs."; -const char *usage = ( - " stockflow enable\n" - " Enable the plugin.\n" - " stockflow disable\n" - " Disable the plugin.\n" - " stockflow fast\n" - " Enable the plugin in fast mode.\n" - " stockflow list\n" - " List any work order settings for your stockpiles.\n" - " stockflow status\n" - " Display whether the plugin is enabled.\n" - "\n" - "While enabled, the 'q' menu of each stockpile will have two new options:\n" - " j: Select a job to order, from an interface like the manager's screen.\n" - " J: Cycle between several options for how many such jobs to order.\n" - "\n" - "Whenever the bookkeeper updates stockpile records, new work orders will\n" - "be placed on the manager's queue for each such selection, reduced by the\n" - "number of identical orders already in the queue.\n" - "\n" - "In fast mode, new work orders will be enqueued once per day, instead of\n" - "waiting for the bookkeeper.\n" -); /* * Lua interface. @@ -342,8 +318,7 @@ static command_result stockflow_cmd(color_ostream &out, vector & parame desired = true; fast = true; } else if (parameters[0] == "usage" || parameters[0] == "help" || parameters[0] == "?") { - out.print("%s: %s\nUsage:\n%s", plugin_name, tagline, usage); - return CR_OK; + return CR_WRONG_USAGE; } else if (parameters[0] == "list") { if (!enabled) { out.printerr("Stockflow is not currently enabled.\n"); @@ -416,7 +391,10 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector : filename to save stockpile settings to (will be overwritten!)\n" - ) - ); - commands.push_back ( - PluginCommand ( - "loadstock", "Load and apply stockpile settings from a file.", - loadstock, loadstock_guard, - "Must be in 'q' mode and have a stockpile selected.\n" - "example: 'loadstock food.dfstock' will load the settings from 'food.dfstock'\n" - "in your stockpile folder and apply them to the selected stockpile.\n" - " -d, --debug: enable debug output\n" - " : filename to load stockpile settings from\n" - ) - ); + commands.push_back(PluginCommand( + "copystock", + "Copy stockpile under cursor.", + copystock, + copystock_guard)); + commands.push_back(PluginCommand( + "savestock", + "Save the active stockpile's settings to a file.", + savestock, + savestock_guard)); + commands.push_back(PluginCommand( + "loadstock", + "Load and apply stockpile settings from a file.", + loadstock, + loadstock_guard)); } return CR_OK; diff --git a/plugins/stocks.cpp b/plugins/stocks.cpp index 7c715d956..62c13dcd5 100644 --- a/plugins/stocks.cpp +++ b/plugins/stocks.cpp @@ -1469,10 +1469,10 @@ static command_result stocks_cmd(color_ostream &out, vector & parameter DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { - commands.push_back( - PluginCommand( - "stocks", "An improved stocks display screen", - stocks_cmd, false, "Run 'stocks show' open the stocks display screen, or 'stocks version' to query the plugin version.")); + commands.push_back(PluginCommand( + "stocks", + "An improved stocks management screen.", + stocks_cmd)); ViewscreenStocks::reset(); diff --git a/plugins/strangemood.cpp b/plugins/strangemood.cpp index de7fa426d..a5b8e74a4 100644 --- a/plugins/strangemood.cpp +++ b/plugins/strangemood.cpp @@ -1234,16 +1234,10 @@ command_result df_strangemood (color_ostream &out, vector & parameters) DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand("strangemood", "Force a strange mood to happen.", df_strangemood, false, - "Options:\n" - " -force - Ignore standard mood preconditions.\n" - " -unit - Use the selected unit instead of picking one randomly.\n" - " -type - Force the mood to be of a specific type.\n" - " Valid types: fey, secretive, possessed, fell, macabre\n" - " -skill - Force the mood to use a specific skill.\n" - " Skill name must be lowercase and without spaces.\n" - " Example: miner, gemcutter, metalcrafter, bonecarver, mason\n" - )); + commands.push_back(PluginCommand( + "strangemood", + "Trigger a strange mood.", + df_strangemood)); rng.init(); return CR_OK; diff --git a/plugins/tailor.cpp b/plugins/tailor.cpp index a48bea2c6..bd11988d0 100644 --- a/plugins/tailor.cpp +++ b/plugins/tailor.cpp @@ -41,26 +41,6 @@ DFHACK_PLUGIN_IS_ENABLED(enabled); REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(ui); -const char* tagline = "Allow the bookkeeper to queue jobs to keep dwarfs in adequate clothing."; -const char* usage = ( - " tailor enable\n" - " Enable the plugin.\n" - " tailor disable\n" - " Disable the plugin.\n" - " tailor status\n" - " Display plugin status\n" - " tailor materials ...\n" - " for example: tailor materials silk cloth yarn leather\n" - " Set allowed material list to the specified list.\n" - " The example sets the list to silk, cloth, yarn, leather, in that order, which is the default.\n" - "\n" - "Whenever the bookkeeper updates stockpile records, this plugin will scan every unit in the fort,\n" - "count up the number that are worn, and then order enough more made to replace all worn items.\n" - "If there are enough replacement items in inventory to replace all worn items, the units wearing them\n" - "will have the worn items confiscated (in the same manner as the _cleanowned_ plugin) so that they'll\n" - "reeequip with replacement items.\n" - ); - class Tailor { // ARMOR, SHOES, HELM, GLOVES, PANTS @@ -581,8 +561,7 @@ static command_result tailor_cmd(color_ostream& out, vector & parameters } else if (parameters.size() == 1 && (parameters[0] == "usage" || parameters[0] == "help" || parameters[0] == "?")) { - out.print("%s: %s\nUsage:\n%s", plugin_name, tagline, usage); - return CR_OK; + return CR_WRONG_USAGE; } else if (parameters.size() == 1 && parameters[0] == "test") { @@ -649,7 +628,10 @@ DFhackCExport command_result plugin_init(color_ostream& out, std::vector & pa DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { tiletypes_hist.load(HISTORY_FILE); - commands.push_back(PluginCommand("tiletypes", "Paint map tiles freely, similar to liquids.", df_tiletypes, true)); + commands.push_back(PluginCommand("tiletypes", "Paints tiles of specified types onto the map.", df_tiletypes, true)); commands.push_back(PluginCommand("tiletypes-command", "Run tiletypes commands (seperated by ' ; ')", df_tiletypes_command)); commands.push_back(PluginCommand("tiletypes-here", "Repeat tiletypes command at cursor (with brush)", df_tiletypes_here)); - commands.push_back(PluginCommand("tiletypes-here-point", "Repeat tiletypes command at cursor (without brush)", df_tiletypes_here_point)); + commands.push_back(PluginCommand("tiletypes-here-point", "Repeat tiletypes command at cursor (with single tile brush)", df_tiletypes_here_point)); return CR_OK; } @@ -1000,11 +1000,7 @@ command_result df_tiletypes (color_ostream &out_, vector & parameters) { if(parameters[i] == "help" || parameters[i] == "?") { - out_.print("This tool allows painting tiles types with a brush, using an optional filter.\n" - "The tool is interactive, similarly to the liquids tool.\n" - "Further help is available inside.\n" - ); - return CR_OK; + return CR_WRONG_USAGE; } } diff --git a/plugins/tubefill.cpp b/plugins/tubefill.cpp index 1803ed520..f86e77c76 100644 --- a/plugins/tubefill.cpp +++ b/plugins/tubefill.cpp @@ -40,9 +40,10 @@ command_result tubefill(color_ostream &out, std::vector & params); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand("tubefill","Fill in all the adamantine tubes again.",tubefill, false, - "Replenishes mined out adamantine but does not fill hollow adamantine tubes.\n" - "Specify 'hollow' to fill hollow tubes, but beware glitchy HFS spawns.\n")); + commands.push_back(PluginCommand( + "tubefill", + "Replentishes mined-out adamantine.", + tubefill)); return CR_OK; } diff --git a/plugins/tweak/tweak.cpp b/plugins/tweak/tweak.cpp index 38ece6970..6d2a46fa8 100644 --- a/plugins/tweak/tweak.cpp +++ b/plugins/tweak/tweak.cpp @@ -23,7 +23,6 @@ #include "../uicommon.h" #include "df/ui.h" #include "df/world.h" -#include "df/squad.h" #include "df/unit.h" #include "df/unit_soul.h" #include "df/historical_entity.h" @@ -37,7 +36,6 @@ #include "df/viewscreen_dwarfmodest.h" #include "df/viewscreen_kitchenprefst.h" #include "df/viewscreen_layer_unit_actionst.h" -#include "df/squad_order_trainst.h" #include "df/ui_build_selector.h" #include "df/ui_sidebar_menus.h" #include "df/building_trapst.h" @@ -67,17 +65,10 @@ #include "df/viewscreen_layer_assigntradest.h" #include "df/viewscreen_tradegoodsst.h" #include "df/viewscreen_layer_militaryst.h" -#include "df/squad_position.h" #include "df/job.h" #include "df/general_ref_building_holderst.h" #include "df/unit_health_info.h" #include "df/caste_body_info.h" -#include "df/activity_entry.h" -#include "df/activity_event_combat_trainingst.h" -#include "df/activity_event_individual_skill_drillst.h" -#include "df/activity_event_skill_demonstrationst.h" -#include "df/activity_event_sparringst.h" -//#include "df/building_hivest.h" #include #include @@ -162,113 +153,9 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector \n" - " Further improves temperature updates by ensuring that 1 degree of\n" - " item temperature is crossed in no more than specified number of frames\n" - " when updating from the environment temperature. Use 0 to disable.\n" - " tweak fast-trade [disable]\n" - " Makes Shift-Enter in the Move Goods to Depot and Trade screens select\n" - " the current item (fully, in case of a stack), and scroll down one line.\n" - " tweak fps-min [disable]\n" - " Fixes the in-game minimum FPS setting (bug 6277)\n" - " tweak hide-priority [disable]\n" - " Adds an option to hide designation priority indicators\n" - " tweak hotkey-clear [disable] \n" - " Adds an option to clear currently-bound hotkeys\n" - " tweak import-priority-category [disable]\n" - " When meeting with a liaison, makes Shift+Left/Right arrow adjust\n" - " the priority of an entire category of imports.\n" - " tweak kitchen-prefs-all [disable]\n" - " Adds an option to toggle cook/brew for all visible items in\n" - " kitchen preferences\n" - " tweak kitchen-prefs-color [disable]\n" - " Changes color of enabled items to green in kitchen preferences\n" - " tweak kitchen-prefs-empty [disable]\n" - " Fixes a layout issue with empty kitchen tabs (bug 9000)\n" - " tweak max-wheelbarrow [disable]\n" - " Allows assigning more than 3 wheelbarrows to a stockpile\n" - " tweak nestbox-color [disable]\n" - " Makes built nestboxes use the color of their material\n" - " tweak military-color-assigned [disable]\n" - " Color squad candidates already assigned to other squads in brown/green\n" - " to make them stand out more in the list.\n" - " tweak military-stable-assign [disable]\n" - " Preserve list order and cursor position when assigning to squad,\n" - " i.e. stop the rightmost list of the Positions page of the military\n" - " screen from constantly jumping to the top.\n" - " tweak partial-items [disable]\n" - " Displays percentages on partially-consumed items such as hospital cloth\n" - " tweak pausing-fps-counter [disable]\n" - " Replace fortress mode FPS counter with one that stops counting \n" - " when paused.\n" - " tweak reaction-gloves [disable]\n" - " Changes custom reactions to produce gloves in sets with correct handedness\n" - " tweak shift-8-scroll [disable]\n" - " Gives Shift+8 (or *) priority when scrolling menus, instead of \n" - " scrolling the map\n" - " tweak stone-status-all [disable]\n" - " Adds an option to toggle the economic status of all stones\n" - " tweak title-start-rename [disable]\n" - " Adds a safe rename option to the title screen \"Start Playing\" menu\n" - " tweak tradereq-pet-gender [disable]\n" - " Displays the gender of pets in the trade request list\n" - // sort these alphabetically -// " tweak military-training [disable]\n" -// " Speed up melee squad training, removing inverse dependency on unit count.\n" - )); + "tweak", + "Various tweaks for minor bugs.", + tweak)); TWEAK_HOOK("adamantine-cloth-wear", adamantine_cloth_wear_armor_hook, incWearTimer); TWEAK_HOOK("adamantine-cloth-wear", adamantine_cloth_wear_helm_hook, incWearTimer); @@ -438,339 +325,6 @@ command_result fix_clothing_ownership(color_ostream &out, df::unit* unit) return CR_OK; } -static void correct_dimension(df::item_actual *self, int32_t &delta, int32_t dim) -{ - // Zero dimension or remainder? - if (dim <= 0 || self->stack_size <= 1) return; - int rem = delta % dim; - if (rem == 0) return; - // If destroys, pass through - int intv = delta / dim; - if (intv >= self->stack_size) return; - // Subtract int part - delta = rem; - self->stack_size -= intv; - if (self->stack_size <= 1) return; - - // If kills the item or cannot split, round up. - if (!self->flags.bits.in_inventory || !Items::getContainer(self)) - { - delta = dim; - return; - } - - // Otherwise split the stack - color_ostream_proxy out(Core::getInstance().getConsole()); - out.print("fix-dimensions: splitting stack #%d for delta %d.\n", self->id, delta); - - auto copy = self->splitStack(self->stack_size-1, true); - if (copy) copy->categorize(true); -} - -struct dimension_liquid_hook : df::item_liquid_miscst { - typedef df::item_liquid_miscst interpose_base; - - DEFINE_VMETHOD_INTERPOSE(bool, subtractDimension, (int32_t delta)) - { - correct_dimension(this, delta, dimension); - return INTERPOSE_NEXT(subtractDimension)(delta); - } -}; - -IMPLEMENT_VMETHOD_INTERPOSE(dimension_liquid_hook, subtractDimension); - -struct dimension_powder_hook : df::item_powder_miscst { - typedef df::item_powder_miscst interpose_base; - - DEFINE_VMETHOD_INTERPOSE(bool, subtractDimension, (int32_t delta)) - { - correct_dimension(this, delta, dimension); - return INTERPOSE_NEXT(subtractDimension)(delta); - } -}; - -IMPLEMENT_VMETHOD_INTERPOSE(dimension_powder_hook, subtractDimension); - -struct dimension_bar_hook : df::item_barst { - typedef df::item_barst interpose_base; - - DEFINE_VMETHOD_INTERPOSE(bool, subtractDimension, (int32_t delta)) - { - correct_dimension(this, delta, dimension); - return INTERPOSE_NEXT(subtractDimension)(delta); - } -}; - -IMPLEMENT_VMETHOD_INTERPOSE(dimension_bar_hook, subtractDimension); - -struct dimension_thread_hook : df::item_threadst { - typedef df::item_threadst interpose_base; - - DEFINE_VMETHOD_INTERPOSE(bool, subtractDimension, (int32_t delta)) - { - correct_dimension(this, delta, dimension); - return INTERPOSE_NEXT(subtractDimension)(delta); - } -}; - -IMPLEMENT_VMETHOD_INTERPOSE(dimension_thread_hook, subtractDimension); - -struct dimension_cloth_hook : df::item_clothst { - typedef df::item_clothst interpose_base; - - DEFINE_VMETHOD_INTERPOSE(bool, subtractDimension, (int32_t delta)) - { - correct_dimension(this, delta, dimension); - return INTERPOSE_NEXT(subtractDimension)(delta); - } -}; - -IMPLEMENT_VMETHOD_INTERPOSE(dimension_cloth_hook, subtractDimension); - -/* -// Unit updates are executed based on an action divisor variable, -// which is computed from the alive unit count and has range 10-100. -static int adjust_unit_divisor(int value) { - return value*10/DF_GLOBAL_FIELD(ui, unit_action_divisor, 10); -} - -static bool can_spar(df::unit *unit) { - return unit->counters2.exhaustion <= 2000 && // actually 4000, but leave a gap - (unit->status2.limbs_grasp_count > 0 || unit->status2.limbs_grasp_max == 0) && - (!unit->health || (unit->health->flags.whole&0x7FF) == 0) && - (!unit->job.current_job || unit->job.current_job->job_type != job_type::Rest); -} - -static bool has_spar_inventory(df::unit *unit, df::job_skill skill) -{ - using namespace df::enums::job_skill; - - auto type = ENUM_ATTR(job_skill, type, skill); - - if (type == job_skill_class::MilitaryWeapon) - { - for (size_t i = 0; i < unit->inventory.size(); i++) - { - auto item = unit->inventory[i]; - if (item->mode == df::unit_inventory_item::Weapon && - item->item->getMeleeSkill() == skill) - return true; - } - - return false; - } - - switch (skill) { - case THROW: - case RANGED_COMBAT: - return false; - - case SHIELD: - for (size_t i = 0; i < unit->inventory.size(); i++) - { - auto item = unit->inventory[i]; - if (item->mode == df::unit_inventory_item::Weapon && - item->item->getType() == item_type::SHIELD) - return true; - } - return false; - - case ARMOR: - for (size_t i = 0; i < unit->inventory.size(); i++) - { - auto item = unit->inventory[i]; - if (item->mode == df::unit_inventory_item::Worn && - item->item->isArmorNotClothing()) - return true; - } - return false; - - default: - return true; - } -} - -struct military_training_ct_hook : df::activity_event_combat_trainingst { - typedef df::activity_event_combat_trainingst interpose_base; - - DEFINE_VMETHOD_INTERPOSE(void, process, (df::unit *unit)) - { - auto act = df::activity_entry::find(activity_id); - int cur_neid = act ? act->next_event_id : 0; - int cur_oc = organize_counter; - - INTERPOSE_NEXT(process)(unit); - - // Shorten the time it takes to organize stuff, so that in - // reality it remains the same instead of growing proportionally - // to the unit count. - if (organize_counter > cur_oc && organize_counter > 0) - organize_counter = adjust_unit_divisor(organize_counter); - - if (act && act->next_event_id > cur_neid) - { - // New events were added. Check them. - for (size_t i = 0; i < act->events.size(); i++) - { - auto event = act->events[i]; - if (event->flags.bits.dismissed || event->event_id < cur_neid) - continue; - - if (auto sp = strict_virtual_cast(event)) - { - // Sparring has a problem in that all of its participants decrement - // the countdown variable. Fix this by multiplying it by the member count. - sp->countdown = sp->countdown * sp->participants.units.size(); - } - else if (auto sd = strict_virtual_cast(event)) - { - // Adjust initial counter values - sd->train_countdown = adjust_unit_divisor(sd->train_countdown); - sd->wait_countdown = adjust_unit_divisor(sd->wait_countdown); - - // Check if the game selected the most skilled unit as the teacher - auto &units = sd->participants.units; - int maxv = -1, cur_xp = -1, minv = 0; - int best = -1; - size_t spar = 0; - - for (size_t j = 0; j < units.size(); j++) - { - auto unit = df::unit::find(units[j]); - if (!unit) continue; - int xp = Units::getExperience(unit, sd->skill, true); - if (units[j] == sd->unit_id) - cur_xp = xp; - if (j == 0 || xp < minv) - minv = xp; - if (xp > maxv) { - maxv = xp; - best = j; - } - if (can_spar(unit) && has_spar_inventory(unit, sd->skill)) - spar++; - } - -#if 0 - color_ostream_proxy out(Core::getInstance().getConsole()); -#endif - - // If the xp gap is low, sometimes replace with sparring - if ((maxv - minv) < 64*15 && spar == units.size() && - random_int(45) >= 30 + (maxv-minv)/64) - { -#if 0 - out.print("Replacing %s demonstration (xp %d-%d, gap %d) with sparring.\n", - ENUM_KEY_STR(job_skill, sd->skill).c_str(), minv, maxv, maxv-minv); -#endif - - if (auto spar = df::allocate()) - { - spar->event_id = sd->event_id; - spar->activity_id = sd->activity_id; - spar->parent_event_id = sd->parent_event_id; - spar->flags = sd->flags; - spar->participants = sd->participants; - spar->building_id = sd->building_id; - spar->countdown = 300*units.size(); - - delete sd; - act->events[i] = spar; - - continue; - } - } - - // If the teacher has less xp than somebody else, switch - if (best >= 0 && maxv > cur_xp) - { -#if 0 - out.print("Replacing %s teacher %d (%d xp) with %d (%d xp); xp gap %d.\n", - ENUM_KEY_STR(job_skill, sd->skill).c_str(), - sd->unit_id, cur_xp, units[best], maxv, maxv-minv); -#endif - - sd->hist_figure_id = sd->participants.histfigs[best]; - sd->unit_id = units[best]; - } - else - { -#if 0 - out.print("Not changing %s demonstration (xp %d-%d, gap %d).\n", - ENUM_KEY_STR(job_skill, sd->skill).c_str(), - minv, maxv, maxv-minv); -#endif - } - } - } - } - } -}; -*/ - -/* -IMPLEMENT_VMETHOD_INTERPOSE(military_training_ct_hook, process); - -struct military_training_sd_hook : df::activity_event_skill_demonstrationst { - typedef df::activity_event_skill_demonstrationst interpose_base; - - DEFINE_VMETHOD_INTERPOSE(void, process, (df::unit *unit)) - { - int cur_oc = organize_counter; - int cur_tc = train_countdown; - - INTERPOSE_NEXT(process)(unit); - - // Shorten the counters if they changed - if (organize_counter > cur_oc && organize_counter > 0) - organize_counter = adjust_unit_divisor(organize_counter); - if (train_countdown > cur_tc) - train_countdown = adjust_unit_divisor(train_countdown); - } -}; - -IMPLEMENT_VMETHOD_INTERPOSE(military_training_sd_hook, process); - -template -bool is_done(T *event, df::unit *unit) -{ - return event->flags.bits.dismissed || - binsearch_index(event->participants.units, unit->id) < 0; -} - -struct military_training_sp_hook : df::activity_event_sparringst { - typedef df::activity_event_sparringst interpose_base; - - DEFINE_VMETHOD_INTERPOSE(void, process, (df::unit *unit)) - { - INTERPOSE_NEXT(process)(unit); - - // Since there are no counters to fix, repeat the call - int cnt = (DF_GLOBAL_FIELD(ui, unit_action_divisor, 10)+5) / 10; - for (int i = 1; i < cnt && !is_done(this, unit); i++) - INTERPOSE_NEXT(process)(unit); - } -}; - -IMPLEMENT_VMETHOD_INTERPOSE(military_training_sp_hook, process); - -struct military_training_id_hook : df::activity_event_individual_skill_drillst { - typedef df::activity_event_individual_skill_drillst interpose_base; - - DEFINE_VMETHOD_INTERPOSE(void, process, (df::unit *unit)) - { - INTERPOSE_NEXT(process)(unit); - - // Since there are no counters to fix, repeat the call - int cnt = (DF_GLOBAL_FIELD(ui, unit_action_divisor, 10)+5) / 10; - for (int i = 1; i < cnt && !is_done(this, unit); i++) - INTERPOSE_NEXT(process)(unit); - } -}; - -IMPLEMENT_VMETHOD_INTERPOSE(military_training_id_hook, process); -*/ - static void enable_hook(color_ostream &out, VMethodInterposeLinkBase &hook, vector ¶meters) { if (vector_get(parameters, 1) == "disable") @@ -931,22 +485,6 @@ static command_result tweak(color_ostream &out, vector ¶meters) enable_tweak(cmd, out, parameters); return CR_OK; } - /*else if (cmd == "fix-dimensions") - { - enable_hook(out, INTERPOSE_HOOK(dimension_liquid_hook, subtractDimension), parameters); - enable_hook(out, INTERPOSE_HOOK(dimension_powder_hook, subtractDimension), parameters); - enable_hook(out, INTERPOSE_HOOK(dimension_bar_hook, subtractDimension), parameters); - enable_hook(out, INTERPOSE_HOOK(dimension_thread_hook, subtractDimension), parameters); - enable_hook(out, INTERPOSE_HOOK(dimension_cloth_hook, subtractDimension), parameters); - }*/ -/* - else if (cmd == "military-training") - { - enable_hook(out, INTERPOSE_HOOK(military_training_ct_hook, process), parameters); - enable_hook(out, INTERPOSE_HOOK(military_training_sd_hook, process), parameters); - enable_hook(out, INTERPOSE_HOOK(military_training_sp_hook, process), parameters); - enable_hook(out, INTERPOSE_HOOK(military_training_id_hook, process), parameters); - }*/ else { return enable_tweak(cmd, out, parameters); diff --git a/plugins/workNow.cpp b/plugins/workNow.cpp index ae76b09f3..2286fee7e 100644 --- a/plugins/workNow.cpp +++ b/plugins/workNow.cpp @@ -29,16 +29,10 @@ DFhackCExport command_result plugin_init(color_ostream& out, std::vector [cnt-gap]\n" - " workflow amount [cnt-gap]\n" - " Set a constraint. The first form counts each stack as only 1 item.\n" - " workflow unlimit \n" - " Delete a constraint.\n" - " workflow unlimit-all\n" - " Delete all constraints.\n" - "Function:\n" - " - When the plugin is enabled, it protects all repeat jobs from removal.\n" - " If they do disappear due to any cause, they are immediately re-added\n" - " to their workshop and suspended.\n" - " - In addition, when any constraints on item amounts are set, repeat jobs\n" - " that produce that kind of item are automatically suspended and resumed\n" - " as the item amount goes above or below the limit. The gap specifies how\n" - " much below the limit the amount has to drop before jobs are resumed;\n" - " this is intended to reduce the frequency of jobs being toggled.\n" - "Constraint format:\n" - " The contstraint spec consists of 4 parts, separated with '/' characters:\n" - " ITEM[:SUBTYPE]/[GENERIC_MAT,...]/[SPECIFIC_MAT:...]/[LOCAL,]\n" - " The first part is mandatory and specifies the item type and subtype,\n" - " using the raw tokens for items, in the same syntax you would e.g. use\n" - " for a custom reaction input. The subsequent parts are optional:\n" - " - A generic material spec constrains the item material to one of\n" - " the hard-coded generic classes, like WOOD, METAL, YARN or MILK.\n" - " - A specific material spec chooses the material exactly, using the\n" - " raw syntax for reaction input materials, e.g. INORGANIC:IRON,\n" - " although for convenience it also allows just IRON, or ACACIA:WOOD.\n" - " - A comma-separated list of miscellaneous flags, which currently can\n" - " be used to ignore imported items or items below a certain quality.\n" - "Constraint examples:\n" - " workflow amount AMMO:ITEM_AMMO_BOLTS/METAL 1000 100\n" - " workflow amount AMMO:ITEM_AMMO_BOLTS/WOOD,BONE 200 50\n" - " Keep metal bolts within 900-1000, and wood/bone within 150-200.\n" - " workflow count FOOD 120 30\n" - " workflow count DRINK 120 30\n" - " Keep the number of prepared food & drink stacks between 90 and 120\n" - " workflow count BIN 30\n" - " workflow count BARREL 30\n" - " workflow count BOX/CLOTH,SILK,YARN 30\n" - " Make sure there are always 25-30 empty bins/barrels/bags.\n" - " workflow count BAR//COAL 20\n" - " workflow count BAR//COPPER 30\n" - " Make sure there are always 15-20 coal and 25-30 copper bars.\n" - " workflow count CRAFTS//GOLD 20\n" - " Produce 15-20 gold crafts.\n" - " workflow count POWDER_MISC/SAND 20\n" - " workflow count BOULDER/CLAY 20\n" - " Collect 15-20 sand bags and clay boulders.\n" - " workflow amount POWDER_MISC//MUSHROOM_CUP_DIMPLE:MILL 100 20\n" - " Make sure there are always 80-100 units of dimple dye.\n" - " In order for this to work, you have to set the material of\n" - " the PLANT input on the Mill Plants job to MUSHROOM_CUP_DIMPLE\n" - " using the 'job item-material' command.\n" - " workflow count CRAFTS///LOCAL,EXCEPTIONAL 100 90\n" - " Maintain 10-100 locally-made crafts of exceptional quality.\n" - ) - ); + "workflow", + "Manage repeat jobs according to stock levels.", + workflow_cmd)); commands.push_back(PluginCommand( "fix-job-postings", - "Fix broken job postings caused by certain versions of workflow", - fix_job_postings_cmd, false, - "fix-job-postings: Fix job postings\n" - "fix-job-postings dry|[any argument]: Dry run only (avoid making changes)\n" - )); + "Fix broken job postings caused by very old versions of workflow.", + fix_job_postings_cmd)); } init_state(out); diff --git a/plugins/zone.cpp b/plugins/zone.cpp index 60f1f2b61..a3a0f2431 100644 --- a/plugins/zone.cpp +++ b/plugins/zone.cpp @@ -66,105 +66,6 @@ REQUIRE_GLOBAL(ui_building_in_assign); REQUIRE_GLOBAL(ui_menu_width); REQUIRE_GLOBAL(world); -static command_result df_zone (color_ostream &out, vector & parameters); - -const string zone_help = - "Allows easier management of pens/pastures, pits and cages.\n" - "Commands:\n" - " help - print this help message\n" - " filters - print list of supported filters\n" - " examples - print some usage examples\n" - " set - set zone under cursor as default for future assigns\n" - " assign - assign creature(s) to a pen or pit\n" - " if no filters are used, a single unit must be selected.\n" - " can be followed by valid building id which will then be set.\n" - " building must be a pen/pasture, pit or cage.\n" - " slaughter - mark creature(s) for slaughter\n" - " if no filters are used, a single unit must be selected.\n" - " 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" - " uinfo - print info about selected units\n" - " zinfo - print info about zone(s) under cursor\n" - "Options:\n" - " verbose - print some more info, mostly useless debug stuff\n" - ; - -const string zone_help_filters = - "Filters (to be used in combination with 'all' or 'count'):\n" - "Required (one of):\n" - " all - process all units\n" - " should be used in combination with further filters\n" - " count - must be followed by number. process X units\n" - " should be used in combination with further filters\n" - "Others (may be used with 'not' prefix):\n" - " age - exact age. must be followed by number\n" - " caged - in a built cage\n" - " egglayer - race lays eggs (use together with 'female')\n" - " female - obvious\n" - " grazer - is a grazer\n" - " male - obvious\n" - " maxage - maximum age. must be followed by number\n" - " merchant - is a merchant / belongs to a merchant\n" - " can be used to pit merchants and slaughter their animals\n" - " (could have weird effects during trading, be careful)\n" - " ('not merchant' is set by default)\n" - " milkable - race is milkable (use together with 'female')\n" - " minage - minimum age. must be followed by number\n" - " named - has name or nickname\n" - " ('not named' is set by default when using the 'slaughter' command)\n" - " own - from own civilization\n" - " race - must be followed by a race raw id (e.g. BIRD_TURKEY)\n" - " tame - tamed\n" - " trainablehunt- can be trained for hunting (and is not already trained)\n" - " trainablewar - can be trained for war (and is not already trained)\n" - " trained - obvious\n" - " unassigned - not assigned to zone, chain or built cage\n" - " war - trained war creature\n" - ; - -const string zone_help_examples = - "Example for assigning single units:\n" - " (ingame) move cursor to a pen/pasture or pit zone\n" - " (dfhack) 'zone set' to use this zone for future assignments\n" - " (dfhack) map 'zone assign' to a hotkey of your choice\n" - " (ingame) select unit with 'v', 'k' or from unit list or inside a cage\n" - " (ingame) press hotkey to assign unit to it's new home (or pit)\n" - "Examples for assigning with filters:\n" - " (this assumes you have already set up a target zone)\n" - " zone assign all own grazer maxage 10\n" - " zone assign all own milkable not grazer\n" - " zone assign count 5 own female milkable\n" - " zone assign all own race DWARF maxage 2\n" - " throw all useless kids into a pit :)\n" - "Notes:\n" - " Unassigning per filters ignores built cages and chains currently. Usually you\n" - " should always use the filter 'own' (which implies tame) unless you want to\n" - " use the zone tool for pitting hostiles. 'own' ignores own dwarves unless you\n" - " specify 'race DWARF' and it ignores merchants and their animals unless you\n" - " specify 'merchant' (so it's safe to use 'assign all own' to one big pasture\n" - " if you want to have all your animals at the same place).\n" - " 'egglayer' and 'milkable' should be used together with 'female'\n" - " well, unless you have a mod with egg-laying male elves who give milk...\n"; - - -/////////////// -// Various small tool functions -// probably many of these should be moved to Unit.h and Building.h sometime later... - -// static df::general_ref_building_civzone_assignedst * createCivzoneRef(); -// static bool unassignUnitFromBuilding(df::unit* unit); -// static command_result assignUnitToZone(color_ostream& out, df::unit* unit, df::building* building, bool verbose); -// static void unitInfo(color_ostream & out, df::unit* creature, bool verbose); -// static void zoneInfo(color_ostream & out, df::building* building, bool verbose); -// static void cageInfo(color_ostream & out, df::building* building, bool verbose); -// static void chainInfo(color_ostream & out, df::building* building, bool verbose); -static bool isInBuiltCageRoom(df::unit*); - static void doMarkForSlaughter(df::unit* unit) { unit->flags2.bits.slaughter = 1; @@ -184,6 +85,8 @@ static bool hasValidMapPos(df::unit* unit) return false; } +static bool isInBuiltCageRoom(df::unit*); + // dump some unit info static void unitInfo(color_ostream & out, df::unit* unit, bool verbose = false) { @@ -1127,8 +1030,7 @@ static struct zone_param_filters_init { zone_param_filters_init() { zone_param_filters["maxage"] = make_pair(1, createMaxAgeFilter); }} zone_param_filters_init_; -static command_result df_zone (color_ostream &out, vector & parameters) -{ +static command_result df_zone(color_ostream &out, vector & parameters) { CoreSuspender suspend; if (!Maps::IsValid()) @@ -1160,18 +1062,7 @@ static command_result df_zone (color_ostream &out, vector & parameters) if (p0 == "help" || p0 == "?") { - out << zone_help << endl; - return CR_OK; - } - if (p0 == "filters") - { - out << zone_help_filters << endl; - return CR_OK; - } - if (p0 == "examples") - { - out << zone_help_examples << endl; - return CR_OK; + return CR_WRONG_USAGE; } else if(p0 == "zinfo") { @@ -2275,13 +2166,8 @@ IMPLEMENT_VMETHOD_INTERPOSE(zone_hook, feed); IMPLEMENT_VMETHOD_INTERPOSE(zone_hook, render); //END zone filters -DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable) -{ - if (!gps) - return CR_FAILURE; - - if (enable != is_enabled) - { +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { + if (enable != is_enabled) { if (!INTERPOSE_HOOK(zone_hook, feed).apply(enable) || !INTERPOSE_HOOK(zone_hook, render).apply(enable)) return CR_FAILURE; @@ -2292,18 +2178,10 @@ DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable) return CR_OK; } -DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) -{ +DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( "zone", - "manage activity zones.", - df_zone, - false, - zone_help.c_str())); - return CR_OK; -} - -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ + "Manage activity zones.", + df_zone)); return CR_OK; } diff --git a/scripts b/scripts index f6c877881..8c89b0891 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit f6c8778817b760a0d53c6fc8a176679df7a6e660 +Subproject commit 8c89b08916a00b85d9bb476bf1855dcd8642a0f7 diff --git a/test/library/gui/widgets.EditField.lua b/test/library/gui/widgets.EditField.lua index 15acfddb0..23558987b 100644 --- a/test/library/gui/widgets.EditField.lua +++ b/test/library/gui/widgets.EditField.lua @@ -54,3 +54,18 @@ function test.editfield_click() expect.eq(3, e.cursor) end) end + +function test.editfield_ignore_keys() + local e = widgets.EditField{ignore_keys={'CUSTOM_B', 'CUSTOM_C'}} + e:setFocus(true) + + e:onInput{_STRING=string.byte('a'), CUSTOM_A=true} + expect.eq('a', e.text, '"a" should be accepted') + e:onInput{_STRING=string.byte('b'), CUSTOM_B=true} + expect.eq('a', e.text, '"b" should be rejected') + e:onInput{_STRING=string.byte('c'), CUSTOM_C=true} + expect.eq('a', e.text, '"c" should be rejected') + e:onInput{_STRING=string.byte('d'), CUSTOM_D=true} + expect.eq('ad', e.text, '"d" should be accepted') + +end diff --git a/test/library/gui/widgets.Label.lua b/test/library/gui/widgets.Label.lua index 6b0097d1e..c43b5e886 100644 --- a/test/library/gui/widgets.Label.lua +++ b/test/library/gui/widgets.Label.lua @@ -29,7 +29,7 @@ function test.correct_frame_body_with_scroll_icons() end local o = fs{} - expect.eq(o.subviews.text.frame_body.width, 9, "Label's frame_body.x2 and .width should be one smaller because of show_scroll_icons.") + expect.eq(o.subviews.text.frame_body.width, 9, "Label's frame_body.x2 and .width should be one smaller because of show_scrollbar.") end function test.correct_frame_body_with_few_text_lines() @@ -50,10 +50,10 @@ function test.correct_frame_body_with_few_text_lines() end local o = fs{} - expect.eq(o.subviews.text.frame_body.width, 10, "Label's frame_body.x2 and .width should not change with show_scroll_icons = false.") + expect.eq(o.subviews.text.frame_body.width, 10, "Label's frame_body.x2 and .width should not change with show_scrollbar = false.") end -function test.correct_frame_body_without_show_scroll_icons() +function test.correct_frame_body_without_show_scrollbar() local t = {} for i = 1, 12 do t[#t+1] = tostring(i) @@ -66,13 +66,13 @@ function test.correct_frame_body_without_show_scroll_icons() view_id = 'text', frame_inset = 0, text = t, - show_scroll_icons = false, + show_scrollbar = false, }, } end local o = fs{} - expect.eq(o.subviews.text.frame_body.width, 10, "Label's frame_body.x2 and .width should not change with show_scroll_icons = false.") + expect.eq(o.subviews.text.frame_body.width, 10, "Label's frame_body.x2 and .width should not change with show_scrollbar = false.") end function test.scroll() diff --git a/test/library/helpdb.lua b/test/library/helpdb.lua index 6c2ef2e9b..96dcbbce0 100644 --- a/test/library/helpdb.lua +++ b/test/library/helpdb.lua @@ -398,8 +398,25 @@ function test.get_entry_short_help() end function test.get_entry_long_help() + local expected = [[ +basic +***** + +**Tags:** map + +**Command:** +"basic" + +Documented +basic. + +Documented +full help. + ]] + expect.eq(expected, h.get_entry_long_help('basic', 13)) + -- long help for plugins/commands that have doc files should match the - -- contents of those files exactly + -- contents of those files exactly (test data is already wrapped) expect.eq(files['hack/docs/docs/tools/hascommands.txt'], h.get_entry_long_help('hascommands')) expect.eq(files['hack/docs/docs/tools/hascommands.txt'], diff --git a/test/library/utils.lua b/test/library/utils.lua index 5261ac913..509fab8bc 100644 --- a/test/library/utils.lua +++ b/test/library/utils.lua @@ -54,3 +54,62 @@ function test.invert_overwrite() expect.eq(i.b, 2) expect.eq(i.a, 3) end + +function test.df_expr_to_ref() + -- userdata field + expect.eq(utils.df_expr_to_ref('df.global.world.engravings'), df.global.world.engravings) + expect.eq(utils.df_expr_to_ref('df.global.world.engravings'), df.global.world:_field('engravings')) + -- primitive field + expect.eq(utils.df_expr_to_ref('df.global.world.original_save_version'), df.global.world:_field('original_save_version')) + -- table field + expect.eq(utils.df_expr_to_ref('df.global.world'), df.global.world) + expect.eq(utils.df_expr_to_ref('df.global'), df.global) + -- table + expect.eq(utils.df_expr_to_ref('df'), df) + + -- userdata object + expect.eq(utils.df_expr_to_ref('scr'), dfhack.gui.getCurViewscreen()) + + local fake_unit + mock.patch(dfhack.gui, 'getSelectedUnit', function() return fake_unit end, function() + -- lightuserdata field + fake_unit = { + null_field=df.NULL, + } + expect.eq(utils.df_expr_to_ref('unit'), fake_unit) + expect.eq(utils.df_expr_to_ref('unit.null_field'), fake_unit.null_field) + + dfhack.with_temp_object(df.unit:new(), function(u) + fake_unit = u + + -- userdata field + expect.eq(utils.df_expr_to_ref('unit.name'), fake_unit.name) + expect.eq(utils.df_expr_to_ref('unit.name'), fake_unit:_field('name')) + + -- primitive field + expect.eq(utils.df_expr_to_ref('unit.profession'), fake_unit:_field('profession')) + end) + + -- vector items + dfhack.with_temp_object(df.new('ptr-vector'), function(vec) + fake_unit = vec + vec:insert('#', df.global.world) + vec:insert('#', df.global.ui) + + expect.eq(utils.df_expr_to_ref('unit'), vec) + + expect.eq(utils.df_expr_to_ref('unit[0]'), utils.df_expr_to_ref('unit.0')) + expect.eq(df.reinterpret_cast(df.world, utils.df_expr_to_ref('unit[0]').value), df.global.world) + + expect.eq(utils.df_expr_to_ref('unit[1]'), utils.df_expr_to_ref('unit.1')) + expect.eq(df.reinterpret_cast(df.ui, utils.df_expr_to_ref('unit[1]').value), df.global.ui) + + expect.error_match('index out of bounds', function() utils.df_expr_to_ref('unit.2') end) + expect.error_match('index out of bounds', function() utils.df_expr_to_ref('unit[2]') end) + expect.error_match('index out of bounds', function() utils.df_expr_to_ref('unit.-1') end) + expect.error_match('index out of bounds', function() utils.df_expr_to_ref('unit[-1]') end) + + expect.error_match('not found', function() utils.df_expr_to_ref('unit.a') end) + end) + end) +end