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