From 15e06640f6b756a82b9da73cb166f64e90bfac0e Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Wed, 15 Jan 2020 12:40:43 +0100 Subject: [PATCH 1/5] Partial correction of issue 1479 and added verbose flag --- docs/changelog.txt | 1 + plugins/getplants.cpp | 227 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 216 insertions(+), 12 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index c1d7bae72..46f71cf6c 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -52,6 +52,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `embark-assistant`: - fixed bug causing crash on worlds without generated metals (as well as pruning vectors as originally intended). - fixed bug causing mineral matching to fail to cut off at the magma sea, reporting presence of things that aren't (like DF does currently). +- `getplants`: fixed designation of plants out of season and added verbose flag, but failed to identify picked plants (which are still designated incorrectly) - `gui/autogems`: fixed error when no world is loaded - `gui/companion-order`: - fixed error when resetting group leaders diff --git a/plugins/getplants.cpp b/plugins/getplants.cpp index 2cf382d01..8e4384879 100644 --- a/plugins/getplants.cpp +++ b/plugins/getplants.cpp @@ -1,5 +1,9 @@ // (un)designate matching plants for gathering/cutting - +// Known issue: +// DF is capable of determining that a shrub has already been picked, leaving an unusable structure part +// behind. This code does not perform such a check (as the location of the required information is +// unknown to the writer of this comment). 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). #include #include "Core.h" @@ -11,12 +15,14 @@ #include "df/map_block.h" #include "df/plant.h" +#include "df/plant_growth.h" #include "df/plant_raw.h" #include "df/tile_dig_designation.h" #include "df/world.h" #include "modules/Designations.h" #include "modules/Maps.h" +#include "modules/Materials.h" using std::string; using std::vector; @@ -27,15 +33,136 @@ using namespace df::enums; DFHACK_PLUGIN("getplants"); REQUIRE_GLOBAL(world); +REQUIRE_GLOBAL(cur_year_tick); + +enum class selectability { + Selectable, + Grass, + Nonselectable, + OutOfSeason, + Unselected +}; + +//selectability selectablePlant(color_ostream &out, const df::plant_raw *plant) +selectability selectablePlant(const df::plant_raw *plant) +{ + const DFHack::MaterialInfo basic_mat = DFHack::MaterialInfo(plant->material_defs.type_basic_mat, plant->material_defs.idx_basic_mat); + bool outOfSeason = false; + + if (plant->flags.is_set(plant_raw_flags::TREE)) + { +// out.print("%s is a selectable tree\n", plant->id.c_str()); + return selectability::Selectable; + } + else if (plant->flags.is_set(plant_raw_flags::GRASS)) + { +// out.print("%s is a non selectable Grass\n", plant->id.c_str()); + return selectability::Grass; + } + + if (basic_mat.material->flags.is_set(material_flags::EDIBLE_RAW) || + basic_mat.material->flags.is_set(material_flags::EDIBLE_COOKED)) + { +// out.print("%s is edible\n", plant->id.c_str()); + return selectability::Selectable; + } + + if (plant->flags.is_set(plant_raw_flags::THREAD) || + plant->flags.is_set(plant_raw_flags::MILL) || + plant->flags.is_set(plant_raw_flags::EXTRACT_VIAL) || + plant->flags.is_set(plant_raw_flags::EXTRACT_BARREL) || + plant->flags.is_set(plant_raw_flags::EXTRACT_STILL_VIAL)) + { +// out.print("%s is thread/mill/extract\n", plant->id.c_str()); + return selectability::Selectable; + } + + if (basic_mat.material->reaction_product.id.size() > 0 || + basic_mat.material->reaction_class.size() > 0) + { +// out.print("%s has a reaction\n", plant->id.c_str()); + return selectability::Selectable; + } + + for (auto i = 0; i < plant->growths.size(); i++) + { + if (plant->growths[i]->item_type == df::item_type::SEEDS || // Only trees have seed growths in vanilla, but raws can be modded... + plant->growths[i]->item_type == df::item_type::PLANT_GROWTH) + { + const DFHack::MaterialInfo growth_mat = DFHack::MaterialInfo(plant->growths[i]->mat_type, plant->growths[i]->mat_index); + if ((plant->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->growths[i]->item_type == df::item_type::PLANT_GROWTH && + growth_mat.material->flags.is_set(material_flags::STOCKPILE_PLANT_GROWTH))) + { + if (*cur_year_tick >= plant->growths[i]->timing_1 && + (plant->growths[i]->timing_2 == -1 || + *cur_year_tick <= plant->growths[i]->timing_2)) + { +// out.print("%s has an edible seed or a stockpile growth\n", plant->id.c_str()); + return selectability::Selectable; + } + else + { + outOfSeason = true; + } + } + } +/* else if (plant->growths[i]->behavior.bits.has_seed) // This code designates beans, etc. when DF doesn't, but plant gatherers still fail to collect anything, so it's useless: bug #0006940. + { + const DFHack::MaterialInfo seed_mat = DFHack::MaterialInfo(plant->material_defs.type_seed, plant->material_defs.idx_seed); + + if (seed_mat.material->flags.is_set(material_flags::EDIBLE_RAW) || + seed_mat.material->flags.is_set(material_flags::EDIBLE_COOKED)) + { + if (*cur_year_tick >= plant->growths[i]->timing_1 && + (plant->growths[i]->timing_2 == -1 || + *cur_year_tick <= plant->growths[i]->timing_2)) + { + return selectability::Selectable; + } + else + { + outOfSeason = true; + } + } + } */ + } + + if (outOfSeason) + { +// out.print("%s has an out of season growth\n", plant->id.c_str()); + return selectability::OutOfSeason; + } + else + { +// out.printerr("%s cannot be gathered\n", plant->id.c_str()); + return selectability::Nonselectable; + } +} command_result df_getplants (color_ostream &out, vector & parameters) { string plantMatStr = ""; - set plantIDs; + std::vector plantSelections; + std::vector collectionCount; set plantNames; - bool deselect = false, exclude = false, treesonly = false, shrubsonly = false, all = false; + bool deselect = false, exclude = false, treesonly = false, shrubsonly = false, all = false, verbose = false; int count = 0; + + plantSelections.resize(world->raws.plants.all.size()); + collectionCount.resize(world->raws.plants.all.size()); + + for (auto i = 0; i < plantSelections.size(); i++) + { + plantSelections[i] = selectability::Unselected; + collectionCount[i] = 0; + } + + bool anyPlantsSelected = false; + for (size_t i = 0; i < parameters.size(); i++) { if(parameters[i] == "help" || parameters[i] == "?") @@ -50,6 +177,8 @@ command_result df_getplants (color_ostream &out, vector & parameters) exclude = true; else if(parameters[i] == "-a") all = true; + else if(parameters[i] == "-v") + verbose = true; else plantNames.insert(parameters[i]); } @@ -75,11 +204,39 @@ command_result df_getplants (color_ostream &out, vector & parameters) { df::plant_raw *plant = world->raws.plants.all[i]; if (all) - plantIDs.insert(i); - else if (plantNames.find(plant->id) != plantNames.end()) + { +// plantSelections[i] = selectablePlant(out, plant); + plantSelections[i] = selectablePlant(plant); + } + else if (plantNames.find(plant->id) != plantNames.end()) { plantNames.erase(plant->id); - plantIDs.insert(i); +// plantSelections[i] = selectablePlant(out, plant); + plantSelections[i] = selectablePlant(plant); + switch (plantSelections[i]) + { + case selectability::Grass: + { + out.printerr("%s is a Grass, and those can not be gathered\n", plant->id.c_str()); + break; + } + + case selectability::Nonselectable: + { + out.printerr("%s does not have any parts that can be gathered\n", plant->id.c_str()); + break; + } + case selectability::OutOfSeason: + { + out.printerr("%s is out of season, with nothing that can be gathered now\n", plant->id.c_str()); + break; + } + case selectability::Selectable: + break; + + case selectability::Unselected: + break; // We won't get to this option + } } } if (plantNames.size() > 0) @@ -91,15 +248,44 @@ command_result df_getplants (color_ostream &out, vector & parameters) return CR_FAILURE; } - if (plantIDs.size() == 0) + for (auto i = 0; i < plantSelections.size(); i++) + { + if (plantSelections[i] == selectability::OutOfSeason || + plantSelections[i] == selectability::Selectable) + { + anyPlantsSelected = true; + break; + } + } + + if (!anyPlantsSelected) { out.print("Valid plant IDs:\n"); for (size_t i = 0; i < world->raws.plants.all.size(); i++) { df::plant_raw *plant = world->raws.plants.all[i]; - if (plant->flags.is_set(plant_raw_flags::GRASS)) +// switch (selectablePlant(out, plant)) + switch (selectablePlant(plant)) + { + case selectability::Grass: + case selectability::Nonselectable: continue; - out.print("* (%s) %s - %s\n", plant->flags.is_set(plant_raw_flags::TREE) ? "tree" : "shrub", plant->id.c_str(), plant->name.c_str()); + + case selectability::OutOfSeason: + { + out.print("* (shrub) %s - %s is out of season\n", plant->id.c_str(), plant->name.c_str()); + break; + } + + case selectability::Selectable: + { + out.print("* (%s) %s - %s\n", plant->flags.is_set(plant_raw_flags::TREE) ? "tree" : "shrub", plant->id.c_str(), plant->name.c_str()); + break; + } + + case selectability::Unselected: // Should never get this alternative + break; + } } return CR_OK; } @@ -113,9 +299,11 @@ command_result df_getplants (color_ostream &out, vector & parameters) int x = plant->pos.x % 16; int y = plant->pos.y % 16; - if (plantIDs.find(plant->material) != plantIDs.end()) + if (plantSelections[plant->material] == selectability::OutOfSeason || + plantSelections[plant->material] == selectability::Selectable) { - if (exclude) + if (exclude || + plantSelections[plant->material] == selectability::OutOfSeason) continue; } else @@ -134,15 +322,29 @@ command_result df_getplants (color_ostream &out, vector & parameters) continue; if (deselect && Designations::unmarkPlant(plant)) { + collectionCount[plant->material]++; ++count; } if (!deselect && Designations::markPlant(plant)) { +// out.print("Designated %s at (%i, %i, %i), %i\n", world->raws.plants.all[plant->material]->id.c_str(), plant->pos.x, plant->pos.y, plant->pos.z, i); + collectionCount[plant->material]++; ++count; } } if (count) - out.print("Updated %d plant designations.\n", count); + if (verbose) + { + for (auto i = 0; i < plantSelections.size(); i++) + { + if (collectionCount [i] > 0) + out.print("Updated %i %s designations.\n", collectionCount [i], world->raws.plants.all [i]->id.c_str()); + } + out.print("\n"); + } + + out.print("Updated %d plant designations.\n", count); + return CR_OK; } @@ -159,6 +361,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, vector Date: Wed, 15 Jan 2020 19:31:19 +0100 Subject: [PATCH 2/5] Reverted STOCKPILE_PLANT_GROWTH to LEAF_MAT --- plugins/getplants.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/getplants.cpp b/plugins/getplants.cpp index 8e4384879..001400681 100644 --- a/plugins/getplants.cpp +++ b/plugins/getplants.cpp @@ -94,7 +94,7 @@ selectability selectablePlant(const df::plant_raw *plant) (growth_mat.material->flags.is_set(material_flags::EDIBLE_COOKED) || growth_mat.material->flags.is_set(material_flags::EDIBLE_RAW))) || (plant->growths[i]->item_type == df::item_type::PLANT_GROWTH && - growth_mat.material->flags.is_set(material_flags::STOCKPILE_PLANT_GROWTH))) + growth_mat.material->flags.is_set(material_flags::LEAF_MAT))) // Will change name to STOCKPILE_PLANT_GROWTH any day now... { if (*cur_year_tick >= plant->growths[i]->timing_1 && (plant->growths[i]->timing_2 == -1 || @@ -333,16 +333,17 @@ command_result df_getplants (color_ostream &out, vector & parameters) } } if (count) + { if (verbose) { for (auto i = 0; i < plantSelections.size(); i++) { - if (collectionCount [i] > 0) - out.print("Updated %i %s designations.\n", collectionCount [i], world->raws.plants.all [i]->id.c_str()); + if (collectionCount[i] > 0) + out.print("Updated %i %s designations.\n", collectionCount[i], world->raws.plants.all[i]->id.c_str()); } out.print("\n"); } - + } out.print("Updated %d plant designations.\n", count); return CR_OK; From 8cebb6cef5c410988fadc08d87e2f5aa984f07dd Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Wed, 15 Jan 2020 21:29:01 +0100 Subject: [PATCH 3/5] removed trailing whitespace --- plugins/getplants.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/getplants.cpp b/plugins/getplants.cpp index 001400681..7db3b13a7 100644 --- a/plugins/getplants.cpp +++ b/plugins/getplants.cpp @@ -127,7 +127,7 @@ selectability selectablePlant(const df::plant_raw *plant) outOfSeason = true; } } - } */ + } */ } if (outOfSeason) From ee2259bbcaf9adab827c16f9858b42cfa33935ae Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Thu, 16 Jan 2020 12:57:09 +0100 Subject: [PATCH 4/5] Replaced poor auto with actual type --- plugins/getplants.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/plugins/getplants.cpp b/plugins/getplants.cpp index 7db3b13a7..1b326b8cd 100644 --- a/plugins/getplants.cpp +++ b/plugins/getplants.cpp @@ -84,7 +84,7 @@ selectability selectablePlant(const df::plant_raw *plant) return selectability::Selectable; } - for (auto i = 0; i < plant->growths.size(); i++) + for (size_t i = 0; i < plant->growths.size(); i++) { if (plant->growths[i]->item_type == df::item_type::SEEDS || // Only trees have seed growths in vanilla, but raws can be modded... plant->growths[i]->item_type == df::item_type::PLANT_GROWTH) @@ -146,7 +146,7 @@ command_result df_getplants (color_ostream &out, vector & parameters) { string plantMatStr = ""; std::vector plantSelections; - std::vector collectionCount; + std::vector collectionCount; set plantNames; bool deselect = false, exclude = false, treesonly = false, shrubsonly = false, all = false, verbose = false; @@ -155,7 +155,7 @@ command_result df_getplants (color_ostream &out, vector & parameters) plantSelections.resize(world->raws.plants.all.size()); collectionCount.resize(world->raws.plants.all.size()); - for (auto i = 0; i < plantSelections.size(); i++) + for (size_t i = 0; i < plantSelections.size(); i++) { plantSelections[i] = selectability::Unselected; collectionCount[i] = 0; @@ -248,7 +248,7 @@ command_result df_getplants (color_ostream &out, vector & parameters) return CR_FAILURE; } - for (auto i = 0; i < plantSelections.size(); i++) + for (size_t i = 0; i < plantSelections.size(); i++) { if (plantSelections[i] == selectability::OutOfSeason || plantSelections[i] == selectability::Selectable) @@ -327,7 +327,7 @@ command_result df_getplants (color_ostream &out, vector & parameters) } if (!deselect && Designations::markPlant(plant)) { -// out.print("Designated %s at (%i, %i, %i), %i\n", world->raws.plants.all[plant->material]->id.c_str(), plant->pos.x, plant->pos.y, plant->pos.z, i); +// 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, i); collectionCount[plant->material]++; ++count; } @@ -336,10 +336,10 @@ command_result df_getplants (color_ostream &out, vector & parameters) { if (verbose) { - for (auto i = 0; i < plantSelections.size(); i++) + for (size_t i = 0; i < plantSelections.size(); i++) { if (collectionCount[i] > 0) - out.print("Updated %i %s designations.\n", collectionCount[i], world->raws.plants.all[i]->id.c_str()); + out.print("Updated %d %s designations.\n", collectionCount[i], world->raws.plants.all[i]->id.c_str()); } out.print("\n"); } @@ -357,11 +357,11 @@ DFhackCExport command_result plugin_init ( color_ostream &out, vector Date: Thu, 16 Jan 2020 13:59:31 +0100 Subject: [PATCH 5/5] Explicit type conversion with %d warning silencing --- plugins/getplants.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/getplants.cpp b/plugins/getplants.cpp index 1b326b8cd..5fa1c8637 100644 --- a/plugins/getplants.cpp +++ b/plugins/getplants.cpp @@ -327,7 +327,7 @@ command_result df_getplants (color_ostream &out, vector & parameters) } if (!deselect && Designations::markPlant(plant)) { -// 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, i); +// 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]++; ++count; } @@ -339,12 +339,12 @@ command_result df_getplants (color_ostream &out, vector & parameters) for (size_t i = 0; i < plantSelections.size(); i++) { if (collectionCount[i] > 0) - out.print("Updated %d %s designations.\n", collectionCount[i], world->raws.plants.all[i]->id.c_str()); + out.print("Updated %d %s designations.\n", (int)collectionCount[i], world->raws.plants.all[i]->id.c_str()); } out.print("\n"); } } - out.print("Updated %d plant designations.\n", count); + out.print("Updated %d plant designations.\n", (int)count); return CR_OK; }