StockpileInfo(building_stockpilest *sp_) : sp(sp_) { MapExtras::MapCache mc; z = sp_->z; x1 = sp_->room.x; x2 = sp_->room.x + sp_->room.width; y1 = sp_->room.y; y2 = sp_->room.y + sp_->room.height; int e = 0; size = 0; free = 0; for (int y = y1; y < y2; y++) for (int x = x1; x < x2; x++) if (sp_->room.extents[e++] == 1) { size++; DFCoord cursor (x,y,z); uint32_t blockX = x / 16; uint32_t tileX = x % 16; uint32_t blockY = y / 16; uint32_t tileY = y % 16; MapExtras::Block * b = mc.BlockAt(cursor/16); if(b && b->is_valid()) { auto &block = *b->getRaw(); df::tile_occupancy &occ = block.occupancy[tileX][tileY]; if (!occ.bits.item) free++; } } }
static command_result GetEmbarkTile(color_ostream &stream, const TileRequest *in, EmbarkTile *out) { MapExtras::MapCache MC; gather_embark_tile(in->want_x() * 3, in->want_y() * 3, out, &MC); MC.trash(); return CR_OK; }
command_result readFlag (Core * c, vector <string> & parameters) { c->Suspend(); // init the map if(!Maps::IsValid()) { c->con.printerr("Can't init map. Make sure you have a map loaded in DF.\n"); c->Resume(); return CR_FAILURE; } int32_t cx, cy, cz; if(!Gui::getCursorCoords(cx,cy,cz)) { c->con.printerr("Cursor is not active.\n"); c->Resume(); return CR_FAILURE; } DFCoord cursor = DFCoord(cx,cy,cz); MapExtras::MapCache * MCache = new MapExtras::MapCache(); t_occupancy oc = MCache->occupancyAt(cursor); c->con.print("Current Value: %d\n", oc.bits.building); c->Resume(); return CR_OK; }
command_result df_grow (color_ostream &out, vector <string> & parameters) { for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") { out << "Usage:\n" "This command turns all living saplings on the map into full-grown trees.\n" "With active cursor, work on the targetted one only.\n"; return CR_OK; } } CoreSuspender suspend; if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } MapExtras::MapCache map; int32_t x,y,z; if(Gui::getCursorCoords(x,y,z)) { auto block = Maps::getTileBlock(x,y,z); stl::vector<df::plant *> *alltrees = &world->plants.all; if(alltrees) { for(size_t i = 0 ; i < alltrees->size(); i++) { df::plant * tree = alltrees->at(i); if(tree->pos.x == x && tree->pos.y == y && tree->pos.z == z) { if(tileShape(map.tiletypeAt(DFCoord(x,y,z))) == tiletype_shape::SAPLING && tileSpecial(map.tiletypeAt(DFCoord(x,y,z))) != tiletype_special::DEAD) { tree->grow_counter = sapling_to_tree_threshold; } break; } } } } else { int grown = 0; for(size_t i = 0 ; i < world->plants.all.size(); i++) { df::plant *p = world->plants.all[i]; df::tiletype ttype = map.tiletypeAt(df::coord(p->pos.x,p->pos.y,p->pos.z)); bool is_shrub = p->flags >= plant_flags::shrub_forest; if(!is_shrub && tileShape(ttype) == tiletype_shape::SAPLING && tileSpecial(ttype) != tiletype_special::DEAD) { p->grow_counter = sapling_to_tree_threshold; } } } return CR_OK; }
//Restrict traffic if tile is visible and liquid is present. void restrictLiquidProc(DFCoord coord, MapExtras::MapCache &map) { df::tile_designation des = map.designationAt(coord); if ((des.bits.hidden == 0) && (des.bits.flow_size != 0)) { des.bits.traffic = tile_traffic::Restricted; map.setDesignationAt(coord, des); } }
command_result df_grow (color_ostream &out, vector <string> & parameters) { for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") { out.print("This command turns all living saplings into full-grown trees.\n"); return CR_OK; } } CoreSuspender suspend; if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } MapExtras::MapCache map; int32_t x,y,z; if(Gui::getCursorCoords(x,y,z)) { vector<df::plant *> * alltrees; if(Maps::ReadVegetation(x/16,y/16,z,alltrees)) { for(size_t i = 0 ; i < alltrees->size(); i++) { df::plant * tree = alltrees->at(i); if(tree->pos.x == x && tree->pos.y == y && tree->pos.z == z) { if(tileShape(map.tiletypeAt(DFCoord(x,y,z))) == tiletype_shape::SAPLING && tileSpecial(map.tiletypeAt(DFCoord(x,y,z))) != tiletype_special::DEAD) { tree->grow_counter = Vegetation::sapling_to_tree_threshold; } break; } } } } else { int grown = 0; for(size_t i = 0 ; i < world->plants.all.size(); i++) { df::plant *p = world->plants.all[i]; df::tiletype ttype = map.tiletypeAt(df::coord(p->pos.x,p->pos.y,p->pos.z)); if(!p->flags.bits.is_shrub && tileShape(ttype) == tiletype_shape::SAPLING && tileSpecial(ttype) != tiletype_special::DEAD) { p->grow_counter = Vegetation::sapling_to_tree_threshold; } } } return CR_OK; }
//Restrict traffice if tile is above visible ice wall. void restrictIceProc(DFCoord coord, MapExtras::MapCache &map) { //There is no ice below the bottom of the map. if (coord.z == 0) return; DFCoord tile_below = DFCoord(coord.x, coord.y, coord.z - 1); df::tiletype tt = map.tiletypeAt(tile_below); df::tile_designation des = map.designationAt(tile_below); if ((des.bits.hidden == 0) && (tileMaterial(tt) == tiletype_material::FROZEN_LIQUID)) { des = map.designationAt(coord); des.bits.traffic = tile_traffic::Restricted; map.setDesignationAt(coord, des); } }
static void putOnGround(MapExtras::MapCache &mc, df::item *item, df::coord pos) { item->pos = pos; item->flags.bits.on_ground = true; if (!mc.addItemOnGround(item)) Core::printerr("Could not add item %d to ground at (%d,%d,%d)\n", item->id, pos.x, pos.y, pos.z); }
void lightingEngineViewscreen::doSun(const lightSource& sky,MapExtras::MapCache& map) { //TODO fix this mess int window_x=*df::global::window_x; int window_y=*df::global::window_y; coord2d window2d(window_x,window_y); int window_z=*df::global::window_z; rect2d vp=getMapViewport(); coord2d vpSize=rect_size(vp); rect2d blockVp; blockVp.first=window2d/16; blockVp.second=(window2d+vpSize)/16; blockVp.second.x=std::min(blockVp.second.x,(int16_t)df::global::world->map.x_count_block); blockVp.second.y=std::min(blockVp.second.y,(int16_t)df::global::world->map.y_count_block); //endof mess for(int blockX=blockVp.first.x;blockX<=blockVp.second.x;blockX++) for(int blockY=blockVp.first.y;blockY<=blockVp.second.y;blockY++) { rgbf cellArray[16][16]; for(int block_x = 0; block_x < 16; block_x++) for(int block_y = 0; block_y < 16; block_y++) cellArray[block_x][block_y] = sky.power; int emptyCell=0; for(int z=window_z;z< df::global::world->map.z_count && emptyCell<256;z++) { MapExtras::Block* b=map.BlockAt(DFCoord(blockX,blockY,z)); if(!b) continue; emptyCell=0; for(int block_x = 0; block_x < 16; block_x++) for(int block_y = 0; block_y < 16; block_y++) { rgbf& curCell=cellArray[block_x][block_y]; curCell=propogateSun(b,block_x,block_y,curCell,z==window_z); if(curCell.dot(curCell)<0.003f) emptyCell++; } } if(emptyCell==256) continue; for(int block_x = 0; block_x < 16; block_x++) for(int block_y = 0; block_y < 16; block_y++) { rgbf& curCell=cellArray[block_x][block_y]; df::coord2d pos; pos.x = blockX*16+block_x; pos.y = blockY*16+block_y; pos=worldToViewportCoord(pos,vp,window2d); if(isInRect(pos,vp) && curCell.dot(curCell)>0.003f) { lightSource sun=lightSource(curCell,15); addLight(getIndex(pos.x,pos.y),sun); } } } }
void onDig(color_ostream& out, void* ptr) { CoreSuspender bob; df::job* job = (df::job*)ptr; if ( job->completion_timer > 0 ) return; if ( job->job_type != df::enums::job_type::Dig && job->job_type != df::enums::job_type::CarveUpwardStaircase && job->job_type != df::enums::job_type::CarveDownwardStaircase && job->job_type != df::enums::job_type::CarveUpDownStaircase && job->job_type != df::enums::job_type::CarveRamp && job->job_type != df::enums::job_type::DigChannel ) return; set<df::coord> jobLocations; for ( df::job_list_link* link = &world->job_list; link != NULL; link = link->next ) { if ( link->item == NULL ) continue; if ( link->item->job_type != df::enums::job_type::Dig && link->item->job_type != df::enums::job_type::CarveUpwardStaircase && link->item->job_type != df::enums::job_type::CarveDownwardStaircase && link->item->job_type != df::enums::job_type::CarveUpDownStaircase && link->item->job_type != df::enums::job_type::CarveRamp && link->item->job_type != df::enums::job_type::DigChannel ) continue; jobLocations.insert(link->item->pos); } MapExtras::MapCache cache; df::coord pos = job->pos; for ( int16_t a = -1; a <= 1; a++ ) { for ( int16_t b = -1; b <= 1; b++ ) { maybeExplore(out, cache, df::coord(pos.x+a,pos.y+b,pos.z), jobLocations); } } cache.trash(); }
void maybeExplore(color_ostream& out, MapExtras::MapCache& cache, df::coord pt, set<df::coord>& jobLocations) { if ( !Maps::isValidTilePos(pt) ) { return; } df::map_block* block = Maps::getTileBlock(pt); if (!block) return; if ( block->designation[pt.x&0xF][pt.y&0xF].bits.hidden ) return; df::tiletype type = block->tiletype[pt.x&0xF][pt.y&0xF]; if ( ENUM_ATTR(tiletype, material, type) != df::enums::tiletype_material::MINERAL ) return; if ( ENUM_ATTR(tiletype, shape, type) != df::enums::tiletype_shape::WALL ) return; if ( block->designation[pt.x&0xF][pt.y&0xF].bits.dig != df::enums::tile_dig_designation::No ) return; uint32_t xMax,yMax,zMax; Maps::getSize(xMax,yMax,zMax); if ( pt.x == 0 || pt.y == 0 || pt.x+1 == xMax*16 || pt.y+1 == yMax*16 ) return; if ( jobLocations.find(pt) != jobLocations.end() ) { return; } int16_t mat = cache.veinMaterialAt(pt); if ( mat == -1 ) return; if ( !digAll ) { df::inorganic_raw* inorganic = world->raws.inorganics[mat]; if ( autodigMaterials.find(inorganic->id) == autodigMaterials.end() ) { return; } } block->designation[pt.x&0xF][pt.y&0xF].bits.dig = df::enums::tile_dig_designation::Default; block->flags.bits.designated = true; // *process_dig = true; // *process_jobs = true; }
bool dig (MapExtras::MapCache & MCache, circle_what what, df::tile_dig_designation type, int32_t x, int32_t y, int32_t z, int x_max, int y_max ) { DFCoord at (x,y,z); auto b = MCache.BlockAt(at/16); if(!b || !b->valid) return false; if(x == 0 || x == x_max * 16 - 1) { //c->con.print("not digging map border\n"); return false; } if(y == 0 || y == y_max * 16 - 1) { //c->con.print("not digging map border\n"); return false; } df::tiletype tt = MCache.tiletypeAt(at); df::tile_designation des = MCache.designationAt(at); // could be potentially used to locate hidden constructions? if(tileMaterial(tt) == df::tiletype_material::CONSTRUCTION && !des.bits.hidden) return false; df::tiletype_shape ts = tileShape(tt); if (ts == tiletype_shape::EMPTY) return false; if(!des.bits.hidden) { do { df::tiletype_shape_basic tsb = ENUM_ATTR(tiletype_shape, basic_shape, ts); if(tsb == tiletype_shape_basic::Wall) { std::cerr << "allowing tt" << (int)tt << ", is wall\n"; break; } if (tsb == tiletype_shape_basic::Floor && (type == tile_dig_designation::DownStair || type == tile_dig_designation::Channel) && ts != tiletype_shape::TREE ) { std::cerr << "allowing tt" << (int)tt << ", is floor\n"; break; } if (tsb == tiletype_shape_basic::Stair && type == tile_dig_designation::Channel ) break; return false; } while(0); } switch(what) { case circle_set: if(des.bits.dig == tile_dig_designation::No) { des.bits.dig = type; } break; case circle_unset: if (des.bits.dig != tile_dig_designation::No) { des.bits.dig = tile_dig_designation::No; } break; case circle_invert: if(des.bits.dig == tile_dig_designation::No) { des.bits.dig = type; } else { des.bits.dig = tile_dig_designation::No; } break; } std::cerr << "allowing tt" << (int)tt << "\n"; MCache.setDesignationAt(at,des); return true; };
command_result digcircle (Core * c, vector <string> & parameters) { static bool filled = false; static circle_what what = circle_set; static df::tile_dig_designation type = tile_dig_designation::Default; static int diameter = 0; auto saved_d = diameter; bool force_help = false; for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") { force_help = true; } else if(parameters[i] == "hollow") { filled = false; } else if(parameters[i] == "filled") { filled = true; } else if(parameters[i] == "set") { what = circle_set; } else if(parameters[i] == "unset") { what = circle_unset; } else if(parameters[i] == "invert") { what = circle_invert; } else if(parameters[i] == "dig") { type = tile_dig_designation::Default; } else if(parameters[i] == "ramp") { type = tile_dig_designation::Ramp; } else if(parameters[i] == "dstair") { type = tile_dig_designation::DownStair; } else if(parameters[i] == "ustair") { type = tile_dig_designation::UpStair; } else if(parameters[i] == "xstair") { type = tile_dig_designation::UpDownStair; } else if(parameters[i] == "chan") { type = tile_dig_designation::Channel; } else if (!from_string(diameter,parameters[i], std::dec)) { diameter = saved_d; } } if(diameter < 0) diameter = -diameter; if(force_help || diameter == 0) { c->con.print( "A command for easy designation of filled and hollow circles.\n" "\n" "Options:\n" " hollow = Set the circle to hollow (default)\n" " filled = Set the circle to filled\n" "\n" " set = set designation\n" " unset = unset current designation\n" " invert = invert current designation\n" "\n" " dig = normal digging\n" " ramp = ramp digging\n" " ustair = staircase up\n" " dstair = staircase down\n" " xstair = staircase up/down\n" " chan = dig channel\n" "\n" " # = diameter in tiles (default = 0)\n" "\n" "After you have set the options, the command called with no options\n" "repeats with the last selected parameters:\n" "'digcircle filled 3' = Dig a filled circle with radius = 3.\n" "'digcircle' = Do it again.\n" ); return CR_OK; } int32_t cx, cy, cz; CoreSuspender suspend(c); if (!Maps::IsValid()) { c->con.printerr("Map is not available!\n"); return CR_FAILURE; } uint32_t x_max, y_max, z_max; Maps::getSize(x_max,y_max,z_max); MapExtras::MapCache MCache; if(!Gui::getCursorCoords(cx,cy,cz) || cx == -30000) { c->con.printerr("Can't get the cursor coords...\n"); return CR_FAILURE; } int r = diameter / 2; int iter; bool adjust; if(diameter % 2) { // paint center if(filled) { lineY(MCache,what,type, cx - r, cx + r, cy, cz,x_max,y_max); } else { dig(MCache, what, type,cx - r, cy, cz,x_max,y_max); dig(MCache, what, type,cx + r, cy, cz,x_max,y_max); } adjust = false; iter = 2; } else { adjust = true; iter = 1; } int lastwhole = r; for(; iter <= diameter - 1; iter +=2) { // top, bottom coords int top = cy - ((iter + 1) / 2) + adjust; int bottom = cy + ((iter + 1) / 2); // see where the current 'line' intersects the circle double val = std::sqrt(double(diameter*diameter - iter*iter)); // adjust for circles with odd diameter if(!adjust) val -= 1; // map the found value to the DF grid double whole; double fraction = std::modf(val / 2.0, & whole); if (fraction > 0.5) whole += 1.0; int right = cx + whole; int left = cx - whole + adjust; int diff = lastwhole - whole; // paint if(filled || iter == diameter - 1) { lineY(MCache,what,type, left, right, top , cz,x_max,y_max); lineY(MCache,what,type, left, right, bottom , cz,x_max,y_max); } else { dig(MCache, what, type,left, top, cz,x_max,y_max); dig(MCache, what, type,left, bottom, cz,x_max,y_max); dig(MCache, what, type,right, top, cz,x_max,y_max); dig(MCache, what, type,right, bottom, cz,x_max,y_max); } if(!filled && diff > 1) { int lright = cx + lastwhole; int lleft = cx - lastwhole + adjust; lineY(MCache,what,type, lleft + 1, left - 1, top + 1 , cz,x_max,y_max); lineY(MCache,what,type, right + 1, lright - 1, top + 1 , cz,x_max,y_max); lineY(MCache,what,type, lleft + 1, left - 1, bottom - 1 , cz,x_max,y_max); lineY(MCache,what,type, right + 1, lright - 1, bottom - 1 , cz,x_max,y_max); } lastwhole = whole; } MCache.WriteAll(); return CR_OK; }
//Helper function for writing new functions that check every tile on the map. //newTraffic is the traffic designation to set. //check takes a coordinate and the map cache as arguments, and returns true if the criteria is met. //minCoord and maxCoord can be used to specify a bounding cube. DFhackCExport command_result setAllMatching(DFHack::Core * c, checkTile checkProc, DFHack::DFCoord minCoord, DFHack::DFCoord maxCoord) { //Initialization. c->Suspend(); DFHack::Maps * Maps = c->getMaps(); DFHack::Gui * Gui = c->getGui(); // init the map if(!Maps->Start()) { c->con.printerr("Can't init map. Make sure you have a map loaded in DF.\n"); c->Resume(); return CR_FAILURE; } //Maximum map size. uint32_t x_max,y_max,z_max; Maps->getSize(x_max,y_max,z_max); uint32_t tx_max = x_max * 16; uint32_t ty_max = y_max * 16; //Ensure maximum coordinate is within map. Truncate to map edge. maxCoord.x = std::min((uint32_t) maxCoord.x, tx_max); maxCoord.y = std::min((uint32_t) maxCoord.y, ty_max); maxCoord.z = std::min(maxCoord.z, z_max); //Check minimum co-ordinates against maximum map size if (minCoord.x > maxCoord.x) { c->con.printerr("Minimum x coordinate is greater than maximum x coordinate.\n"); c->Resume(); return CR_FAILURE; } if (minCoord.y > maxCoord.y) { c->con.printerr("Minimum y coordinate is greater than maximum y coordinate.\n"); c->Resume(); return CR_FAILURE; } if (minCoord.z > maxCoord.y) { c->con.printerr("Minimum z coordinate is greater than maximum z coordinate.\n"); c->Resume(); return CR_FAILURE; } MapExtras::MapCache * MCache = new MapExtras::MapCache(Maps); c->con.print("Setting traffic...\n"); //Loop through every single tile for(uint32_t x = minCoord.x; x <= maxCoord.x; x++) { for(uint32_t y = minCoord.y; y <= maxCoord.y; y++) { for(uint32_t z = minCoord.z; z <= maxCoord.z; z++) { DFHack::DFCoord tile = DFHack::DFCoord(x, y, z); checkProc(tile, MCache); } } } MCache->WriteAll(); c->con.print("Complete!\n"); c->Resume(); return CR_OK; }
command_result mapexport (color_ostream &out, std::vector <std::string> & parameters) { bool showHidden = false; int filenameParameter = 1; for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") { out.print("Exports the currently visible map to a file.\n" "Usage: mapexport [options] <filename>\n" "Example: mapexport all embark.dfmap\n" "Options:\n" " all - Export the entire map, not just what's revealed.\n" ); return CR_OK; } if (parameters[i] == "all") { showHidden = true; filenameParameter++; } } CoreSuspender suspend; uint32_t x_max=0, y_max=0, z_max=0; if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } if (parameters.size() < filenameParameter) { out.printerr("Please supply a filename.\n"); return CR_FAILURE; } std::string filename = parameters[filenameParameter-1]; if (filename.rfind(".dfmap") == std::string::npos) filename += ".dfmap"; out << "Writing to " << filename << "..." << std::endl; std::ofstream output_file(filename, std::ios::out | std::ios::trunc | std::ios::binary); if (!output_file.is_open()) { out.printerr("Couldn't open the output file.\n"); return CR_FAILURE; } ZeroCopyOutputStream *raw_output = new OstreamOutputStream(&output_file); GzipOutputStream *zip_output = new GzipOutputStream(raw_output); CodedOutputStream *coded_output = new CodedOutputStream(zip_output); coded_output->WriteLittleEndian32(0x50414DDF); //Write our file header Maps::getSize(x_max, y_max, z_max); MapExtras::MapCache map; DFHack::Materials *mats = Core::getInstance().getMaterials(); out << "Writing map info..." << std::endl; dfproto::Map protomap; protomap.set_x_size(x_max); protomap.set_y_size(y_max); protomap.set_z_size(z_max); out << "Writing material dictionary..." << std::endl; for (size_t i = 0; i < world->raws.inorganics.size(); i++) { dfproto::Material *protomaterial = protomap.add_inorganic_material(); protomaterial->set_index(i); protomaterial->set_name(world->raws.inorganics[i]->id); } for (size_t i = 0; i < world->raws.plants.all.size(); i++) { dfproto::Material *protomaterial = protomap.add_organic_material(); protomaterial->set_index(i); protomaterial->set_name(world->raws.plants.all[i]->id); } std::map<df::coord,std::pair<uint32_t,uint16_t> > constructionMaterials; if (Constructions::isValid()) { for (uint32_t i = 0; i < Constructions::getCount(); i++) { df::construction *construction = Constructions::getConstruction(i); constructionMaterials[construction->pos] = std::make_pair(construction->mat_index, construction->mat_type); } } coded_output->WriteVarint32(protomap.ByteSize()); protomap.SerializeToCodedStream(coded_output); DFHack::t_feature blockFeatureGlobal; DFHack::t_feature blockFeatureLocal; out.print("Writing map block information"); for(uint32_t z = 0; z < z_max; z++) { for(uint32_t b_y = 0; b_y < y_max; b_y++) { for(uint32_t b_x = 0; b_x < x_max; b_x++) { if (b_x == 0 && b_y == 0 && z % 10 == 0) out.print("."); // Get the map block df::coord2d blockCoord(b_x, b_y); MapExtras::Block *b = map.BlockAt(DFHack::DFCoord(b_x, b_y, z)); if (!b || !b->valid) { continue; } dfproto::Block protoblock; protoblock.set_x(b_x); protoblock.set_y(b_y); protoblock.set_z(z); { // Find features uint32_t index = b->raw.global_feature; if (index != -1) Maps::GetGlobalFeature(blockFeatureGlobal, index); index = b->raw.local_feature; if (index != -1) Maps::GetLocalFeature(blockFeatureLocal, blockCoord, index); } int global_z = df::global::world->map.region_z + z; // Iterate over all the tiles in the block for(uint32_t y = 0; y < 16; y++) { for(uint32_t x = 0; x < 16; x++) { df::coord2d coord(x, y); df::tile_designation des = b->DesignationAt(coord); df::tile_occupancy occ = b->OccupancyAt(coord); // Skip hidden tiles if (!showHidden && des.bits.hidden) { continue; } dfproto::Tile *prototile = protoblock.add_tile(); prototile->set_x(x); prototile->set_y(y); // Check for liquid if (des.bits.flow_size) { prototile->set_liquid_type((dfproto::Tile::LiquidType)des.bits.liquid_type); prototile->set_flow_size(des.bits.flow_size); } df::tiletype type = b->TileTypeAt(coord); prototile->set_type((dfproto::Tile::TileType)tileShape(type)); prototile->set_tile_material((dfproto::Tile::TileMaterialType)tileMaterial(type)); df::coord map_pos = df::coord(b_x*16+x,b_y*16+y,z); switch (tileMaterial(type)) { case tiletype_material::SOIL: case tiletype_material::STONE: prototile->set_material_type(0); prototile->set_material_index(b->baseMaterialAt(coord)); break; case tiletype_material::MINERAL: prototile->set_material_type(0); prototile->set_material_index(b->veinMaterialAt(coord)); break; case tiletype_material::FEATURE: if (blockFeatureLocal.type != -1 && des.bits.feature_local) { if (blockFeatureLocal.type == feature_type::deep_special_tube && blockFeatureLocal.main_material == 0) // stone { prototile->set_material_type(0); prototile->set_material_index(blockFeatureLocal.sub_material); } if (blockFeatureGlobal.type != -1 && des.bits.feature_global && blockFeatureGlobal.type == feature_type::feature_underworld_from_layer && blockFeatureGlobal.main_material == 0) // stone { prototile->set_material_type(0); prototile->set_material_index(blockFeatureGlobal.sub_material); } } break; case tiletype_material::CONSTRUCTION: if (constructionMaterials.find(map_pos) != constructionMaterials.end()) { prototile->set_material_index(constructionMaterials[map_pos].first); prototile->set_material_type(constructionMaterials[map_pos].second); } break; default: break; } } } PlantList *plants; if (Maps::ReadVegetation(b_x, b_y, z, plants)) { for (PlantList::const_iterator it = plants->begin(); it != plants->end(); it++) { const df::plant & plant = *(*it); df::coord2d loc(plant.pos.x, plant.pos.y); loc = loc % 16; if (showHidden || !b->DesignationAt(loc).bits.hidden) { dfproto::Plant *protoplant = protoblock.add_plant(); protoplant->set_x(loc.x); protoplant->set_y(loc.y); protoplant->set_is_shrub(plant.flags.bits.is_shrub); protoplant->set_material(plant.material); } } } coded_output->WriteVarint32(protoblock.ByteSize()); protoblock.SerializeToCodedStream(coded_output); } // block x // Clean uneeded memory map.trash(); } // block y } // z delete coded_output; delete zip_output; delete raw_output; mats->Finish(); out.print("\nMap succesfully exported!\n"); return CR_OK; }
DFhackCExport command_result expdig (Core * c, vector <string> & parameters) { bool force_help = false; static explo_how how = EXPLO_NOTHING; static explo_what what = EXPLO_HIDDEN; for(int i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") { force_help = true; } else if(parameters[i] == "all") { what = EXPLO_ALL; } else if(parameters[i] == "hidden") { what = EXPLO_HIDDEN; } else if(parameters[i] == "designated") { what = EXPLO_DESIGNATED; } else if(parameters[i] == "diag5") { how = EXPLO_DIAG5; } else if(parameters[i] == "clear") { how = EXPLO_CLEAR; } else if(parameters[i] == "ladder") { how = EXPLO_LADDER; } else if(parameters[i] == "cross") { how = EXPLO_CROSS; } } if(force_help || how == EXPLO_NOTHING) { c->con.print("This command can be used for exploratory mining.\n" "http://df.magmawiki.com/index.php/DF2010:Exploratory_mining\n" "\n" "There are two variables that can be set: pattern and filter.\n" "Patterns:\n" " diag5 = diagonals separated by 5 tiles\n" " ladder = A 'ladder' pattern\n" " clear = Just remove all dig designations\n" " cross = A cross, exactly in the middle of the map.\n" "Filters:\n" " all = designate whole z-level\n" " hidden = designate only hidden tiles of z-level (default)\n" " designated = Take current designation and apply pattern to it.\n" "\n" "After you have a pattern set, you can use 'expdig' to apply it:\n" "'expdig diag5 hidden' = set filter to hidden, pattern to diag5.\n" "'expdig' = apply the pattern with filter.\n" ); return CR_OK; } c->Suspend(); Gui * gui = c->getGui(); Maps * maps = c->getMaps(); uint32_t x_max, y_max, z_max; if(!maps->Start()) { c->Resume(); c->con.printerr("Can't init the map...\n"); return CR_FAILURE; } maps->getSize(x_max,y_max,z_max); int32_t xzzz,yzzz,z_level; if(!gui->getViewCoords(xzzz,yzzz,z_level)) { c->Resume(); c->con.printerr("Can't get view coords...\n"); return CR_FAILURE; } auto apply = [&](uint32_t bx, uint32_t by, digmask & dm) -> bool { df_block * bl = maps->getBlock(bx,by,z_level); if(!bl) return false; int x = 0,mx = 16; if(bx == 0) x = 1; if(bx == x_max - 1) mx = 15; for(; x < mx; x++) { int y = 0,my = 16; if(by == 0) y = 1; if(by == y_max - 1) my = 15; for(; y < my; y++) { naked_designation & des = bl->designation[x][y].bits; short unsigned int tt = bl->tiletype[x][y]; // could be potentially used to locate hidden constructions? if(tileMaterial(tt) == CONSTRUCTED && !des.hidden) continue; if(!isWallTerrain(tt) && !des.hidden) continue; if(how == EXPLO_CLEAR) { des.dig = designation_no; continue; } if(dm[y][x]) { if(what == EXPLO_ALL || des.dig == designation_default && what == EXPLO_DESIGNATED || des.hidden && what == EXPLO_HIDDEN) { des.dig = designation_default; } } else if(what == EXPLO_DESIGNATED) { des.dig = designation_no; } } } bl->flags.set(BLOCK_DESIGNATED); return true; }; if(how == EXPLO_DIAG5) { int which; for(uint32_t x = 0; x < x_max; x++) { for(int32_t y = 0 ; y < y_max; y++) { which = (4*x + y) % 5; apply(x,y_max - 1 - y,diag5[which]); } } } else if(how == EXPLO_LADDER) { int which; for(uint32_t x = 0; x < x_max; x++) { which = x % 3; for(int32_t y = 0 ; y < y_max; y++) { apply(x,y,ladder[which]); } } } else if(how == EXPLO_CROSS) { // middle + recentering for the image int xmid = x_max * 8 - 8; int ymid = y_max * 8 - 8; MapExtras::MapCache mx (maps); for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++) { DFCoord pos(xmid+x,ymid+y,z_level); short unsigned int tt = mx.tiletypeAt(pos); if(tt == 0) continue; t_designation des = mx.designationAt(pos); if(tileMaterial(tt) == CONSTRUCTED && !des.bits.hidden) continue; if(!isWallTerrain(tt) && !des.bits.hidden) continue; if(cross[y][x]) { des.bits.dig = designation_default; mx.setDesignationAt(pos,des); } } mx.WriteAll(); } else for(uint32_t x = 0; x < x_max; x++) for(int32_t y = 0 ; y < y_max; y++) apply(x,y,all_tiles); c->Resume(); return CR_OK; }
DFhackCExport command_result tiletraffic(DFHack::Core * c, std::vector<std::string> & params) { //Target traffic types. e_traffic target = traffic_normal; //!!! Options Later !!! //Loop through parameters for(int i = 0; i < params.size();i++) { if(params[i] == "help" || params[i] == "?") { c->con.print("Set traffic types for all tiles on the map.\n" "Traffic Type Codes:\n" " H: High Traffic\n" " N: Normal Traffic\n" " L: Low Traffic\n" " R: Restricted Traffic\n" ); return CR_OK; } switch (toupper(params[i][0])) { case 'H': target = traffic_high; break; case 'N': target = traffic_normal; break; case 'L': target = traffic_low; break; case 'R': target = traffic_restricted; break; } } //Initialization. c->Suspend(); DFHack::Maps * Maps = c->getMaps(); DFHack::Gui * Gui = c->getGui(); // init the map if(!Maps->Start()) { c->con.printerr("Can't init map. Make sure you have a map loaded in DF.\n"); c->Resume(); return CR_FAILURE; } //Maximum map size. uint32_t x_max,y_max,z_max; Maps->getSize(x_max,y_max,z_max); uint32_t tx_max = x_max * 16; uint32_t ty_max = y_max * 16; MapExtras::MapCache * MCache = new MapExtras::MapCache(Maps); c->con.print("Entire map ... FILLING!\n"); //Loop through every single tile for(uint32_t x = 0; x <= tx_max; x++) { for(uint32_t y = 0; y <= ty_max; y++) { for(uint32_t z = 0; z <= z_max; z++) { DFHack::DFCoord tile = DFHack::DFCoord(x, y, z); DFHack::t_designation des = MCache->designationAt(tile); des.bits.traffic = target; MCache->setDesignationAt(tile, des); } } } MCache->WriteAll(); c->Resume(); return CR_OK; }
DFhackCExport command_result vdig (Core * c, vector <string> & parameters) { uint32_t x_max,y_max,z_max; bool updown = false; for(int i = 0; i < parameters.size();i++) { if(parameters.size() && parameters[0]=="x") updown = true; else if(parameters[i] == "help" || parameters[i] == "?") { c->con.print("Designates a whole vein under the cursor for digging.\n" "Options:\n" "x - follow veins through z-levels with stairs.\n" ); return CR_OK; } } Console & con = c->con; c->Suspend(); DFHack::Maps * Maps = c->getMaps(); DFHack::Gui * Gui = c->getGui(); // init the map if(!Maps->Start()) { con.printerr("Can't init map. Make sure you have a map loaded in DF.\n"); c->Resume(); 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); while(cx == -30000) { con.printerr("Cursor is not active. Point the cursor at a vein.\n"); c->Resume(); return CR_FAILURE; } 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) { con.printerr("I won't dig the borders. That would be cheating!\n"); c->Resume(); return CR_FAILURE; } MapExtras::MapCache * MCache = new MapExtras::MapCache(Maps); DFHack::t_designation des = MCache->designationAt(xy); int16_t tt = MCache->tiletypeAt(xy); int16_t veinmat = MCache->veinMaterialAt(xy); if( veinmat == -1 ) { con.printerr("This tile is not a vein.\n"); delete MCache; c->Resume(); return CR_FAILURE; } con.print("%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(); c->Resume(); return CR_OK; }
command_result prospector (color_ostream &con, vector <string> & parameters) { bool showHidden = false; bool showPlants = true; bool showSlade = true; bool showTemple = true; bool showValue = false; bool showTube = false; for(size_t i = 0; i < parameters.size();i++) { if (parameters[i] == "all") { showHidden = true; } else if (parameters[i] == "value") { showValue = true; } else if (parameters[i] == "hell") { showHidden = showTube = true; } else return CR_WRONG_USAGE; } CoreSuspender suspend; // Embark screen active: estimate using world geology data if (VIRTUAL_CAST_VAR(screen, df::viewscreen_choose_start_sitest, Core::getTopViewscreen())) return embark_prospector(con, screen, showHidden, showValue); if (!Maps::IsValid()) { con.printerr("Map is not available!\n"); return CR_FAILURE; } uint32_t x_max = 0, y_max = 0, z_max = 0; Maps::getSize(x_max, y_max, z_max); MapExtras::MapCache map; DFHack::Materials *mats = Core::getInstance().getMaterials(); DFHack::t_feature blockFeatureGlobal; DFHack::t_feature blockFeatureLocal; bool hasAquifer = false; bool hasDemonTemple = false; bool hasLair = false; MatMap baseMats; MatMap layerMats; MatMap veinMats; MatMap plantMats; MatMap treeMats; matdata liquidWater; matdata liquidMagma; matdata aquiferTiles; matdata tubeTiles; uint32_t vegCount = 0; for(uint32_t z = 0; z < z_max; z++) { for(uint32_t b_y = 0; b_y < y_max; b_y++) { for(uint32_t b_x = 0; b_x < x_max; b_x++) { // Get the map block df::coord2d blockCoord(b_x, b_y); MapExtras::Block *b = map.BlockAt(DFHack::DFCoord(b_x, b_y, z)); if (!b || !b->is_valid()) { continue; } // Find features b->GetGlobalFeature(&blockFeatureGlobal); b->GetLocalFeature(&blockFeatureLocal); int global_z = world->map.region_z + z; // Iterate over all the tiles in the block for(uint32_t y = 0; y < 16; y++) { for(uint32_t x = 0; x < 16; x++) { df::coord2d coord(x, y); df::tile_designation des = b->DesignationAt(coord); df::tile_occupancy occ = b->OccupancyAt(coord); // Skip hidden tiles if (!showHidden && des.bits.hidden) { continue; } // Check for aquifer if (des.bits.water_table) { hasAquifer = true; aquiferTiles.add(global_z); } // Check for lairs if (occ.bits.monster_lair) { hasLair = true; } // Check for liquid if (des.bits.flow_size) { if (des.bits.liquid_type == tile_liquid::Magma) liquidMagma.add(global_z); else liquidWater.add(global_z); } df::tiletype type = b->tiletypeAt(coord); df::tiletype_shape tileshape = tileShape(type); df::tiletype_material tilemat = tileMaterial(type); // We only care about these types switch (tileshape) { case tiletype_shape::WALL: case tiletype_shape::FORTIFICATION: break; case tiletype_shape::EMPTY: /* A heuristic: tubes inside adamantine have EMPTY:AIR tiles which still have feature_local set. Also check the unrevealed status, so as to exclude any holes mined by the player. */ if (tilemat == tiletype_material::AIR && des.bits.feature_local && des.bits.hidden && blockFeatureLocal.type == feature_type::deep_special_tube) { tubeTiles.add(global_z); } default: continue; } // Count the material type baseMats[tilemat].add(global_z); // Find the type of the tile switch (tilemat) { case tiletype_material::SOIL: case tiletype_material::STONE: layerMats[b->layerMaterialAt(coord)].add(global_z); break; case tiletype_material::MINERAL: veinMats[b->veinMaterialAt(coord)].add(global_z); break; case tiletype_material::FEATURE: if (blockFeatureLocal.type != -1 && des.bits.feature_local) { if (blockFeatureLocal.type == feature_type::deep_special_tube && blockFeatureLocal.main_material == 0) // stone { veinMats[blockFeatureLocal.sub_material].add(global_z); } else if (showTemple && blockFeatureLocal.type == feature_type::deep_surface_portal) { hasDemonTemple = true; } } if (showSlade && blockFeatureGlobal.type != -1 && des.bits.feature_global && blockFeatureGlobal.type == feature_type::feature_underworld_from_layer && blockFeatureGlobal.main_material == 0) // stone { layerMats[blockFeatureGlobal.sub_material].add(global_z); } break; case tiletype_material::LAVA_STONE: // TODO ? break; default: break; } } } // Check plants this way, as the other way wasn't getting them all // and we can check visibility more easily here if (showPlants) { auto block = Maps::getBlockColumn(b_x,b_y); vector<df::plant *> *plants = block ? &block->plants : NULL; if(plants) { for (PlantList::const_iterator it = plants->begin(); it != plants->end(); it++) { const df::plant & plant = *(*it); if (plant.pos.z != z) continue; df::coord2d loc(plant.pos.x, plant.pos.y); loc = loc % 16; if (showHidden || !b->DesignationAt(loc).bits.hidden) { if(plant.flags.bits.is_shrub) plantMats[plant.material].add(global_z); else treeMats[plant.material].add(global_z); } } } } // Block end } // block x // Clean uneeded memory map.trash(); } // block y } // z MatMap::const_iterator it; con << "Base materials:" << std::endl; for (it = baseMats.begin(); it != baseMats.end(); ++it) { con << std::setw(25) << ENUM_KEY_STR(tiletype_material,(df::tiletype_material)it->first) << " : " << it->second.count << std::endl; } if (liquidWater.count || liquidMagma.count) { con << std::endl << "Liquids:" << std::endl; if (liquidWater.count) { con << std::setw(25) << "WATER" << " : "; printMatdata(con, liquidWater); } if (liquidWater.count) { con << std::setw(25) << "MAGMA" << " : "; printMatdata(con, liquidMagma); } } con << std::endl << "Layer materials:" << std::endl; printMats<df::inorganic_raw, shallower>(con, layerMats, world->raws.inorganics, showValue); printVeins(con, veinMats, mats, showValue); if (showPlants) { con << "Shrubs:" << std::endl; printMats<df::plant_raw, std::greater>(con, plantMats, world->raws.plants.all, showValue); con << "Wood in trees:" << std::endl; printMats<df::plant_raw, std::greater>(con, treeMats, world->raws.plants.all, showValue); } if (hasAquifer) { con << "Has aquifer"; if (aquiferTiles.count) { con << " : "; printMatdata(con, aquiferTiles); } else con << std::endl; } if (showTube && tubeTiles.count) { con << "Has HFS tubes : "; printMatdata(con, tubeTiles); } if (hasDemonTemple) { con << "Has demon temple" << std::endl; } if (hasLair) { con << "Has lair" << std::endl; } // Cleanup mats->Finish(); con << std::endl; return CR_OK; }
void colorTile(const df::tiletype_material& tileMat,MapExtras::MapCache& cache,const DFCoord& pos,screenTile& trg,bool isUndug=false) { t_matpair mat; switch(tileMat) { case df::tiletype_material::ASHES: trg.fg=COLOR_GREY; trg.bold=false; break; case df::tiletype_material::CAMPFIRE: trg.fg=COLOR_YELLOW; trg.bold=true; break; case df::tiletype_material::SOIL: mat=cache.baseMaterialAt(pos); { df::material* m=lookupMaterial(mat,trg); if(m && isUndug) { trg.tile=m->tile; } break; } case df::tiletype_material::STONE: case df::tiletype_material::LAVA_STONE: mat=cache.baseMaterialAt(pos); lookupMaterial(mat,trg); break; case df::tiletype_material::CONSTRUCTION: mat=cache.staticMaterialAt(pos); lookupMaterial(mat,trg,true); break; case df::tiletype_material::MINERAL: mat.mat_index=cache.veinMaterialAt(pos); mat.mat_type=0;//inorganic { df::material* m=lookupMaterial(mat,trg); if(m && isUndug) { trg.tile=m->tile; } } break; case df::tiletype_material::FROZEN_LIQUID: trg.fg=COLOR_CYAN; trg.bold=true; break; case df::tiletype_material::PLANT: case df::tiletype_material::GRASS_LIGHT: //MORE INFO IN MAP BLOCK EVENTS trg.fg=COLOR_GREEN; trg.bold=true; break; case df::tiletype_material::GRASS_DARK: trg.fg=COLOR_GREEN; trg.bold=false; break; case df::tiletype_material::GRASS_DRY: trg.fg=COLOR_YELLOW; trg.bold=true; break; case df::tiletype_material::GRASS_DEAD: trg.fg=COLOR_BROWN; trg.bold=false; break; case df::tiletype_material::DRIFTWOOD: trg.fg=COLOR_WHITE; trg.bold=true; break; case df::tiletype_material::MAGMA: trg.fg=COLOR_RED; trg.bold=true; break; case df::tiletype_material::POOL: case df::tiletype_material::RIVER: case df::tiletype_material::BROOK: trg.fg=COLOR_BROWN; trg.bold=false; break; } }
void Offscreen::drawBuffer( rect2d window,int z,std::vector<screenTile>& buffer ) { if(!df::global::world) return; //TODO static array of images for each tiletype MapExtras::MapCache cache; int w=window.second.x-window.first.x; int h=window.second.y-window.first.y; rect2d localWindow=mkrect_wh(0,0,w+1,h+1); if(buffer.size()!=w*h) buffer.resize(w*h); //basic tiletype stuff here for(int x=window.first.x;x<window.second.x;x++) //todo, make it by block, minimal improvement over cache prob though for(int y=window.first.y;y<window.second.y;y++) { DFCoord coord(x,y,z); df::tiletype tt=cache.tiletypeAt(coord); df::tiletype_shape shape = ENUM_ATTR(tiletype,shape,tt); df::tiletype_shape_basic basic_shape = ENUM_ATTR(tiletype_shape, basic_shape, shape); t_matpair mat=cache.staticMaterialAt(coord); df::tiletype_material tileMat= ENUM_ATTR(tiletype,material,tt); df::tile_designation d=cache.designationAt(coord); df::tile_occupancy o=cache.occupancyAt(coord); df::tiletype_special sp=ENUM_ATTR(tiletype,special,tt); int wx=x-window.first.x; int wy=y-window.first.y; screenTile& curTile=buffer[wx*h+wy]; if(d.bits.hidden) { curTile.tile=0; continue; } if(shape==df::tiletype_shape::EMPTY || shape==df::tiletype_shape::RAMP_TOP) { //empty,liquids and '.' for other stuff... DFCoord coord2(x,y,z-1); df::tiletype tt2=cache.tiletypeAt(coord2); df::tiletype_shape shape2 = ENUM_ATTR(tiletype,shape,tt); df::tiletype_material tileMat2= ENUM_ATTR(tiletype,material,tt2); df::tile_designation d2=cache.designationAt(coord2); df::tiletype_special sp2=ENUM_ATTR(tiletype,special,tt2); bool unDug2= (sp2!=df::tiletype_special::SMOOTH && shape2==df::tiletype_shape::WALL); if (d2.bits.flow_size>0) { if(shape!=df::tiletype_shape::RAMP_TOP) //don't show liquid amount on ramp tops curTile.tile='0'+d2.bits.flow_size; //TODO lookup setting for this else curTile.tile=tilePics[tt]; curTile.fg=(d2.bits.liquid_type)?(COLOR_RED):(COLOR_BLUE); continue; } else if(shape2==df::tiletype_shape::EMPTY) { curTile.tile=178; //look up settings curTile.fg=COLOR_CYAN; continue; } else { if(shape==df::tiletype_shape::RAMP_TOP) curTile.tile=tilePics[tt]; else curTile.tile='.'; colorTile(tileMat2,cache,coord2,curTile,unDug2); continue; } } bool inliquid=false; bool unDug= (sp!=df::tiletype_special::SMOOTH && shape==df::tiletype_shape::WALL); if (d.bits.flow_size>0) { curTile.tile='0'+d.bits.flow_size; curTile.fg=(d.bits.liquid_type)?(COLOR_RED):(COLOR_BLUE); curTile.bold=true; inliquid=true; } if(!inliquid && shape!=df::tiletype_shape::RAMP_TOP) { curTile.tile=tilePics[tt]; colorTile(tileMat,cache,coord,curTile,unDug); if(!unDug) { curTile.bg=0; } } else { if(shape==df::tiletype_shape::RAMP || shape==df::tiletype_shape::BROOK_BED || shape==df::tiletype_shape::RAMP_TOP) curTile.tile=tilePics[tt]; if(!inliquid) colorTile(tileMat,cache,coord,curTile,true); } } //plants for(int bx=window.first.x/16;bx<=window.second.x/16;bx++) //blocks have items by id. So yeah each item a search would be slow for(int by=window.first.y/16;by<=window.second.y/16;by++) { MapExtras::Block* b=cache.BlockAt(DFCoord(bx,by,z)); if(!b || !b->getRaw()) continue; std::vector<df::plant*>& plants=b->getRaw()->plants; for(int i=0;i<plants.size();i++) { df::plant* p=plants[i]; if(p->pos.z==z && isInRect(df::coord2d(p->pos.x,p->pos.y),window)) { int wx=p->pos.x-window.first.x; int wy=p->pos.y-window.first.y; screenTile& curTile=buffer[wx*h+wy]; drawPlant(p,curTile); } } std::vector<df::block_square_event*>& events=b->getRaw()->block_events; for(size_t i=0;i<events.size();i++)//maybe aggregate all the events to one array and move to a function. { df::block_square_event* e=events[i]; switch(e->getType()) { case df::block_square_event_type::grass: { df::block_square_event_grassst* grass=static_cast<df::block_square_event_grassst*>(e); MaterialInfo mat(419, grass->plant_index); if(mat.isPlant()) { df::plant_raw* p=mat.plant; for(int x=0;x<16;x++) for(int y=0;y<16;y++) { int wx=x+bx*16-window.first.x; int wy=y+by*16-window.first.y; if(isInRect(df::coord2d(wx,wy),localWindow) && grass->amount[x][y]>0) { screenTile& curTile=buffer[wx*h+wy]; /* df::tiletype tt=b->tiletypeAt(df::coord2d(x,y)); df::tiletype_special sp=ENUM_ATTR(tiletype,special,tt); df::tiletype_special::DEAD; df::tiletype_special::WET; df::tiletype_special::NORMAL; +variants */ curTile.tile=p->tiles.grass_tiles[0]; curTile.fg=p->colors.grass_colors_0[0]; curTile.bg=p->colors.grass_colors_1[0]; curTile.bold=p->colors.grass_colors_2[0]; } } //TODO alt-tiles } break; } case df::block_square_event_type::material_spatter: { //liquid: //0 nothing //1->49 color //50->99 wave //100->255 two waves //color only, if small //draw waves, if pool df::block_square_event_material_spatterst* spatter=static_cast<df::block_square_event_material_spatterst*>(e); MaterialInfo mat(spatter); if(mat.material) { for(int x=0;x<16;x++) for(int y=0;y<16;y++) { int wx=x+bx*16-window.first.x; int wy=y+by*16-window.first.y; uint8_t amount=spatter->amount[x][y]; if(isInRect(df::coord2d(wx,wy),localWindow) && amount>0) { screenTile& curTile=buffer[wx*h+wy]; curTile.fg=mat.material->tile_color[0]; curTile.bold=mat.material->tile_color[2]; if(spatter->mat_state==df::matter_state::Liquid && amount>49) { if(amount>99) curTile.tile=247; else curTile.tile=126; } } } } break; } default:; } } std::vector<df::flow_info*>& flows=b->getRaw()->flows; for(size_t i=0;i<flows.size();i++) { df::flow_info* f=flows[i]; int wx=f->pos.x-window.first.x; int wy=f->pos.y-window.first.y; if(f->density>0 && isInRect(df::coord2d(wx,wy),localWindow)) { screenTile& curTile=buffer[wx*h+wy]; drawFlow(f,curTile); } } } //in df items blink between stuff, but i don't have time for that //also move up, before flows std::vector<df::item*>& items=df::global::world->items.other[df::items_other_id::IN_PLAY]; for(int i=0;i<items.size();i++) { df::item* it=items[i]; if(it->flags.bits.on_ground && it->pos.z==z && isInRect(df::coord2d(it->pos.x,it->pos.y),window)) { int wx=it->pos.x-window.first.x; int wy=it->pos.y-window.first.y; screenTile& curTile=buffer[wx*h+wy]; drawItem(it,curTile); } } //buildings std::vector<df::building*>& buildings=df::global::world->buildings.all; for(int i=0;i<buildings.size();i++) { df::building* build=buildings[i]; if(z!=build->z) continue; if(!build->isVisibleInUI()) continue; if(isInRect(df::coord2d(build->x1,build->y1),window)||isInRect(df::coord2d(build->x2,build->y2),window)) { df::building_drawbuffer drawBuffer; build->getDrawExtents(&drawBuffer); int bw=drawBuffer.x2-drawBuffer.x1; int bh=drawBuffer.y2-drawBuffer.y1; build->drawBuilding(&drawBuffer,0); //might be viewscreen dependant int wx=build->x1-window.first.x; int wy=build->y1-window.first.y; for(int x=0;x<=bw;x++) for(int y=0;y<=bh;y++) { df::coord2d p(x+wx,y+wy); if(isInRect(p,localWindow)) { screenTile& curTile=buffer[p.x*h+p.y]; if(drawBuffer.tile[x][y]!=32) { curTile.tile=drawBuffer.tile[x][y]; curTile.fg=drawBuffer.fore[x][y]; curTile.bg=drawBuffer.back[x][y]; curTile.bold=drawBuffer.bright[x][y]; } } } } } //units. TODO No multi tile units yet. std::vector<df::unit*>& units=df::global::world->units.active; for(int i=0;i<units.size();i++) { df::unit* u=units[i]; if(!u->flags1.bits.dead && u->pos.z==z && isInRect(df::coord2d(u->pos.x,u->pos.y),window)) { int wx=u->pos.x-window.first.x; int wy=u->pos.y-window.first.y; screenTile& curTile=buffer[wx*h+wy]; drawUnit(u,curTile); } } }
command_result expdig (Core * c, vector <string> & parameters) { bool force_help = false; static explo_how how = EXPLO_NOTHING; static explo_what what = EXPLO_HIDDEN; for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") { force_help = true; } else if(parameters[i] == "all") { what = EXPLO_ALL; } else if(parameters[i] == "hidden") { what = EXPLO_HIDDEN; } else if(parameters[i] == "designated") { what = EXPLO_DESIGNATED; } else if(parameters[i] == "diag5") { how = EXPLO_DIAG5; } else if(parameters[i] == "diag5r") { how = EXPLO_DIAG5R; } else if(parameters[i] == "clear") { how = EXPLO_CLEAR; } else if(parameters[i] == "ladder") { how = EXPLO_LADDER; } else if(parameters[i] == "ladderr") { how = EXPLO_LADDERR; } else if(parameters[i] == "cross") { how = EXPLO_CROSS; } } if(force_help || how == EXPLO_NOTHING) { c->con.print( "This command can be used for exploratory mining.\n" "http://dwarffortresswiki.org/Exploratory_mining\n" "\n" "There are two variables that can be set: pattern and filter.\n" "Patterns:\n" " diag5 = diagonals separated by 5 tiles\n" " diag5r = diag5 rotated 90 degrees\n" " ladder = A 'ladder' pattern\n" "ladderr = ladder rotated 90 degrees\n" " clear = Just remove all dig designations\n" " cross = A cross, exactly in the middle of the map.\n" "Filters:\n" " all = designate whole z-level\n" " hidden = designate only hidden tiles of z-level (default)\n" " designated = Take current designation and apply pattern to it.\n" "\n" "After you have a pattern set, you can use 'expdig' to apply it:\n" "'expdig diag5 hidden' = set filter to hidden, pattern to diag5.\n" "'expdig' = apply the pattern with filter.\n" ); return CR_OK; } CoreSuspender suspend(c); uint32_t x_max, y_max, z_max; if (!Maps::IsValid()) { c->con.printerr("Map is not available!\n"); return CR_FAILURE; } Maps::getSize(x_max,y_max,z_max); int32_t xzzz,yzzz,z_level; if(!Gui::getViewCoords(xzzz,yzzz,z_level)) { c->con.printerr("Can't get view coords...\n"); return CR_FAILURE; } if(how == EXPLO_DIAG5) { int which; for(uint32_t x = 0; x < x_max; x++) { for(int32_t y = 0 ; y < y_max; y++) { which = (4*x + y) % 5; stamp_pattern(x,y_max - 1 - y, z_level, diag5[which], how, what, x_max, y_max); } } } else if(how == EXPLO_DIAG5R) { int which; for(uint32_t x = 0; x < x_max; x++) { for(int32_t y = 0 ; y < y_max; y++) { which = (4*x + 1000-y) % 5; stamp_pattern(x,y_max - 1 - y, z_level, diag5r[which], how, what, x_max, y_max); } } } else if(how == EXPLO_LADDER) { int which; for(uint32_t x = 0; x < x_max; x++) { which = x % 3; for(int32_t y = 0 ; y < y_max; y++) { stamp_pattern(x, y, z_level, ladder[which], how, what, x_max, y_max); } } } else if(how == EXPLO_LADDERR) { int which; for(int32_t y = 0 ; y < y_max; y++) { which = y % 3; for(uint32_t x = 0; x < x_max; x++) { stamp_pattern(x, y, z_level, ladderr[which], how, what, x_max, y_max); } } } else if(how == EXPLO_CROSS) { // middle + recentering for the image int xmid = x_max * 8 - 8; int ymid = y_max * 8 - 8; MapExtras::MapCache mx; for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++) { DFCoord pos(xmid+x,ymid+y,z_level); df::tiletype tt = mx.tiletypeAt(pos); if(tt == tiletype::Void) continue; df::tile_designation des = mx.designationAt(pos); if(tileMaterial(tt) == tiletype_material::CONSTRUCTION && !des.bits.hidden) continue; if(!isWallTerrain(tt) && !des.bits.hidden) continue; if(cross[y][x]) { des.bits.dig = tile_dig_designation::Default; mx.setDesignationAt(pos,des); } } mx.WriteAll(); } else for(uint32_t x = 0; x < x_max; x++) { for(int32_t y = 0 ; y < y_max; y++) { stamp_pattern(x, y, z_level, all_tiles, how, what, x_max, y_max); } } return CR_OK; }
command_result vdig (Core * c, vector <string> & parameters) { // HOTKEY COMMAND: CORE ALREADY SUSPENDED uint32_t x_max,y_max,z_max; bool updown = false; for(size_t i = 0; i < parameters.size();i++) { if(parameters.size() && parameters[0]=="x") updown = true; else return CR_WRONG_USAGE; } Console & con = c->con; if (!Maps::IsValid()) { c->con.printerr("Map is not available!\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); while(cx == -30000) { con.printerr("Cursor is not active. Point the cursor at a vein.\n"); return CR_FAILURE; } 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) { con.printerr("I won't dig the borders. That would be cheating!\n"); return CR_FAILURE; } MapExtras::MapCache * MCache = new MapExtras::MapCache; df::tile_designation des = MCache->designationAt(xy); df::tiletype tt = MCache->tiletypeAt(xy); int16_t veinmat = MCache->veinMaterialAt(xy); if( veinmat == -1 ) { con.printerr("This tile is not a vein.\n"); delete MCache; return CR_FAILURE; } con.print("%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 df::tile_designation des = MCache->designationAt(current); df::tile_designation des_minus; df::tile_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 == tile_dig_designation::DownStair) des_minus.bits.dig = tile_dig_designation::UpDownStair; else des_minus.bits.dig = tile_dig_designation::UpStair; MCache->setDesignationAt(current-1,des_minus); des.bits.dig = tile_dig_designation::DownStair; } if(current.z < z_max - 1 && above && vmat_plus == vmat2) { flood.push(current+ 1); if(des_plus.bits.dig == tile_dig_designation::UpStair) des_plus.bits.dig = tile_dig_designation::UpDownStair; else des_plus.bits.dig = tile_dig_designation::DownStair; MCache->setDesignationAt(current+1,des_plus); if(des.bits.dig == tile_dig_designation::DownStair) des.bits.dig = tile_dig_designation::UpDownStair; else des.bits.dig = tile_dig_designation::UpStair; } } if(des.bits.dig == tile_dig_designation::No) des.bits.dig = tile_dig_designation::Default; MCache->setDesignationAt(current,des); } } MCache->WriteAll(); return CR_OK; }
command_result prospector (color_ostream &con, vector <string> & parameters) { bool showHidden = false; bool showPlants = true; bool showValue = false; bool showHFS = false; for(size_t i = 0; i < parameters.size();i++) { if (parameters[i] == "all") { showHidden = true; } else if (parameters[i] == "value") { showValue = true; } else if (parameters[i] == "hell") { showHidden = showHFS = true; } else return CR_WRONG_USAGE; } CoreSuspender suspend; // Embark screen active: estimate using world geology data if (VIRTUAL_CAST_VAR(screen, df::viewscreen_choose_start_sitest, Core::getTopViewscreen())) return embark_prospector(con, screen, showHidden, showValue); if (!Maps::IsValid()) { con.printerr("Map is not available!\n"); return CR_FAILURE; } uint32_t x_max = 0, y_max = 0, z_max = 0; Maps::getSize(x_max, y_max, z_max); MapExtras::MapCache map; DFHack::Materials *mats = Core::getInstance().getMaterials(); DFHack::t_feature blockFeature; bool hasAquifer = false; MatMap baseMats; MatMap layerMats; MatMap veinMats; MatMap plantMats; MatMap treeMats; matdata liquidWater; matdata liquidMagma; matdata aquiferTiles; matdata hfsTiles; uint32_t vegCount = 0; for(uint32_t z = 0; z < z_max; z++) { for(uint32_t b_y = 0; b_y < y_max; b_y++) { for(uint32_t b_x = 0; b_x < x_max; b_x++) { // Get the map block df::coord2d blockCoord(b_x, b_y); MapExtras::Block *b = map.BlockAt(DFHack::DFCoord(b_x, b_y, z)); if (!b || !b->is_valid()) { continue; } // Find features b->GetFeature(&blockFeature); int global_z = world->map.region_z + z; // Iterate over all the tiles in the block for(uint32_t y = 0; y < 16; y++) { for(uint32_t x = 0; x < 16; x++) { df::coord2d coord(x, y); df::tile_designation des = b->DesignationAt(coord); df::tile_occupancy occ = b->OccupancyAt(coord); // Skip hidden tiles if (!showHidden && des.bits.hidden) { continue; } // Check for aquifer if (des.bits.water_table) { hasAquifer = true; aquiferTiles.add(global_z); } // Check for liquid if (des.bits.flow_size) { if (des.bits.liquid_type == tile_liquid::Magma) liquidMagma.add(global_z); else liquidWater.add(global_z); } df::tiletype type = b->tiletypeAt(coord); df::tiletype_shape tileshape = tileShape(type); df::tiletype_material tilemat = tileMaterial(type); // We only care about these types switch (tileshape) { case tiletype_shape::WALL: case tiletype_shape::FORTIFICATION: break; case tiletype_shape::EMPTY: /* find the top of the HFS chamber */ if (tilemat == tiletype_material::AIR && des.bits.feature && des.bits.hidden && blockFeature.type == feature_type::glowing_pit) { hfsTiles.add(global_z); } default: continue; } // Count the material type baseMats[tilemat].add(global_z); // Find the type of the tile switch (tilemat) { case tiletype_material::SOIL: case tiletype_material::STONE: layerMats[b->layerMaterialAt(coord)].add(global_z); break; case tiletype_material::MINERAL: veinMats[b->veinMaterialAt(coord)].add(global_z); break; case tiletype_material::LAVA_STONE: // TODO ? break; default: break; } } } // Check plants this way, as the other way wasn't getting them all // and we can check visibility more easily here if (showPlants) { auto block = Maps::getBlock(b_x,b_y,z); stl::vector<df::plant *> *plants = block ? &block->plants : NULL; if(plants) { for (auto it = plants->begin(); it != plants->end(); it++) { const df::plant & plant = *(*it); df::coord2d loc(plant.pos.x, plant.pos.y); loc = loc % 16; if (showHidden || !b->DesignationAt(loc).bits.hidden) { if(plant.flags.bits.is_shrub) plantMats[plant.plant_id].add(global_z); else treeMats[plant.wood_id].add(global_z); } } } } // Block end } // block x // Clean uneeded memory map.trash(); } // block y } // z MatMap::const_iterator it; con << "Base materials:" << std::endl; for (it = baseMats.begin(); it != baseMats.end(); ++it) { con << std::setw(25) << ENUM_KEY_STR(tiletype_material,(df::tiletype_material)it->first) << " : " << it->second.count << std::endl; } if (liquidWater.count || liquidMagma.count) { con << std::endl << "Liquids:" << std::endl; if (liquidWater.count) { con << std::setw(25) << "WATER" << " : "; printMatdata(con, liquidWater); } if (liquidWater.count) { con << std::setw(25) << "MAGMA" << " : "; printMatdata(con, liquidMagma); } } con << std::endl << "Layer materials:" << std::endl; printMats<df::matgloss_stone, shallower>(con, layerMats, world->raws.matgloss.stone, showValue); printVeins(con, veinMats, mats, showValue); if (showPlants) { con << "Shrubs:" << std::endl; printMats<df::matgloss_plant, std::greater>(con, plantMats, world->raws.matgloss.plant, showValue); con << "Wood in trees:" << std::endl; printMats<df::matgloss_wood, std::greater>(con, treeMats, world->raws.matgloss.wood, showValue); } if (hasAquifer) { con << "Has aquifer"; if (aquiferTiles.count) { con << " : "; printMatdata(con, aquiferTiles); } else con << std::endl; } if (showHFS && hfsTiles.count) { con << "Has HFS : "; printMatdata(con, hfsTiles); } // Cleanup mats->Finish(); con << std::endl; return CR_OK; }
DFhackCExport command_result filltraffic(DFHack::Core * c, std::vector<std::string> & params) { //Maximum map size. uint32_t x_max,y_max,z_max; //Source and target traffic types. e_traffic source = traffic_normal; e_traffic target = traffic_normal; //Option flags bool updown = false; bool checkpit = true; bool checkbuilding = true; //Loop through parameters for(int i = 0; i < params.size();i++) { if(params[i] == "help" || params[i] == "?") { c->con.print("Flood-fill selected traffic type from the cursor.\n" "Traffic Type Codes:\n" "\tH: High Traffic\n" "\tN: Normal Traffic\n" "\tL: Low Traffic\n" "\tR: Restricted Traffic\n" "Other Options:\n" "\tX: Fill accross z-levels.\n" "\tB: Include buildings and stockpiles.\n" "\tP: Include empty space.\n" "Example:\n" "'filltraffic H' - When used in a room with doors,\n" " it will set traffic to HIGH in just that room." ); return CR_OK; } switch (toupper(params[i][0])) { case 'H': target = traffic_high; break; case 'N': target = traffic_normal; break; case 'L': target = traffic_low; break; case 'R': target = traffic_restricted; break; case 'X': updown = true; break; case 'B': checkbuilding = false; break; case 'P': checkpit = false; break; } } //Initialization. c->Suspend(); DFHack::Maps * Maps = c->getMaps(); DFHack::Gui * Gui = c->getGui(); // init the map if(!Maps->Start()) { c->con.printerr("Can't init map. Make sure you have a map loaded in DF.\n"); c->Resume(); 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); while(cx == -30000) { c->con.printerr("Cursor is not active.\n"); c->Resume(); return CR_FAILURE; } DFHack::DFCoord xy ((uint32_t)cx,(uint32_t)cy,cz); MapExtras::MapCache * MCache = new MapExtras::MapCache(Maps); DFHack::t_designation des = MCache->designationAt(xy); int16_t tt = MCache->tiletypeAt(xy); DFHack::t_occupancy oc; if (checkbuilding) oc = MCache->occupancyAt(xy); source = des.bits.traffic; if(source == target) { c->con.printerr("This tile is already set to the target traffic type.\n"); delete MCache; c->Resume(); return CR_FAILURE; } if(DFHack::isWallTerrain(tt)) { c->con.printerr("This tile is a wall. Please select a passable tile.\n"); delete MCache; c->Resume(); return CR_FAILURE; } if(checkpit && DFHack::isOpenTerrain(tt)) { c->con.printerr("This tile is a hole. Please select a passable tile.\n"); delete MCache; c->Resume(); return CR_FAILURE; } if(checkbuilding && oc.bits.building) { c->con.printerr("This tile contains a building. Please select an empty tile.\n"); delete MCache; c->Resume(); return CR_FAILURE; } c->con.print("%d/%d/%d ... FILLING!\n", cx,cy,cz); //Naive four-way or six-way flood fill with possible tiles on a stack. stack <DFHack::DFCoord> flood; flood.push(xy); while(!flood.empty()) { xy = flood.top(); flood.pop(); des = MCache->designationAt(xy); if (des.bits.traffic != source) continue; tt = MCache->tiletypeAt(xy); if(DFHack::isWallTerrain(tt)) continue; if(checkpit && DFHack::isOpenTerrain(tt)) continue; if (checkbuilding) { oc = MCache->occupancyAt(xy); if(oc.bits.building) continue; } //This tile is ready. Set its traffic level and add surrounding tiles. if (MCache->testCoord(xy)) { des.bits.traffic = target; MCache->setDesignationAt(xy,des); if (xy.x > 0) { flood.push(DFHack::DFCoord(xy.x - 1, xy.y, xy.z)); } if (xy.x < tx_max - 1) { flood.push(DFHack::DFCoord(xy.x + 1, xy.y, xy.z)); } if (xy.y > 0) { flood.push(DFHack::DFCoord(xy.x, xy.y - 1, xy.z)); } if (xy.y < ty_max - 1) { flood.push(DFHack::DFCoord(xy.x, xy.y + 1, xy.z)); } if (updown) { if (xy.z > 0 && DFHack::LowPassable(tt)) { flood.push(DFHack::DFCoord(xy.x, xy.y, xy.z - 1)); } if (xy.z < z_max && DFHack::HighPassable(tt)) { flood.push(DFHack::DFCoord(xy.x, xy.y, xy.z + 1)); } } } } MCache->WriteAll(); c->Resume(); return CR_OK; }
static bool detachItem(MapExtras::MapCache &mc, df::item *item) { if (!item->specific_refs.empty()) return false; if (item->world_data_id != -1) return false; for (size_t i = 0; i < item->general_refs.size(); i++) { df::general_ref *ref = item->general_refs[i]; switch (ref->getType()) { case general_ref_type::PROJECTILE: case general_ref_type::BUILDING_HOLDER: case general_ref_type::BUILDING_CAGED: case general_ref_type::BUILDING_TRIGGER: case general_ref_type::BUILDING_TRIGGERTARGET: case general_ref_type::BUILDING_CIVZONE_ASSIGNED: return false; default: continue; } } if (item->flags.bits.on_ground) { if (!mc.removeItemOnGround(item)) Core::printerr("Item was marked on_ground, but not in block: %d (%d,%d,%d)\n", item->id, item->pos.x, item->pos.y, item->pos.z); item->flags.bits.on_ground = false; return true; } else if (item->flags.bits.in_inventory) { bool found = false; for (int i = item->general_refs.size()-1; i >= 0; i--) { df::general_ref *ref = item->general_refs[i]; switch (ref->getType()) { case general_ref_type::CONTAINED_IN_ITEM: if (auto item2 = ref->getItem()) { // Viewscreens hold general_ref_contains_itemst pointers for (auto screen = Core::getTopViewscreen(); screen; screen = screen->parent) { auto vsitem = strict_virtual_cast<df::viewscreen_itemst>(screen); if (vsitem && vsitem->item == item2) return false; } item2->flags.bits.weight_computed = false; removeRef(item2->general_refs, general_ref_type::CONTAINS_ITEM, item->id); } break; case general_ref_type::UNIT_HOLDER: if (auto unit = ref->getUnit()) { // Unit view sidebar holds inventory item pointers if (ui->main.mode == ui_sidebar_mode::ViewUnits && (!ui_selected_unit || vector_get(world->units.active, *ui_selected_unit) == unit)) return false; for (int i = unit->inventory.size()-1; i >= 0; i--) { df::unit_inventory_item *inv_item = unit->inventory[i]; if (inv_item->item != item) continue; resetUnitInvFlags(unit, inv_item); vector_erase_at(unit->inventory, i); delete inv_item; } } break; default: continue; } found = true; vector_erase_at(item->general_refs, i); delete ref; } if (!found) return false; item->flags.bits.in_inventory = false; return true; } else if (item->flags.bits.removed) { item->flags.bits.removed = false; if (item->flags.bits.garbage_collect) { item->flags.bits.garbage_collect = false; item->categorize(true); } return true; } else return false; }
DFhackCExport command_result digcircle (Core * c, vector <string> & parameters) { static bool filled = false; static circle_what what = circle_set; static e_designation type = designation_default; static int diameter = 0; auto saved_d = diameter; bool force_help = false; for(int i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") { force_help = true; } else if(parameters[i] == "hollow") { filled = false; } else if(parameters[i] == "filled") { filled = true; } else if(parameters[i] == "set") { what = circle_set; } else if(parameters[i] == "unset") { what = circle_unset; } else if(parameters[i] == "invert") { what = circle_invert; } else if(parameters[i] == "dig") { type = designation_default; } else if(parameters[i] == "ramp") { type = designation_ramp; } else if(parameters[i] == "dstair") { type = designation_d_stair; } else if(parameters[i] == "ustair") { type = designation_u_stair; } else if(parameters[i] == "xstair") { type = designation_ud_stair; } else if(parameters[i] == "chan") { type = designation_channel; } else if (!from_string(diameter,parameters[i], std::dec)) { diameter = saved_d; } } if(diameter < 0) diameter = -diameter; if(force_help || diameter == 0) { c->con.print( "A command for easy designation of filled and hollow circles.\n" "\n" "Options:\n" " hollow = Set the circle to hollow (default)\n" " filled = Set the circle to filled\n" "\n" " set = set designation\n" " unset = unset current designation\n" " invert = invert current designation\n" "\n" " dig = normal digging\n" " ramp = ramp digging\n" " ustair = staircase up\n" " dstair = staircase down\n" " xstair = staircase up/down\n" " chan = dig channel\n" "\n" " # = diameter in tiles (default = 0)\n" "\n" "After you have set the options, the command called with no options\n" "repeats with the last selected parameters:\n" "'digcircle filled 3' = Dig a filled circle with radius = 3.\n" "'digcircle' = Do it again.\n" ); return CR_OK; } int32_t cx, cy, cz; c->Suspend(); Gui * gui = c->getGui(); Maps * maps = c->getMaps(); if(!maps->Start()) { c->Resume(); c->con.printerr("Can't init the map...\n"); return CR_FAILURE; } uint32_t x_max, y_max, z_max; maps->getSize(x_max,y_max,z_max); MapExtras::MapCache MCache (maps); if(!gui->getCursorCoords(cx,cy,cz) || cx == -30000) { c->Resume(); c->con.printerr("Can't get the cursor coords...\n"); return CR_FAILURE; } auto dig = [&](int32_t x, int32_t y, int32_t z) -> bool { DFCoord at (x,y,z); auto b = MCache.BlockAt(at/16); if(!b || !b->valid) return false; if(x == 0 || x == x_max * 16 - 1) { //c->con.print("not digging map border\n"); return false; } if(y == 0 || y == y_max * 16 - 1) { //c->con.print("not digging map border\n"); return false; } uint16_t tt = MCache.tiletypeAt(at); t_designation des = MCache.designationAt(at); // could be potentially used to locate hidden constructions? if(tileMaterial(tt) == CONSTRUCTED && !des.bits.hidden) return false; TileShape ts = tileShape(tt); if(ts == EMPTY) return false; if(!des.bits.hidden) { do { if(isWallTerrain(tt)) { std::cerr << "allowing tt" << tt << ", is wall\n"; break; } if(isFloorTerrain(tt) && (type == designation_d_stair || type == designation_channel) && ts != TREE_OK && ts != TREE_DEAD ) { std::cerr << "allowing tt" << tt << ", is floor\n"; break; } if(isStairTerrain(tt) && type == designation_channel ) break; return false; } while(0); } switch(what) { case circle_set: if(des.bits.dig == designation_no) { des.bits.dig = type; } break; case circle_unset: if (des.bits.dig != designation_no) { des.bits.dig = designation_no; } case circle_invert: if(des.bits.dig == designation_no) { des.bits.dig = type; } else { des.bits.dig = designation_no; } break; } std::cerr << "allowing tt" << tt << "\n"; MCache.setDesignationAt(at,des); return true; }; auto lineX = [&](int32_t y1, int32_t y2, int32_t x, int32_t z) -> bool { for(int32_t y = y1; y <= y2; y++) { dig(x,y,z); } return true; }; auto lineY = [&](int32_t x1, int32_t x2, int32_t y, int32_t z) -> bool { for(int32_t x = x1; x <= x2; x++) { dig(x,y,z); } return true; }; int r = diameter / 2; int iter; bool adjust; if(diameter % 2) { // paint center if(filled) { lineY(cx - r, cx + r, cy, cz); } else { dig(cx - r, cy, cz); dig(cx + r, cy, cz); } adjust = false; iter = 2; } else { adjust = true; iter = 1; } int lastwhole = r; for(; iter <= diameter - 1; iter +=2) { // top, bottom coords int top = cy - ((iter + 1) / 2) + adjust; int bottom = cy + ((iter + 1) / 2); // see where the current 'line' intersects the circle double val = std::sqrt(double(diameter*diameter - iter*iter)); // adjust for circles with odd diameter if(!adjust) val -= 1; // map the found value to the DF grid double whole; double fraction = std::modf(val / 2.0, & whole); if (fraction > 0.5) whole += 1.0; int right = cx + whole; int left = cx - whole + adjust; int diff = lastwhole - whole; // paint if(filled || iter == diameter - 1) { lineY(left, right, top , cz); lineY(left, right, bottom , cz); } else { dig(left, top, cz); dig(left, bottom, cz); dig(right, top, cz); dig(right, bottom, cz); } if(!filled && diff > 1) { int lright = cx + lastwhole; int lleft = cx - lastwhole + adjust; lineY(lleft + 1, left - 1, top + 1 , cz); lineY(right + 1, lright - 1, top + 1 , cz); lineY(lleft + 1, left - 1, bottom - 1 , cz); lineY(right + 1, lright - 1, bottom - 1 , cz); } lastwhole = whole; } MCache.WriteAll(); c->Resume(); return CR_OK; }
command_result writeFlag (Core * c, vector <string> & parameters) { if (parameters.size() == 0) { c->con.print("No value specified\n"); return CR_FAILURE; } if (parameters[0] == "help" || parameters[0] == "?") { c->con.print("Set the building occupancy flag.\n" "Value must be between 0 and 7, inclusive.\n"); return CR_OK; } char value; switch (parameters[0][0]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': value = parameters[0][0] - '0'; break; default: c->con.print("Invalid value specified\n"); return CR_FAILURE; break; //Redundant. } c->Suspend(); // init the map if(!Maps::IsValid()) { c->con.printerr("Can't init map. Make sure you have a map loaded in DF.\n"); c->Resume(); return CR_FAILURE; } int32_t cx, cy, cz; if(!Gui::getCursorCoords(cx,cy,cz)) { c->con.printerr("Cursor is not active.\n"); c->Resume(); return CR_FAILURE; } DFCoord cursor = DFCoord(cx,cy,cz); MapExtras::MapCache * MCache = new MapExtras::MapCache(); t_occupancy oc = MCache->occupancyAt(cursor); oc.bits.building = value; MCache->setOccupancyAt(cursor, oc); MCache->WriteAll(); c->Resume(); return CR_OK; }
command_result changelayer (color_ostream &out, std::vector <std::string> & parameters) { CoreSuspender suspend; string material; bool force = false; bool all_biomes = false; bool all_layers = false; bool verbose = false; warned = false; for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") { out.print(changelayer_help.c_str()); return CR_OK; } if(parameters[i] == "trouble") { out.print(changelayer_trouble.c_str()); return CR_OK; } if(parameters[i] == "force") force = true; if(parameters[i] == "all_biomes") all_biomes = true; if(parameters[i] == "all_layers") all_layers = true; if(parameters[i] == "verbose") verbose = true; } if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } if (parameters.empty()) { out.printerr("You need to specify a material!\n"); return CR_WRONG_USAGE; } material = parameters[0]; MaterialInfo mat_new; if (!mat_new.findInorganic(material)) { out.printerr("No such material!\n"); return CR_FAILURE; } // check if specified material is stone or gem or soil if (mat_new.inorganic->material.flags.is_set(material_flags::IS_METAL) || mat_new.inorganic->material.flags.is_set(material_flags::NO_STONE_STOCKPILE)) { out.printerr("Invalid material - you must select a type of stone or gem or soil.\n"); return CR_FAILURE; } MapExtras::MapCache mc; int32_t regionX, regionY, regionZ; Maps::getPosition(regionX,regionY,regionZ); int32_t cursorX, cursorY, cursorZ; Gui::getCursorCoords(cursorX,cursorY,cursorZ); if(cursorX == -30000) { out.printerr("No cursor; place cursor over tile.\n"); return CR_FAILURE; } DFCoord cursor (cursorX,cursorY,cursorZ); uint32_t blockX = cursorX / 16; uint32_t tileX = cursorX % 16; uint32_t blockY = cursorY / 16; uint32_t tileY = cursorY % 16; MapExtras::Block * b = mc.BlockAt(cursor/16); if(!b || !b->is_valid()) { out.printerr("No data.\n"); return CR_OK; } df::tile_designation des = b->DesignationAt(cursor%16); // get biome and geolayer at cursor position uint32_t biome = des.bits.biome; uint32_t layer = des.bits.geolayer_index; if(verbose) { out << "biome: " << biome << endl << "geolayer: " << layer << endl; } // there is no Maps::WriteGeology or whatever, and I didn't want to mess with the library and add it // so I copied the stuff which reads the geology information and modified it to be able to change it // // a more elegant solution would probably look like this: // 1) modify Maps::ReadGeology to accept and fill one more optional vector // where the geolayer ids of the 9 biomes are stored // 2) call ReadGeology here, modify the data in the vectors without having to do all that map stuff // 3) write Maps::WriteGeology, pass the vectors, let it do it's work // Step 1) is optional, but it would make implementing 3) easier. // Otherwise that "check which geo_index is used by biome X" loop would need to be done again. // no need to touch the same geology more than once // though it wouldn't matter much since there is not much data to be processed vector<uint16_t> v_geoprocessed; v_geoprocessed.clear(); // iterate over 8 surrounding regions + local region for (int i = eNorthWest; i < eBiomeCount; i++) { if(verbose) out << "---Biome: " << i; if(!all_biomes && i!=biome) { if(verbose) out << "-skipping" << endl; continue; } else { if(verbose) out << "-checking" << endl; } // check against worldmap boundaries, fix if needed // regionX is in embark squares // regionX/16 is in 16x16 embark square regions // i provides -1 .. +1 offset from the current region int bioRX = world->map.region_x / 16 + ((i % 3) - 1); if (bioRX < 0) bioRX = 0; if (bioRX >= world->world_data->world_width) bioRX = world->world_data->world_width - 1; int bioRY = world->map.region_y / 16 + ((i / 3) - 1); if (bioRY < 0) bioRY = 0; if (bioRY >= world->world_data->world_height) bioRY = world->world_data->world_height - 1; // get index into geoblock vector uint16_t geoindex = world->world_data->region_map[bioRX][bioRY].geo_index; if(verbose) out << "geoindex: " << geoindex << endl; bool skip = false; for(int g=0; g<v_geoprocessed.size(); g++) { if(v_geoprocessed.at(g)==geoindex) { if(verbose) out << "already processed" << endl; skip = true; break; } } if(skip) continue; v_geoprocessed.push_back(geoindex); /// geology blocks have a vector of layer descriptors // get the vector with pointer to layers df::world_geo_biome *geo_biome = df::world_geo_biome::find(geoindex); if (!geo_biome) { if(verbose) out << "no geology found here." << endl; continue; } vector <df::world_geo_layer*> &geolayers = geo_biome->layers; // complain if layer is out of range // geology has up to 16 layers currently, but can have less! if(layer >= geolayers.size() || layer < 0) { if(verbose) out << "layer out of range!"; continue; } // now let's actually write the new mat id to the layer(s) if(all_layers) { for (size_t j = 0; j < geolayers.size(); j++) { MaterialInfo mat_old; mat_old.decode(0, geolayers[j]->mat_index); if(conversionAllowed(out, mat_new, mat_old, force)) { if(verbose) out << "changing geolayer " << j << " from " << mat_old.getToken() << " to " << mat_new.getToken() << endl; geolayers[j]->mat_index = mat_new.index; } } } else { MaterialInfo mat_old; mat_old.decode(0, geolayers[layer]->mat_index); if(conversionAllowed(out, mat_new, mat_old, force)) { if(verbose) out << "changing geolayer " << layer << " from " << mat_old.getToken() << " to " << mat_new.getToken() << endl; geolayers[layer]->mat_index = mat_new.index; } } } out.print("Done.\n"); // Give control back to DF. return CR_OK; }
command_result df_probe (color_ostream &out, vector <string> & parameters) { //bool showBlock, showDesig, showOccup, showTile, showMisc; /* if (!parseOptions(parameters, showBlock, showDesig, showOccup, showTile, showMisc)) { out.printerr("Unknown parameters!\n"); return CR_FAILURE; } */ CoreSuspender suspend; DFHack::Materials *Materials = Core::getInstance().getMaterials(); std::vector<t_matglossInorganic> inorganic; bool hasmats = Materials->CopyInorganicMaterials(inorganic); if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } MapExtras::MapCache mc; int32_t regionX, regionY, regionZ; Maps::getPosition(regionX,regionY,regionZ); int32_t cursorX, cursorY, cursorZ; Gui::getCursorCoords(cursorX,cursorY,cursorZ); if(cursorX == -30000) { out.printerr("No cursor; place cursor over tile to probe.\n"); return CR_FAILURE; } DFCoord cursor (cursorX,cursorY,cursorZ); uint32_t blockX = cursorX / 16; uint32_t tileX = cursorX % 16; uint32_t blockY = cursorY / 16; uint32_t tileY = cursorY % 16; MapExtras::Block * b = mc.BlockAt(cursor/16); if(!b || !b->is_valid()) { out.printerr("No data.\n"); return CR_OK; } auto &block = *b->getRaw(); out.print("block addr: 0x%x\n\n", &block); /* if (showBlock) { out.print("block flags:\n"); print_bits<uint32_t>(block.blockflags.whole,out); out.print("\n\n"); } */ df::tiletype tiletype = mc.tiletypeAt(cursor); df::tile_designation &des = block.designation[tileX][tileY]; df::tile_occupancy &occ = block.occupancy[tileX][tileY]; /* if(showDesig) { out.print("designation\n"); print_bits<uint32_t>(block.designation[tileX][tileY].whole, out); out.print("\n\n"); } if(showOccup) { out.print("occupancy\n"); print_bits<uint32_t>(block.occupancy[tileX][tileY].whole, out); out.print("\n\n"); } */ // tiletype out.print("tiletype: "); describeTile(out, tiletype); out.print("static: "); describeTile(out, mc.staticTiletypeAt(cursor)); out.print("base: "); describeTile(out, mc.baseTiletypeAt(cursor)); out.print("temperature1: %d U\n",mc.temperature1At(cursor)); out.print("temperature2: %d U\n",mc.temperature2At(cursor)); int offset = block.region_offset[des.bits.biome]; int bx = clip_range(block.region_pos.x + (offset % 3) - 1, 0, world->world_data->world_width-1); int by = clip_range(block.region_pos.y + (offset / 3) - 1, 0, world->world_data->world_height-1); auto biome = &world->world_data->region_map[bx][by]; int sav = biome->savagery; int evi = biome->evilness; int sindex = sav > 65 ? 2 : sav < 33 ? 0 : 1; int eindex = evi > 65 ? 2 : evi < 33 ? 0 : 1; int surr = sindex + eindex * 3; const char* surroundings[] = { "Serene", "Mirthful", "Joyous Wilds", "Calm", "Wilderness", "Untamed Wilds", "Sinister", "Haunted", "Terrifying" }; // biome, geolayer out << "biome: " << des.bits.biome << " (" << "region id=" << biome->region_id << ", " << surroundings[surr] << ", " << "savagery " << biome->savagery << ", " << "evilness " << biome->evilness << ")" << std::endl; out << "geolayer: " << des.bits.geolayer_index << std::endl; int16_t base_rock = mc.layerMaterialAt(cursor); if(base_rock != -1) { out << "Layer material: " << dec << base_rock; if(hasmats) out << " / " << inorganic[base_rock].id << " / " << inorganic[base_rock].name << endl; else out << endl; } int16_t vein_rock = mc.veinMaterialAt(cursor); if(vein_rock != -1) { out << "Vein material (final): " << dec << vein_rock; if(hasmats) out << " / " << inorganic[vein_rock].id << " / " << inorganic[vein_rock].name << endl; else out << endl; } MaterialInfo minfo(mc.baseMaterialAt(cursor)); if (minfo.isValid()) out << "Base material: " << minfo.getToken() << " / " << minfo.toString() << endl; minfo.decode(mc.staticMaterialAt(cursor)); if (minfo.isValid()) out << "Static material: " << minfo.getToken() << " / " << minfo.toString() << endl; // liquids if(des.bits.flow_size) { if(des.bits.liquid_type == tile_liquid::Magma) out <<"magma: "; else out <<"water: "; out << des.bits.flow_size << std::endl; } if(des.bits.flow_forbid) out << "flow forbid" << std::endl; if(des.bits.pile) out << "stockpile?" << std::endl; if(des.bits.rained) out << "rained?" << std::endl; if(des.bits.smooth) out << "smooth?" << std::endl; if(des.bits.water_salt) out << "salty" << endl; if(des.bits.water_stagnant) out << "stagnant" << endl; #define PRINT_FLAG( FIELD, BIT ) out.print("%-16s= %c\n", #BIT , ( FIELD.bits.BIT ? 'Y' : ' ' ) ) PRINT_FLAG( des, hidden ); PRINT_FLAG( des, light ); PRINT_FLAG( des, outside ); PRINT_FLAG( des, subterranean ); PRINT_FLAG( des, water_table ); PRINT_FLAG( des, rained ); PRINT_FLAG( occ, monster_lair); df::coord2d pc(blockX, blockY); t_feature local; t_feature global; Maps::ReadFeatures(&block,&local,&global); PRINT_FLAG( des, feature_local ); if(local.type != -1) { out.print("%-16s", ""); out.print(" %4d", block.local_feature); out.print(" (%2d)", local.type); out.print(" addr 0x%X ", local.origin); out.print(" %s\n", sa_feature(local.type)); } PRINT_FLAG( des, feature_global ); if(global.type != -1) { out.print("%-16s", ""); out.print(" %4d", block.global_feature); out.print(" (%2d)", global.type); out.print(" %s\n", sa_feature(global.type)); } #undef PRINT_FLAG out << "local feature idx: " << block.local_feature << endl; out << "global feature idx: " << block.global_feature << endl; out << std::endl; if(block.occupancy[tileX][tileY].bits.no_grow) out << "no grow" << endl; for(size_t e=0; e<block.block_events.size(); e++) { df::block_square_event * blev = block.block_events[e]; df::block_square_event_type blevtype = blev->getType(); switch(blevtype) { case df::block_square_event_type::grass: { df::block_square_event_grassst * gr_ev = (df::block_square_event_grassst *)blev; if(gr_ev->amount[tileX][tileY] > 0) { out << "amount of grass: " << (int)gr_ev->amount[tileX][tileY] << endl; } break; } case df::block_square_event_type::world_construction: { df::block_square_event_world_constructionst * co_ev = (df::block_square_event_world_constructionst*)blev; uint16_t bits = co_ev->tile_bitmask[tileY]; out << "construction bits: " << bits << endl; break; } default: //out << "unhandled block event type!" << endl; break; } } return CR_OK; }