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++; } } }
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); } } } }
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; }
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; }
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 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; }
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; }
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 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 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; }
command_result df_probe (Core * c, vector <string> & parameters) { //bool showBlock, showDesig, showOccup, showTile, showMisc; Console & con = c->con; /* if (!parseOptions(parameters, showBlock, showDesig, showOccup, showTile, showMisc)) { con.printerr("Unknown parameters!\n"); return CR_FAILURE; } */ CoreSuspender suspend(c); DFHack::Gui *Gui = c->getGui(); DFHack::Materials *Materials = c->getMaterials(); DFHack::VersionInfo* mem = c->vinfo; std::vector<t_matglossInorganic> inorganic; bool hasmats = Materials->CopyInorganicMaterials(inorganic); if (!Maps::IsValid()) { c->con.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) { con.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->valid) { con.printerr("No data.\n"); return CR_OK; } mapblock40d & block = b->raw; con.print("block addr: 0x%x\n\n", block.origin); /* if (showBlock) { con.print("block flags:\n"); print_bits<uint32_t>(block.blockflags.whole,con); con.print("\n\n"); } */ df::tiletype tiletype = mc.tiletypeAt(cursor); df::tile_designation &des = block.designation[tileX][tileY]; /* if(showDesig) { con.print("designation\n"); print_bits<uint32_t>(block.designation[tileX][tileY].whole, con); con.print("\n\n"); } if(showOccup) { con.print("occupancy\n"); print_bits<uint32_t>(block.occupancy[tileX][tileY].whole, con); con.print("\n\n"); } */ // tiletype con.print("tiletype: %d", tiletype); if(tileName(tiletype)) con.print(" = %s",tileName(tiletype)); con.print("\n"); df::tiletype_shape shape = tileShape(tiletype); df::tiletype_material material = tileMaterial(tiletype); df::tiletype_special special = tileSpecial(tiletype); df::tiletype_variant variant = tileVariant(tiletype); con.print("%-10s: %4d %s\n","Class" ,shape, ENUM_KEY_STR(tiletype_shape, shape)); con.print("%-10s: %4d %s\n","Material" , material, ENUM_KEY_STR(tiletype_material, material)); con.print("%-10s: %4d %s\n","Special" , special, ENUM_KEY_STR(tiletype_special, special)); con.print("%-10s: %4d %s\n" ,"Variant" , variant, ENUM_KEY_STR(tiletype_variant, variant)); con.print("%-10s: %s\n" ,"Direction", tileDirection(tiletype).getStr()); con.print("\n"); con.print("temperature1: %d U\n",mc.temperature1At(cursor)); con.print("temperature2: %d U\n",mc.temperature2At(cursor)); // biome, geolayer con << "biome: " << des.bits.biome << std::endl; con << "geolayer: " << des.bits.geolayer_index << std::endl; int16_t base_rock = mc.baseMaterialAt(cursor); if(base_rock != -1) { con << "Layer material: " << dec << base_rock; if(hasmats) con << " / " << inorganic[base_rock].id << " / " << inorganic[base_rock].name << endl; else con << endl; } int16_t vein_rock = mc.veinMaterialAt(cursor); if(vein_rock != -1) { con << "Vein material (final): " << dec << vein_rock; if(hasmats) con << " / " << inorganic[vein_rock].id << " / " << inorganic[vein_rock].name << endl; else con << endl; } // liquids if(des.bits.flow_size) { if(des.bits.liquid_type == tile_liquid::Magma) con <<"magma: "; else con <<"water: "; con << des.bits.flow_size << std::endl; } if(des.bits.flow_forbid) con << "flow forbid" << std::endl; if(des.bits.pile) con << "stockpile?" << std::endl; if(des.bits.rained) con << "rained?" << std::endl; if(des.bits.smooth) con << "smooth?" << std::endl; if(des.bits.water_salt) con << "salty" << endl; if(des.bits.water_stagnant) con << "stagnant" << endl; #define PRINT_FLAG( X ) con.print("%-16s= %c\n", #X , ( des.X ? 'Y' : ' ' ) ) PRINT_FLAG( bits.hidden ); PRINT_FLAG( bits.light ); PRINT_FLAG( bits.outside ); PRINT_FLAG( bits.subterranean ); PRINT_FLAG( bits.water_table ); PRINT_FLAG( bits.rained ); df::coord2d pc(blockX, blockY); t_feature local; t_feature global; Maps::ReadFeatures(&(b->raw),&local,&global); PRINT_FLAG( bits.feature_local ); if(local.type != -1) { con.print("%-16s", ""); con.print(" %4d", block.local_feature); con.print(" (%2d)", local.type); con.print(" addr 0x%X ", local.origin); con.print(" %s\n", sa_feature(local.type)); } PRINT_FLAG( bits.feature_global ); if(global.type != -1) { con.print("%-16s", ""); con.print(" %4d", block.global_feature); con.print(" (%2d)", global.type); con.print(" %s\n", sa_feature(global.type)); } #undef PRINT_FLAG con << "local feature idx: " << block.local_feature << endl; con << "global feature idx: " << block.global_feature << endl; con << "mystery: " << block.mystery << endl; con << std::endl; return CR_OK; }
void lightingEngineViewscreen::doOcupancyAndLights() { float daycol; if(dayHour<0) { int length=1200/daySpeed; daycol= (*df::global::cur_year_tick % length)/ (float)length; } else daycol= fmod(dayHour,24.0f)/24.0f; //1->12h 0->24h rgbf sky_col=getSkyColor(daycol); lightSource sky(sky_col, -1);//auto calculate best size MapExtras::MapCache cache; doSun(sky,cache); 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=coord2d(window_x,window_y)/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); for(int blockX=blockVp.first.x;blockX<=blockVp.second.x;blockX++) for(int blockY=blockVp.first.y;blockY<=blockVp.second.y;blockY++) { MapExtras::Block* b=cache.BlockAt(DFCoord(blockX,blockY,window_z)); MapExtras::Block* bDown=cache.BlockAt(DFCoord(blockX,blockY,window_z-1)); if(!b) continue; //empty blocks fixed by sun propagation for(int block_x = 0; block_x < 16; block_x++) for(int block_y = 0; block_y < 16; block_y++) { df::coord2d pos; pos.x = blockX*16+block_x; pos.y = blockY*16+block_y; df::coord2d gpos=pos; pos=worldToViewportCoord(pos,vp,window2d); if(!isInRect(pos,vp)) continue; int tile=getIndex(pos.x,pos.y); rgbf& curCell=ocupancy[tile]; curCell=matAmbience.transparency; df::tiletype type = b->tiletypeAt(gpos); df::tile_designation d = b->DesignationAt(gpos); if(d.bits.hidden) { curCell=rgbf(0,0,0); continue; // do not process hidden stuff, TODO other hidden stuff } //df::tile_occupancy o = b->OccupancyAt(gpos); df::tiletype_shape shape = ENUM_ATTR(tiletype,shape,type); df::tiletype_shape_basic basic_shape = ENUM_ATTR(tiletype_shape, basic_shape, shape); df::tiletype_material tileMat= ENUM_ATTR(tiletype,material,type); DFHack::t_matpair mat=b->staticMaterialAt(gpos); matLightDef* lightDef=getMaterialDef(mat.mat_type,mat.mat_index); if(!lightDef || !lightDef->isTransparent) lightDef=&matWall; if(shape==df::tiletype_shape::BROOK_BED ) { curCell=rgbf(0,0,0); } else if(shape==df::tiletype_shape::WALL) { if(tileMat==df::tiletype_material::FROZEN_LIQUID) applyMaterial(tile,matIce); else applyMaterial(tile,*lightDef); } else if(!d.bits.liquid_type && d.bits.flow_size>0 ) { applyMaterial(tile,matWater, (float)d.bits.flow_size/7.0f, (float)d.bits.flow_size/7.0f); } if(d.bits.liquid_type && d.bits.flow_size>0) { applyMaterial(tile,matLava,(float)d.bits.flow_size/7.0f,(float)d.bits.flow_size/7.0f); } else if(shape==df::tiletype_shape::EMPTY || shape==df::tiletype_shape::RAMP_TOP || shape==df::tiletype_shape::STAIR_DOWN || shape==df::tiletype_shape::STAIR_UPDOWN) { if(bDown) { df::tile_designation d2=bDown->DesignationAt(gpos); if(d2.bits.liquid_type && d2.bits.flow_size>0) { applyMaterial(tile,matLava); } } } } df::map_block* block=b->getRaw(); if(!block) continue; //flows for(int i=0;i<block->flows.size();i++) { df::flow_info* f=block->flows[i]; if(f && f->density>0 && f->type==df::flow_type::Dragonfire || f->type==df::flow_type::Fire) { df::coord2d pos=f->pos; pos=worldToViewportCoord(pos,vp,window2d); int tile=getIndex(pos.x,pos.y); if(isInRect(pos,vp)) { rgbf fireColor; if(f->density>60) { fireColor=rgbf(0.98f,0.91f,0.30f); } else if(f->density>30) { fireColor=rgbf(0.93f,0.16f,0.16f); } else { fireColor=rgbf(0.64f,0.0f,0.0f); } lightSource fire(fireColor,f->density/5); addLight(tile,fire); } } } //plants for(int i=0;i<block->plants.size();i++) { df::plant* cPlant=block->plants[i]; if (cPlant->grow_counter <180000) //todo maybe smaller light/oclusion? continue; df::coord2d pos=cPlant->pos; pos=worldToViewportCoord(pos,vp,window2d); int tile=getIndex(pos.x,pos.y); if(isInRect(pos,vp)) { applyMaterial(tile,419,cPlant->material); } } //blood and other goo for(int i=0;i<block->block_events.size();i++) { df::block_square_event* ev=block->block_events[i]; df::block_square_event_type ev_type=ev->getType(); if(ev_type==df::block_square_event_type::material_spatter) { df::block_square_event_material_spatterst* spatter=static_cast<df::block_square_event_material_spatterst*>(ev); matLightDef* m=getMaterialDef(spatter->mat_type,spatter->mat_index); if(!m) continue; if(!m->isEmiting) continue; for(int x=0;x<16;x++) for(int y=0;y<16;y++) { df::coord2d pos; pos.x = blockX*16+x; pos.y = blockY*16+y; int16_t amount=spatter->amount[x][y]; if(amount<=0) continue; pos=worldToViewportCoord(pos,vp,window2d); if(isInRect(pos,vp)) { addLight(getIndex(pos.x,pos.y),m->makeSource((float)amount/100)); } } } } } if(df::global::cursor->x>-30000) { int wx=df::global::cursor->x-window_x+vp.first.x; int wy=df::global::cursor->y-window_y+vp.first.y; int tile=getIndex(wx,wy); applyMaterial(tile,matCursor); } //citizen only emit light, if defined //or other creatures if(matCitizen.isEmiting || creatureDefs.size()>0) for (int i=0;i<df::global::world->units.active.size();++i) { df::unit *u = df::global::world->units.active[i]; coord2d pos=worldToViewportCoord(coord2d(u->pos.x,u->pos.y),vp,window2d); if(u->pos.z==window_z && isInRect(pos,vp)) { if (DFHack::Units::isCitizen(u) && !u->counters.unconscious) addLight(getIndex(pos.x,pos.y),matCitizen.makeSource()); creatureLightDef *def=getCreatureDef(u); if(def && !u->flags1.bits.dead) { addLight(getIndex(pos.x,pos.y),def->light.makeSource()); } } } //items if(itemDefs.size()>0) { std::vector<df::item*>& vec=df::global::world->items.other[items_other_id::IN_PLAY]; for(size_t i=0;i<vec.size();i++) { df::item* curItem=vec[i]; df::coord itemPos=DFHack::Items::getPosition(curItem); coord2d pos=worldToViewportCoord(itemPos,vp,window2d); itemLightDef* mat=0; if( itemPos.z==window_z && isInRect(pos,vp) && (mat=getItemDef(curItem)) ) { if( ((mat->equiped || mat->haul ||mat->inBuilding ||mat->inContainer) && curItem->flags.bits.in_inventory)|| //TODO split this up (mat->onGround && curItem->flags.bits.on_ground) ) { if(mat->light.isEmiting) addLight(getIndex(pos.x,pos.y),mat->light.makeSource()); if(!mat->light.isTransparent) addOclusion(getIndex(pos.x,pos.y),mat->light.transparency,1); } } } } //buildings for(size_t i = 0; i < df::global::world->buildings.all.size(); i++) { df::building *bld = df::global::world->buildings.all[i]; if(window_z!=bld->z) continue; if(bld->getBuildStage()<bld->getMaxBuildStage()) //only work if fully built continue; df::coord2d p1(bld->x1,bld->y1); df::coord2d p2(bld->x2,bld->y2); p1=worldToViewportCoord(p1,vp,window2d); p2=worldToViewportCoord(p2,vp,window2d); if(isInRect(p1,vp)||isInRect(p2,vp)) { int tile; if(isInRect(p1,vp)) tile=getIndex(p1.x,p1.y); //TODO multitile buildings. How they would work? else tile=getIndex(p2.x,p2.y); df::building_type type = bld->getType(); buildingLightDef* def=getBuildingDef(bld); if(!def) continue; if(type==df::enums::building_type::Door) { df::building_doorst* door=static_cast<df::building_doorst*>(bld); if(!door->door_flags.bits.closed) continue; } else if(type==df::enums::building_type::Floodgate) { df::building_floodgatest* gate=static_cast<df::building_floodgatest*>(bld); if(!gate->gate_flags.bits.closed) continue; } if(def->useMaterial) { matLightDef* mat=getMaterialDef(bld->mat_type,bld->mat_index); if(!mat)mat=&matWall; if(!def->poweredOnly || !bld->isUnpowered()) //not powered. Add occlusion only. { if(def->light.isEmiting) { addLight(tile,def->light.makeSource(def->size)); } else if(mat->isEmiting) { addLight(tile,mat->makeSource(def->size)); } } if(def->light.isTransparent) { addOclusion(tile,def->light.transparency,def->size); } else { addOclusion(tile,mat->transparency,def->size); } } else { if(!def->poweredOnly || !bld->isUnpowered())//not powered. Add occlusion only. addOclusion(tile,def->light.transparency,def->size); else applyMaterial(tile,def->light,def->size,def->thickness); } } } }