From e71408b40bc0aedf18fb2cc7ae583e9aeb2587b8 Mon Sep 17 00:00:00 2001 From: PeridexisErrant Date: Wed, 24 Dec 2014 18:24:52 +1100 Subject: [PATCH] replace hellhole.cpp with hfs-pit.lua A port/update. May not have great argument handling, and there's a few magic numbers, but it's a huge improvement over a non-compiling plugin. --- NEWS | 1 + Readme.rst | 14 + needs_porting/_notes.txt | 4 - needs_porting/hellhole.cpp | 1281 ------------------------------------ scripts/hfs-pit.lua | 88 +++ 5 files changed, 103 insertions(+), 1285 deletions(-) delete mode 100644 needs_porting/hellhole.cpp create mode 100644 scripts/hfs-pit.lua diff --git a/NEWS b/NEWS index a05e75465..93e93f5a6 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ DFHack Future New Scripts position: Reports the current date, time, month, and season, plus some location info. Port/update of position.py + hfs-pit: Digs a hole to hell under the cursor. Replaces needs_porting/hellhole.cpp Misc Improvements further work on needs_porting diff --git a/Readme.rst b/Readme.rst index 465037cea..872295a2f 100644 --- a/Readme.rst +++ b/Readme.rst @@ -2329,6 +2329,20 @@ For example, to grow 40 plump helmet spawn:: growcrops plump 40 +hfs-pit +======= +Creates a pit to the underworld at the cursor. + +Takes three arguments: diameter of the pit in tiles, whether to wall off +the pit, and whether to insert stairs. If no arguments are given, the default +is "hfs-pit 1 0 0", ie single-tile wide with no walls or stairs. + + hfs-pit 4 0 1 + hfs-pit 2 1 0 + +First example is a four-across pit with stairs but no walls; second is a +two-across pit with stairs but no walls. + lever ===== Allow manipulation of in-game levers from the dfhack console. diff --git a/needs_porting/_notes.txt b/needs_porting/_notes.txt index 35a7ef5bf..cdd364d12 100644 --- a/needs_porting/_notes.txt +++ b/needs_porting/_notes.txt @@ -3,10 +3,6 @@ TODO: high value target - a proof of concept plugin to allow copy-pasting in DF; does both terrain and buildings/constructions creaturemanager.cpp modify skills and labors of creatures, kill creatures, etc; impressive but I suspect most functions implemented elsewhere - dfbauxtite.cpp - changes material of mechanisms to bauxtite (ie magma-safe) - hellhole.cpp - instantly creates a hole to the HFS In progress: hotkey-notes.lua diff --git a/needs_porting/hellhole.cpp b/needs_porting/hellhole.cpp deleted file mode 100644 index a38d14cbf..000000000 --- a/needs_porting/hellhole.cpp +++ /dev/null @@ -1,1281 +0,0 @@ -// Burn a hole straight to hell! - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -using namespace std; - -#include -#include -#include -using namespace DFHack; - - -#ifdef LINUX_BUILD -#include -void waitmsec (int delay) -{ - usleep(delay); -} -#else -#include -void waitmsec (int delay) -{ - Sleep(delay); -} -#endif - -#define minmax(MinV,V,MaxV) (max((MinV),min((MaxV),(V)))) - -//User interaction enums. -//Pit Type (these only have meaning within hellhole, btw) -#define PITTYPEMACRO \ - X(pitTypeChasm,"Bottomless Chasm" ) \ - X(pitTypeEerie,"Bottomless Eerie Pit" ) \ - X(pitTypeFloor,"Pit with floor" ) \ - X(pitTypeSolid,"Solid Pillar" ) \ - X(pitTypeOasis,"Oasis Pit (ends at magma, no hell access)" ) \ - X(pitTypeOPool,"Oasis Pool, with partial aquifer (default 5 z-levels)" ) \ - X(pitTypeMagma,"Magma Pit (similar to volcano, no hell access)" ) \ - X(pitTypeMPool,"Magma Pool (default 5 z-levels)" ) -//end PITTYPEMACRO - -#define X(name,desc) name, -enum e_pitType -{ - pitTypeInvalid=-1, - PITTYPEMACRO - pitTypeCount, -}; -#undef X - - -#define X(name,desc) desc, -const char * pitTypeDesc[pitTypeCount+1] = -{ - PITTYPEMACRO - "" -}; -#undef X - - - - -int getyesno( const char * msg , int default_value ) -{ - const int bufferlen=4; - static char buf[bufferlen]; - memset(buf,0,bufferlen); - while (-1) - { - if (msg) printf("\n%s (default=%s)\n:" , msg , (default_value?"yes":"no") ); - fflush(stdin); - fgets(buf,bufferlen,stdin); - switch (buf[0]) - { - case 0: - case 0x0d: - case 0x0a: - return default_value; - case 'y': - case 'Y': - case 'T': - case 't': - case '1': - return -1; - case 'n': - case 'N': - case 'F': - case 'f': - case '0': - return 0; - } - } - return 0; -} - -int getint( const char * msg , int min, int max, int default_value ) { - const int bufferlen=16; - static char buf[bufferlen]; - int n=0; - memset(buf,0,bufferlen); - while (-1) - { - if (msg) printf("\n%s (default=%d)\n:" , msg , default_value); - fflush(stdin); - fgets(buf,bufferlen,stdin); - if ( !buf[0] || 0x0a==buf[0] || 0x0d==buf[0] ) - { - return default_value; - } - if ( sscanf(buf,"%d", &n) ) - { - if (n>=min && n<=max ) - { - return n; - } - } - } -} - -int getint( const char * msg , int min, int max ) -{ - const int bufferlen=16; - static char buf[bufferlen]; - int n=0; - memset(buf,0,bufferlen); - while (-1) - { - if (msg) - { - printf("\n%s \n:" , msg ); - } - fflush(stdin); - fgets(buf,bufferlen,stdin); - - if ( !buf[0] || 0x0a==buf[0] || 0x0d==buf[0] ) - { - continue; - } - if ( sscanf(buf,"%d", &n) ) - { - if (n>=min && n<=max ) - { - return n; - } - } - } -} - - - -//Interactive, get pit type from user -e_pitType selectPitType() -{ - while ( -1 ) - { - printf("Enter the type of hole to dig:\n" ); - for (int n=0;n=0, replace with v. -//Returns number of neighbors found. -int checkneighbors(unsigned char pattern[16][16], int x, int y, unsigned char n , char v ) -{ - int r=0; - if ( x>0 && y>0 && n==pattern[x-1][y-1] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - if ( x>0 && n==pattern[x-1][y ] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - if ( y>0 && n==pattern[x ][y-1] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - if ( x<15 && n==pattern[x+1][y ] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - if ( x<15 && y>0 && n==pattern[x+1][y-1] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - if ( x<15 && y<15 && n==pattern[x+1][y+1] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - if ( y<15 && n==pattern[x ][y+1] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - if ( x>0 && y<15 && n==pattern[x-1][y+1] ) - { - ++r; - if (v>-1) pattern[x][y]=v; - } - return r; -} -//convenience -int checkneighbors(unsigned char pattern[16][16], int x, int y, unsigned char n ) -{ - return checkneighbors(pattern,x,y,n,-1); -} - -void settileat(unsigned char pattern[16][16], const unsigned char needle, const unsigned char v, const int index ) -{ - int ok=0; - int safety=256*256; - int y,x,i=0; - //Scan for sequential index - while ( !ok && --safety ) - { - for (y=0 ; !ok && y<16 ; ++y ) - { - for (x=0 ; !ok && x<16 ; ++x ) - { - if ( needle==pattern[x][y] ) - { - ++i; - if ( index==i ) - { - //Got it! - pattern[x][y]=v; - ok=-1; - } - } - } - } - } -} - - -//FIXME: good candidate for adding to dfhack. Maybe the Maps should have those cached so they can be queried? -//Is a given feature present at the given tile? -int isfeature( - vector global_features, - std::map > local_features, - const mapblock40d &block, const DFCoord &pc, const int x, const int y, const e_feature Feat -) -{ - //const TileRow * tp; - //tp = getTileTypeP(block.tiletypes[x][y]); - const t_designation * d; - d = &block.designation[x][y]; - - if ( block.local_feature > -1 && d->bits.feature_local ) { - if ( Feat==local_features[pc][block.local_feature]->type ) return Feat; - } - if ( block.global_feature > -1 && d->bits.feature_global ) { - if ( Feat==global_features[block.global_feature].type ) return Feat; - } - - return 0; -} - -// 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 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 > 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::BROOK_TOP != tp->shape) - { - 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; -} diff --git a/scripts/hfs-pit.lua b/scripts/hfs-pit.lua new file mode 100644 index 000000000..9592d0a31 --- /dev/null +++ b/scripts/hfs-pit.lua @@ -0,0 +1,88 @@ +-- Creates a pit under the target leading straight to the Underworld. Type '?' for help. +-- Based on script by IndigoFenix, @ https://gist.github.com/IndigoFenix/8776696 + +args={...} + +if args[1] == '?' then + print("Example usage: 'hfs-pit 2 1 1'") + print("First parameter is size of the pit in all directions.") + print("Second parameter is 1 to wall off the sides of the pit on all layers except the underworld, or anything else to leave them open.") + print("Third parameter is 1 to add stairs. Stairs are buggy; they will not reveal the bottom until you dig somewhere, but underworld creatures will path in.") + print("If no arguments are given, the default is 'hfs-pit 1 0 0', ie single-tile wide with no walls or stairs.") + return +end + +pos = copyall(df.global.cursor) +size = tonumber(args[1]) +if size == nil or size < 1 then size = 1 end + +wallOff = tonumber(args[2]) +stairs = tonumber(args[3]) + +--Get the layer of the underworld +for index,value in ipairs(df.global.world.cur_savegame.map_features) do + local featureType=value:getType() + if featureType==9 then --Underworld + underworldLayer = value.layer + end +end + +if pos.x==-30000 then + qerror("Select a location by placing the cursor") +end +local x = 0 +local y = 0 +for x=pos.x-size,pos.x+size,1 do + for y=pos.y-size,pos.y+size,1 do + z=1 + local hitAir = false + local hitCeiling = false + while z <= pos.z do + local block = dfhack.maps.ensureTileBlock(x,y,z) + if block then + if block.tiletype[x%16][y%16] ~= 335 then + hitAir = true + end + if hitAir == true then + if not hitCeiling then + if block.global_feature ~= underworldLayer or z > 10 then hitCeiling = true end + if stairs == 1 and x == pos.x and y == pos.y then + if block.tiletype[x%16][y%16] == 32 then + if z == pos.z then + block.tiletype[x%16][y%16] = 56 + else + block.tiletype[x%16][y%16] = 55 + end + else + block.tiletype[x%16][y%16] = 57 + end + end + end + if hitCeiling == true then + if block.designation[x%16][y%16].flow_size > 0 or wallOff == 1 then needsWall = true else needsWall = false end + if (x == pos.x-size or x == pos.x+size or y == pos.y-size or y == pos.y+size) and z==pos.z then + --Do nothing, this is the lip of the hole + elseif x == pos.x-size and y == pos.y-size then if needsWall == true then block.tiletype[x%16][y%16]=320 end + elseif x == pos.x-size and y == pos.y+size then if needsWall == true then block.tiletype[x%16][y%16]=321 end + elseif x == pos.x+size and y == pos.y+size then if needsWall == true then block.tiletype[x%16][y%16]=322 end + elseif x == pos.x+size and y == pos.y-size then if needsWall == true then block.tiletype[x%16][y%16]=323 end + elseif x == pos.x-size or x == pos.x+size then if needsWall == true then block.tiletype[x%16][y%16]=324 end + elseif y == pos.y-size or y == pos.y+size then if needsWall == true then block.tiletype[x%16][y%16]=325 end + elseif stairs == 1 and x == pos.x and y == pos.y then + if z == pos.z then block.tiletype[x%16][y%16]=56 + else block.tiletype[x%16][y%16]=55 end + else block.tiletype[x%16][y%16]=32 + end + block.designation[x%16][y%16].hidden = false + --block.designation[x%16][y%16].liquid_type = true -- if true, magma. if false, water. + block.designation[x%16][y%16].flow_size = 0 + dfhack.maps.enableBlockUpdates(block) + block.designation[x%16][y%16].flow_forbid = false + end + end + block.designation[x%16][y%16].hidden = false + end + z = z+1 + end + end +end \ No newline at end of file