DFhackCExport command_result df_flows (Core * c, vector <string> & parameters) { uint32_t x_max,y_max,z_max; DFHack::designations40d designations; DFHack::Maps *Maps; c->Suspend(); Maps = c->getMaps(); // init the map if(!Maps->Start()) { c->con.printerr("Can't init map.\n"); c->Resume(); return CR_FAILURE; } DFHack::t_blockflags bflags; Maps->getSize(x_max,y_max,z_max); // walk the map, count flowing tiles, magma, water uint32_t flow1=0, flow2=0, flowboth=0, water=0, magma=0; c->con.print("Counting flows and liquids ...\n"); for(uint32_t x = 0; x< x_max;x++) { for(uint32_t y = 0; y< y_max;y++) { for(uint32_t z = 0; z< z_max;z++) { if(Maps->getBlock(x,y,z)) { Maps->ReadBlockFlags(x, y, z, bflags); Maps->ReadDesignations(x, y, z, &designations); if (bflags.bits.liquid_1) flow1++; if (bflags.bits.liquid_2) flow2++; if (bflags.bits.liquid_1 && bflags.bits.liquid_2) flowboth++; for (uint32_t i = 0; i < 16;i++) for (uint32_t j = 0; j < 16;j++) { if (designations[i][j].bits.liquid_type == DFHack::liquid_magma) magma++; if (designations[i][j].bits.liquid_type == DFHack::liquid_water) water++; } } } } } c->con.print("Blocks with liquid_1=true: %d\n" "Blocks with liquid_2=true: %d\n" "Blocks with both: %d\n" "Water tiles: %d\n" "Magma tiles: %d\n" ,flow1, flow2, flowboth, water, magma ); c->Resume(); return CR_OK; }
int main(int argc, char *argv[]) { bool temporary_terminal = TemporaryTerminal(); uint32_t x_max = 0, y_max = 0, z_max = 0; DFHack::ContextManager manager("Memory.xml"); DFHack::Context *context = manager.getSingleContext(); if (!context->Attach()) { std::cerr << "Unable to attach to DF!" << std::endl; if(temporary_terminal) std::cin.ignore(); return 1; } DFHack::Maps *maps = context->getMaps(); if (!maps->Start()) { std::cerr << "Cannot get map info!" << std::endl; context->Detach(); if(temporary_terminal) std::cin.ignore(); return 1; } maps->getSize(x_max, y_max, z_max); MapExtras::MapCache map(maps); 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 DFHack::DFCoord blockCoord(b_x, b_y); MapExtras::Block *b = map.BlockAt(DFHack::DFCoord(b_x, b_y, z)); if (!b || !b->valid) { continue; } DFHack::t_blockflags flags = b->BlockFlags(); flags.whole = flags.whole ^ 0xFFFFFFFF; b->setBlockFlags(flags); b->Write(); } // block x } // block y } // z maps->Finish(); context->Detach(); return 0; }
int main (void) { uint32_t x_max,y_max,z_max; DFHack::designations40d designations; DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF; try { DF = DFMgr.getSingleContext(); DF->Attach(); } catch (exception& e) { cerr << e.what() << endl; #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } DFHack::Maps *Maps =DF->getMaps(); DFHack::Gui *Gui =DF->getGui(); // walk the map, save the hide bits, reveal. cout << "Pausing..." << endl; // horrible hack to make sure the pause is really set // preblem here is that we could be 'arriving' at the wrong time and DF could be in the middle of a frame. // that could mean that revealing, even with suspending DF's thread, would mean unleashing hell *in the same frame* // this here hack sets the pause state, resumes DF, waits a second for it to enter the pause (I know, BS value.) and suspends. Gui->SetPauseState(true); DF->Resume(); waitmsec(1000); DF->Suspend(); // init the map if(!Maps->Start()) { cerr << "Can't init map." << endl; #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } cout << "Revealing, please wait..." << endl; Maps->getSize(x_max,y_max,z_max); vector <hideblock> hidesaved; for(uint32_t x = 0; x< x_max;x++) { for(uint32_t y = 0; y< y_max;y++) { for(uint32_t z = 0; z< z_max;z++) { if(Maps->isValidBlock(x,y,z)) { hideblock hb; hb.x = x; hb.y = y; hb.z = z; // read block designations Maps->ReadDesignations(x,y,z, &designations); // change the hidden flag to 0 for (uint32_t i = 0; i < 16;i++) for (uint32_t j = 0; j < 16;j++) { hb.hiddens[i][j] = designations[i][j].bits.hidden; designations[i][j].bits.hidden = 0; } hidesaved.push_back(hb); // write the designations back Maps->WriteDesignations(x,y,z, &designations); } } } } // FIXME: force game pause here! DF->Detach(); cout << "Map revealed. The game has been paused for you." << endl; cout << "Unpausing can unleash the forces of hell!" << endl << endl; cout << "Press any key to unreveal." << endl; cout << "Close to keep the map revealed." << endl; cin.ignore(); cout << "Unrevealing... please wait." << endl; // FIXME: do some consistency checks here! DF->Attach(); Maps = DF->getMaps(); Maps->Start(); for(int i = 0; i < hidesaved.size();i++) { hideblock & hb = hidesaved[i]; Maps->ReadDesignations(hb.x,hb.y,hb.z, &designations); for (uint32_t i = 0; i < 16;i++) for (uint32_t j = 0; j < 16;j++) { designations[i][j].bits.hidden = hb.hiddens[i][j]; } Maps->WriteDesignations(hb.x,hb.y,hb.z, &designations); } #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; cin.ignore(); #endif return 0; }
DFhackCExport command_result tubefill(DFHack::Core * c, std::vector<std::string> & params) { uint32_t x_max,y_max,z_max; DFHack::designations40d designations; DFHack::tiletypes40d tiles; int32_t oldT, newT; uint64_t count = 0; int dirty=0; for(int i = 0; i < params.size();i++) { if(params[i] == "help" || params[i] == "?") { c->con.print("Replenishes mined out adamantine and hollow adamantine tubes.\n" "May cause !!FUN!!\n" ); return CR_OK; } } c->Suspend(); DFHack::Maps *Mapz = c->getMaps(); // init the map if (!Mapz->Start()) { c->con.printerr("Can't init map.\n"); c->Resume(); return CR_FAILURE; } Mapz->getSize(x_max,y_max,z_max); if(!Mapz->StartFeatures()) { c->con.printerr("Can't get map features.\n"); c->Resume(); return CR_FAILURE; } // walk the map for (uint32_t x = 0; x< x_max;x++) { for (uint32_t y = 0; y< y_max;y++) { for (uint32_t z = 0; z< z_max;z++) { DFHack::t_feature * locf = 0; DFHack::t_feature * glof = 0; if (Mapz->ReadFeatures(x,y,z,&locf,&glof)) { // we're looking for addy tubes if(!locf) continue; if(locf->type != DFHack::feature_Adamantine_Tube) continue; dirty=0; Mapz->ReadDesignations(x,y,z, &designations); Mapz->ReadTileTypes(x,y,z, &tiles); for (uint32_t ty=0;ty<16;++ty) { for (uint32_t tx=0;tx<16;++tx) { if(!designations[tx][ty].bits.feature_local) continue; oldT = tiles[tx][ty]; if ( DFHack::tileShape(oldT) != DFHack::WALL ) { //Current tile is not a wall. //Set current tile, as accurately as can be expected //newT = DFHack::findSimilarTileType(oldT,DFHack::WALL); newT = DFHack::findTileType( DFHack::WALL, DFHack::FEATSTONE, DFHack::tilevariant_invalid, DFHack::TILE_NORMAL, DFHack::TileDirection() ); //If no change, skip it (couldn't find a good tile type) if ( oldT == newT) continue; //Set new tile type, clear designation tiles[tx][ty] = newT; dirty=1; ++count; } } } //If anything was changed, write it all. if (dirty) { Mapz->WriteTileTypes(x,y,z, &tiles); } } } } } c->Resume(); c->con.print("Found and changed %d tiles.\n", count); return CR_OK; }
int main (int argc, char** argv) { bool temporary_terminal = TemporaryTerminal(); bool quiet = false; for(int i = 1; i < argc; i++) { string test = argv[i]; if(test == "-q") { quiet = true; } } uint32_t x_max,y_max,z_max; vector<DFHack::t_spattervein> splatter; DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF = DFMgr.getSingleContext(); try { DF->Attach(); } catch (exception& e) { cerr << e.what() << endl; if(temporary_terminal) cin.ignore(); return 1; } DFHack::Maps *Mapz = DF->getMaps(); // init the map if(!Mapz->Start()) { cerr << "Can't init map." << endl; if(temporary_terminal) cin.ignore(); return 1; } Mapz->getSize(x_max,y_max,z_max); uint8_t zeroes [16][16] = {{0}}; DFHack::occupancies40d occ; // walk the map for(uint32_t x = 0; x< x_max;x++) { for(uint32_t y = 0; y< y_max;y++) { for(uint32_t z = 0; z< z_max;z++) { if(Mapz->isValidBlock(x,y,z)) { Mapz->ReadVeins(x,y,z,0,0,&splatter); Mapz->ReadOccupancy(x,y,z,&occ); for(int i = 0; i < 16; i++) for(int j = 0; j < 16; j++) { occ[i][j].bits.arrow_color = 0; occ[i][j].bits.broken_arrows_variant = 0; } Mapz->WriteOccupancy(x,y,z,&occ); for(uint32_t i = 0; i < splatter.size(); i++) { DFHack::t_spattervein & vein = splatter[i]; // filter snow if(vein.mat1 == water_idx && vein.matter_state == DFHack::state_powder) continue; // filter mud if(vein.mat1 == mud_idx && vein.matter_state == DFHack::state_solid) continue; uint32_t addr = vein.address_of; uint32_t offset = offsetof(DFHack::t_spattervein, intensity); // TODO: make this actually destroy the objects/remove them from the vector? // still, this is safe. DF->WriteRaw(addr + offset,sizeof(zeroes),(uint8_t *) zeroes); } } } } } DF->Detach(); if (!quiet && temporary_terminal) { cout << "Done. Press any key to continue" << endl; cin.ignore(); } return 0; }
DFhackCExport command_result cleanmap (Core * c, vector <string> & parameters) { const uint32_t water_idx = 6; const uint32_t mud_idx = 12; bool snow = false; bool mud = false; bool help = false; for(int i = 0; i < parameters.size();i++) { if(parameters[i] == "snow") snow = true; else if(parameters[i] == "mud") mud = true; else if(parameters[i] == "help" ||parameters[i] == "?") { help = true; } } if(help) { c->con.print("This command cleans the coverings from the map. Snow and mud are ignored by default.\n" "Options:\n" "snow - also remove snow\n" "mud - also remove mud\n" ); return CR_OK; } c->Suspend(); vector<DFHack::t_spattervein *> splatter; DFHack::Maps *Mapz = c->getMaps(); // init the map if(!Mapz->Start()) { c->con << "Can't init map." << std::endl; c->Resume(); return CR_FAILURE; } uint32_t x_max,y_max,z_max; Mapz->getSize(x_max,y_max,z_max); // walk the map for(uint32_t x = 0; x< x_max;x++) { for(uint32_t y = 0; y< y_max;y++) { for(uint32_t z = 0; z< z_max;z++) { df_block * block = Mapz->getBlock(x,y,z); if(block) { Mapz->SortBlockEvents(x,y,z,0,0,&splatter); for(int i = 0; i < 16; i++) for(int j = 0; j < 16; j++) { block->occupancy[i][j].bits.arrow_color = 0; block->occupancy[i][j].bits.broken_arrows_variant = 0; } for(uint32_t i = 0; i < splatter.size(); i++) { DFHack::t_spattervein * vein = splatter[i]; // filter snow if(!snow && vein->mat1 == water_idx && vein->matter_state == DFHack::state_powder) continue; // filter mud if(!mud && vein->mat1 == mud_idx && vein->matter_state == DFHack::state_solid) continue; Mapz->RemoveBlockEvent(x,y,z,(t_virtual *) vein); } } } } } 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; }
int main (void) { bool temporary_terminal = TemporaryTerminal(); uint32_t x_max,y_max,z_max; DFHack::designations40d designations; DFHack::tiletypes40d tiles; int32_t oldT, newT; uint64_t count = 0; int dirty=0; DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF = DFMgr.getSingleContext(); //Init try { DF->Attach(); } catch (exception& e) { cerr << e.what() << endl; if(temporary_terminal) cin.ignore(); return 1; } DFHack::Maps *Mapz = DF->getMaps(); // init the map if (!Mapz->Start()) { cerr << "Can't init map." << endl; if(temporary_terminal) cin.ignore(); return 1; } Mapz->getSize(x_max,y_max,z_max); if(!Mapz->StartFeatures()) { cerr << "Can't get features." << endl; if(temporary_terminal) cin.ignore(); return 1; } // walk the map for (uint32_t x = 0; x< x_max;x++) { for (uint32_t y = 0; y< y_max;y++) { for (uint32_t z = 0; z< z_max;z++) { DFHack::t_feature * locf = 0; DFHack::t_feature * glof = 0; if (Mapz->ReadFeatures(x,y,z,&locf,&glof)) { // we're looking for addy tubes if(!locf) continue; if(locf->type != DFHack::feature_Adamantine_Tube) continue; dirty=0; Mapz->ReadDesignations(x,y,z, &designations); Mapz->ReadTileTypes(x,y,z, &tiles); for (uint32_t ty=0;ty<16;++ty) { for (uint32_t tx=0;tx<16;++tx) { if(!designations[tx][ty].bits.feature_local) continue; oldT = tiles[tx][ty]; if ( DFHack::tileShape(oldT) != DFHack::WALL ) { //Current tile is not a wall. //Set current tile, as accurately as can be expected //newT = DFHack::findSimilarTileType(oldT,DFHack::WALL); newT = DFHack::findTileType( DFHack::WALL, DFHack::FEATSTONE, DFHack::tilevariant_invalid, DFHack::TILE_NORMAL, DFHack::TileDirection() ); //If no change, skip it (couldn't find a good tile type) if ( oldT == newT) continue; //Set new tile type, clear designation tiles[tx][ty] = newT; dirty=1; ++count; } } } //If anything was changed, write it all. if (dirty) { Mapz->WriteTileTypes(x,y,z, &tiles); } } } } } DF->Detach(); cout << "Found and changed " << count << " tiles." << endl; if(temporary_terminal) { cout << "Done. Press any key to continue" << endl; cin.ignore(); } return 0; }
int main (int argc, char* argv[]) { // Command line options bool updown = false; if(argc > 1 && strcmp(argv[1],"-x") == 0) updown = true; DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context * DF; try { DF = DFMgr.getSingleContext(); DF->Attach(); } catch (exception& e) { cerr << e.what() << endl; #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } uint32_t x_max,y_max,z_max; DFHack::Maps * Maps = DF->getMaps(); DFHack::Gui * Gui = DF->getGui(); // init the map if(!Maps->Start()) { cerr << "Can't init map. Make sure you have a map loaded in DF." << endl; DF->Detach(); #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } int32_t cx, cy, cz; Maps->getSize(x_max,y_max,z_max); uint32_t tx_max = x_max * 16; uint32_t ty_max = y_max * 16; Gui->getCursorCoords(cx,cy,cz); while(cx == -30000) { cerr << "Cursor is not active. Point the cursor at a vein." << endl; DF->Resume(); cin.ignore(); DF->Suspend(); Gui->getCursorCoords(cx,cy,cz); } DFHack::DFCoord xy ((uint32_t)cx,(uint32_t)cy,cz); if(xy.x == 0 || xy.x == tx_max - 1 || xy.y == 0 || xy.y == ty_max - 1) { cerr << "I won't dig the borders. That would be cheating!" << endl; DF->Detach(); #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } MapCache * MCache = new MapCache(Maps); DFHack::t_designation des = MCache->designationAt(xy); int16_t tt = MCache->tiletypeAt(xy); int16_t veinmat = MCache->veinMaterialAt(xy); if( veinmat == -1 ) { cerr << "This tile is non-vein. Bye :)" << endl; delete MCache; DF->Detach(); #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } printf("%d/%d/%d tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole); stack <DFHack::DFCoord> flood; flood.push(xy); while( !flood.empty() ) { DFHack::DFCoord current = flood.top(); flood.pop(); int16_t vmat2 = MCache->veinMaterialAt(current); tt = MCache->tiletypeAt(current); if(!DFHack::isWallTerrain(tt)) continue; if(vmat2!=veinmat) continue; // found a good tile, dig+unset material DFHack::t_designation des = MCache->designationAt(current); DFHack::t_designation des_minus; DFHack::t_designation des_plus; des_plus.whole = des_minus.whole = 0; int16_t vmat_minus = -1; int16_t vmat_plus = -1; bool below = 0; bool above = 0; if(updown) { if(MCache->testCoord(current-1)) { below = 1; des_minus = MCache->designationAt(current-1); vmat_minus = MCache->veinMaterialAt(current-1); } if(MCache->testCoord(current+1)) { above = 1; des_plus = MCache->designationAt(current+1); vmat_plus = MCache->veinMaterialAt(current+1); } } if(MCache->testCoord(current)) { MCache->clearMaterialAt(current); if(current.x < tx_max - 2) { flood.push(DFHack::DFCoord(current.x + 1, current.y, current.z)); if(current.y < ty_max - 2) { flood.push(DFHack::DFCoord(current.x + 1, current.y + 1,current.z)); flood.push(DFHack::DFCoord(current.x, current.y + 1,current.z)); } if(current.y > 1) { flood.push(DFHack::DFCoord(current.x + 1, current.y - 1,current.z)); flood.push(DFHack::DFCoord(current.x, current.y - 1,current.z)); } } if(current.x > 1) { flood.push(DFHack::DFCoord(current.x - 1, current.y,current.z)); if(current.y < ty_max - 2) { flood.push(DFHack::DFCoord(current.x - 1, current.y + 1,current.z)); flood.push(DFHack::DFCoord(current.x, current.y + 1,current.z)); } if(current.y > 1) { flood.push(DFHack::DFCoord(current.x - 1, current.y - 1,current.z)); flood.push(DFHack::DFCoord(current.x, current.y - 1,current.z)); } } if(updown) { if(current.z > 0 && below && vmat_minus == vmat2) { flood.push(current-1); if(des_minus.bits.dig == DFHack::designation_d_stair) des_minus.bits.dig = DFHack::designation_ud_stair; else des_minus.bits.dig = DFHack::designation_u_stair; MCache->setDesignationAt(current-1,des_minus); des.bits.dig = DFHack::designation_d_stair; } if(current.z < z_max - 1 && above && vmat_plus == vmat2) { flood.push(current+ 1); if(des_plus.bits.dig == DFHack::designation_u_stair) des_plus.bits.dig = DFHack::designation_ud_stair; else des_plus.bits.dig = DFHack::designation_d_stair; MCache->setDesignationAt(current+1,des_plus); if(des.bits.dig == DFHack::designation_d_stair) des.bits.dig = DFHack::designation_ud_stair; else des.bits.dig = DFHack::designation_u_stair; } } if(des.bits.dig == DFHack::designation_no) des.bits.dig = DFHack::designation_default; MCache->setDesignationAt(current,des); } } MCache->WriteAll(); delete MCache; DF->Detach(); #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; cin.ignore(); #endif return 0; }
//Helper function for writing new functions that check every tile on the map. //newTraffic is the traffic designation to set. //check takes a coordinate and the map cache as arguments, and returns true if the criteria is met. //minCoord and maxCoord can be used to specify a bounding cube. DFhackCExport command_result setAllMatching(DFHack::Core * c, checkTile checkProc, DFHack::DFCoord minCoord, DFHack::DFCoord maxCoord) { //Initialization. c->Suspend(); DFHack::Maps * Maps = c->getMaps(); DFHack::Gui * Gui = c->getGui(); // init the map if(!Maps->Start()) { c->con.printerr("Can't init map. Make sure you have a map loaded in DF.\n"); c->Resume(); return CR_FAILURE; } //Maximum map size. uint32_t x_max,y_max,z_max; Maps->getSize(x_max,y_max,z_max); uint32_t tx_max = x_max * 16; uint32_t ty_max = y_max * 16; //Ensure maximum coordinate is within map. Truncate to map edge. maxCoord.x = std::min((uint32_t) maxCoord.x, tx_max); maxCoord.y = std::min((uint32_t) maxCoord.y, ty_max); maxCoord.z = std::min(maxCoord.z, z_max); //Check minimum co-ordinates against maximum map size if (minCoord.x > maxCoord.x) { c->con.printerr("Minimum x coordinate is greater than maximum x coordinate.\n"); c->Resume(); return CR_FAILURE; } if (minCoord.y > maxCoord.y) { c->con.printerr("Minimum y coordinate is greater than maximum y coordinate.\n"); c->Resume(); return CR_FAILURE; } if (minCoord.z > maxCoord.y) { c->con.printerr("Minimum z coordinate is greater than maximum z coordinate.\n"); c->Resume(); return CR_FAILURE; } MapExtras::MapCache * MCache = new MapExtras::MapCache(Maps); c->con.print("Setting traffic...\n"); //Loop through every single tile for(uint32_t x = minCoord.x; x <= maxCoord.x; x++) { for(uint32_t y = minCoord.y; y <= maxCoord.y; y++) { for(uint32_t z = minCoord.z; z <= maxCoord.z; z++) { DFHack::DFCoord tile = DFHack::DFCoord(x, y, z); checkProc(tile, MCache); } } } MCache->WriteAll(); c->con.print("Complete!\n"); c->Resume(); return CR_OK; }
command_result df_tiles (Core * c, vector <string> & parameters) { int32_t x,y,z; uint32_t x_max,y_max,z_max; DFHack::Maps * Maps; DFHack::Gui * Position; Brush * brush = new RectangleBrush(1,1); Maps = c->getMaps(); Maps->Start(); Maps->getSize(x_max,y_max,z_max); Position = c->getGui(); string command = ""; if(command=="help" || command == "?") { c->con.print ( "Usage: This command sets the properties of the tile painter brush\n" " It is best used from the console, or as an alias bound to a hotkey\n" " After setting the brush\n" "\n" "Modes:\n" "none - nothing, the default" "magma [0-7] - magma, accepts depth\n" "water [0-7] - water\n" "obsidian - obsidian wall\n" "obsfloor - obsidian floors\n" "obsramp - obsidian ramp (forces 1 z-level brush)\n" "riversource - an endless source of water (floor tile)\n" "type ### - plain tiletype painter. For a list of tile types see:\n" " http://df.magmawiki.com/index.php/DF2010:Tile_types_in_DF_memory\n" "\n" "Set-Modes (only for magma/water):\n" "add - set liquid level everywhere\n" "keep - set liquid level only where liquids are already present\n" "\n" "Brush:\n" "point - single tile [p]\n" "#x#[x#] - block with cursor at bottom north-west [r]\n" " (any place, any size)\n" " Example:" " 3x3x2 = rectangle 3x3 x2 z-levels\n" " The z-level part is optional - ommiting it is\n" " the same as setting it to 1.\n" "h#x#[x#] - Same as previous, only the rectangle is 'hollow'.\n" "block - DF map block with cursor in it\n" " (regular spaced 16x16x1 blocks)\n" "column - Column from cursor, up through free space\n" "line - A line between two points.\n" "circle [#] - A filled circle, optional # specifies radius in tiles.\n" "hcircle [#,#] - A hollow circle (ring). First # specifies radius\n" " second # ring thickness in tiles.\n" "\n" "Other:\n" "help or ? - print this list of commands\n" "paint - same effect as if you also the 'paint' command at the same time.\n" "\n" ); } else if(command == "m") { mode = "magma"; } else if(command == "o") { mode = "obsidian"; } else if(command == "of") { mode = "obsidian_floor"; } else if(command == "w") { mode = "water"; } else if(command == "f") { mode = "flowbits"; } else if(command == "rs") { mode = "riversource"; } else if(command == "point" || command == "p") { delete brush; brushname = "point"; brush = new RectangleBrush(1,1); } else if(command == "range" || command == "r") { cout << " :set range width<" << width << "># "; getline(cin, command); width = command == "" ? width : atoi (command.c_str()); if(width < 1) width = 1; cout << " :set range height<" << height << "># "; getline(cin, command); height = command == "" ? height : atoi (command.c_str()); if(height < 1) height = 1; cout << " :set range z-levels<" << z_levels << "># "; getline(cin, command); z_levels = command == "" ? z_levels : atoi (command.c_str()); if(z_levels < 1) z_levels = 1; delete brush; if(width == 1 && height == 1 && z_levels == 1) { brushname="point"; } else { brushname = "range"; } brush = new RectangleBrush(width,height,z_levels,0,0,0); } else if(command == "block") { delete brush; brushname = "block"; brush = new BlockBrush(); } else if(command == "column") { delete brush; brushname = "column"; brush = new ColumnBrush(); } else if(command == "q") { end = true; } else if(command == "f+") { flowmode = "f+"; } else if(command == "f-") { flowmode = "f-"; } else if(command == "f.") { flowmode = "f."; } else if(command == "s+") { setmode = "s+"; } else if(command == "s-") { setmode = "s-"; } else if(command == "s.") { setmode = "s."; } // blah blah, bad code, bite me. else if(command == "0") amount = 0; else if(command == "1") amount = 1; else if(command == "2") amount = 2; else if(command == "3") amount = 3; else if(command == "4") amount = 4; else if(command == "5") amount = 5; else if(command == "6") amount = 6; else if(command == "7") amount = 7; else if(command.empty()) { DF->Suspend(); do { if(!Maps->Start()) { cout << "Can't see any DF map loaded." << endl; break; } if(!Position->getCursorCoords(x,y,z)) { cout << "Can't get cursor coords! Make sure you have a cursor active in DF." << endl; break; } cout << "cursor coords: " << x << "/" << y << "/" << z << endl; MapCache mcache(Maps); DFHack::DFCoord cursor(x,y,z); coord_vec all_tiles = brush->points(mcache,cursor); cout << "working..." << endl; if(mode == "obsidian") { coord_vec::iterator iter = all_tiles.begin(); while (iter != all_tiles.end()) { mcache.setTiletypeAt(*iter, 331); mcache.setTemp1At(*iter,10015); mcache.setTemp2At(*iter,10015); DFHack::t_designation des = mcache.designationAt(*iter); des.bits.flow_size = 0; mcache.setDesignationAt(*iter, des); iter ++; } } if(mode == "obsidian_floor") { coord_vec::iterator iter = all_tiles.begin(); while (iter != all_tiles.end()) { mcache.setTiletypeAt(*iter, 340); iter ++; } } else if(mode == "riversource") { set <Block *> seen_blocks; coord_vec::iterator iter = all_tiles.begin(); while (iter != all_tiles.end()) { mcache.setTiletypeAt(*iter, 90); DFHack::t_designation a = mcache.designationAt(*iter); a.bits.liquid_type = DFHack::liquid_water; a.bits.liquid_static = false; a.bits.flow_size = 7; mcache.setTemp1At(*iter,10015); mcache.setTemp2At(*iter,10015); mcache.setDesignationAt(*iter,a); Block * b = mcache.BlockAt((*iter)/16); DFHack::t_blockflags bf = b->BlockFlags(); bf.bits.liquid_1 = true; bf.bits.liquid_2 = true; b->setBlockFlags(bf); iter++; } } else if(mode== "magma" || mode== "water" || mode == "flowbits") { set <Block *> seen_blocks; coord_vec::iterator iter = all_tiles.begin(); while (iter != all_tiles.end()) { DFHack::DFCoord current = *iter; DFHack::t_designation des = mcache.designationAt(current); uint16_t tt = mcache.tiletypeAt(current); DFHack::naked_designation & flow = des.bits; // don't put liquids into places where they don't belong... if(!DFHack::FlowPassable(tt)) { iter++; continue; } if(mode != "flowbits") { if(setmode == "s.") { flow.flow_size = amount; } else if(setmode == "s+") { if(flow.flow_size < amount) flow.flow_size = amount; } else if(setmode == "s-") { if (flow.flow_size > amount) flow.flow_size = amount; } if(amount != 0 && mode == "magma") { flow.liquid_type = DFHack::liquid_magma; mcache.setTemp1At(current,12000); mcache.setTemp2At(current,12000); } else if(amount != 0 && mode == "water") { flow.liquid_type = DFHack::liquid_water; mcache.setTemp1At(current,10015); mcache.setTemp2At(current,10015); } else if(amount == 0 && (mode == "water" || mode == "magma")) { // reset temperature to sane default mcache.setTemp1At(current,10015); mcache.setTemp2At(current,10015); } mcache.setDesignationAt(current,des); } seen_blocks.insert(mcache.BlockAt((*iter) / 16)); iter++; } set <Block *>::iterator biter = seen_blocks.begin(); while (biter != seen_blocks.end()) { DFHack::t_blockflags bflags = (*biter)->BlockFlags(); if(flowmode == "f+") { bflags.bits.liquid_1 = true; bflags.bits.liquid_2 = true; (*biter)->setBlockFlags(bflags); } else if(flowmode == "f-") { bflags.bits.liquid_1 = false; bflags.bits.liquid_2 = false; (*biter)->setBlockFlags(bflags); } else { cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl; cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl; } biter ++; } } if(mcache.WriteAll()) cout << "OK" << endl; else cout << "Something failed horribly! RUN!" << endl; Maps->Finish(); } while (0); } else { cout << command << " : unknown command." << endl; } return CR_OK; }
DFhackCExport command_result df_liquids (Core * c, vector <string> & parameters) { int32_t x,y,z; uint32_t x_max,y_max,z_max; DFHack::Maps * Maps; DFHack::Gui * Position; for(int i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") { c->con.print("This tool allows placing magma, water and other similar things.\n" "It is interactive and further help is available when you run it.\n" ); return CR_OK; } } Brush * brush = new RectangleBrush(1,1); string brushname = "point"; bool end = false; c->con << "Welcome to the liquid spawner.\nType 'help' or '?' for a list of available commands, 'q' to quit.\nPress return after a command to confirm." << std::endl; string mode="magma"; string flowmode="f+"; string setmode ="s."; unsigned int amount = 7; int width = 1, height = 1, z_levels = 1; while(!end) { string command = ""; std::stringstream str; str <<"[" << mode << ":" << brushname << ":" << amount << ":" << flowmode << ":" << setmode << "]#"; if(c->con.lineedit(str.str(),command,liquids_hist) == -1) return CR_FAILURE; if(command=="help" || command == "?") { c->con << "Modes:" << endl << "m - switch to magma" << endl << "w - switch to water" << endl << "o - make obsidian wall instead" << endl << "of - make obsidian floors" << endl << "rs - make a river source" << endl << "f - flow bits only" << endl << "Set-Modes (only for magma/water):" << endl << "s+ - only add" << endl << "s. - set" << endl << "s- - only remove" << endl << "Properties (only for magma/water):" << endl << "f+ - make the spawned liquid flow" << endl << "f. - don't change flow state (read state in flow mode)" << endl << "f- - make the spawned liquid static" << endl << "0-7 - set liquid amount" << endl << "Brush:" << endl << "point - single tile [p]" << endl << "range - block with cursor at bottom north-west [r]" << endl << " (any place, any size)" << endl << "block - DF map block with cursor in it" << endl << " (regular spaced 16x16x1 blocks)" << endl << "column - Column from cursor, up through free space" << endl << "Other:" << endl << "q - quit" << endl << "help or ? - print this list of commands" << endl << "empty line - put liquid" << endl << endl << "Usage: point the DF cursor at a tile you want to modify" << endl << "and use the commands available :)" << endl; } else if(command == "m") { mode = "magma"; } else if(command == "o") { mode = "obsidian"; } else if(command == "of") { mode = "obsidian_floor"; } else if(command == "w") { mode = "water"; } else if(command == "f") { mode = "flowbits"; } else if(command == "rs") { mode = "riversource"; } else if(command == "point" || command == "p") { delete brush; brushname = "point"; brush = new RectangleBrush(1,1); } else if(command == "range" || command == "r") { std::stringstream str; CommandHistory range_hist; str << " :set range width<" << width << "># "; c->con.lineedit(str.str(),command,range_hist); range_hist.add(command); width = command == "" ? width : atoi (command.c_str()); if(width < 1) width = 1; str.str(""); str << " :set range height<" << height << "># "; c->con.lineedit(str.str(),command,range_hist); range_hist.add(command); height = command == "" ? height : atoi (command.c_str()); if(height < 1) height = 1; str.str(""); str << " :set range z-levels<" << z_levels << "># "; c->con.lineedit(str.str(),command,range_hist); range_hist.add(command); z_levels = command == "" ? z_levels : atoi (command.c_str()); if(z_levels < 1) z_levels = 1; delete brush; if(width == 1 && height == 1 && z_levels == 1) { brushname="point"; } else { brushname = "range"; } brush = new RectangleBrush(width,height,z_levels,0,0,0); } else if(command == "block") { delete brush; brushname = "block"; brush = new BlockBrush(); } else if(command == "column") { delete brush; brushname = "column"; brush = new ColumnBrush(); } else if(command == "q") { end = true; } else if(command == "f+") { flowmode = "f+"; } else if(command == "f-") { flowmode = "f-"; } else if(command == "f.") { flowmode = "f."; } else if(command == "s+") { setmode = "s+"; } else if(command == "s-") { setmode = "s-"; } else if(command == "s.") { setmode = "s."; } // blah blah, bad code, bite me. else if(command == "0") amount = 0; else if(command == "1") amount = 1; else if(command == "2") amount = 2; else if(command == "3") amount = 3; else if(command == "4") amount = 4; else if(command == "5") amount = 5; else if(command == "6") amount = 6; else if(command == "7") amount = 7; else if(command.empty()) { c->Suspend(); Maps = c->getMaps(); Maps->Start(); Maps->getSize(x_max,y_max,z_max); Position = c->getGui(); do { if(!Maps->Start()) { c->con << "Can't see any DF map loaded." << endl; break; } if(!Position->getCursorCoords(x,y,z)) { c->con << "Can't get cursor coords! Make sure you have a cursor active in DF." << endl; break; } c->con << "cursor coords: " << x << "/" << y << "/" << z << endl; MapCache mcache(Maps); DFHack::DFCoord cursor(x,y,z); coord_vec all_tiles = brush->points(mcache,cursor); c->con << "working..." << endl; if(mode == "obsidian") { coord_vec::iterator iter = all_tiles.begin(); while (iter != all_tiles.end()) { mcache.setTiletypeAt(*iter, 331); mcache.setTemp1At(*iter,10015); mcache.setTemp2At(*iter,10015); DFHack::t_designation des = mcache.designationAt(*iter); des.bits.flow_size = 0; mcache.setDesignationAt(*iter, des); iter ++; } } if(mode == "obsidian_floor") { coord_vec::iterator iter = all_tiles.begin(); while (iter != all_tiles.end()) { mcache.setTiletypeAt(*iter, 340); iter ++; } } else if(mode == "riversource") { set <Block *> seen_blocks; coord_vec::iterator iter = all_tiles.begin(); while (iter != all_tiles.end()) { mcache.setTiletypeAt(*iter, 90); DFHack::t_designation a = mcache.designationAt(*iter); a.bits.liquid_type = DFHack::liquid_water; a.bits.liquid_static = false; a.bits.flow_size = 7; mcache.setTemp1At(*iter,10015); mcache.setTemp2At(*iter,10015); mcache.setDesignationAt(*iter,a); Block * b = mcache.BlockAt((*iter)/16); DFHack::t_blockflags bf = b->BlockFlags(); bf.bits.liquid_1 = true; bf.bits.liquid_2 = true; b->setBlockFlags(bf); iter++; } } else if(mode== "magma" || mode== "water" || mode == "flowbits") { set <Block *> seen_blocks; coord_vec::iterator iter = all_tiles.begin(); while (iter != all_tiles.end()) { DFHack::DFCoord current = *iter; DFHack::t_designation des = mcache.designationAt(current); uint16_t tt = mcache.tiletypeAt(current); DFHack::naked_designation & flow = des.bits; // don't put liquids into places where they don't belong... if(!DFHack::FlowPassable(tt)) { iter++; continue; } if(mode != "flowbits") { if(setmode == "s.") { flow.flow_size = amount; } else if(setmode == "s+") { if(flow.flow_size < amount) flow.flow_size = amount; } else if(setmode == "s-") { if (flow.flow_size > amount) flow.flow_size = amount; } if(amount != 0 && mode == "magma") { flow.liquid_type = DFHack::liquid_magma; mcache.setTemp1At(current,12000); mcache.setTemp2At(current,12000); } else if(amount != 0 && mode == "water") { flow.liquid_type = DFHack::liquid_water; mcache.setTemp1At(current,10015); mcache.setTemp2At(current,10015); } else if(amount == 0 && (mode == "water" || mode == "magma")) { // reset temperature to sane default mcache.setTemp1At(current,10015); mcache.setTemp2At(current,10015); } mcache.setDesignationAt(current,des); } seen_blocks.insert(mcache.BlockAt((*iter) / 16)); iter++; } set <Block *>::iterator biter = seen_blocks.begin(); while (biter != seen_blocks.end()) { DFHack::t_blockflags bflags = (*biter)->BlockFlags(); if(flowmode == "f+") { bflags.bits.liquid_1 = true; bflags.bits.liquid_2 = true; (*biter)->setBlockFlags(bflags); } else if(flowmode == "f-") { bflags.bits.liquid_1 = false; bflags.bits.liquid_2 = false; (*biter)->setBlockFlags(bflags); } else { c->con << "flow bit 1 = " << bflags.bits.liquid_1 << endl; c->con << "flow bit 2 = " << bflags.bits.liquid_2 << endl; } biter ++; } } if(mcache.WriteAll()) c->con << "OK" << endl; else c->con << "Something failed horribly! RUN!" << endl; Maps->Finish(); } while (0); c->Resume(); } else { c->con << command << " : unknown command." << endl; } } return CR_OK; }
int main (void) { int32_t x,y,z,tx,ty; //DFHack::designations40d designations; DFHack::tiletypes40d tiles; //DFHack::t_temperatures temp1,temp2; uint32_t x_max,y_max,z_max; int32_t oldT, newT; int count, dirty; //Brush defaults DFHack::TileShape BrushClass = DFHack::WALL; DFHack::TileMaterial BrushMat = DFHack::tilematerial_invalid; int BrushType = -1; DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF; DFHack::Maps * Maps; DFHack::Gui * Gui; try { DF=DFMgr.getSingleContext(); DF->Attach(); Maps = DF->getMaps(); Maps->Start(); Maps->getSize(x_max,y_max,z_max); Gui = DF->getGui(); } catch (exception& e) { cerr << e.what() << endl; #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } bool end = false; cout << "Welcome to the Tile Drawing tool.\nType 'help' or ? for a list of available commands, 'q' to quit" << endl; string mode = "wall"; string command = ""; while(!end) { DF->Resume(); cout << endl << ":"; getline(cin, command); int ch = command[0]; if(command.length()<=0) ch=0; if( ((int)command.find("help")) >=0 ) ch='?'; //under windows, find was casting unsigned! switch(ch) { case '?': cout << "Modes:" << endl << "O - draw Open Space" << endl << "M - draw material only (shape unchanged)" << endl << "m number - use Material value entered" << endl << "r - use Rock/stone material" << endl << "l - use Soil material" << endl << "v - use Vein material" << endl << "H - draw tile shape only (material unchanged)" << endl << "h number - draw Tile Shape value entered" << endl << "w - draw Wall tiles" << endl << "f - draw Floor tiles" << endl << "t number - draw exact tile type entered" << endl << "Commands:" << endl << "p - print tile shapes and materials, and current brush" << endl << "P - print all tile types" << endl << "q - quit" << endl << "help OR ? - print this list of commands" << endl << "d - being drawing" << endl << endl << "Usage:\nChoose a mode (default is walls), then enter 'd' to being drawing.\nMove the cursor in DF wherever you want to draw.\nPress any key to pause drawing." << endl; break; case 'p': //Classes printf("\nTile Type Classes:\n"); for(int i=0;i<DFHack::tileshape_count;++i) { printf("%4i ; %s\n", i, DFHack::TileShapeString[i] ,0 ); } //Materials printf("\nTile Type Materials:\n"); for(int i=0;i<DFHack::tilematerial_count;++i) { printf("%4i ; %s\n", i, DFHack::TileMaterialString[i] ,0 ); } //fall through... case 10: case 13: case 0: //Print current cursor & brush settings. cout << "\nCurrent Brush:\n"; cout << "tile = "; if(BrushClass<0) cout<<"(not drawing)"; else cout<<DFHack::TileShapeString[BrushClass]; cout << endl; cout << "mat = "; if(BrushMat<0) cout<<"(not drawing)"; else cout<<DFHack::TileMaterialString[BrushMat]; cout << endl; cout << "type = "; if(BrushType<0){ cout<<"(not drawing)"; }else{ printtiletype(BrushType); } break; case 'P': cout << "\nAll Valid Tile Types:\n"; for(int i=0;i<TILE_TYPE_ARRAY_LENGTH;++i) { if( DFHack::tileTypeTable[i].name ) printtiletype(i); } case 'w': BrushType=-1; BrushClass = DFHack::WALL; cout << "Tile brush shape set to Wall." << endl; break; case 'f': BrushType=-1; BrushClass = DFHack::FLOOR; cout << "Tile brush shape set to Floor." << endl; break; case 'h': BrushType=-1; BrushClass = (DFHack::TileShape)atol( command.c_str()+1 ); cout << "Tile brush shape set to " << BrushClass << endl; break; case 'M': BrushClass = DFHack::tileshape_invalid; cout << "Tile brush will not draw tile shape." << endl; break; case 'r': BrushType=-1; BrushMat = DFHack::STONE; cout << "Tile brush material set to Rock." << endl; break; case 'l': BrushType=-1; BrushMat = DFHack::SOIL; cout << "Tile brush material set to Soil." << endl; break; case 'v': BrushType=-1; BrushMat = DFHack::VEIN; cout << "Tile brush material set to Vein." << endl; break; case 'm': BrushType=-1; BrushMat = (DFHack::TileMaterial)atol( command.c_str()+1 ); cout << "Tile brush material set to " << BrushMat << endl; break; case 'H': BrushMat = DFHack::tilematerial_invalid; cout << "Tile brush will not draw material." << endl; break; case 'O': BrushType=-1; BrushClass = DFHack::EMPTY; BrushMat = DFHack::AIR; cout << "Tile brush will draw Open Space." << endl; break; case 't': BrushClass = DFHack::tileshape_invalid ; BrushMat = DFHack::tilematerial_invalid; BrushType = atol( command.c_str()+1 ); cout << "Tile brush type set to:" << endl; printtiletype(BrushType); break; case 'q': end = true; cout << "Bye!" << endl; break; case 'd': { count=0; cout << "Beginning to draw at cursor." << endl << "Press any key to stop drawing." << endl; //DF->Suspend(); kbhit(); //throw away, just to be sure. for(;;) { if(!Maps->Start()) { cout << "Can't see any DF map loaded." << endl; break; } if(!Gui->getCursorCoords(x,y,z)) { cout << "Can't get cursor coords! Make sure you have a cursor active in DF." << endl; break; } //cout << "cursor coords: " << x << "/" << y << "/" << z << endl; tx=x%16; ty=y%16; if(!Maps->isValidBlock(x/16,y/16,z)) { cout << "Invalid block." << endl; break; } //Read the tiles. dirty=0; Maps->ReadTileTypes((x/16),(y/16),z, &tiles); oldT = tiles[tx][ty]; newT = -1; if( 0<BrushType ){ //Explicit tile type set. Trust the user. newT = BrushType; }else if( 0==BrushMat && 0==BrushClass ){ //Special case, Empty Air. newT = 32; }else if( BrushMat>=0 && BrushClass>=0 && ( BrushClass != DFHack::tileTypeTable[oldT].shape || BrushMat != DFHack::tileTypeTable[oldT].material) ){ //Set tile material and class newT = DFHack::findTileType(BrushClass,BrushMat, DFHack::tileTypeTable[oldT].variant , DFHack::tileTypeTable[oldT].special , DFHack::tileTypeTable[oldT].direction ); if(newT<0) newT = DFHack::findTileType(BrushClass,BrushMat, DFHack::tilevariant_invalid, DFHack::tileTypeTable[oldT].special , DFHack::tileTypeTable[oldT].direction ); if(newT<0) newT = DFHack::findTileType(BrushClass,BrushMat, DFHack::tilevariant_invalid , DFHack::tileTypeTable[oldT].special , (uint32_t)0 ); }else if( BrushMat<0 && BrushClass>=0 && BrushClass != DFHack::tileTypeTable[oldT].shape ){ //Set current tile class only, as accurately as can be expected newT = DFHack::findSimilarTileType(oldT,BrushClass); }else if( BrushClass<0 && BrushMat>=0 && BrushMat != DFHack::tileTypeTable[oldT].material ){ //Set current tile material only newT = DFHack::findTileType(DFHack::tileTypeTable[oldT].shape,BrushMat, DFHack::tileTypeTable[oldT].variant , DFHack::tileTypeTable[oldT].special , DFHack::tileTypeTable[oldT].direction ); if(newT<0) newT = DFHack::findTileType(DFHack::tileTypeTable[oldT].shape,BrushMat, DFHack::tilevariant_invalid , DFHack::tileTypeTable[oldT].special , DFHack::tileTypeTable[oldT].direction ); if(newT<0) newT = DFHack::findTileType(DFHack::tileTypeTable[oldT].shape,BrushMat, DFHack::tilevariant_invalid , DFHack::tileTypeTable[oldT].special , (uint32_t)0 ); } //If no change, skip it (couldn't find a good tile type, or already what we want) if ( newT > 0 && oldT != newT ){ //Set new tile type tiles[tx][ty] = newT; dirty=-1; } //If anything was changed, write it all. if (dirty) { //Maps->WriteDesignations(x/16,y/16,z/16, &designations); Maps->WriteTileTypes(x/16,y/16,z, &tiles); printf("(%4d,%4d,%4d)",x,y,z); ++count; } Maps->Finish(); Sleep(10); if( kbhit() ) break; } cin.clear(); cout << endl << count << " tiles were drawn." << endl << "Drawing halted. Entering command mode." << endl; } continue; break; default: cout << "Unknown command: " << command << endl; } } DF->Detach(); #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; cin.ignore(); #endif return 0; }
/** * Book of Immolations, chapter 1, verse 35: * Armok emerged from the hellish depths and beheld the sunny realms for the first time. * And he cursed the plants and trees for their bloodless wood, turning them into ash and smoldering ruin. * Armok was pleased and great temples were built by the dwarves, for they shared his hatred for trees and plants. */ static command_result immolations (Core * c, do_what what, bool shrubs, bool trees, bool help) { static const char * what1 = "destroys"; static const char * what2 = "burns"; if(help) { c->con.print("Without any options, this command %s a plant under the cursor.\n" "Options:\n" "shrubs - affect all shrubs\n" "trees - affect all trees\n" "all - affect all plants\n", what == do_immolate? what2 : what1 ); return CR_OK; } c->Suspend(); DFHack::Maps *maps = c->getMaps(); if (!maps->Start()) { c->con.printerr( "Cannot get map info!\n"); c->Resume(); return CR_FAILURE; } DFHack::Gui * Gui = c->getGui(); uint32_t x_max, y_max, z_max; maps->getSize(x_max, y_max, z_max); MapExtras::MapCache map(maps); DFHack::Vegetation *veg = c->getVegetation(); if (!veg->all_plants) { std::cerr << "Unable to read vegetation!" << std::endl; return CR_FAILURE; } if(shrubs || trees) { int destroyed = 0; for(size_t i = 0 ; i < veg->all_plants->size(); i++) { DFHack::df_plant *p = veg->all_plants->at(i); if(shrubs && p->is_shrub || trees && !p->is_shrub) { if (what == do_immolate) p->is_burning = true; p->hitpoints = 0; destroyed ++; } } c->con.print("Praise Armok!\n"); } else { int32_t x,y,z; if(Gui->getCursorCoords(x,y,z)) { vector<DFHack::df_plant *> * alltrees; if(maps->ReadVegetation(x/16,y/16,z,alltrees)) { bool didit = false; for(size_t i = 0 ; i < alltrees->size(); i++) { DFHack::df_plant * tree = alltrees->at(i); if(tree->x == x && tree->y == y && tree->z == z) { if(what == do_immolate) tree->is_burning = true; tree->hitpoints = 0; didit = true; break; } } /* if(!didit) { cout << "----==== There's NOTHING there! ====----" << endl; } */ } } else { c->con.printerr("No mass destruction and no cursor...\n" ); } } // Cleanup veg->Finish(); maps->Finish(); c->Resume(); return CR_OK; }
int main(int argc, char *argv[]) { /* initialize your non-curses data structures here */ signal(SIGINT, finish); /* arrange interrupts to terminate */ setlocale(LC_ALL,""); initscr(); /* initialize the curses library */ keypad(stdscr, TRUE); /* enable keyboard mapping */ nonl(); /* tell curses not to do NL->CR/NL on output */ cbreak(); /* take input chars one at a time, no wait for \n */ noecho(); /* don't echo input */ //nodelay(stdscr, true); keypad(stdscr, TRUE); scrollok(stdscr, TRUE); if (has_colors()) { start_color(); /* * Simple color assignment, often all we need. */ init_pair(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK); init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK); init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK); init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK); init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK); init_color(COLOR_CYAN, 700, 700, 700); // lt grey init_color(COLOR_MAGENTA, 500, 500, 500); // dk grey init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK); init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK); init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK); } int x_max,y_max,z_max; uint32_t x_max_a,y_max_a,z_max_a; /* uint16_t tiletypes[16][16]; DFHack::t_designation designations[16][16]; uint8_t regionoffsets[16]; */ map <int16_t, uint32_t> materials; materials.clear(); mapblock40d blocks[3][3]; vector<DFHack::t_effect_df40d> effects; vector< vector <uint16_t> > layerassign; vector<t_vein> veinVector; vector<t_frozenliquidvein> IceVeinVector; vector<t_spattervein> splatter; vector<t_grassvein> grass; vector<t_worldconstruction> wconstructs; t_temperatures b_temp1; t_temperatures b_temp2; DFHack::Materials * Mats = 0; DFHack::Maps * Maps = 0; DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context* DF; try { pDF = DF = DFMgr.getSingleContext(); DF->Attach(); Maps = DF->getMaps(); } catch (exception& e) { cerr << e.what() << endl; #ifndef LINUX_BUILD cin.ignore(); #endif finish(0); } bool hasmats = true; try { Mats = DF->getMaterials(); } catch (exception& e) { hasmats = false; } // init the map if(!Maps->Start()) { error = "Can't find a map to look at."; finish(0); } Maps->getSize(x_max_a,y_max_a,z_max_a); x_max = x_max_a; y_max = y_max_a; z_max = z_max_a; bool hasInorgMats = false; bool hasPlantMats = false; bool hasCreatureMats = false; if(hasmats) { // get stone matgloss mapping if(Mats->ReadInorganicMaterials()) { hasInorgMats = true; } if(Mats->ReadCreatureTypes()) { hasCreatureMats = true; } if(Mats->ReadOrganicMaterials()) { hasPlantMats = true; } } /* // get region geology if(!DF.ReadGeology( layerassign )) { error = "Can't read local geology."; pDF = 0; finish(0); } */ // FIXME: could fail on small forts int cursorX = x_max/2 - 1; int cursorY = y_max/2 - 1; int cursorZ = z_max/2 - 1; bool dig = false; bool dump = false; bool digbit = false; bool dotwiddle; unsigned char twiddle = 0; int vein = 0; int filenum = 0; bool dirtybit = false; uint32_t blockaddr = 0; uint32_t blockaddr2 = 0; t_blockflags bflags; bflags.whole = 0; enum e_tempmode { TEMP_NO, TEMP_1, TEMP_2, WATER_SALT, WATER_STAGNANT }; e_tempmode temperature = TEMP_NO; // resume so we don't block DF while we wait for input DF->Resume(); for (;;) { dig = false; dump = false; dotwiddle = false; digbit = false; int c = getch(); /* refresh, accept single keystroke of input */ flushinp(); clrscr(); /* process the command keystroke */ switch(c) { case KEY_DOWN: cursorY ++; break; case KEY_UP: cursorY --; break; case KEY_LEFT: cursorX --; break; case KEY_RIGHT: cursorX ++; break; case KEY_NPAGE: cursorZ --; break; case KEY_PPAGE: cursorZ ++; break; case '+': vein ++; break; case 'd': dig = true; break; case 'o': dump = true; break; case '-': vein --; break; case 'z': digbit = true; break; case '/': if(twiddle != 0) twiddle--; break; case '*': twiddle++; break; case 't': dotwiddle = true; break; case 'b': temperature = TEMP_NO; break; case 'n': temperature = TEMP_1; break; case 'm': temperature = TEMP_2; break; case 'c': temperature = WATER_SALT; break; case 'v': temperature = WATER_STAGNANT; break; case 27: // escape key DF->Detach(); return 0; break; default: break; } cursorX = max(cursorX, 0); cursorY = max(cursorY, 0); cursorZ = max(cursorZ, 0); cursorX = min(cursorX, x_max - 1); cursorY = min(cursorY, y_max - 1); cursorZ = min(cursorZ, z_max - 1); if(twiddle > 31) twiddle = 31; // clear data before we suspend memset(blocks,0,sizeof(blocks)); veinVector.clear(); IceVeinVector.clear(); effects.clear(); splatter.clear(); grass.clear(); dirtybit = 0; // Supend, read/write data DF->Suspend(); // restart cleared modules Maps->Start(); if(hasmats) { Mats->Start(); if(hasInorgMats) { Mats->ReadInorganicMaterials(); } if(hasPlantMats) { Mats->ReadOrganicMaterials(); } if(hasCreatureMats) { Mats->ReadCreatureTypes(); } } /* if(DF.InitReadEffects(effectnum)) { for(uint32_t i = 0; i < effectnum;i++) { t_effect_df40d effect; DF.ReadEffect(i,effect); effects.push_back(effect); } } */ for(int i = -1; i <= 1; i++) for(int j = -1; j <= 1; j++) { mapblock40d * Block = &blocks[i+1][j+1]; if(Maps->isValidBlock(cursorX+i,cursorY+j,cursorZ)) { Maps->ReadBlock40d(cursorX+i,cursorY+j,cursorZ, Block); // extra processing of the block in the middle if(i == 0 && j == 0) { if(hasInorgMats) do_features(DF, Block, cursorX, cursorY, 50,10, Mats->inorganic); // read veins Maps->ReadVeins(cursorX+i,cursorY+j,cursorZ,&veinVector,&IceVeinVector,&splatter,&grass, &wconstructs); // get pointer to block blockaddr = Maps->getBlockPtr(cursorX+i,cursorY+j,cursorZ); blockaddr2 = Block->origin; // dig all veins and trees if(dig) { for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++) { int16_t tiletype = Block->tiletypes[x][y]; TileShape tc = tileShape(tiletype); TileMaterial tm = tileMaterial(tiletype); if( tc == WALL && tm == VEIN || tc == TREE_OK || tc == TREE_DEAD) { Block->designation[x][y].bits.dig = designation_default; } } Maps->WriteDesignations(cursorX+i,cursorY+j,cursorZ, &(Block->designation)); } // read temperature data Maps->ReadTemperatures(cursorX+i,cursorY+j,cursorZ,&b_temp1, &b_temp2 ); if(dotwiddle) { bitset<32> bs = Block->designation[0][0].whole; bs.flip(twiddle); Block->designation[0][0].whole = bs.to_ulong(); Maps->WriteDesignations(cursorX+i,cursorY+j,cursorZ, &(Block->designation)); dotwiddle = false; } // do a dump of the block data if(dump) { hexdump(DF,blockaddr,0x1E00,filenum); filenum++; } // read/write dirty bit of the block Maps->ReadDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit); Maps->ReadBlockFlags(cursorX+i,cursorY+j,cursorZ,bflags); if(digbit) { dirtybit = !dirtybit; Maps->WriteDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit); } } } } // Resume, print stuff to the terminal DF->Resume(); for(int i = -1; i <= 1; i++) for(int j = -1; j <= 1; j++) { mapblock40d * Block = &blocks[i+1][j+1]; for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++) { int color = COLOR_BLACK; color = pickColor(Block->tiletypes[x][y]); /* if(!Block->designation[x][y].bits.hidden) { puttile(x+(i+1)*16,y+(j+1)*16,Block->tiletypes[x][y], color); } else*/ { attron(A_STANDOUT); puttile(x+(i+1)*16,y+(j+1)*16,Block->tiletypes[x][y], color); attroff(A_STANDOUT); } } // print effects for the center tile /* if(i == 0 && j == 0) { for(uint zz = 0; zz < effects.size();zz++) { if(effects[zz].z == cursorZ && !effects[zz].isHidden) { // block coords to tile coords uint16_t x = effects[zz].x - (cursorX * 16); uint16_t y = effects[zz].y - (cursorY * 16); if(x < 16 && y < 16) { putch(x + 16,y + 16,'@',COLOR_WHITE); } } } } */ } gotoxy(50,0); cprintf("arrow keys, PGUP, PGDN = navigate"); gotoxy(50,1); cprintf("+,- = switch vein"); gotoxy(50,2); uint32_t mineralsize = veinVector.size(); uint32_t icesize = IceVeinVector.size(); uint32_t splattersize = splatter.size(); uint32_t grasssize = grass.size(); uint32_t wconstrsize = wconstructs.size(); uint32_t totalVeinSize = mineralsize+ icesize + splattersize + grasssize + wconstrsize; if(vein == totalVeinSize) vein = totalVeinSize - 1; if(vein < -1) vein = -1; cprintf("X %d/%d, Y %d/%d, Z %d/%d. Vein %d of %d",cursorX+1,x_max,cursorY+1,y_max,cursorZ,z_max,vein+1,totalVeinSize); if(!veinVector.empty() || !IceVeinVector.empty() || !splatter.empty() || !grass.empty() || !wconstructs.empty()) { if(vein != -1 && vein < totalVeinSize) { uint32_t realvein = 0; if(vein < mineralsize) { realvein = vein; //iterate through vein rows for(uint32_t j = 0;j<16;j++) { //iterate through the bits for (uint32_t k = 0; k< 16;k++) { // and the bit array with a one-bit mask, check if the bit is set bool set = !!(((1 << k) & veinVector[realvein].assignment[j]) >> k); if(set) { putch(k+16,j+16,'$',COLOR_RED); } } } if(hasInorgMats) { gotoxy(50,3); cprintf("Mineral: %s",Mats->inorganic[veinVector[vein].type].id); } } else if (vein < mineralsize + icesize) { realvein = vein - mineralsize; t_frozenliquidvein &frozen = IceVeinVector[realvein]; for(uint32_t i = 0;i<16;i++) { for (uint32_t j = 0; j< 16;j++) { int color = COLOR_BLACK; int tile = frozen.tiles[i][j]; color = pickColor(tile); attron(A_STANDOUT); puttile(i+16,j+16,tile, color); attroff(A_STANDOUT); } } gotoxy(50,3); cprintf("ICE"); } else if(vein < mineralsize + icesize + splattersize) { realvein = vein - mineralsize - icesize; for(uint32_t yyy = 0; yyy < 16; yyy++) { for(uint32_t xxx = 0; xxx < 16; xxx++) { uint8_t intensity = splatter[realvein].intensity[xxx][yyy]; if(intensity) { attron(A_STANDOUT); putch(xxx+16,yyy+16,'*', COLOR_RED); attroff(A_STANDOUT); } } } if(hasCreatureMats) { gotoxy(50,3); cprintf("Spatter: %s",PrintSplatterType(splatter[realvein].mat1,splatter[realvein].mat2,Mats->race).c_str()); } } else if(vein < mineralsize + icesize + splattersize + grasssize) { realvein = vein - mineralsize - icesize - splattersize; t_grassvein & grassy =grass[realvein]; for(uint32_t yyy = 0; yyy < 16; yyy++) { for(uint32_t xxx = 0; xxx < 16; xxx++) { uint8_t intensity = grassy.intensity[xxx][yyy]; if(intensity) { attron(A_STANDOUT); putch(xxx+16,yyy+16,'X', COLOR_RED); attroff(A_STANDOUT); } } } if(hasPlantMats) { gotoxy(50,3); cprintf("Grass: 0x%x, %s",grassy.address_of, Mats->organic[grassy.material].id); } } else { realvein = vein - mineralsize - icesize - splattersize - grasssize; t_worldconstruction & wconstr=wconstructs[realvein]; for(uint32_t j = 0; j < 16; j++) { for(uint32_t k = 0; k < 16; k++) { bool set = !!(((1 << k) & wconstr.assignment[j]) >> k); if(set) { putch(k+16,j+16,'$',COLOR_RED); } } } if(hasInorgMats) { gotoxy(50,3); cprintf("Road: 0x%x, %d - %s", wconstr.address_of, wconstr.material,Mats->inorganic[wconstr.material].id); } } }
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 tiletraffic(DFHack::Core * c, std::vector<std::string> & params) { //Target traffic types. e_traffic target = traffic_normal; //!!! Options Later !!! //Loop through parameters for(int i = 0; i < params.size();i++) { if(params[i] == "help" || params[i] == "?") { c->con.print("Set traffic types for all tiles on the map.\n" "Traffic Type Codes:\n" " H: High Traffic\n" " N: Normal Traffic\n" " L: Low Traffic\n" " R: Restricted Traffic\n" ); return CR_OK; } switch (toupper(params[i][0])) { case 'H': target = traffic_high; break; case 'N': target = traffic_normal; break; case 'L': target = traffic_low; break; case 'R': target = traffic_restricted; break; } } //Initialization. c->Suspend(); DFHack::Maps * Maps = c->getMaps(); DFHack::Gui * Gui = c->getGui(); // init the map if(!Maps->Start()) { c->con.printerr("Can't init map. Make sure you have a map loaded in DF.\n"); c->Resume(); return CR_FAILURE; } //Maximum map size. uint32_t x_max,y_max,z_max; Maps->getSize(x_max,y_max,z_max); uint32_t tx_max = x_max * 16; uint32_t ty_max = y_max * 16; MapExtras::MapCache * MCache = new MapExtras::MapCache(Maps); c->con.print("Entire map ... FILLING!\n"); //Loop through every single tile for(uint32_t x = 0; x <= tx_max; x++) { for(uint32_t y = 0; y <= ty_max; y++) { for(uint32_t z = 0; z <= z_max; z++) { DFHack::DFCoord tile = DFHack::DFCoord(x, y, z); DFHack::t_designation des = MCache->designationAt(tile); des.bits.traffic = target; MCache->setDesignationAt(tile, des); } } } MCache->WriteAll(); c->Resume(); return CR_OK; }
// FIXME: use block cache, break into manageable bits int main (void) { srand ( (unsigned int)time(NULL) ); //Message of intent cout << "DF Hole" << endl << "This tool will instantly dig a chasm, pit, pipe, etc through hell, wherever your cursor is." << endl << "This can not be undone! End program now if you don't want hellish fun." << endl ; //User selection of settings should have it own routine, a structure for settings, I know //sloppy mess, but this is just a demo utility. //Pit Types. e_pitType pittype = selectPitType(); //Here are all the settings. //Default values are set here. int pitdepth=0; int roof=-1; int holeradius=6; int wallthickness=1; int wallpillar=1; int holepillar=1; int exposehell = 0; int fillmagma=0; int fillwater=0; int stopatmagma=0; int exposemagma=0; int aquify=0; //The Tile Type to use for the walls lining the hole //263 is semi-molten rock, 331 is obsidian uint32_t whell=263, wmolten=263, wmagma=331, wcave=331; //The Tile Type to use for the hole's floor at bottom of the map //35 is chasm, 42 is eerie pit , 340 is obsidian floor, 344 is featstone floor, 264 is 'magma flow' floor uint32_t floor=35, cap=340; int floorvar=0; //Modify default settings based on pit type. switch ( pittype ) { case pitTypeChasm: floor=35; break; case pitTypeEerie: floor=42; break; case pitTypeFloor: floor=344; floorvar=3; break; case pitTypeSolid: holeradius=0; wallthickness=7; wallpillar=4; break; case pitTypeOasis: stopatmagma=-1; fillwater=-1; holeradius=5; wallthickness=2; //aquify=-1; floor=340; floorvar=3; break; case pitTypeOPool: pitdepth=5; fillwater=-1; holeradius=5; wallthickness=2; //aquify=-1; floor=340; floorvar=3; break; case pitTypeMagma: stopatmagma=-1; exposemagma=-1; wallthickness=2; fillmagma=-1; floor=264; break; case pitTypeMPool: pitdepth=5; wallthickness=2; fillmagma=-1; floor=340; floorvar=3; break; } //Should tiles be revealed? int reveal=0; int accept = getyesno("Use default settings?",1); while ( !accept ) { //Pit Depth pitdepth = getint( "Enter max depth (0 for bottom of map)", 0, INT_MAX, pitdepth ); //Hole Size holeradius = getint( "Enter hole radius, 0 to 16", 0, 16, holeradius ); //Wall thickness wallthickness = getint( "Enter wall thickness, 0 to 16", 0, 16, wallthickness ); //Obsidian Pillars holepillar = getint( "Number of Obsidian Pillars in hole, 0 to 255", 0, 255, holepillar ); wallpillar = getint( "Number of Obsidian Pillars in wall, 0 to 255", 0, 255, wallpillar ); //Open Hell? exposehell=getyesno("Expose the pit to hell (no walls in hell)?",exposehell); //Stop when magma sea is hit? stopatmagma=getyesno("Stop at magma sea?",stopatmagma); exposemagma=getyesno("Expose magma sea (no walls in magma)?",exposemagma); //Fill? fillmagma=getyesno("Fill with magma?",fillmagma); if (fillmagma) aquify=fillwater=0; fillwater=getyesno("Fill with water?",fillwater); //aquify=getyesno("Aquifer?",aquify); /////////////////////////////////////////////////////////////////////////////////////////////// //Print settings. //If a settings struct existed, this could be in a routine printf("Using Settings:\n"); printf("Pit Type......: %d = %s\n", pittype, pitTypeDesc[pittype]); printf("Depth.........: %d\n", pitdepth); printf("Hole Radius...: %d\n", holeradius); printf("Wall Thickness: %d\n", wallthickness); printf("Pillars, Hole.: %d\n", holepillar); printf("Pillars, Wall.: %d\n", wallpillar); printf("Expose Hell...: %c\n", (exposehell?'Y':'N') ); printf("Stop at Magma.: %c\n", (stopatmagma?'Y':'N') ); printf("Expose Magma..: %c\n", (exposemagma?'Y':'N') ); printf("Magma Fill....: %c\n", (fillmagma?'Y':'N') ); printf("Water Fill....: %c\n", (fillwater?'Y':'N') ); printf("Aquifer.......: %c\n", (aquify?'Y':'N') ); accept = getyesno("Accept these settings?",1); } int64_t n; uint32_t x_max,y_max,z_max; //Pattern to dig unsigned char pattern[16][16]; for (int regen=1;regen; ) { regen=0; memset(pattern,0,sizeof(pattern)); //Calculate a randomized circle. //These values found through experimentation. int x=0, y=0, n=0; //Two concentric irregular circles //Outer circle, solid. if ( wallthickness ) { drawcircle(holeradius+wallthickness, pattern, 2); } //Inner circle, hole. if ( holeradius ) { drawcircle(holeradius, pattern, 1); } //Post-process to be certain the wall totally encloses hole. if (wallthickness) { for (y=0;y<16;++y) { for (x=0;x<16;++x) { if ( 1==pattern[x][y] ) { //No hole at edges. if ( x<1 || x>14 || y<1 || y>14 ) { pattern[x][y]=2; } } else if ( 0==pattern[x][y] ) { //check neighbors checkneighbors( pattern , x,y, 1, 2); } } } } //Makes sure that somewhere random gets a vertical pillar of rock which is safe //to dig stairs down, to permit access to anywhere within the pit from the top. for (n=holepillar; n ; --n) { settileat( pattern , 1 , 3 , rand()&255 ); } for (n=wallpillar; n ; --n) { settileat( pattern , 2 , 3 , rand()&255 ); } //Note: //At this point, the pattern holds: //0 for all tiles which will be ignored. //1 for all tiles set to empty pit space. //2 for all normal walls. //3 for the straight obsidian top-to-bottom wall. //4 is randomized between wall or floor (!not implemented!) printf("\nPattern:\n"); const char patternkey[] = ".cW!?567890123"; //Print the pattern for (y=0;y<16;++y) { for (x=0;x<16;++x) { cout << patternkey[ pattern[x][y] ]; } cout << endl; } cout << endl; regen = !getyesno("Acceptable Pattern?",1); } //Post-process settings to fix problems here if (pitdepth<1) { pitdepth=INT_MAX; } /////////////////////////////////////////////////////////////////////////////////////////////// cerr << "Loading memory map..." << endl; //Connect to DF! DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context *DF = DFMgr.getSingleContext(); //Init cerr << "Attaching to DF..." << endl; try { DF->Attach(); } catch (exception& e) { cerr << e.what() << endl; #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } // init the map DFHack::Maps *Mapz = DF->getMaps(); if (!Mapz->Start()) { cerr << "Can't init map. Exiting." << endl; #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } Mapz->getSize(x_max,y_max,z_max); //Get cursor int32_t cursorX, cursorY, cursorZ; DFHack::Gui *Gui = DF->getGui(); Gui->getCursorCoords(cursorX,cursorY,cursorZ); if (-30000==cursorX) { cout << "No cursor position found. Exiting." << endl; #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } //Block coordinates int32_t bx=cursorX/16, by=cursorY/16, bz=cursorZ; //Tile coordinates within block int32_t tx=cursorX%16, ty=cursorY%16, tz=cursorZ; /* //Access the DF interface to pause the game. //Copied from the reveal tool. DFHack::Gui *Gui =DF->getGui(); cout << "Pausing..." << endl; Gui->SetPauseState(true); DF->Resume(); waitmsec(1000); DF->Suspend(); */ //Verify that every z-level at this location exists. for (int32_t Z = 0; Z<= bz ;Z++) { if ( ! Mapz->isValidBlock(bx,by,Z) ) { cout << "This block does't exist! Exiting." << endl; #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } } //Get all the map features. vector<DFHack::t_feature> global_features; if (!Mapz->ReadGlobalFeatures(global_features)) { cout << "Couldn't load global features! Probably a version problem." << endl; #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } std::map <DFHack::DFCoord, std::vector<DFHack::t_feature *> > local_features; if (!Mapz->ReadLocalFeatures(local_features)) { cout << "Couldn't load local features! Probably a version problem." << endl; #ifndef LINUX_BUILD cin.ignore(); #endif return 1; } //Get info on current tile, to determine how to generate the pit mapblock40d topblock; Mapz->ReadBlock40d( bx, by, bz , &topblock ); //Related block info DFCoord pc(bx,by); mapblock40d block; const TileRow * tp; t_designation * d; ////////////////////////////////////// //From top to bottom, dig this thing. ////////////////////////////////////// //Top level, cap. //Might make this an option in the future //For now, no wall means no cap. if (wallthickness) { Mapz->ReadBlock40d( bx, by, bz , &block ); for (uint32_t x=0;x<16;++x) { for (uint32_t y=0;y<16;++y) { if ( (pattern[x][y]>1) || (roof && pattern[x][y]) ) { tp = getTileRow(block.tiletypes[x][y]); d = &block.designation[x][y]; //Only modify this level if it's 'empty' if ( EMPTY != tp->shape && RAMP_TOP != tp->shape && STAIR_DOWN != tp->shape && DFHack::TILE_STREAM_TOP != tp->special) { continue; } //Need a floor for empty space. if (reveal) { d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; } //Always clear the dig designation. d->bits.dig = designation_no; //unlock fluids, so they fall down the pit. d->bits.flow_forbid = d->bits.liquid_static=0; block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; //Remove aquifer, to prevent bugginess d->bits.water_table=0; //Set the tile. block.tiletypes[x][y] = cap + rand()%4; } } } //Write the block. Mapz->WriteBlockFlags(bx,by,bz, block.blockflags ); Mapz->WriteDesignations(bx,by,bz, &block.designation ); Mapz->WriteTileTypes(bx,by,bz, &block.tiletypes ); Mapz->WriteDirtyBit(bx,by,bz,1); } /////////////////////////////////////////////////////////////////////////////////////////////// //All levels in between. int done=0; uint32_t t,v; int32_t z = bz-1; int32_t bottom = max(0,bz-pitdepth-1); assert( bottom>=0 && bottom<=bz ); for ( ; !done && z>=bottom ; --z) { int watercount=0; int magmacount=0; int moltencount=0; int rockcount=0; int veincount=0; int emptycount=0; int hellcount=0; int templecount=0; int adamcount=0; int featcount=0; int tpat; cout << z << endl; assert( Mapz->isValidBlock(bx,by,z) ); if (!Mapz->ReadBlock40d( bx, by, z , &block )) { cout << "Bad block! " << bx << "," << by << "," << z << endl; } //Pre-process this z-level, to get some tile statistics. for (int32_t x=0;x<16;++x) { for (int32_t y=0;y<16;++y) { t=0; tp = getTileRow(block.tiletypes[x][y]); d = &block.designation[x][y]; tpat=pattern[x][y]; //Tile type material categories switch ( tp->material ) { case AIR: ++emptycount; break; case MAGMA: ++moltencount; break; case VEIN: ++veincount; break; case FEATSTONE: case HFS: case OBSIDIAN: //basicly, ignored. break; default: if ( EMPTY == tp->shape || RAMP_TOP == tp->shape || STAIR_DOWN == tp->shape ) { ++emptycount; } else { ++rockcount; } break; } //Magma and water if ( d->bits.flow_size ) { if (d->bits.liquid_type) { ++magmacount; } else { ++watercount; } } //Check for Features if ( block.local_feature > -1 || block.global_feature > -1 ) { //Count tiles which actually are in the feature. //It is possible for a block to have a feature, but no tiles to be feature. if ( d->bits.feature_global || d->bits.feature_local ) { //All features ++featcount; if ( d->bits.feature_global && d->bits.feature_local ) { cout << "warn:tile is global and local at same time!" << endl; } n=0; if ( block.global_feature > -1 && d->bits.feature_global ) { n=global_features[block.global_feature].type; switch ( n ) { case feature_Other: //no count break; case feature_Adamantine_Tube: ++adamcount; break; case feature_Underworld: ++hellcount; break; case feature_Hell_Temple: ++templecount; break; default: //something here. for debugging, it may be interesting to know. if (n) cout << '(' << n << ')'; } } n=0; if ( block.local_feature > -1 && d->bits.feature_local ) { n=local_features[pc][block.local_feature]->type; switch ( n ) { case feature_Other: //no count break; case feature_Adamantine_Tube: ++adamcount; break; case feature_Underworld: ++hellcount; break; case feature_Hell_Temple: ++templecount; break; default: //something here. for debugging, it may be interesting to know. if (n) cout << '[' << n << ']'; } } } } } } //If stopping at magma, and no no non-feature stone in this layer, and magma found, then we're either at //or below the magma sea / molten rock. if ( stopatmagma && (moltencount || magmacount) && (!exposemagma || !rockcount) ) { //If not exposing magma, quit at the first sign of magma. //If exposing magma, quite once magma is exposed. done=-1; } ///////////////////////////////////////////////////////////////////////////////////////////////// //Some checks, based on settings and stats collected //First check, are we at illegal depth? if ( !done && hellcount && stopatmagma ) { //Panic! done=-1; tpat=0; cout << "error: illegal breach of hell!" << endl; } ///////////////////////////////////////////////////////////////////////////////////////////////// //Actually process the current z-level. //These loops do the work. for (int32_t x=0;!done && x<16;++x) { for (int32_t y=0;!done && y<16;++y) { t=0; tp = getTileRow(block.tiletypes[x][y]); d = &block.designation[x][y]; tpat=pattern[x][y]; //Up front, remove aquifer, to prevent bugginess //It may be added back if aquify is set. d->bits.water_table=0; //Change behaviour based on settings and stats from this z-level //In hell? if ( tpat && tpat!=3 && isfeature(global_features, local_features,block,pc,x,y,feature_Underworld ) ) { if ( exposehell ) { tpat=0; } } //Expose magma? if ( tpat && tpat!=3 && exposemagma ) { //Leave certain tiles unchanged. switch ( tp->material ) { case HFS: case FEATSTONE: case MAGMA: tpat=0; default: break; } //Adamantine may be left unchanged... if ( isfeature(global_features, local_features,block,pc,x,y,feature_Adamantine_Tube ) ) { tpat=0; } //Leave magma sea unchanged. if ( d->bits.flow_size && d->bits.liquid_type) { tpat=0; } } //For all situations... //Special modification for walls, always for adamantine. if ( isfeature(global_features, local_features,block,pc,x,y,feature_Adamantine_Tube ) ) { if ( 2==pattern[x][y] || 3==pattern[x][y] ) { tpat=2; } } //Border or space? switch (tpat) { case 0: continue; break; case 1: //Empty Space t=32; //d->bits.light = topblock.designation[x][y].bits.light; //d->bits.skyview = topblock.designation[x][y].bits.skyview; //d->bits.subterranean = topblock.designation[x][y].bits.subterranean; //Erase special markers? //d->bits.feature_global = d->bits.feature_local = 0; //Water? Magma? if (fillmagma || fillwater) { d->bits.flow_size=7; d->bits.water_stagnant = false; d->bits.water_salt = false; if (fillmagma) { d->bits.liquid_type=liquid_magma; } else { d->bits.liquid_type=liquid_water; } } else { //Otherwise, remove all liquids. d->bits.flow_size=0; d->bits.water_stagnant = false; d->bits.water_salt = false; d->bits.liquid_type = liquid_water; } break; case 2: //Wall. //First guess based on current material switch ( tp->material ) { case OBSIDIAN: t=wmagma; break; case MAGMA: t=wmolten; break; case HFS: //t=whell; break; case VEIN: t=440; //Solid vein block break; case FEATSTONE: t=335; //Solid feature stone block break; default: t=wcave; } //Adamantine (a local feature) trumps veins. { //Local Feature? if ( block.local_feature > -1 ) { switch ( n=local_features[pc][block.local_feature]->type ) { case feature_Underworld: case feature_Hell_Temple: //Only adopt these if there is no global feature present if ( block.global_feature >-1 ) { break; } case feature_Adamantine_Tube: //Always for adamantine, sometimes for others //Whatever the feature is made of. "featstone wall" d->bits.feature_global = 0; d->bits.feature_local = 1; t=335; break; } } //Global Feature? else if (block.global_feature > -1 && !d->bits.feature_local ) { switch ( n=global_features[block.global_feature].type ) { case feature_Adamantine_Tube: case feature_Underworld: case feature_Hell_Temple: //Whatever the feature is made of. "featstone wall" d->bits.feature_global = 1; t=335; break; } } } //Erase any liquids, as they cause problems. d->bits.flow_size=0; d->bits.water_stagnant = false; d->bits.water_salt = false; d->bits.liquid_type=liquid_water; //Placing an aquifer? //(bugged, these aquifers don't generate water!) if ( aquify ) { //Only normal stone types can be aquified if ( tp->material!=MAGMA && tp->material!=FEATSTONE && tp->material!=HFS ) { //Only place next to the hole. //If no hole, place in middle. if ( checkneighbors(pattern,x,y,1) || (7==x && 7==y) ) { d->bits.water_table = 1; //t=265; //soil wall } } } break; case 3: ////No obsidian walls on bottom of map! //if(z<1 && (d->bits.feature_global || d->bits.feature_local) ) { // t=335; //} //Special wall, always sets to obsidian, to give a stairway t=331; //Erase special markers d->bits.feature_global = d->bits.feature_local = 0; //Erase any liquids, as they cause problems. d->bits.flow_size=0; d->bits.water_stagnant = false; d->bits.water_salt = false; d->bits.liquid_type=liquid_water; break; default: cout << ".error,bad pattern."; } //For all tiles. if (reveal) { d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; } //Always clear the dig designation. d->bits.dig=designation_no; //Make it underground, because it is capped d->bits.subterranean=1; d->bits.light=0; d->bits.skyview=0; //unlock fluids, so they fall down the pit. d->bits.flow_forbid = d->bits.liquid_static=0; block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; //Set the tile. block.tiletypes[x][y] = t; } } //Write the block. Mapz->WriteBlockFlags(bx,by,z, block.blockflags ); Mapz->WriteDesignations(bx,by,z, &block.designation ); Mapz->WriteTileTypes(bx,by,z, &block.tiletypes ); Mapz->WriteDirtyBit(bx,by,z,1); } //Re-process the last z-level handled above. z++; assert( z>=0 ); /////////////////////////////////////////////////////////////////////////////////////////////// //The bottom level is special. if (-1) { if (!Mapz->ReadBlock40d( bx, by, z , &block )) { cout << "Bad block! " << bx << "," << by << "," << z << endl; } for (uint32_t x=0;x<16;++x) { for (uint32_t y=0;y<16;++y) { t=floor; v=floorvar; tp = getTileRow(block.tiletypes[x][y]); d = &block.designation[x][y]; if ( exposehell ) { //Leave hell tiles unchanged when exposing hell. if ( isfeature(global_features,local_features,block,pc,x,y,feature_Underworld) ) { continue; } } //Does expose magma need anything at this level? if ( exposemagma && stopatmagma ) { continue; } switch (pattern[x][y]) { case 0: continue; break; case 1: //Empty becomes floor. //Base floor type on the z-level first, features, then tile type. if (!z) { //Bottom of map, use the floor specified, always. break; } ////Only place floor where ground is already solid when exposing //if( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ){ // continue; //} if ( d->bits.feature_global || d->bits.feature_global ) { //Feature Floor! t=344; break; } //Tile material check. switch ( tp->material ) { case OBSIDIAN: t=340; v=3; break; case MAGMA: v=0; t=264; //magma flow break; case HFS: //should only happen at bottom of map break; case VEIN: t=441; //vein floor v=3; break; case FEATSTONE: t=344; v=3; break; } break; case 2: case 3: //Walls already drawn. //Ignore. continue; break; } //For all tiles. if (reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden; //Always clear the dig designation. d->bits.dig=designation_no; //unlock fluids d->bits.flow_forbid = d->bits.liquid_static=0; block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1; //Set the tile. block.tiletypes[x][y] = t + ( v ? rand()&v : 0 ); } } //Write the block. Mapz->WriteBlockFlags(bx,by,z, block.blockflags ); Mapz->WriteDesignations(bx,by,z, &block.designation ); Mapz->WriteTileTypes(bx,by,z, &block.tiletypes ); Mapz->WriteDirtyBit(bx,by,z,1); } DF->Detach(); #ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; cin.ignore(); #endif return 0; }
int main (int argc, const char* argv[]) { // Command line options bool updown = false; bool quiet = true; // let's be more useful when double-clicked on windows #ifndef LINUX_BUILD quiet = false; #endif int dig_up_n = 5; int dig_down_n = 5; for(int i = 1; i < argc; i++) { string arg_cur = argv[i]; string arg_next = ""; int arg_next_int = -99999; /* Check if argv[i+1] is a number >= 0 */ if (i < argc-1) { arg_next = argv[i+1]; arg_next_int = strtoint(arg_next); if (arg_next != "0" && arg_next_int == 0) { arg_next_int = -99999; } } if (arg_cur == "-x") { updown = true; } else if (arg_cur == "-q") { quiet = true; } else if(arg_cur == "-u" && i < argc-1) { if (arg_next_int < 0 || arg_next_int >= 99999) { usage(argc, argv); return 1; } dig_up_n = arg_next_int; i++; } else if(arg_cur == "-d" && i < argc-1) { if (arg_next_int < 0 || arg_next_int >= 99999) { usage(argc, argv); return 1; } dig_down_n = arg_next_int; i++; } else { usage(argc, argv); return 1; } } DFHack::ContextManager DFMgr("Memory.xml"); DFHack::Context * DF; try { DF = DFMgr.getSingleContext(); DF->Attach(); } catch (exception& e) { cerr << "Error getting context: " << e.what() << endl; if (!quiet) cin.ignore(); return 1; } uint32_t x_max,y_max,z_max; DFHack::Maps * Maps = DF->getMaps(); DFHack::Gui * Gui = DF->getGui(); // init the map if(!Maps->Start()) { cerr << "Can't init map. Make sure you have a map loaded in DF." << endl; DF->Detach(); if (!quiet) cin.ignore(); return 1; } int32_t cx, cy, cz; Maps->getSize(x_max,y_max,z_max); uint32_t tx_max = x_max * 16; uint32_t ty_max = y_max * 16; Gui->getCursorCoords(cx,cy,cz); if (cx == -30000) { cerr << "Cursor is not active. Point the cursor at the position to dig at." << endl; DF->Detach(); if (!quiet) { cin.ignore(); } return 1; } DFHack::DFCoord xy ((uint32_t)cx,(uint32_t)cy,cz); if(xy.x == 0 || xy.x == tx_max - 1 || xy.y == 0 || xy.y == ty_max - 1) { cerr << "I won't dig the borders. That would be cheating!" << endl; DF->Detach(); if (!quiet) { cin.ignore(); } return 1; } MapCache * MCache = new MapCache(Maps); DFHack::t_designation des = MCache->designationAt(xy); int16_t tt = MCache->tiletypeAt(xy); int16_t veinmat = MCache->veinMaterialAt(xy); /* if( veinmat == -1 ) { cerr << "This tile is non-vein. Bye :)" << endl; delete MCache; DF->Detach(); if (!quiet) { cin.ignore(); } return 1; } */ printf("Digging at (%d/%d/%d), tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole); // 1 < xy.x < tx_max - 1 // 1 < xy.y < ty_max - 1 // xy.z // X____ // X_XXX // XXXXX // __XXX // __XXX // _____ pos map[] = { { 0,0 } , { 0,1 } , { 0,2 } , { 2,2 }, { 3,2 }, { 4,2 } , { 0,3 }, { 1,3 }, { 2,3 }, { 3,3 }, { 4,3 } , { 2,4 }, { 3,4 }, { 4,4 } // this is mirrored, goes left instead of right , {-2,2 }, {-3,2 }, {-4,2 } , {-1,3 }, {-2,3 }, {-3,3 }, {-4,3 } , {-2,4 }, {-3,4 }, {-4,4 } }; DFHack::DFCoord npos = xy; if (dig_up_n > 0) { for (int j = 0; j < dig_up_n; j++) { for (int i = 0; i < sizeof(map)/sizeof(map[0]); i++) { npos=xy; npos.x += map[i].x; npos.y -= 4*j + map[i].y; printf("Digging at (%d/%d/%d)\n", npos.x, npos.y, npos.z); digat(MCache, npos); } } } if (dig_down_n > 0) { for (int j = 0; j < dig_down_n; j++) { for (int i = 0; i < sizeof(map)/sizeof(map[0]); i++) { npos=xy; npos.x += map[i].x; npos.y += 4*j + map[i].y; printf("Digging at (%d/%d/%d)\n", npos.x, npos.y, npos.z); digat(MCache, npos); } } } MCache->WriteAll(); delete MCache; DF->Detach(); if (!quiet) { cout << "Done. Press any key to continue" << endl; cin.ignore(); } return 0; }