diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 7e9dd959c..de87481af 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -74,6 +74,8 @@ DFHACK_PLUGIN(fixveins fixveins.cpp) DFHACK_PLUGIN(fixpositions fixpositions.cpp) #DFHACK_PLUGIN(versionosd versionosd.cpp) +add_subdirectory(export) + # this is the skeleton plugin. If you want to make your own, make a copy and then change it OPTION(BUILD_SKELETON "Build the skeleton plugin." OFF) if(BUILD_SKELETON) diff --git a/plugins/export/CMakeLists.txt b/plugins/export/CMakeLists.txt new file mode 100644 index 000000000..1ff69fb27 --- /dev/null +++ b/plugins/export/CMakeLists.txt @@ -0,0 +1,31 @@ +PROJECT (export) +# A list of source files +SET(PROJECT_SRCS + export.cpp +) +# A list of headers +SET(PROJECT_HDRS + export.h +) +SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE) + +# mash them together (headers are marked as headers and nothing will try to compile them) +LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS}) + +#linux +IF(UNIX) + add_definitions(-DLINUX_BUILD) + SET(PROJECT_LIBS + # add any extra linux libs here + ${PROJECT_LIBS} + ) +# windows +ELSE(UNIX) + SET(PROJECT_LIBS + # add any extra linux libs here + ${PROJECT_LIBS} + $(NOINHERIT) + ) +ENDIF(UNIX) +# this makes sure all the stuff is put in proper places and linked to dfhack +DFHACK_PLUGIN(export ${PROJECT_SRCS} LINK_LIBRARIES ${PROJECT_LIBS}) diff --git a/plugins/export/export.cpp b/plugins/export/export.cpp new file mode 100644 index 000000000..4915e34c8 --- /dev/null +++ b/plugins/export/export.cpp @@ -0,0 +1,183 @@ +// some headers required for a plugin. Nothing special, just the basics. +#include +#include +#include +#include +using namespace std; + +#define DFHACK_WANT_MISCUTILS +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace DFHack; +using namespace DFHack::Simple; +using namespace DFHack::Simple; + +using df::global::ui; +using df::global::world; + +// our own, empty header. +#include "export.h" + + +// Here go all the command declarations... +// mostly to allow having the mandatory stuff on top of the file and commands on the bottom +DFhackCExport command_result export_dwarves (Core * c, std::vector & parameters); + +// A plugins must be able to return its name. This must correspond to the filename - export.plug.so or export.plug.dll +DFhackCExport const char * plugin_name ( void ) +{ + return "export"; +} + +// Mandatory init function. If you have some global state, create it here. +DFhackCExport command_result plugin_init ( Core * c, std::vector &commands) +{ + // Fill the command list with your commands. + commands.clear(); + commands.push_back(PluginCommand("export", + "Export dwarves to RuneSmith-compatible XML.", + export_dwarves /*, + true or false - true means that the command can't be used from non-interactive user interface'*/)); + return CR_OK; +} + +// This is called right before the plugin library is removed from memory. +DFhackCExport command_result plugin_shutdown ( Core * c ) +{ + return CR_OK; +} + +static char* physicals[] = { + "Strength", + "Agility", + "Toughness", + "Endurance", + "Recuperation", + "DiseaseResistance", +}; + +static char* mentals[] = { + "Willpower", + "Memory", + "Focus", + "Intuition", + "Patience", + "Empathy", + "SocialAwareness", + "Creatvity", //Speeling deliberate + "Musicality", + "AnalyticalAbility", + "LinguisticAbility", + "SpatialSense", + "KinaestheticSense", +}; + +static void element(const char* name, const char* content, ostream& out, const char* extra_indent="") { + out << extra_indent << " <" << name << ">" << content << "" << endl; +} + +static void element(const char* name, const uint32_t content, ostream& out, const char* extra_indent="") { + out << extra_indent << " <" << name << ">" << content << "" << endl; +} + +static void printAttributes(Core* c, df::unit* cre, ostream& out) { + out << " " << endl; + for (int i = 0; i < NUM_CREATURE_PHYSICAL_ATTRIBUTES; i++) { + element(physicals[i], cre->body.physical_attrs[i].unk1, out, " "); + } + + df::unit_soul * s = cre->status.current_soul; + if (s) { + for (int i = 0; i < NUM_CREATURE_MENTAL_ATTRIBUTES; i++) { + element(mentals[i], s->mental_attrs[i].unk1, out, " "); + } + } + out << " " << endl; +} + +static void printTraits(Core* c, df::unit* cre, ostream& out) { + out << " " << endl; + df::unit_soul * s = cre->status.current_soul; + if (s) { + for (int i = 0; i < NUM_CREATURE_TRAITS; i++) { + out << " "; + string trait = c->vinfo->getTrait(i, s->traits[i]); + if (!trait.empty()) { + out << trait.c_str(); + } + out << "" << endl; + } + } + out << " " << endl; +} + +// GDC needs: +// Name +// Nickname +// Sex +// Attributes +// Traits +static void export_dwarf(Core* c, df::unit* cre, ostream& out) { + string info = cre->name.first_name; + info += " "; + info += Translation::TranslateName(&cre->name, false); + info[0] = toupper(info[0]); + c->con.print("Exporting %s\n", info.c_str()); + + out << " " << endl; + element("Name", info.c_str(), out); + element("Nickname", cre->name.nickname.c_str(), out); + element("Sex", cre->sex == 0 ? "Female" : "Male", out); + printAttributes(c, cre, out); + printTraits(c, cre, out); + + out << " " << endl; +} + +DFhackCExport command_result export_dwarves (Core * c, std::vector & parameters) +{ + string filename; + if (parameters.size() == 1) { + filename = parameters[0]; + } else { + c->con.print("export \n"); + return CR_OK; + } + + ofstream outf(filename); + if (!outf) { + c->con.printerr("Failed to open file %s\n", filename.c_str()); + return CR_FAILURE; + } + + c->Suspend(); + + uint32_t race = ui->race_id; + uint32_t civ = ui->civ_id; + + outf << "" << endl << "" << endl; + + for (int i = 0; i < world->units.all.size(); ++i) + { + df::unit* cre = world->units.all[i]; + if (cre->race == race && cre->civ_id == civ) { + export_dwarf(c, cre, outf); + } + } + outf << "" << endl; + + c->Resume(); + return CR_OK; +} diff --git a/plugins/export/export.h b/plugins/export/export.h new file mode 100644 index 000000000..7b9637ef9 --- /dev/null +++ b/plugins/export/export.h @@ -0,0 +1 @@ +#pragma once \ No newline at end of file diff --git a/plugins/liquids.cpp b/plugins/liquids.cpp index 6e6c19ac5..6d268316a 100644 --- a/plugins/liquids.cpp +++ b/plugins/liquids.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -141,6 +142,64 @@ public: }; }; +/** + * Flood-fill water tiles from cursor (for wclean) + * example: remove salt flag from a river + */ +class FloodBrush : public Brush +{ +public: + FloodBrush(Core *c){c_ = c;}; + ~FloodBrush(){}; + coord_vec points(MapCache & mc, DFHack::DFCoord start) + { + coord_vec v; + + std::stack to_flood; + to_flood.push(start); + + std::set seen; + + while (!to_flood.empty()) { + DFCoord xy = to_flood.top(); + to_flood.pop(); + + df::tile_designation des = mc.designationAt(xy); + + if (seen.find(xy) == seen.end() + && des.bits.flow_size + && des.bits.liquid_type == tile_liquid::Water) { + v.push_back(xy); + seen.insert(xy); + + maybeFlood(DFCoord(xy.x - 1, xy.y, xy.z), to_flood, mc); + maybeFlood(DFCoord(xy.x + 1, xy.y, xy.z), to_flood, mc); + maybeFlood(DFCoord(xy.x, xy.y - 1, xy.z), to_flood, mc); + maybeFlood(DFCoord(xy.x, xy.y + 1, xy.z), to_flood, mc); + + uint16_t tt = mc.tiletypeAt(xy); + if (LowPassable(tt)) + { + maybeFlood(DFCoord(xy.x, xy.y, xy.z - 1), to_flood, mc); + } + if (HighPassable(tt)) + { + maybeFlood(DFCoord(xy.x, xy.y, xy.z + 1), to_flood, mc); + } + } + } + + return v; + } +private: + void maybeFlood(DFCoord c, std::stack &to_flood, MapCache &mc) { + if (mc.testCoord(c)) { + to_flood.push(c); + } + } + Core *c_; +}; + CommandHistory liquids_hist; DFhackCExport command_result df_liquids (Core * c, vector & parameters); @@ -229,6 +288,8 @@ DFhackCExport command_result df_liquids (Core * c, vector & parameters) << "block - DF map block with cursor in it" << endl << " (regular spaced 16x16x1 blocks)" << endl << "column - Column from cursor, up through free space" << endl + << "flood - Flood-fill water tiles from cursor" << endl + << " (only makes sense with wclean)" << endl << "Other:" << endl << "q - quit" << endl << "help or ? - print this list of commands" << endl @@ -317,6 +378,12 @@ DFhackCExport command_result df_liquids (Core * c, vector & parameters) brushname = "column"; brush = new ColumnBrush(); } + else if(command == "flood") + { + delete brush; + brushname = "flood"; + brush = new FloodBrush(c); + } else if(command == "q") { end = true;