diff --git a/library/include/dfhack/modules/Vegetation.h b/library/include/dfhack/modules/Vegetation.h index 5760401a3..e874830d8 100644 --- a/library/include/dfhack/modules/Vegetation.h +++ b/library/include/dfhack/modules/Vegetation.h @@ -11,6 +11,10 @@ #include "dfhack/DFTypes.h" namespace DFHack { + /** + * \ingroup grp_vegetation + */ + const uint32_t sapling_to_tree_threshold = 0x1D880; /** * \ingroup grp_vegetation */ @@ -34,12 +38,16 @@ namespace DFHack uint16_t y; // +0x42 uint16_t z; // +0x44 uint16_t padding; // +0x46 - uint32_t unknown_1; // +0x48 + uint32_t grow_counter; // +0x48 uint16_t temperature_1; // +0x4C uint16_t temperature_2; // +0x4E - maybe fraction? uint32_t is_burning; // 0x50: yes, just one flag uint32_t hitpoints; // 0x54 - uint32_t unknown_3; // 0x58 + /** + * 0x58 - maybe related to the order in which plants are updated + * the updates are staggered into 8 groups? + */ + uint32_t unknown_3; // a vector is here }; /** diff --git a/tools/examples/treedump.cpp b/tools/examples/treedump.cpp index 79d08819d..af6bf9b96 100644 --- a/tools/examples/treedump.cpp +++ b/tools/examples/treedump.cpp @@ -45,9 +45,9 @@ void print_tree( DFHack::Context * DF , DFHack::dfh_plant & tree) cout << "shrub"; } cout << endl; - printf("unknown_1: 0x%08x\n", tdata.unknown_1); - printf("temperature_1: %d\n", tdata.temperature_1); - printf("temperature_2: %d\n", tdata.temperature_2); + printf("Grow counter: 0x%08x\n", tdata.grow_counter); + printf("temperature 1: %d\n", tdata.temperature_1); + printf("temperature 2: %d\n", tdata.temperature_2); printf("On fire: %d\n", tdata.is_burning); printf("hitpoints: 0x%08x\n", tdata.hitpoints); printf("unknown_3: 0x%08x\n", tdata.unknown_3); diff --git a/tools/playground/CMakeLists.txt b/tools/playground/CMakeLists.txt index d63dd8ef4..950552547 100644 --- a/tools/playground/CMakeLists.txt +++ b/tools/playground/CMakeLists.txt @@ -19,9 +19,12 @@ ENDIF() # a creature mood dump hack. has hardcoded offsets DFHACK_TOOL(dfmoodump moodump.cpp) -# burn trees to ashes +# burn trees and shrubs to ashes DFHACK_TOOL(dfimmolate immolate.cpp) +# grow saplings into trees instantly +DFHACK_TOOL(dfgrow grow.cpp) + # bauxite - turn all mechanisms into bauxite mechanisms # Author: Alex Legg # FIXME: turned off. there is no reliable Items module. diff --git a/tools/playground/grow.cpp b/tools/playground/grow.cpp new file mode 100644 index 000000000..a5ab64617 --- /dev/null +++ b/tools/playground/grow.cpp @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include + +using namespace std; +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + srand(time(0)); + + uint32_t x_max = 0, y_max = 0, z_max = 0; + DFHack::ContextManager manager("Memory.xml"); + + DFHack::Context *context = manager.getSingleContext(); + if (!context->Attach()) + { + std::cerr << "Unable to attach to DF!" << std::endl; + #ifndef LINUX_BUILD + std::cin.ignore(); + #endif + return 1; + } + + DFHack::Maps *maps = context->getMaps(); + if (!maps->Start()) + { + std::cerr << "Cannot get map info!" << std::endl; + context->Detach(); + #ifndef LINUX_BUILD + std::cin.ignore(); + #endif + return 1; + } + DFHack::Gui * Gui = context->getGui(); + maps->getSize(x_max, y_max, z_max); + MapExtras::MapCache map(maps); + uint32_t vegCount = 0; + DFHack::Vegetation *veg = context->getVegetation(); + if (!veg->Start(vegCount)) + { + std::cerr << "Unable to read vegetation!" << std::endl; + return 1; + } + int32_t x,y,z; + if(Gui->getCursorCoords(x,y,z)) + { + vector alltrees; + if(maps->ReadVegetation(x/16,y/16,z,&alltrees)) + { + for(int i = 0 ; i < alltrees.size(); i++) + { + DFHack::dfh_plant & tree = alltrees[i]; + if(tree.sdata.x == x && tree.sdata.y == y && tree.sdata.z == z) + { + if(DFHack::tileShape(map.tiletypeAt(DFHack::DFCoord(x,y,z))) == DFHack::SAPLING_OK) + { + tree.sdata.grow_counter = DFHack::sapling_to_tree_threshold; + veg->Write(tree); + } + break; + } + } + } + } + else + { + int grown = 0; + for(int i = 0 ; i < vegCount; i++) + { + DFHack::dfh_plant p; + veg->Read(i,p); + uint16_t ttype = map.tiletypeAt(DFHack::DFCoord(p.sdata.x,p.sdata.y,p.sdata.z)); + if(!p.sdata.is_shrub && DFHack::tileShape(ttype) == DFHack::SAPLING_OK) + { + p.sdata.grow_counter = DFHack::sapling_to_tree_threshold; + veg->Write(p); + } + } + } + + // Cleanup + veg->Finish(); + maps->Finish(); + context->Detach(); + #ifndef LINUX_BUILD + std::cout << " Press any key to finish."; + std::cin.ignore(); + #endif + std::cout << std::endl; + return 0; +} diff --git a/tools/playground/immolate.cpp b/tools/playground/immolate.cpp new file mode 100644 index 000000000..b9c09ba73 --- /dev/null +++ b/tools/playground/immolate.cpp @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include + +using namespace std; +#include +#include +#include +#include +#include + +bool parseOptions(int argc, char **argv, + bool &trees, bool &shrubs, bool &immolate) +{ + char c; + xgetopt opt(argc, argv, "sti"); + opt.opterr = 0; + while ((c = opt()) != -1) + { + switch (c) + { + case 's': + shrubs = true; + break; + case 't': + trees = true; + break; + case 'i': + immolate = true; + break; + case '?': + switch (opt.optopt) + { + // For when we take arguments + default: + if (isprint(opt.optopt)) + std::cerr << "Unknown option -" << opt.optopt << "!" + << std::endl; + else + std::cerr << "Unknown option character " << (int) opt.optopt << "!" + << std::endl; + } + default: + // Um..... + return false; + } + } + return true; +} + +int main(int argc, char *argv[]) +{ + bool all_trees = false; + bool all_shrubs = false; + bool immolate = false; + srand(time(0)); + if (!parseOptions(argc, argv, all_trees, all_shrubs, immolate)) + { + return -1; + } + + uint32_t x_max = 0, y_max = 0, z_max = 0; + DFHack::ContextManager manager("Memory.xml"); + + DFHack::Context *context = manager.getSingleContext(); + if (!context->Attach()) + { + std::cerr << "Unable to attach to DF!" << std::endl; + #ifndef LINUX_BUILD + std::cin.ignore(); + #endif + return 1; + } + + DFHack::Maps *maps = context->getMaps(); + if (!maps->Start()) + { + std::cerr << "Cannot get map info!" << std::endl; + context->Detach(); + #ifndef LINUX_BUILD + std::cin.ignore(); + #endif + return 1; + } + DFHack::Gui * Gui = context->getGui(); + maps->getSize(x_max, y_max, z_max); + MapExtras::MapCache map(maps); + uint32_t vegCount = 0; + DFHack::Vegetation *veg = context->getVegetation(); + if (!veg->Start(vegCount)) + { + std::cerr << "Unable to read vegetation!" << std::endl; + return 1; + } + if(all_shrubs || all_trees) + { + int destroyed = 0; + for(int i = 0 ; i < vegCount; i++) + { + DFHack::dfh_plant p; + veg->Read(i,p); + if(all_shrubs && p.sdata.is_shrub || all_trees && !p.sdata.is_shrub) + { + //p.sdata.temperature_1 = 0; + //p.sdata.temperature_2 = 0; + if (immolate) + p.sdata.is_burning = true; + p.sdata.hitpoints = 0; + veg->Write(p); + destroyed ++; + } + } + cout << "Sacrificed " << destroyed; + if(all_shrubs) + cout << " shrubs to Armok." << endl; + if(all_trees) + cout << " trees to Armok." << endl; + cout << "----==== Praise Armok! ====----" << endl; + } + else + { + int32_t x,y,z; + if(Gui->getCursorCoords(x,y,z)) + { + vector alltrees; + if(maps->ReadVegetation(x/16,y/16,z,&alltrees)) + { + bool didit = false; + for(int i = 0 ; i < alltrees.size(); i++) + { + DFHack::dfh_plant & tree = alltrees[i]; + if(tree.sdata.x == x && tree.sdata.y == y && tree.sdata.z == z) + { + cout << "----==== Praise Armok! ====----" << endl; + if(immolate) + tree.sdata.is_burning = true; + tree.sdata.hitpoints = 0; + veg->Write(tree); + didit = true; + break; + } + } + if(!didit) + { + cout << "----==== There's NOTHING there! ====----" << endl; + } + } + } + else + { + cout << "No mass destruction and no cursor." << endl; + cout << "----==== Armok is not pleased! ====----" << endl; + } + } + // Cleanup + veg->Finish(); + maps->Finish(); + context->Detach(); + #ifndef LINUX_BUILD + std::cout << " Press any key to finish."; + std::cin.ignore(); + #endif + std::cout << std::endl; + return 0; +}