diff --git a/docs/Authors.rst b/docs/Authors.rst index 55ecbb17c..31789aa52 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -110,6 +110,7 @@ Nikolay Amiantov abbradar nocico nocico Omniclasm OwnageIsMagic OwnageIsMagic +palenerd dlmarquis Patrik Lundell PatrikLundell Paul Fenwick pjf PeridexisErrant PeridexisErrant diff --git a/docs/Contributing.rst b/docs/Contributing.rst index ab92d0571..0619e8ba3 100644 --- a/docs/Contributing.rst +++ b/docs/Contributing.rst @@ -13,7 +13,7 @@ Contributing Code ================= Several things should be kept in mind when contributing code to DFHack. -Code Format +Code format ----------- * Four space indents for C++. Never use tabs for indentation in any language. * LF (Unix style) line terminators @@ -26,18 +26,45 @@ Code Format * #includes should be sorted. C++ libraries first, then dfhack modules, then df structures, then local includes. Within each category they should be sorted alphabetically. -How to get new code into DFHack +Pull request guidelines +----------------------- +* Pull requests should be based on (and submitted to) the default branch of the + relevant repo, which is the branch you see when you access the repo on GitHub + or clone the repo without specifying a branch. As of 0.47.04-r1, this is + ``develop`` for the main DFHack repo and ``master`` for other repos. +* Use a new branch for each feature or bugfix so that your changes can be merged + independently (i.e. not the ``master`` or ``develop`` branch of your fork). + + * An exception: for a collection of small miscellaneous changes (e.g. + structures research), one branch instead of many small branches is fine. It + is still preferred that this branch be dedicated to this purpose, i.e. not + ``master`` or ``develop``. Your pull request may be merged at any point + unless you indicate that it isn't ready (see below), but you can continue to + push to the same branch and open new pull requests as needed. + +* Try to keep pull requests relatively small so that they are easier to review + and merge. + + * If you expect to make a large number of related additions or changes (e.g. + adding a large new plugin), multiple PRs are preferred, as they allow more + frequent (and easier) feedback. If development of this feature is expected + to take a while, we may create a dedicated branch to merge your pull + requests into instead of the repo's default branch. + +* If you plan to make additional changes to your pull request in the near + future, or if it isn't quite ready to be merged, mark it as a + `draft pull request `_ + or add "WIP" to the title. Otherwise, your pull request may be reviewed and/or + merged prematurely. + +General contribution guidelines ------------------------------- -* Submit pull requests to the ``develop`` branch, not the ``master`` branch. - (The ``master`` branch always points at the most recent release) -* Use a new branch for each feature or bugfix so that your changes can be merged independently - (i.e. not the master or develop branch of your fork). -* If possible, compile on multiple platforms when changing anything that compiles -* It must pass CI - run ``python travis/all.py`` to check this. +* If convenient, compile on multiple platforms when changing anything that + compiles. Our CI should catch anything that fails to build, but checking in + advance can be faster. * Update documentation when applicable - see `docs-standards` for details. * Update ``changelog.txt`` and ``docs/Authors.rst`` when applicable. See `build-changelog` for more information on the changelog format. -* Create a GitHub pull request once finished * Submit ideas and bug reports as :issue:`issues on GitHub <>`. Posts in the forum thread can easily get missed or forgotten. * Work on :issue:`reported problems ` diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 3a4133873..6699163c2 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -291,6 +291,8 @@ One-shot subcommands: 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 @@ -305,6 +307,7 @@ Subcommands that persist until disabled or DF quits: :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 @@ -335,12 +338,14 @@ Subcommands that persist until disabled or DF quits: 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 +: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. :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 -:reaction-gloves: Fixes reactions to produce gloves in sets with correct handedness (:bug:`6273`) + +.. comment: sort these alphabetically .. _fix-armory: diff --git a/docs/changelog.txt b/docs/changelog.txt index bf953d562..e7a01f4fe 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -34,12 +34,14 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: # Future ## New Tweaks +- `tweak` do-job-now: adds a job priority toggle to the jobs list - `tweak` reaction-gloves: adds an option to make reactions produce gloves in sets with correct handedness ## Fixes - Fixed a segfault when attempting to start a headless session with a graphical PRINT_MODE setting - Fixed an issue with the macOS launcher failing to un-quarantine some files - Linux: fixed ``dfhack.getDFPath()`` (Lua) and ``Process::getPath()`` (C++) to always return the DF root path, even if the working directory has changed +- `getplants`: fixed issues causing plants to be collected even if they have no growths (or unripe growths) - `labormanager`: fixed handling of new jobs in 0.47 - `embark-assistant`: fixed a couple of incursion handling bugs. - Fixed ``Units::isEggLayer``, ``Units::isGrazer``, ``Units::isMilkable``, ``Units::isTrainableHunting``, ``Units::isTrainableWar``, and ``Units::isTamable`` ignoring the unit's caste diff --git a/library/PluginManager.cpp b/library/PluginManager.cpp index db42c5c84..a1b1bd293 100644 --- a/library/PluginManager.cpp +++ b/library/PluginManager.cpp @@ -316,8 +316,8 @@ bool Plugin::load(color_ostream &con) { std::string msg = stl_sprintf("Warning: Plugin %s compiled for DFHack %s, running DFHack %s\n", *plug_name, plug_git_desc, dfhack_git_desc); - con << msg; - cerr << msg; + con << msg << flush; + cerr << msg << flush; } } else diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 422060803..ddcfcd31e 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -204,14 +204,15 @@ void Units::setNickname(df::unit *unit, std::string nick) df::historical_figure *id_hfig = NULL; switch (identity->type) { + case df::identity_type::None: case df::identity_type::HidingCurse: - case df::identity_type::Identity: case df::identity_type::FalseIdentity: + case df::identity_type::InfiltrationIdentity: + case df::identity_type::Identity: break; // We want the nickname to end up in the identity - case df::identity_type::Unk_1: // Guess, but that's how it worked in the past + case df::identity_type::Impersonating: case df::identity_type::TrueName: - case df::identity_type::Unk_4: // Pure guess, as this is a new case, still unseen id_hfig = df::historical_figure::find(identity->histfig_id); break; } diff --git a/library/xml b/library/xml index ecd6bcc9e..9fca46ccc 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ecd6bcc9ed67c62fa605561b27574467df792342 +Subproject commit 9fca46ccca28e0948014b9d56a096ad7343473f1 diff --git a/plugins/getplants.cpp b/plugins/getplants.cpp index b4b7a493b..cfe499a9b 100644 --- a/plugins/getplants.cpp +++ b/plugins/getplants.cpp @@ -9,11 +9,16 @@ #include "TileTypes.h" #include "df/map_block.h" +#include "df/map_block_column.h" #include "df/plant.h" #include "df/plant_growth.h" #include "df/plant_raw.h" #include "df/tile_dig_designation.h" +#include "df/ui.h" #include "df/world.h" +#include "df/world_data.h" +#include "df/world_object_data.h" +#include "df/world_site.h" #include "modules/Designations.h" #include "modules/Maps.h" @@ -27,7 +32,9 @@ using namespace DFHack; using namespace df::enums; DFHACK_PLUGIN("getplants"); +REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(world); +REQUIRE_GLOBAL(cur_year); REQUIRE_GLOBAL(cur_year_tick); enum class selectability { @@ -224,6 +231,106 @@ selectability selectablePlant(const df::plant_raw *plant, bool farming) } } +// Formula for determination of the variance in plant growth maturation time, determined via disassembly. +// The x and y parameters are in tiles relative to the embark. +bool ripe(int32_t x, int32_t y, int32_t start, int32_t end) { + int32_t time = (((435522653 - (((y + 3) * x + 5) * ((y + 7) * y * 400181475 + 289700012))) & 0x3FFFFFFF) % 2000 + *cur_year_tick) % 403200; + + return time >= start && (end == -1 || time <= end); +} + +// Looks in the picked growths vector to see if a matching growth has been marked as picked. +bool picked(const df::plant *plant, int32_t growth_subtype) { + df::world_data *world_data = world->world_data; + df::world_site *site = df::world_site::find(ui->site_id); + int32_t pos_x = site->global_min_x + plant->pos.x / 48; + int32_t pos_y = site->global_min_y + plant->pos.y / 48; + size_t id = pos_x + pos_y * 16 * world_data->world_width; + df::world_object_data *object_data = df::world_object_data::find(id); + df::map_block_column *column = world->map.map_block_columns[(plant->pos.x / 16) * world->map.x_count_block + (plant->pos.y / 16)]; + + for (size_t i = 0; i < object_data->picked_growths.x.size(); i++) { + if (object_data->picked_growths.x[i] == plant->pos.x && + object_data->picked_growths.y[i] == plant->pos.y && + object_data->picked_growths.z[i] - column->z_base == plant->pos.z && + object_data->picked_growths.subtype[i] == growth_subtype && + object_data->picked_growths.year[i] == *cur_year) { + return true; + } + } + + return false; +} + +bool designate(const df::plant *plant, bool farming) { + df::plant_raw *plant_raw = world->raws.plants.all[plant->material]; + const DFHack::MaterialInfo basic_mat = DFHack::MaterialInfo(plant_raw->material_defs.type[plant_material_def::basic_mat], plant_raw->material_defs.idx[plant_material_def::basic_mat]); + + if (basic_mat.material->flags.is_set(material_flags::EDIBLE_RAW) || + basic_mat.material->flags.is_set(material_flags::EDIBLE_COOKED)) + { + return Designations::markPlant(plant); + } + + if (plant_raw->flags.is_set(plant_raw_flags::THREAD) || + plant_raw->flags.is_set(plant_raw_flags::MILL) || + plant_raw->flags.is_set(plant_raw_flags::EXTRACT_VIAL) || + plant_raw->flags.is_set(plant_raw_flags::EXTRACT_BARREL) || + plant_raw->flags.is_set(plant_raw_flags::EXTRACT_STILL_VIAL)) + { + if (!farming) { + return Designations::markPlant(plant); + } + } + + if (basic_mat.material->reaction_product.id.size() > 0 || + basic_mat.material->reaction_class.size() > 0) + { + if (!farming) { + return Designations::markPlant(plant); + } + } + + for (size_t i = 0; i < plant_raw->growths.size(); i++) + { + if (plant_raw->growths[i]->item_type == df::item_type::SEEDS || // Only trees have seed growths in vanilla, but raws can be modded... + plant_raw->growths[i]->item_type == df::item_type::PLANT_GROWTH) + { + const DFHack::MaterialInfo growth_mat = DFHack::MaterialInfo(plant_raw->growths[i]->mat_type, plant_raw->growths[i]->mat_index); + if ((plant_raw->growths[i]->item_type == df::item_type::SEEDS && + (growth_mat.material->flags.is_set(material_flags::EDIBLE_COOKED) || + growth_mat.material->flags.is_set(material_flags::EDIBLE_RAW))) || + (plant_raw->growths[i]->item_type == df::item_type::PLANT_GROWTH && + growth_mat.material->flags.is_set(material_flags::LEAF_MAT))) // Will change name to STOCKPILE_PLANT_GROWTH any day now... + { + bool seedSource = plant_raw->growths[i]->item_type == df::item_type::SEEDS; + + if (plant_raw->growths[i]->item_type == df::item_type::PLANT_GROWTH) + { + for (size_t k = 0; growth_mat.material->reaction_product.material.mat_type.size(); k++) + { + if (growth_mat.material->reaction_product.material.mat_type[k] == plant_raw->material_defs.type[plant_material_def::seed] && + growth_mat.material->reaction_product.material.mat_index[k] == plant_raw->material_defs.idx[plant_material_def::seed]) + { + seedSource = true; + break; + } + } + } + + if ((!farming || seedSource) && + ripe(plant->pos.x, plant->pos.y, plant_raw->growths[i]->timing_1, plant_raw->growths[i]->timing_2) && + !picked(plant, i)) + { + return Designations::markPlant(plant); + } + } + } + } + + return false; +} + command_result df_getplants (color_ostream &out, vector & parameters) { string plantMatStr = ""; @@ -448,7 +555,7 @@ command_result df_getplants (color_ostream &out, vector & parameters) collectionCount[plant->material]++; ++count; } - if (!deselect && Designations::markPlant(plant)) + if (!deselect && designate(plant, farming)) { // out.print("Designated %s at (%i, %i, %i), %d\n", world->raws.plants.all[plant->material]->id.c_str(), plant->pos.x, plant->pos.y, plant->pos.z, (int)i); collectionCount[plant->material]++; diff --git a/plugins/tweak/tweak.cpp b/plugins/tweak/tweak.cpp index 13e08f174..237014209 100644 --- a/plugins/tweak/tweak.cpp +++ b/plugins/tweak/tweak.cpp @@ -86,6 +86,7 @@ #include "tweaks/civ-agreement-ui.h" #include "tweaks/condition-material.h" #include "tweaks/craft-age-wear.h" +#include "tweaks/do-job-now.h" #include "tweaks/eggs-fertile.h" #include "tweaks/embark-profile-name.h" #include "tweaks/farm-plot-select.h" @@ -182,6 +183,7 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector *input) { + if (input->count(interface_key::BUILDJOB_NOW)) { + df::job *job = vector_get(jobs, cursor_pos); + if (job) { + job->flags.bits.do_now = !job->flags.bits.do_now; + } + + return true; + } + + return false; + } + + DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set *input)) { + if (!handleInput(input)) { + INTERPOSE_NEXT(feed)(input); + } + } + + DEFINE_VMETHOD_INTERPOSE(void, render, ()) { + INTERPOSE_NEXT(render)(); + int x = 32; + auto dim = Screen::getWindowSize(); + int y = dim.y - 2; + bool do_now = false; + + df::job *job = vector_get(jobs, cursor_pos); + if (job) { + do_now = job->flags.bits.do_now; + } + + OutputHotkeyString(x, y, (!do_now ? "Do job now!" : "Reset priority"), + interface_key::BUILDJOB_NOW, false, x, job ? COLOR_WHITE : COLOR_DARKGREY, COLOR_LIGHTRED); + } +}; + +IMPLEMENT_VMETHOD_INTERPOSE(do_job_now_hook, feed); +IMPLEMENT_VMETHOD_INTERPOSE(do_job_now_hook, render); diff --git a/scripts b/scripts index 70ce0a12b..823d47c4d 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 70ce0a12bc0eb14b3782abe7033a6d2dd31863fe +Subproject commit 823d47c4d181ac5b754dce5d605f3e7f242aed26