summaryrefslogtreecommitdiff
path: root/plugins/liquids.cpp
diff options
context:
space:
mode:
authorPetr Mrázek2011-07-25 10:14:58 +0200
committerPetr Mrázek2011-07-25 10:14:58 +0200
commitd65f5596cbe5b2b20dc932cf6d841f29cb9d77bb (patch)
treee75e8064aff2b85eff071fc59d71fad60f8becd4 /plugins/liquids.cpp
parentbd9643c8cca04117167c3e708fc23e35b1a42b45 (diff)
downloaddfhack-d65f5596cbe5b2b20dc932cf6d841f29cb9d77bb.tar.gz
dfhack-d65f5596cbe5b2b20dc932cf6d841f29cb9d77bb.tar.bz2
dfhack-d65f5596cbe5b2b20dc932cf6d841f29cb9d77bb.tar.xz
Ported mode, probe. Some changes required for that.
Diffstat (limited to 'plugins/liquids.cpp')
-rw-r--r--plugins/liquids.cpp506
1 files changed, 506 insertions, 0 deletions
diff --git a/plugins/liquids.cpp b/plugins/liquids.cpp
new file mode 100644
index 00000000..6a34d2fa
--- /dev/null
+++ b/plugins/liquids.cpp
@@ -0,0 +1,506 @@
+#include <iostream>
+#include <vector>
+#include <map>
+#include <set>
+#include <cstdlib>
+using namespace std;
+
+#include <DFHack.h>
+#include <dfhack/extra/MapExtras.h>
+using namespace MapExtras;
+#include <dfhack/extra/termutil.h>
+
+
+
+
+
+typedef vector <DFHack::DFCoord> coord_vec;
+
+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;
+
+ for(int xi = 0; xi < 16; xi++)
+ {
+ for(int yi = 0; yi < 16; yi++)
+ {
+ v.push_back(iterc);
+ iterc.y++;
+ }
+ 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))
+ {
+ uint16_t tt = mc.tiletypeAt(start);
+ if(DFHack::LowPassable(tt) || juststarted && DFHack::HighPassable(tt))
+ {
+ v.push_back(start);
+ juststarted = false;
+ start.z++;
+ }
+ else break;
+ }
+ return v;
+ };
+};
+
+int main (int argc, char** argv)
+{
+ bool temporary_terminal = TemporaryTerminal();
+ bool quiet = false;
+ for(int i = 1; i < argc; i++)
+ {
+ string test = argv[i];
+ if(test == "-q")
+ {
+ quiet = true;
+ }
+ }
+ int32_t x,y,z;
+
+ uint32_t x_max,y_max,z_max;
+
+ DFHack::ContextManager DFMgr("Memory.xml");
+ DFHack::Context *DF;
+ DFHack::Maps * Maps;
+ DFHack::Gui * Position;
+ Brush * brush = new RectangleBrush(1,1);
+ string brushname = "point";
+ try
+ {
+ DF=DFMgr.getSingleContext();
+ DF->Attach();
+ Maps = DF->getMaps();
+ Maps->Start();
+ Maps->getSize(x_max,y_max,z_max);
+ Position = DF->getGui();
+ }
+ catch (exception& e)
+ {
+ cerr << e.what() << endl;
+ if(temporary_terminal)
+ cin.ignore();
+ return 1;
+ }
+ bool end = false;
+ cout << "Welcome to the liquid spawner.\nType 'help' or '?' for a list of available commands, 'q' to quit.\nPress return after a command to confirm." << endl;
+ string mode="magma";
+
+ string flowmode="f+";
+ string setmode ="s.";
+ unsigned int amount = 7;
+ int width = 1, height = 1, z_levels = 1;
+ while(!end)
+ {
+ DF->Resume();
+ string command = "";
+ cout <<"[" << mode << ":" << brushname << ":" << amount << ":" << flowmode << ":" << setmode << "]# ";
+ getline(cin, command);
+ if (std::cin.eof())
+ {
+ command = "q";
+ std::cout << std::endl; // No newline from the user here!
+ }
+ if(command=="help" || command == "?")
+ {
+ cout << "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
+ << "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
+ << "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;
+ }
+ 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 == "point" || command == "p")
+ {
+ delete brush;
+ brushname = "point";
+ brush = new RectangleBrush(1,1);
+ }
+ else if(command == "range" || command == "r")
+ {
+ cout << " :set range width<" << width << "># ";
+ getline(cin, command);
+ width = command == "" ? width : atoi (command.c_str());
+ if(width < 1) width = 1;
+
+ cout << " :set range height<" << height << "># ";
+ getline(cin, command);
+ height = command == "" ? height : atoi (command.c_str());
+ if(height < 1) height = 1;
+
+ cout << " :set range z-levels<" << z_levels << "># ";
+ getline(cin, command);
+ z_levels = command == "" ? z_levels : atoi (command.c_str());
+ if(z_levels < 1) z_levels = 1;
+ delete brush;
+ if(width == 1 && height == 1 && z_levels == 1)
+ {
+ brushname="point";
+ }
+ else
+ {
+ brushname = "range";
+ }
+ brush = new RectangleBrush(width,height,z_levels,0,0,0);
+ }
+ else if(command == "block")
+ {
+ delete brush;
+ brushname = "block";
+ brush = new BlockBrush();
+ }
+ else if(command == "column")
+ {
+ delete brush;
+ brushname = "column";
+ brush = new ColumnBrush();
+ }
+ 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->Suspend();
+ do
+ {
+ if(!Maps->Start())
+ {
+ cout << "Can't see any DF map loaded." << endl;
+ break;
+ }
+ if(!Position->getCursorCoords(x,y,z))
+ {
+ cout << "Can't get cursor coords! Make sure you have a cursor active in DF." << endl;
+ break;
+ }
+ cout << "cursor coords: " << x << "/" << y << "/" << z << endl;
+ MapCache mcache(Maps);
+ DFHack::DFCoord cursor(x,y,z);
+ coord_vec all_tiles = brush->points(mcache,cursor);
+ cout << "working..." << endl;
+ if(mode == "obsidian")
+ {
+ coord_vec::iterator iter = all_tiles.begin();
+ while (iter != all_tiles.end())
+ {
+ mcache.setTiletypeAt(*iter, 331);
+ mcache.setTemp1At(*iter,10015);
+ mcache.setTemp2At(*iter,10015);
+ DFHack::t_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, 340);
+ iter ++;
+ }
+ }
+ else if(mode == "riversource")
+ {
+ set <Block *> seen_blocks;
+ coord_vec::iterator iter = all_tiles.begin();
+ while (iter != all_tiles.end())
+ {
+ mcache.setTiletypeAt(*iter, 90);
+
+ DFHack::t_designation a = mcache.designationAt(*iter);
+ a.bits.liquid_type = DFHack::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== "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;
+ DFHack::t_designation des = mcache.designationAt(current);
+ uint16_t tt = mcache.tiletypeAt(current);
+ DFHack::naked_designation & flow = des.bits;
+ // don't put liquids into places where they don't belong...
+ if(!DFHack::FlowPassable(tt))
+ {
+ iter++;
+ continue;
+ }
+ if(mode != "flowbits")
+ {
+ if(setmode == "s.")
+ {
+ flow.flow_size = amount;
+ }
+ else if(setmode == "s+")
+ {
+ if(flow.flow_size < amount)
+ flow.flow_size = amount;
+ }
+ else if(setmode == "s-")
+ {
+ if (flow.flow_size > amount)
+ flow.flow_size = amount;
+ }
+ if(amount != 0 && mode == "magma")
+ {
+ flow.liquid_type = DFHack::liquid_magma;
+ mcache.setTemp1At(current,12000);
+ mcache.setTemp2At(current,12000);
+ }
+ else if(amount != 0 && mode == "water")
+ {
+ flow.liquid_type = DFHack::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((*iter) / 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
+ {
+ cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl;
+ cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl;
+ }
+ biter ++;
+ }
+ }
+ if(mcache.WriteAll())
+ cout << "OK" << endl;
+ else
+ cout << "Something failed horribly! RUN!" << endl;
+ Maps->Finish();
+ } while (0);
+ }
+ else
+ {
+ cout << command << " : unknown command." << endl;
+ }
+ }
+ DF->Detach();
+ if(temporary_terminal && !quiet)
+ {
+ cout << "Done. Press any key to continue" << endl;
+ cin.ignore();
+ }
+ return 0;
+}