int main (int argc, char* argv[]) { // Command line options bool updown = false; if(argc > 1 && strcmp(argv[1],"-x") == 0) updown = true; DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context * DF; try { DF = DFMgr.getSingleContext(); DF->Attach(); } catch (exception& e) { cerr << e.what() << endl; #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } uint32_t x_max,y_max,z_max; DFHack::Maps * Maps = DF->getMaps(); DFHack::Gui * Gui = DF->getGui(); // init the map if(!Maps->Start()) { cerr << "Can't init map. Make sure you have a map loaded in DF." << endl; DF->Detach(); #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } int32_t cx, cy, cz; Maps->getSize(x_max,y_max,z_max); uint32_t tx_max = x_max * 16; uint32_t ty_max = y_max * 16; Gui->getCursorCoords(cx,cy,cz); while(cx == -30000) { cerr << "Cursor is not active. Point the cursor at a vein." << endl; DF->Resume(); cin.ignore(); DF->Suspend(); Gui->getCursorCoords(cx,cy,cz); } DFHack::DFCoord xy ((uint32_t)cx,(uint32_t)cy,cz); if(xy.x == 0 || xy.x == tx_max - 1 || xy.y == 0 || xy.y == ty_max - 1) { cerr << "I won't dig the borders. That would be cheating!" << endl; DF->Detach(); #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } MapCache * MCache = new MapCache(Maps); DFHack::t_designation des = MCache->designationAt(xy); int16_t tt = MCache->tiletypeAt(xy); int16_t veinmat = MCache->veinMaterialAt(xy); if( veinmat == -1 ) { cerr << "This tile is non-vein. Bye :)" << endl; delete MCache; DF->Detach(); #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } printf("%d/%d/%d tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole); stack <DFHack::DFCoord> flood; flood.push(xy); while( !flood.empty() ) { DFHack::DFCoord current = flood.top(); flood.pop(); int16_t vmat2 = MCache->veinMaterialAt(current); tt = MCache->tiletypeAt(current); if(!DFHack::isWallTerrain(tt)) continue; if(vmat2!=veinmat) continue; // found a good tile, dig+unset material DFHack::t_designation des = MCache->designationAt(current); DFHack::t_designation des_minus; DFHack::t_designation des_plus; des_plus.whole = des_minus.whole = 0; int16_t vmat_minus = -1; int16_t vmat_plus = -1; bool below = 0; bool above = 0; if(updown) { if(MCache->testCoord(current-1)) { below = 1; des_minus = MCache->designationAt(current-1); vmat_minus = MCache->veinMaterialAt(current-1); } if(MCache->testCoord(current+1)) { above = 1; des_plus = MCache->designationAt(current+1); vmat_plus = MCache->veinMaterialAt(current+1); } } if(MCache->testCoord(current)) { MCache->clearMaterialAt(current); if(current.x < tx_max - 2) { flood.push(DFHack::DFCoord(current.x + 1, current.y, current.z)); if(current.y < ty_max - 2) { flood.push(DFHack::DFCoord(current.x + 1, current.y + 1,current.z)); flood.push(DFHack::DFCoord(current.x, current.y + 1,current.z)); } if(current.y > 1) { flood.push(DFHack::DFCoord(current.x + 1, current.y - 1,current.z)); flood.push(DFHack::DFCoord(current.x, current.y - 1,current.z)); } } if(current.x > 1) { flood.push(DFHack::DFCoord(current.x - 1, current.y,current.z)); if(current.y < ty_max - 2) { flood.push(DFHack::DFCoord(current.x - 1, current.y + 1,current.z)); flood.push(DFHack::DFCoord(current.x, current.y + 1,current.z)); } if(current.y > 1) { flood.push(DFHack::DFCoord(current.x - 1, current.y - 1,current.z)); flood.push(DFHack::DFCoord(current.x, current.y - 1,current.z)); } } if(updown) { if(current.z > 0 && below && vmat_minus == vmat2) { flood.push(current-1); if(des_minus.bits.dig == DFHack::designation_d_stair) des_minus.bits.dig = DFHack::designation_ud_stair; else des_minus.bits.dig = DFHack::designation_u_stair; MCache->setDesignationAt(current-1,des_minus); des.bits.dig = DFHack::designation_d_stair; } if(current.z < z_max - 1 && above && vmat_plus == vmat2) { flood.push(current+ 1); if(des_plus.bits.dig == DFHack::designation_u_stair) des_plus.bits.dig = DFHack::designation_ud_stair; else des_plus.bits.dig = DFHack::designation_d_stair; MCache->setDesignationAt(current+1,des_plus); if(des.bits.dig == DFHack::designation_d_stair) des.bits.dig = DFHack::designation_ud_stair; else des.bits.dig = DFHack::designation_u_stair; } } if(des.bits.dig == DFHack::designation_no) des.bits.dig = DFHack::designation_default; MCache->setDesignationAt(current,des); } } MCache->WriteAll(); delete MCache; DF->Detach(); #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; cin.ignore(); #endif return 0; }
command_result df_liquids_execute(color_ostream &out, OperationMode &cur_mode, df::coord cursor) { // create brush type depending on old parameters Brush *brush; switch (cur_mode.brush) { case B_POINT: brush = new RectangleBrush(1,1,1,0,0,0); break; case B_RANGE: brush = new RectangleBrush(cur_mode.size.x,cur_mode.size.y,cur_mode.size.z,0,0,0); break; case B_BLOCK: brush = new BlockBrush(); break; case B_COLUMN: brush = new ColumnBrush(); break; case B_FLOOD: brush = new FloodBrush(&Core::getInstance()); break; default: // this should never happen! out << "Old brushtype is invalid! Resetting to point brush.\n"; cur_mode.brush = B_POINT; brush = new RectangleBrush(1,1,1,0,0,0); } std::auto_ptr<Brush> brush_ref(brush); if (!Maps::IsValid()) { out << "Can't see any DF map loaded." << endl; return CR_FAILURE; } MapCache mcache; coord_vec all_tiles = brush->points(mcache,cursor); // Force the game to recompute its walkability cache df::global::world->reindex_pathfinding = true; switch (cur_mode.paint) { case P_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; des.bits.flow_forbid = false; mcache.setDesignationAt(*iter, des); iter ++; } break; } case P_OBSIDIAN_FLOOR: { coord_vec::iterator iter = all_tiles.begin(); while (iter != all_tiles.end()) { mcache.setTiletypeAt(*iter, findRandomVariant(tiletype::LavaFloor1)); iter ++; } break; } case P_RIVER_SOURCE: { 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); b->enableBlockUpdates(true); iter++; } break; } case P_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++; } break; } case P_MAGMA: case P_WATER: case P_FLOW_BITS: { 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 auto block = mcache.BlockAt(curblock); if(!block) { iter ++; continue; } auto raw_block = block->getRaw(); 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(cur_mode.paint != P_FLOW_BITS) { unsigned old_amount = des.bits.flow_size; unsigned new_amount = old_amount; df::tile_liquid old_liquid = des.bits.liquid_type; df::tile_liquid new_liquid = old_liquid; // Compute new liquid type and amount switch (cur_mode.setmode) { case M_KEEP: new_amount = cur_mode.amount; break; case M_INC: if(old_amount < cur_mode.amount) new_amount = cur_mode.amount; break; case M_DEC: if (old_amount > cur_mode.amount) new_amount = cur_mode.amount; } if (cur_mode.paint == P_MAGMA) new_liquid = tile_liquid::Magma; else if (cur_mode.paint == P_WATER) new_liquid = tile_liquid::Water; // Store new amount and type des.bits.flow_size = new_amount; des.bits.liquid_type = new_liquid; // Compute temperature if (!old_amount) old_liquid = tile_liquid::Water; if (!new_amount) new_liquid = tile_liquid::Water; if (old_liquid != new_liquid) { if (new_liquid == tile_liquid::Water) { mcache.setTemp1At(current,10015); mcache.setTemp2At(current,10015); } else { mcache.setTemp1At(current,12000); mcache.setTemp2At(current,12000); } } // mark the tile passable or impassable like the game does des.bits.flow_forbid = (new_liquid == tile_liquid::Magma || new_amount > 3); mcache.setDesignationAt(current,des); // request flow engine updates block->enableBlockUpdates(new_amount != old_amount, new_liquid != old_liquid); } if (cur_mode.permaflow != PF_KEEP && raw_block) { auto &flow = raw_block->liquid_flow[current.x&15][current.y&15]; flow.bits.perm_flow_dir = permaflow_id[cur_mode.permaflow]; flow.bits.temp_flow_timer = 0; } seen_blocks.insert(block); iter++; } set <Block *>::iterator biter = seen_blocks.begin(); while (biter != seen_blocks.end()) { switch (cur_mode.flowmode) { case M_INC: (*biter)->enableBlockUpdates(true); break; case M_DEC: if (auto block = (*biter)->getRaw()) { block->flags.clear(block_flags::update_liquid); block->flags.clear(block_flags::update_liquid_twice); } break; case M_KEEP: { auto block = (*biter)->getRaw(); out << "flow bit 1 = " << block->flags.is_set(block_flags::update_liquid) << endl; out << "flow bit 2 = " << block->flags.is_set(block_flags::update_liquid_twice) << endl; } } biter ++; } break; } } if(!mcache.WriteAll()) { out << "Something failed horribly! RUN!" << endl; return CR_FAILURE; } return CR_OK; }
command_result df_liquids_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; // Force the game to recompute its walkability cache df::global::world->reindex_pathfinding = true; 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; des.bits.flow_forbid = false; 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.update_liquid = true; bf.bits.update_liquid_twice = 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); } // mark the tile passable or impassable like the game does des.bits.flow_forbid = des.bits.flow_size && (des.bits.liquid_type == tile_liquid::Magma || des.bits.flow_size > 3); 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.update_liquid = true; bflags.bits.update_liquid_twice = true; (*biter)->setBlockFlags(bflags); } else if(flowmode == "f-") { bflags.bits.update_liquid = false; bflags.bits.update_liquid_twice = false; (*biter)->setBlockFlags(bflags); } else { out << "flow bit 1 = " << bflags.bits.update_liquid << endl; out << "flow bit 2 = " << bflags.bits.update_liquid_twice << endl; } biter ++; } } if(mcache.WriteAll()) out << "OK" << endl; else out << "Something failed horribly! RUN!" << endl; } while (0); // cleanup delete brush; return CR_OK; }
command_result revflood(color_ostream &out, vector<string> & params) { for(size_t i = 0; i < params.size();i++) { if(params[i] == "help" || params[i] == "?") return CR_WRONG_USAGE; } CoreSuspender suspend; uint32_t x_max,y_max,z_max; if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } if(revealed != NOT_REVEALED) { out.printerr("This is only safe to use with non-revealed map.\n"); return CR_FAILURE; } t_gamemodes gm; World::ReadGameMode(gm); if(!World::isFortressMode(gm.g_type) || gm.g_mode != game_mode::DWARF ) { out.printerr("Only in proper dwarf mode.\n"); return CR_FAILURE; } int32_t cx, cy, cz; Maps::getSize(x_max,y_max,z_max); uint32_t tx_max = x_max * 16; uint32_t ty_max = y_max * 16; Gui::getCursorCoords(cx,cy,cz); if(cx == -30000) { out.printerr("Cursor is not active. Point the cursor at some empty space you want to be unhidden.\n"); return CR_FAILURE; } DFCoord xy ((uint32_t)cx,(uint32_t)cy,cz); MapCache * MCache = new MapCache; df::tiletype tt = MCache->tiletypeAt(xy); if(isWallTerrain(tt)) { out.printerr("Point the cursor at some empty space you want to be unhidden.\n"); delete MCache; return CR_FAILURE; } // hide all tiles, flush cache Maps::getSize(x_max,y_max,z_max); for(size_t i = 0; i < world->map.map_blocks.size(); i++) { df::map_block * b = world->map.map_blocks[i]; // change the hidden flag to 0 for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++) { b->designation[x][y].bits.hidden = 1; } } MCache->trash(); typedef std::pair <DFCoord, bool> foo; std::stack < foo > flood; flood.push( foo(xy,false) ); while( !flood.empty() ) { foo tile = flood.top(); DFCoord & current = tile.first; bool & from_below = tile.second; flood.pop(); if(!MCache->testCoord(current)) continue; df::tiletype tt = MCache->baseTiletypeAt(current); df::tile_designation des = MCache->designationAt(current); if(!des.bits.hidden) { continue; } bool below = 0; bool above = 0; bool sides = 0; bool unhide = 1; // by tile shape, determine behavior and action switch (tileShape(tt)) { // walls: case tiletype_shape::WALL: if(from_below) unhide = 0; break; // air/free space case tiletype_shape::EMPTY: case tiletype_shape::RAMP_TOP: case tiletype_shape::STAIR_UPDOWN: case tiletype_shape::STAIR_DOWN: case tiletype_shape::BROOK_TOP: above = below = sides = true; break; // has floor case tiletype_shape::FORTIFICATION: case tiletype_shape::STAIR_UP: case tiletype_shape::RAMP: case tiletype_shape::FLOOR: case tiletype_shape::BRANCH: case tiletype_shape::TRUNK_BRANCH: case tiletype_shape::TWIG: case tiletype_shape::SAPLING: case tiletype_shape::SHRUB: case tiletype_shape::BOULDER: case tiletype_shape::PEBBLES: case tiletype_shape::BROOK_BED: case tiletype_shape::ENDLESS_PIT: if(from_below) unhide = 0; above = sides = true; break; } if (tileMaterial(tt) == tiletype_material::PLANT || tileMaterial(tt) == tiletype_material::MUSHROOM) { if(from_below) unhide = 0; above = sides = true; } if(unhide) { des.bits.hidden = false; MCache->setDesignationAt(current,des); } if(sides) { flood.push(foo(DFCoord(current.x + 1, current.y ,current.z),false)); flood.push(foo(DFCoord(current.x + 1, current.y + 1 ,current.z),false)); flood.push(foo(DFCoord(current.x, current.y + 1 ,current.z),false)); flood.push(foo(DFCoord(current.x - 1, current.y + 1 ,current.z),false)); flood.push(foo(DFCoord(current.x - 1, current.y ,current.z),false)); flood.push(foo(DFCoord(current.x - 1, current.y - 1 ,current.z),false)); flood.push(foo(DFCoord(current.x, current.y - 1 ,current.z),false)); flood.push(foo(DFCoord(current.x + 1, current.y - 1 ,current.z),false)); } if(above) { flood.push(foo(DFCoord(current.x, current.y ,current.z + 1),true)); } if(below) { flood.push(foo(DFCoord(current.x, current.y ,current.z - 1),false)); } } MCache->WriteAll(); delete MCache; return CR_OK; }