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 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; }