develop
			
			
		
		
						commit
						2f76a52959
					
				| @ -0,0 +1,33 @@ | ||||
| PROJECT (cursecheck) | ||||
| # A list of source files | ||||
| SET(PROJECT_SRCS | ||||
|     cursecheck.cpp | ||||
| ) | ||||
| # A list of headers | ||||
| SET(PROJECT_HDRS | ||||
|     cursecheck.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}) | ||||
| 
 | ||||
| # option to use a thread for no particular reason | ||||
| #OPTION(SKELETON_THREAD "Use threads in the skeleton plugin." ON) | ||||
| #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(cursecheck ${PROJECT_SRCS} LINK_LIBRARIES ${PROJECT_LIBS}) | ||||
| @ -0,0 +1,372 @@ | ||||
| // cursecheck plugin
 | ||||
| //
 | ||||
| // check single tile or whole map/world for cursed creatures by checking if a valid curse date (!=-1) is set
 | ||||
| // if a cursor is active only the selected tile will be observed
 | ||||
| // without cursor the whole map will be checked
 | ||||
| // by default cursed creatures will be only counted
 | ||||
| //
 | ||||
| // the tool was intended to help finding vampires but it will also list necromancers, werebeasts and zombies
 | ||||
| //
 | ||||
| // Options:
 | ||||
| //   detail  - print full name, date of birth, date of curse (vamp might use fake identity, though)
 | ||||
| //             show if the creature is active or dead, missing, ghostly (ghost vampires should not exist in 34.05)
 | ||||
| //             identify type of curse (works fine for vanilla ghosts, vamps, werebeasts, zombies and necromancers)
 | ||||
| //   nick    - set nickname to 'CURSED' (does not always show up ingame, some vamps don't like nicknames)
 | ||||
| //   all     - don't ignore dead and inactive creatures (former ghosts, dead necromancers, ...)
 | ||||
| //   verbose - acts like detail but also lists all curse tags (if you want to know it all).
 | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <iomanip> | ||||
| #include <climits> | ||||
| #include <vector> | ||||
| #include <string> | ||||
| #include <sstream> | ||||
| #include <ctime> | ||||
| #include <cstdio> | ||||
| using namespace std; | ||||
| 
 | ||||
| #include "Core.h" | ||||
| #include "Console.h" | ||||
| #include "PluginManager.h" | ||||
| #include "modules/Units.h" | ||||
| #include <modules/Translation.h> | ||||
| #include "modules/Gui.h" | ||||
| #include "MiscUtils.h" | ||||
| 
 | ||||
| #include "df/unit.h" | ||||
| #include "df/unit_soul.h" | ||||
| #include "df/historical_entity.h" | ||||
| #include "df/historical_figure.h" | ||||
| #include "df/historical_figure_info.h" | ||||
| #include "df/assumed_identity.h" | ||||
| #include "df/language_name.h" | ||||
| #include "df/world.h" | ||||
| #include "df/world_raws.h" | ||||
| #include "df/death_info.h" | ||||
| 
 | ||||
| using std::vector; | ||||
| using std::string; | ||||
| using namespace DFHack; | ||||
| using namespace df::enums; | ||||
| using df::global::world; | ||||
| using df::global::cursor; | ||||
| 
 | ||||
| command_result cursecheck (color_ostream &out, vector <string> & parameters); | ||||
| 
 | ||||
| DFHACK_PLUGIN("cursecheck"); | ||||
| 
 | ||||
| DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) | ||||
| { | ||||
|     commands.clear(); | ||||
|     commands.push_back(PluginCommand("cursecheck", | ||||
|         "Checks for cursed creatures (vampires, necromancers, zombies, ...).", | ||||
|         cursecheck, false )); | ||||
|     return CR_OK; | ||||
| } | ||||
| 
 | ||||
| DFhackCExport command_result plugin_shutdown ( color_ostream &out ) | ||||
| { | ||||
|     return CR_OK; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // code for setting nicknames is copypasta from rename.cpp
 | ||||
| // will not work in all cases, some vampires don't like to get nicks
 | ||||
| 
 | ||||
| static void set_nickname(df::language_name *name, std::string nick) | ||||
| { | ||||
|     if (!name->has_name) | ||||
|     { | ||||
|         *name = df::language_name(); | ||||
| 
 | ||||
|         name->language = 0; | ||||
|         name->has_name = true; | ||||
|     } | ||||
| 
 | ||||
|     name->nickname = nick; | ||||
| } | ||||
| 
 | ||||
| void setUnitNickname(df::unit *unit, const std::string &nick) | ||||
| { | ||||
|     // There are >=3 copies of the name, and the one
 | ||||
|     // in the unit is not the authoritative one.
 | ||||
|     // This is the reason why military units often
 | ||||
|     // lose nicknames set from Dwarf Therapist.
 | ||||
|     set_nickname(&unit->name, nick); | ||||
| 
 | ||||
|     if (unit->status.current_soul) | ||||
|         set_nickname(&unit->status.current_soul->name, nick); | ||||
| 
 | ||||
|     df::historical_figure *figure = df::historical_figure::find(unit->hist_figure_id); | ||||
|     if (figure) | ||||
|     { | ||||
|         set_nickname(&figure->name, nick); | ||||
| 
 | ||||
|         // v0.34.01: added the vampire's assumed identity
 | ||||
|         if (figure->info && figure->info->reputation) | ||||
|         { | ||||
|             auto identity = df::assumed_identity::find(figure->info->reputation->cur_identity); | ||||
| 
 | ||||
|             if (identity) | ||||
|             { | ||||
|                 auto id_hfig = df::historical_figure::find(identity->histfig_id); | ||||
| 
 | ||||
|                 if (id_hfig) | ||||
|                 { | ||||
|                     // Even DF doesn't do this bit, because it's apparently
 | ||||
|                     // only used for demons masquerading as gods, so you
 | ||||
|                     // can't ever change their nickname in-game.
 | ||||
|                     set_nickname(&id_hfig->name, nick); | ||||
|                 } | ||||
|                 else | ||||
|                     set_nickname(&identity->name, nick); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void cursedump (color_ostream &out, df::unit * unit); | ||||
| 
 | ||||
| std::string determineCurse(df::unit * unit) | ||||
| { | ||||
|     string cursetype = "unknown"; | ||||
|              | ||||
|     // ghosts: ghostly, duh
 | ||||
|     if(unit->flags3.bits.ghostly) | ||||
|         cursetype = "ghost"; | ||||
| 
 | ||||
|     // zombies: undead or hate life (according to ag), not bloodsuckers
 | ||||
|     if( (unit->curse.add_tags1.bits.OPPOSED_TO_LIFE || unit->curse.add_tags1.bits.NOT_LIVING) | ||||
|         && !unit->curse.add_tags1.bits.BLOODSUCKER ) | ||||
|         cursetype = "zombie"; | ||||
| 
 | ||||
|     // necromancers: alive, don't eat, don't drink, don't age
 | ||||
|     if(!unit->curse.add_tags1.bits.NOT_LIVING  | ||||
|         && unit->curse.add_tags1.bits.NO_EAT  | ||||
|         && unit->curse.add_tags1.bits.NO_DRINK  | ||||
|         && unit->curse.add_tags2.bits.NO_AGING | ||||
|         ) | ||||
|         cursetype = "necromancer"; | ||||
| 
 | ||||
|     // werecreatures: alive, DO eat, DO drink, don't age
 | ||||
|     if(!unit->curse.add_tags1.bits.NOT_LIVING  | ||||
|         && !unit->curse.add_tags1.bits.NO_EAT  | ||||
|         && !unit->curse.add_tags1.bits.NO_DRINK  | ||||
|         && unit->curse.add_tags2.bits.NO_AGING ) | ||||
|         cursetype = "werebeast"; | ||||
| 
 | ||||
|     // vampires: bloodsucker (obvious enough)
 | ||||
|     if(unit->curse.add_tags1.bits.BLOODSUCKER) | ||||
|         cursetype = "vampire"; | ||||
| 
 | ||||
|     return cursetype; | ||||
| } | ||||
| 
 | ||||
| command_result cursecheck (color_ostream &out, vector <string> & parameters) | ||||
| { | ||||
|     CoreSuspender suspend; | ||||
|     int32_t cursorX, cursorY, cursorZ; | ||||
|     Gui::getCursorCoords(cursorX,cursorY,cursorZ); | ||||
| 
 | ||||
|     bool giveDetails = false; | ||||
|     bool giveNick = false; | ||||
|     bool ignoreDead = true; | ||||
|     bool verbose = false; | ||||
|     size_t cursecount = 0; | ||||
| 
 | ||||
|     for(size_t i = 0; i < parameters.size();i++) | ||||
|     { | ||||
|         if(parameters[i] == "help" || parameters[i] == "?") | ||||
|         { | ||||
|             out.print(  "  Search for cursed creatures (ghosts, vampires, necromancers, zombies, werebeasts).\n" | ||||
|                         "  With map cursor active only the current tile will be checked.\n" | ||||
|                         "  Without an in-game cursor the whole map/world will be scanned.\n" | ||||
|                         "  By default cursed creatures are only counted to make it more interesting.\n" | ||||
|                         "  By default dead and passive creatures (aka really dead) are ignored.\n" | ||||
|                         "Options:\n" | ||||
|                         "  detail  - show details (name and age shown ingame might differ)\n" | ||||
|                         "  nick    - try to set cursetype as nickname (does not always work)\n" | ||||
|                         "  all     - include dead and passive creatures\n" | ||||
|                         "  verbose - show all curse tags (if you really want to know it all)\n" | ||||
|                         ); | ||||
|             return CR_OK; | ||||
|         } | ||||
|         if(parameters[i] == "detail") | ||||
|             giveDetails = true; | ||||
|         if(parameters[i] == "nick") | ||||
|             giveNick = true; | ||||
|         if(parameters[i] == "all") | ||||
|             ignoreDead = false; | ||||
|         if(parameters[i] == "verbose") | ||||
|         { | ||||
|             // verbose makes no sense without enabling details
 | ||||
|             giveDetails = true;  | ||||
|             verbose = true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // check whole map if no cursor is active
 | ||||
|     bool checkWholeMap = false; | ||||
|     if(cursorX == -30000) | ||||
|     { | ||||
|         out.print("No cursor; will check all units on the map.\n"); | ||||
|         checkWholeMap = true; | ||||
|     } | ||||
| 
 | ||||
|     for(size_t i = 0; i < world->units.all.size(); i++) | ||||
|     { | ||||
|         df::unit * unit = world->units.all[i]; | ||||
| 
 | ||||
|         // don't spam all completely dead creatures if not explicitly wanted
 | ||||
|         if(unit->flags1.bits.dead && ignoreDead) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         // bail out if we have a map cursor and creature is not at that specific position
 | ||||
|         if ( !checkWholeMap && (unit->pos.x != cursorX || unit->pos.y != cursorY || unit->pos.z != cursorZ) ) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         // non-cursed creatures have curse_year == -1
 | ||||
|         if(unit->relations.curse_year != -1) | ||||
|         { | ||||
|             cursecount++; | ||||
| 
 | ||||
|             string cursetype = determineCurse(unit); | ||||
|                        | ||||
|             if(giveNick) | ||||
|             { | ||||
|                 setUnitNickname(unit, cursetype); //"CURSED");
 | ||||
|             } | ||||
| 
 | ||||
|             if(giveDetails) | ||||
|             { | ||||
|                 if(unit->name.has_name) | ||||
|                 { | ||||
|                     string firstname = unit->name.first_name; | ||||
|                     string restofname = Translation::TranslateName(&unit->name, false); | ||||
|                     firstname[0] = toupper(firstname[0]); | ||||
| 
 | ||||
|                     // if creature has no nickname, restofname will already contain firstname
 | ||||
|                     // no need for double output
 | ||||
|                     if(restofname.compare(0, firstname.length(),firstname) != 0) | ||||
|                         out.print("%s ", firstname.c_str()); | ||||
|                     out.print("%s ", restofname.c_str()); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // happens with unnamed zombies and resurrected body parts
 | ||||
|                     out.print("Unnamed creature "); | ||||
|                 } | ||||
| 
 | ||||
|                 auto death = df::death_info::find(unit->counters.death_id); | ||||
|                 bool missing = false; | ||||
|                 if (death && !death->flags.bits.discovered) | ||||
|                 { | ||||
|                     missing = true; | ||||
|                 } | ||||
|                  | ||||
|                 out.print("born in %d, cursed in %d to be a %s. (%s%s%s)\n", | ||||
|                     unit->relations.birth_year, | ||||
|                     unit->relations.curse_year, | ||||
|                     cursetype.c_str(), | ||||
|                     // technically most cursed creatures are undead, 
 | ||||
|                     // therefore output 'active' if they are not completely dead
 | ||||
|                     unit->flags1.bits.dead ? "deceased" : "active", | ||||
|                     unit->flags3.bits.ghostly ? "-ghostly" : "", | ||||
|                     missing ? "-missing" : "" | ||||
|                     ); | ||||
| 
 | ||||
|                 if (missing) | ||||
|                 { | ||||
|                     out.print("- You can use 'tweak clear-missing' to allow engraving a memorial easier.\n"); | ||||
|                 } | ||||
| 
 | ||||
|                 // dump all curse flags on demand
 | ||||
|                 if (verbose) | ||||
|                 { | ||||
|                     cursedump(out, unit); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (checkWholeMap) | ||||
|         out.print("Number of cursed creatures on map: %d \n", cursecount); | ||||
|     else | ||||
|         out.print("Number of cursed creatures on tile: %d \n", cursecount); | ||||
|      | ||||
|     return CR_OK; | ||||
| } | ||||
| 
 | ||||
| void cursedump (color_ostream &out, df::unit * unit) | ||||
| { | ||||
|     out << "Curse flags: "; | ||||
|     if(unit->curse.add_tags1.bits.BLOODSUCKER) | ||||
|         out << "bloodsucker "; | ||||
|     if(unit->curse.add_tags1.bits.EXTRAVISION) | ||||
|         out << "extravision "; | ||||
|     if(unit->curse.add_tags1.bits.OPPOSED_TO_LIFE) | ||||
|         out << "opposed_to_life "; | ||||
|     if(unit->curse.add_tags1.bits.NOT_LIVING) | ||||
|         out << "not_living "; | ||||
|     if(unit->curse.add_tags1.bits.NOEXERT) | ||||
|         out << "noexpert "; | ||||
|     if(unit->curse.add_tags1.bits.NOPAIN) | ||||
|         out << "nopain "; | ||||
|     if(unit->curse.add_tags1.bits.NOBREATHE) | ||||
|         out << "nobreathe "; | ||||
|     if(unit->curse.add_tags1.bits.HAS_BLOOD) | ||||
|         out << "has_blood "; | ||||
|     if(unit->curse.add_tags1.bits.NOSTUN) | ||||
|         out << "nostun "; | ||||
|     if(unit->curse.add_tags1.bits.NONAUSEA) | ||||
|         out << "nonausea "; | ||||
|     if(unit->curse.add_tags1.bits.NO_DIZZINESS) | ||||
|         out << "no_dizziness "; | ||||
|     if(unit->curse.add_tags1.bits.TRANCES) | ||||
|         out << "trances "; | ||||
|     if(unit->curse.add_tags1.bits.NOEMOTION) | ||||
|         out << "noemotion "; | ||||
|     if(unit->curse.add_tags1.bits.PARALYZEIMMUNE) | ||||
|         out << "paralyzeimmune "; | ||||
|     if(unit->curse.add_tags1.bits.NOFEAR) | ||||
|         out << "nofear "; | ||||
|     if(unit->curse.add_tags1.bits.NO_EAT) | ||||
|         out << "no_eat "; | ||||
|     if(unit->curse.add_tags1.bits.NO_DRINK) | ||||
|         out << "no_drink "; | ||||
|     if(unit->curse.add_tags1.bits.MISCHIEVOUS) | ||||
|         out << "mischievous "; | ||||
|     if(unit->curse.add_tags1.bits.NO_PHYS_ATT_GAIN) | ||||
|         out << "no_phys_att_gain "; | ||||
|     if(unit->curse.add_tags1.bits.NO_PHYS_ATT_RUST) | ||||
|         out << "no_phys_att_rust "; | ||||
|     if(unit->curse.add_tags1.bits.NOTHOUGHT) | ||||
|         out << "nothought "; | ||||
|     if(unit->curse.add_tags1.bits.NO_THOUGHT_CENTER_FOR_MOVEMENT) | ||||
|         out << "no_thought_center_for_movement "; | ||||
|     if(unit->curse.add_tags1.bits.CAN_SPEAK) | ||||
|         out << "can_speak "; | ||||
|     if(unit->curse.add_tags1.bits.CAN_LEARN) | ||||
|         out << "can_learn "; | ||||
|     if(unit->curse.add_tags1.bits.CRAZED) | ||||
|         out << "crazed "; | ||||
|     if(unit->curse.add_tags1.bits.BLOODSUCKER) | ||||
|         out << "bloodsucker "; | ||||
|     if(unit->curse.add_tags1.bits.SUPERNATURAL) | ||||
|         out << "supernatural "; | ||||
| 
 | ||||
|     if(unit->curse.add_tags2.bits.NO_AGING) | ||||
|         out << "no_aging "; | ||||
|     if(unit->curse.add_tags2.bits.STERILE) | ||||
|         out << "sterile "; | ||||
|     if(unit->curse.add_tags2.bits.FIT_FOR_ANIMATION) | ||||
|         out << "fit_for_animation "; | ||||
|     if(unit->curse.add_tags2.bits.FIT_FOR_RESURRECTION) | ||||
|         out << "fit_for_resurrection "; | ||||
| 
 | ||||
|     out << endl << endl; | ||||
| } | ||||
| @ -0,0 +1 @@ | ||||
| #pragma once | ||||
| @ -0,0 +1,33 @@ | ||||
| PROJECT (liquidsgo) | ||||
| # A list of source files | ||||
| SET(PROJECT_SRCS | ||||
|     liquidsgo.cpp | ||||
| ) | ||||
| # A list of headers | ||||
| SET(PROJECT_HDRS | ||||
|     liquidsgo.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}) | ||||
| 
 | ||||
| # option to use a thread for no particular reason | ||||
| #OPTION(SKELETON_THREAD "Use threads in the skeleton plugin." ON) | ||||
| #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(liquidsgo ${PROJECT_SRCS} LINK_LIBRARIES ${PROJECT_LIBS}) | ||||
| @ -0,0 +1,709 @@ | ||||
| // plugin liquidsgo
 | ||||
| //
 | ||||
| // This is a rewrite of the liquids module which can also be used non-interactively (hotkey).
 | ||||
| // First the user sets the mode and other parameters with the interactive command liqiudsgo
 | ||||
| // just like in the original liquids module.
 | ||||
| // They are stored in statics to allow being used after the interactive session was closed.
 | ||||
| // After defining an action the non-interactive command liquidsgo-here can be used to call the 
 | ||||
| // execute method without the necessity to go back to the console. This allows convenient painting
 | ||||
| // of liquids and obsidian using the ingame cursor and a hotkey.
 | ||||
| //
 | ||||
| // Commands:
 | ||||
| // liquidsgo      - basically the original liquids with the map changing stuff moved to an execute method
 | ||||
| // liquidsgo-here - runs the execute method with the last settings from liquidsgo
 | ||||
| //                  (intended to be mapped to a hotkey)
 | ||||
| // Options:
 | ||||
| // ?, help        - print some help
 | ||||
| //
 | ||||
| // TODO: 
 | ||||
| // - maybe allow all parameters be passed as command line options? tedious parsing but might be useful
 | ||||
| // - grab the code from digcircle to get a circle brush - could be nice when painting with obsidian
 | ||||
| // - maybe store the last parameters in a file to make them persistent after dfhack is closed?
 | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <vector> | ||||
| #include <stack> | ||||
| #include <map> | ||||
| #include <set> | ||||
| #include <cstdlib> | ||||
| #include <sstream> | ||||
| using std::vector; | ||||
| using std::string; | ||||
| using std::endl; | ||||
| using std::set; | ||||
| 
 | ||||
| #include "Core.h" | ||||
| #include "Console.h" | ||||
| #include "Export.h" | ||||
| #include "PluginManager.h" | ||||
| #include "modules/Vegetation.h" | ||||
| #include "modules/Maps.h" | ||||
| #include "modules/Gui.h" | ||||
| #include "TileTypes.h" | ||||
| #include "modules/MapCache.h" | ||||
| using namespace MapExtras; | ||||
| using namespace DFHack; | ||||
| using namespace df::enums; | ||||
| typedef vector <df::coord> coord_vec; | ||||
| 
 | ||||
| CommandHistory liquidsgo_hist; | ||||
| 
 | ||||
| command_result df_liquidsgo (color_ostream &out, vector <string> & parameters); | ||||
| command_result df_liquidsgo_here (color_ostream &out, vector <string> & parameters); | ||||
| command_result df_liquidsgo_execute (color_ostream &out); | ||||
| 
 | ||||
| DFHACK_PLUGIN("liquidsgo"); | ||||
| 
 | ||||
| DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) | ||||
| { | ||||
|     liquidsgo_hist.load("liquidsgo.history"); | ||||
|     commands.clear(); | ||||
|     commands.push_back(PluginCommand( | ||||
|         "liquidsgo", "Place magma, water or obsidian.",  | ||||
|         df_liquidsgo, true)); // interactive, needs console for prompt
 | ||||
|     commands.push_back(PluginCommand( | ||||
|         "liquidsgo-here", "Use settings from liquidsgo at cursor position.", | ||||
|         df_liquidsgo_here, Gui::cursor_hotkey, // non-interactive, needs ingame cursor
 | ||||
|         "  Identical to pressing enter in liquidsgo, intended for use as keybinding.\n" | ||||
|         "  Can (but doesn't need to) be called while liquidsgo is running in the console.")); | ||||
|     return CR_OK; | ||||
| } | ||||
| 
 | ||||
| DFhackCExport command_result plugin_shutdown ( color_ostream &out ) | ||||
| { | ||||
|     liquidsgo_hist.save("liquidsgo.history"); | ||||
|     return CR_OK; | ||||
| } | ||||
| 
 | ||||
| class Brush | ||||
| { | ||||
| public: | ||||
|     virtual ~Brush(){}; | ||||
|     virtual coord_vec points(MapCache & mc,DFHack::DFCoord start) = 0; | ||||
| }; | ||||
| /**
 | ||||
|  * generic 3D rectangle brush. you can specify the dimensions of | ||||
|  * the rectangle and optionally which tile is its 'center' | ||||
|  */ | ||||
| class RectangleBrush : public Brush | ||||
| { | ||||
| public: | ||||
|     RectangleBrush(int x, int y, int z = 1, int centerx = -1, int centery = -1, int centerz = -1) | ||||
|     { | ||||
|         if(centerx == -1) | ||||
|             cx_ = x/2; | ||||
|         else | ||||
|             cx_ = centerx; | ||||
|         if(centery == -1) | ||||
|             cy_ = y/2; | ||||
|         else | ||||
|             cy_ = centery; | ||||
|         if(centerz == -1) | ||||
|             cz_ = z/2; | ||||
|         else | ||||
|             cz_ = centerz; | ||||
|         x_ = x; | ||||
|         y_ = y; | ||||
|         z_ = z; | ||||
|     }; | ||||
|     coord_vec points(MapCache & mc, DFHack::DFCoord start) | ||||
|     { | ||||
|         coord_vec v; | ||||
|         DFHack::DFCoord iterstart(start.x - cx_, start.y - cy_, start.z - cz_); | ||||
|         DFHack::DFCoord iter = iterstart; | ||||
|         for(int xi = 0; xi < x_; xi++) | ||||
|         { | ||||
|             for(int yi = 0; yi < y_; yi++) | ||||
|             { | ||||
|                 for(int zi = 0; zi < z_; zi++) | ||||
|                 { | ||||
|                     if(mc.testCoord(iter)) | ||||
|                         v.push_back(iter); | ||||
|                     iter.z++; | ||||
|                 } | ||||
|                 iter.z = iterstart.z; | ||||
|                 iter.y++; | ||||
|             } | ||||
|             iter.y = iterstart.y; | ||||
|             iter.x ++; | ||||
|         } | ||||
|         return v; | ||||
|     }; | ||||
|     ~RectangleBrush(){}; | ||||
| private: | ||||
|     int x_, y_, z_; | ||||
|     int cx_, cy_, cz_; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * stupid block brush, legacy. use when you want to apply something to a whole DF map block. | ||||
|  */ | ||||
| class BlockBrush : public Brush | ||||
| { | ||||
| public: | ||||
|     BlockBrush(){}; | ||||
|     ~BlockBrush(){}; | ||||
|     coord_vec points(MapCache & mc, DFHack::DFCoord start) | ||||
|     { | ||||
|         coord_vec v; | ||||
|         DFHack::DFCoord blockc = start / 16; | ||||
|         DFHack::DFCoord iterc = blockc * 16; | ||||
|         if( !mc.testCoord(start) ) | ||||
|             return v; | ||||
|         auto starty = iterc.y; | ||||
|         for(int xi = 0; xi < 16; xi++) | ||||
|         { | ||||
|             for(int yi = 0; yi < 16; yi++) | ||||
|             { | ||||
|                 v.push_back(iterc); | ||||
|                 iterc.y++; | ||||
|             } | ||||
|             iterc.y = starty; | ||||
|             iterc.x ++; | ||||
|         } | ||||
|         return v; | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * Column from a position through open space tiles | ||||
|  * example: create a column of magma | ||||
|  */ | ||||
| class ColumnBrush : public Brush | ||||
| { | ||||
| public: | ||||
|     ColumnBrush(){}; | ||||
|     ~ColumnBrush(){}; | ||||
|     coord_vec points(MapCache & mc, DFHack::DFCoord start) | ||||
|     { | ||||
|         coord_vec v; | ||||
|         bool juststarted = true; | ||||
|         while (mc.testCoord(start)) | ||||
|         { | ||||
|             df::tiletype tt = mc.tiletypeAt(start); | ||||
|             if(DFHack::LowPassable(tt) || juststarted && DFHack::HighPassable(tt)) | ||||
|             { | ||||
|                 v.push_back(start); | ||||
|                 juststarted = false; | ||||
|                 start.z++; | ||||
|             } | ||||
|             else break; | ||||
|         } | ||||
|         return v; | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * 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<DFCoord> to_flood; | ||||
| 	    to_flood.push(start); | ||||
| 
 | ||||
| 		std::set<DFCoord> 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); | ||||
| 
 | ||||
| 				df::tiletype 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<DFCoord> &to_flood, MapCache &mc) { | ||||
| 		if (mc.testCoord(c)) { | ||||
| 			to_flood.push(c); | ||||
| 		} | ||||
| 	} | ||||
| 	Core *c_; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| // static stuff to be remembered between sessions
 | ||||
| static string brushname = "point"; | ||||
| static string mode="magma"; | ||||
| static string flowmode="f+"; | ||||
| static string setmode ="s."; | ||||
| static unsigned int amount = 7; | ||||
| static int width = 1, height = 1, z_levels = 1; | ||||
| 
 | ||||
| command_result df_liquidsgo (color_ostream &out_, vector <string> & parameters) | ||||
| { | ||||
|     assert(out_.is_console()); | ||||
|     Console &out = static_cast<Console&>(out_); | ||||
| 
 | ||||
|     for(size_t i = 0; i < parameters.size();i++) | ||||
|     { | ||||
|         if(parameters[i] == "help" || parameters[i] == "?") | ||||
|         { | ||||
|             out.print(  "This tool allows placing magma, water and other similar things.\n" | ||||
|                         "It is interactive and further help is available when you run it.\n" | ||||
|                         "The settings will be remembered until dfhack is closed and you can call\n" | ||||
|                         "'liquidsgo-here' (mapped to a hotkey) to paint liquids at the cursor position\n" | ||||
|                         "without the need to go back to the dfhack console.\n"); | ||||
|             return CR_OK; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (!Maps::IsValid()) | ||||
|     { | ||||
|         out.printerr("Map is not available!\n"); | ||||
|         return CR_FAILURE; | ||||
|     } | ||||
| 
 | ||||
|     bool end = false; | ||||
| 
 | ||||
|     out << "Welcome to the liquid spawner.\nType 'help' or '?' for a list of available commands, 'q' to quit.\nPress return after a command to confirm." << std::endl; | ||||
| 
 | ||||
|     while(!end) | ||||
|     { | ||||
|         string command = ""; | ||||
| 
 | ||||
|         std::stringstream str; | ||||
|         str <<"[" << mode << ":" << brushname; | ||||
|         if (brushname == "range") | ||||
|             str << "(w" << width << ":h" << height << ":z" << z_levels << ")"; | ||||
|         str << ":" << amount << ":" << flowmode << ":" << setmode << "]#"; | ||||
|         if(out.lineedit(str.str(),command,liquidsgo_hist) == -1) | ||||
|             return CR_FAILURE; | ||||
| 
 | ||||
|         if(command=="help" || command == "?") | ||||
|         { | ||||
|             out << "Modes:" << endl | ||||
|                  << "m             - switch to magma" << endl | ||||
|                  << "w             - switch to water" << endl | ||||
|                  << "o             - make obsidian wall instead" << endl | ||||
|                  << "of            - make obsidian floors" << endl | ||||
|                  << "rs            - make a river source" << endl | ||||
|                  << "f             - flow bits only" << endl | ||||
|                  << "wclean        - remove salt and stagnant flags from tiles" << endl | ||||
|                  << "Set-Modes (only for magma/water):" << endl | ||||
|                  << "s+            - only add" << endl | ||||
|                  << "s.            - set" << endl | ||||
|                  << "s-            - only remove" << endl | ||||
|                  << "Properties (only for magma/water):" << endl | ||||
|                  << "f+            - make the spawned liquid flow" << endl | ||||
|                  << "f.            - don't change flow state (read state in flow mode)" << endl | ||||
|                  << "f-            - make the spawned liquid static" << endl | ||||
|                  << "0-7           - set liquid amount" << endl | ||||
|                  << "Brush:" << endl | ||||
|                  << "point         - single tile [p]" << endl | ||||
|                  << "range         - block with cursor at bottom north-west [r]" << endl | ||||
|                  << "                (any place, any size)" << endl | ||||
|                  << "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 | ||||
|                  << "empty line    - put liquid" << endl | ||||
|                  << endl | ||||
|                  << "Usage: point the DF cursor at a tile you want to modify" << endl | ||||
|                  << "and use the commands available :)" << endl; | ||||
|             out << endl << "Settings will be remembered until you quit DF. You can call liquidsgo-here to execute the last configured action. Useful in combination with keybindings." << endl; | ||||
|         } | ||||
|         else if(command == "m") | ||||
|         { | ||||
|             mode = "magma"; | ||||
|         } | ||||
|         else if(command == "o") | ||||
|         { | ||||
|             mode = "obsidian"; | ||||
|         } | ||||
|         else if(command == "of") | ||||
|         { | ||||
|             mode = "obsidian_floor"; | ||||
|         } | ||||
|         else if(command == "w") | ||||
|         { | ||||
|             mode = "water"; | ||||
|         } | ||||
|         else if(command == "f") | ||||
|         { | ||||
|             mode = "flowbits"; | ||||
|         } | ||||
|         else if(command == "rs") | ||||
|         { | ||||
|             mode = "riversource"; | ||||
|         } | ||||
|         else if(command == "wclean") | ||||
|         { | ||||
|             mode = "wclean"; | ||||
|         } | ||||
|         else if(command == "point" || command == "p") | ||||
|         { | ||||
|             brushname = "point"; | ||||
|         } | ||||
|         else if(command == "range" || command == "r") | ||||
|         { | ||||
|             std::stringstream str; | ||||
|             CommandHistory range_hist; | ||||
|             str << " :set range width<" << width << "># "; | ||||
|             out.lineedit(str.str(),command,range_hist); | ||||
|             range_hist.add(command); | ||||
|             width = command == "" ? width : atoi (command.c_str()); | ||||
|             if(width < 1) width = 1; | ||||
| 
 | ||||
|             str.str(""); | ||||
|             str << " :set range height<" << height << "># "; | ||||
|             out.lineedit(str.str(),command,range_hist); | ||||
|             range_hist.add(command); | ||||
|             height = command == "" ? height : atoi (command.c_str()); | ||||
|             if(height < 1) height = 1; | ||||
| 
 | ||||
|             str.str(""); | ||||
|             str << " :set range z-levels<" << z_levels << "># "; | ||||
|             out.lineedit(str.str(),command,range_hist); | ||||
|             range_hist.add(command); | ||||
|             z_levels = command == "" ? z_levels : atoi (command.c_str()); | ||||
|             if(z_levels < 1) z_levels = 1; | ||||
|             if(width == 1 && height == 1 && z_levels == 1) | ||||
|             { | ||||
|                 brushname = "point"; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 brushname = "range"; | ||||
|             } | ||||
|         } | ||||
|         else if(command == "block") | ||||
|         { | ||||
|             brushname = "block"; | ||||
|         } | ||||
|         else if(command == "column") | ||||
|         { | ||||
|             brushname = "column"; | ||||
|         } | ||||
| 		else if(command == "flood") | ||||
| 		{ | ||||
| 			brushname = "flood"; | ||||
| 		} | ||||
|         else if(command == "q") | ||||
|         { | ||||
|             end = true; | ||||
|         } | ||||
|         else if(command == "f+") | ||||
|         { | ||||
|             flowmode = "f+"; | ||||
|         } | ||||
|         else if(command == "f-") | ||||
|         { | ||||
|             flowmode = "f-"; | ||||
|         } | ||||
|         else if(command == "f.") | ||||
|         { | ||||
|             flowmode = "f."; | ||||
|         } | ||||
|         else if(command == "s+") | ||||
|         { | ||||
|             setmode = "s+"; | ||||
|         } | ||||
|         else if(command == "s-") | ||||
|         { | ||||
|             setmode = "s-"; | ||||
|         } | ||||
|         else if(command == "s.") | ||||
|         { | ||||
|             setmode = "s."; | ||||
|         } | ||||
|         // blah blah, bad code, bite me.
 | ||||
|         else if(command == "0") | ||||
|             amount = 0; | ||||
|         else if(command == "1") | ||||
|             amount = 1; | ||||
|         else if(command == "2") | ||||
|             amount = 2; | ||||
|         else if(command == "3") | ||||
|             amount = 3; | ||||
|         else if(command == "4") | ||||
|             amount = 4; | ||||
|         else if(command == "5") | ||||
|             amount = 5; | ||||
|         else if(command == "6") | ||||
|             amount = 6; | ||||
|         else if(command == "7") | ||||
|             amount = 7; | ||||
|         else if(command.empty()) | ||||
|         { | ||||
|             df_liquidsgo_execute(out); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             out << command << " : unknown command." << endl; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     return CR_OK; | ||||
| } | ||||
| 
 | ||||
| command_result df_liquidsgo_here (color_ostream &out, vector <string> & parameters) | ||||
| { | ||||
|     for(size_t i = 0; i < parameters.size();i++) | ||||
|     { | ||||
|         if(parameters[i] == "help" || parameters[i] == "?") | ||||
|         { | ||||
|             out << "This command is supposed to be mapped to a hotkey." << endl; | ||||
|             out << "It will use the current/last parameters set in liquidsgo." << endl; | ||||
|             return CR_OK; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     out.print("Run liquidsgo-here with these parameters: "); | ||||
|     out << "[" << mode << ":" << brushname; | ||||
|     if (brushname == "range") | ||||
|         out << "(w" << width << ":h" << height << ":z" << z_levels << ")"; | ||||
|     out << ":" << amount << ":" << flowmode << ":" << setmode << "]\n"; | ||||
| 
 | ||||
|     return df_liquidsgo_execute(out); | ||||
| } | ||||
| 
 | ||||
| command_result df_liquidsgo_execute(color_ostream &out) | ||||
| { | ||||
|     // create brush type depending on old parameters
 | ||||
|     Brush * brush; | ||||
| 
 | ||||
|     if (brushname == "point") | ||||
|     { | ||||
|         brush = new RectangleBrush(1,1,1,0,0,0); | ||||
|         //width = 1;
 | ||||
|         //height = 1;
 | ||||
|         //z_levels = 1;
 | ||||
|     } | ||||
|     else if (brushname == "range") | ||||
|     { | ||||
|         brush = new RectangleBrush(width,height,z_levels,0,0,0); | ||||
|     } | ||||
|     else if(brushname == "block") | ||||
|     { | ||||
|         brush = new BlockBrush(); | ||||
|     } | ||||
|     else if(brushname == "column") | ||||
|     { | ||||
|         brush = new ColumnBrush(); | ||||
|     } | ||||
|     else if(brushname == "flood") | ||||
|     { | ||||
|         brush = new FloodBrush(&Core::getInstance()); | ||||
| 	} | ||||
|     else | ||||
|     { | ||||
|         // this should never happen!
 | ||||
|         out << "Old brushtype is invalid! Resetting to point brush.\n"; | ||||
|         brushname = "point"; | ||||
|         width = 1; | ||||
|         height = 1; | ||||
|         z_levels = 1; | ||||
|         brush = new RectangleBrush(width,height,z_levels,0,0,0); | ||||
| 	} | ||||
| 
 | ||||
|     CoreSuspender suspend; | ||||
| 
 | ||||
|     do | ||||
|     { | ||||
|         if (!Maps::IsValid()) | ||||
|         { | ||||
|             out << "Can't see any DF map loaded." << endl; | ||||
|             break;; | ||||
|         } | ||||
|         int32_t x,y,z; | ||||
|         if(!Gui::getCursorCoords(x,y,z)) | ||||
|         { | ||||
|             out << "Can't get cursor coords! Make sure you have a cursor active in DF." << endl; | ||||
|             break; | ||||
|         } | ||||
|         out << "cursor coords: " << x << "/" << y << "/" << z << endl; | ||||
|         MapCache mcache; | ||||
|         DFHack::DFCoord cursor(x,y,z); | ||||
|         coord_vec all_tiles = brush->points(mcache,cursor); | ||||
|         out << "working..." << endl; | ||||
|         if(mode == "obsidian") | ||||
|         { | ||||
|             coord_vec::iterator iter = all_tiles.begin(); | ||||
|             while (iter != all_tiles.end()) | ||||
|             { | ||||
|                 mcache.setTiletypeAt(*iter, tiletype::LavaWall); | ||||
|                 mcache.setTemp1At(*iter,10015); | ||||
|                 mcache.setTemp2At(*iter,10015); | ||||
|                 df::tile_designation des = mcache.designationAt(*iter); | ||||
|                 des.bits.flow_size = 0; | ||||
|                 mcache.setDesignationAt(*iter, des); | ||||
|                 iter ++; | ||||
|             } | ||||
|         } | ||||
|         if(mode == "obsidian_floor") | ||||
|         { | ||||
|             coord_vec::iterator iter = all_tiles.begin(); | ||||
|             while (iter != all_tiles.end()) | ||||
|             { | ||||
|                 mcache.setTiletypeAt(*iter, findRandomVariant(tiletype::LavaFloor1)); | ||||
|                 iter ++; | ||||
|             } | ||||
|         } | ||||
|         else if(mode == "riversource") | ||||
|         { | ||||
|             coord_vec::iterator iter = all_tiles.begin(); | ||||
|             while (iter != all_tiles.end()) | ||||
|             { | ||||
|                 mcache.setTiletypeAt(*iter, tiletype::RiverSource); | ||||
| 
 | ||||
|                 df::tile_designation a = mcache.designationAt(*iter); | ||||
|                 a.bits.liquid_type = tile_liquid::Water; | ||||
|                 a.bits.liquid_static = false; | ||||
|                 a.bits.flow_size = 7; | ||||
|                 mcache.setTemp1At(*iter,10015); | ||||
|                 mcache.setTemp2At(*iter,10015); | ||||
|                 mcache.setDesignationAt(*iter,a); | ||||
| 
 | ||||
|                 Block * b = mcache.BlockAt((*iter)/16); | ||||
|                 DFHack::t_blockflags bf = b->BlockFlags(); | ||||
|                 bf.bits.liquid_1 = true; | ||||
|                 bf.bits.liquid_2 = true; | ||||
|                 b->setBlockFlags(bf); | ||||
| 
 | ||||
|                 iter++; | ||||
|             } | ||||
|         } | ||||
|         else if(mode=="wclean") | ||||
|         { | ||||
|             coord_vec::iterator iter = all_tiles.begin(); | ||||
|             while (iter != all_tiles.end()) | ||||
|             { | ||||
|                 DFHack::DFCoord current = *iter; | ||||
|                 df::tile_designation des = mcache.designationAt(current); | ||||
|                 des.bits.water_salt = false; | ||||
|                 des.bits.water_stagnant = false; | ||||
|                 mcache.setDesignationAt(current,des); | ||||
|                 iter++; | ||||
|             } | ||||
|         } | ||||
|         else if(mode== "magma" || mode== "water" || mode == "flowbits") | ||||
|         { | ||||
|             set <Block *> seen_blocks; | ||||
|             coord_vec::iterator iter = all_tiles.begin(); | ||||
|             while (iter != all_tiles.end()) | ||||
|             { | ||||
|                 DFHack::DFCoord current = *iter; // current tile coord
 | ||||
|                 DFHack::DFCoord curblock = current /16; // current block coord
 | ||||
|                 // check if the block is actually there
 | ||||
|                 if(!mcache.BlockAt(curblock)) | ||||
|                 { | ||||
|                     iter ++; | ||||
|                     continue; | ||||
|                 } | ||||
|                 df::tile_designation des = mcache.designationAt(current); | ||||
|                 df::tiletype tt = mcache.tiletypeAt(current); | ||||
|                 // don't put liquids into places where they don't belong...
 | ||||
|                 if(!DFHack::FlowPassable(tt)) | ||||
|                 { | ||||
|                     iter++; | ||||
|                     continue; | ||||
|                 } | ||||
|                 if(mode != "flowbits") | ||||
|                 { | ||||
|                     if(setmode == "s.") | ||||
|                     { | ||||
|                         des.bits.flow_size = amount; | ||||
|                     } | ||||
|                     else if(setmode == "s+") | ||||
|                     { | ||||
|                         if(des.bits.flow_size < amount) | ||||
|                             des.bits.flow_size = amount; | ||||
|                     } | ||||
|                     else if(setmode == "s-") | ||||
|                     { | ||||
|                         if (des.bits.flow_size > amount) | ||||
|                             des.bits.flow_size = amount; | ||||
|                     } | ||||
|                     if(amount != 0 && mode == "magma") | ||||
|                     { | ||||
|                         des.bits.liquid_type =  tile_liquid::Magma; | ||||
|                         mcache.setTemp1At(current,12000); | ||||
|                         mcache.setTemp2At(current,12000); | ||||
|                     } | ||||
|                     else if(amount != 0 && mode == "water") | ||||
|                     { | ||||
|                         des.bits.liquid_type =  tile_liquid::Water; | ||||
|                         mcache.setTemp1At(current,10015); | ||||
|                         mcache.setTemp2At(current,10015); | ||||
|                     } | ||||
|                     else if(amount == 0 && (mode == "water" || mode == "magma")) | ||||
|                     { | ||||
|                         // reset temperature to sane default
 | ||||
|                         mcache.setTemp1At(current,10015); | ||||
|                         mcache.setTemp2At(current,10015); | ||||
|                     } | ||||
|                     mcache.setDesignationAt(current,des); | ||||
|                 } | ||||
|                 seen_blocks.insert(mcache.BlockAt(current / 16)); | ||||
|                 iter++; | ||||
|             } | ||||
|             set <Block *>::iterator biter = seen_blocks.begin(); | ||||
|             while (biter != seen_blocks.end()) | ||||
|             { | ||||
|                 DFHack::t_blockflags bflags = (*biter)->BlockFlags(); | ||||
|                 if(flowmode == "f+") | ||||
|                 { | ||||
|                     bflags.bits.liquid_1 = true; | ||||
|                     bflags.bits.liquid_2 = true; | ||||
|                     (*biter)->setBlockFlags(bflags); | ||||
|                 } | ||||
|                 else if(flowmode == "f-") | ||||
|                 { | ||||
|                     bflags.bits.liquid_1 = false; | ||||
|                     bflags.bits.liquid_2 = false; | ||||
|                     (*biter)->setBlockFlags(bflags); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     out << "flow bit 1 = " << bflags.bits.liquid_1 << endl;  | ||||
|                     out << "flow bit 2 = " << bflags.bits.liquid_2 << endl; | ||||
|                 } | ||||
|                 biter ++; | ||||
|             } | ||||
|         } | ||||
|         if(mcache.WriteAll()) | ||||
|             out << "OK" << endl; | ||||
|         else | ||||
|             out << "Something failed horribly! RUN!" << endl; | ||||
|     } while (0); | ||||
| 
 | ||||
|     // cleanup
 | ||||
|     delete brush; | ||||
|      | ||||
|     return CR_OK; | ||||
| } | ||||
| @ -0,0 +1 @@ | ||||
| #pragma once | ||||
		Loading…
	
		Reference in New Issue