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; }
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); } }
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; }
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; }
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 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; }
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 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; }
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 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; }
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 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; }
command_result filltraffic(color_ostream &out, std::vector<std::string> & params) { // HOTKEY COMMAND; CORE ALREADY SUSPENDED //Maximum map size. uint32_t x_max,y_max,z_max; //Source and target traffic types. df::tile_traffic source = tile_traffic::Normal; df::tile_traffic target = tile_traffic::Normal; //Option flags bool updown = false; bool checkpit = true; bool checkbuilding = true; //Loop through parameters for(size_t i = 0; i < params.size();i++) { if (params[i] == "help" || params[i] == "?" || params[i].size() != 1) return CR_WRONG_USAGE; switch (toupper(params[i][0])) { case 'H': target = tile_traffic::High; break; case 'N': target = tile_traffic::Normal; break; case 'L': target = tile_traffic::Low; break; case 'R': target = tile_traffic::Restricted; break; case 'X': updown = true; break; case 'B': checkbuilding = false; break; case 'P': checkpit = false; break; default: return CR_WRONG_USAGE; } } if (!Maps::IsValid()) { out.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) { out.printerr("Cursor is not active.\n"); return CR_FAILURE; } DFCoord xy ((uint32_t)cx,(uint32_t)cy,cz); MapExtras::MapCache MCache; df::tile_designation des = MCache.designationAt(xy); df::tiletype tt = MCache.tiletypeAt(xy); df::tile_occupancy oc; if (checkbuilding) oc = MCache.occupancyAt(xy); source = (df::tile_traffic)des.bits.traffic; if(source == target) { out.printerr("This tile is already set to the target traffic type.\n"); return CR_FAILURE; } if(isWallTerrain(tt)) { out.printerr("This tile is a wall. Please select a passable tile.\n"); return CR_FAILURE; } if(checkpit && isOpenTerrain(tt)) { out.printerr("This tile is a hole. Please select a passable tile.\n"); return CR_FAILURE; } if(checkbuilding && oc.bits.building) { out.printerr("This tile contains a building. Please select an empty tile.\n"); return CR_FAILURE; } out.print("%d/%d/%d ... FILLING!\n", cx,cy,cz); //Naive four-way or six-way flood fill with possible tiles on a stack. stack <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(isWallTerrain(tt)) continue; if(checkpit && 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(DFCoord(xy.x - 1, xy.y, xy.z)); } if (xy.x < int32_t(tx_max) - 1) { flood.push(DFCoord(xy.x + 1, xy.y, xy.z)); } if (xy.y > 0) { flood.push(DFCoord(xy.x, xy.y - 1, xy.z)); } if (xy.y < int32_t(ty_max) - 1) { flood.push(DFCoord(xy.x, xy.y + 1, xy.z)); } if (updown) { if (xy.z > 0 && LowPassable(tt)) { flood.push(DFCoord(xy.x, xy.y, xy.z - 1)); } if (xy.z < int32_t(z_max) && HighPassable(tt)) { flood.push(DFCoord(xy.x, xy.y, xy.z + 1)); } } } } MCache.WriteAll(); return CR_OK; }