1 | /* SCCS Id: @(#)extralev.c 3.3 1999/11/26 */ 2 | /* Copyright 1988, 1989 by Ken Arromdee */ 3 | /* NetHack may be freely redistributed. See license for details. */ 4 | 5 | /* 6 | * Support code for "rogue"-style level. 7 | */ 8 | 9 | #include "hack.h" 10 | 11 | #ifdef REINCARNATION 12 | 13 | struct rogueroom { 14 | xchar rlx, rly; 15 | xchar dx, dy; 16 | boolean real; 17 | uchar doortable; 18 | int nroom; /* Only meaningful for "real" rooms */ 19 | }; 20 | #define UP 1 21 | #define DOWN 2 22 | #define LEFT 4 23 | #define RIGHT 8 24 | 25 | static NEARDATA struct rogueroom r[3][3]; 26 | STATIC_DCL void FDECL(roguejoin,(int,int,int,int,int)); 27 | STATIC_DCL void FDECL(roguecorr,(int,int,int)); 28 | STATIC_DCL void FDECL(miniwalk,(int,int)); 29 | 30 | STATIC_OVL 31 | void 32 | roguejoin(x1,y1,x2,y2, horiz) 33 | int x1,y1,x2,y2; 34 | int horiz; 35 | { 36 | register int x,y,middle; 37 | #ifndef MAX 38 | #define MAX(a,b) (((a) > (b)) ? (a) : (b)) 39 | #endif 40 | #ifndef MIN 41 | #define MIN(a,b) (((a) < (b)) ? (a) : (b)) 42 | #endif 43 | if (horiz) { 44 | middle = x1 + rn2(x2-x1+1); 45 | for(x=MIN(x1,middle); x<=MAX(x1,middle); x++) 46 | corr(x, y1); 47 | for(y=MIN(y1,y2); y<=MAX(y1,y2); y++) 48 | corr(middle,y); 49 | for(x=MIN(middle,x2); x<=MAX(middle,x2); x++) 50 | corr(x, y2); 51 | } else { 52 | middle = y1 + rn2(y2-y1+1); 53 | for(y=MIN(y1,middle); y<=MAX(y1,middle); y++) 54 | corr(x1, y); 55 | for(x=MIN(x1,x2); x<=MAX(x1,x2); x++) 56 | corr(x, middle); 57 | for(y=MIN(middle,y2); y<=MAX(middle,y2); y++) 58 | corr(x2,y); 59 | } 60 | } 61 | 62 | STATIC_OVL 63 | void 64 | roguecorr(x, y, dir) 65 | int x,y,dir; 66 | { 67 | register int fromx, fromy, tox, toy; 68 | 69 | if (dir==DOWN) { 70 | r[x][y].doortable &= ~DOWN; 71 | if (!r[x][y].real) { 72 | fromx = r[x][y].rlx; fromy = r[x][y].rly; 73 | fromx += 1 + 26*x; fromy += 7*y; 74 | } else { 75 | fromx = r[x][y].rlx + rn2(r[x][y].dx); 76 | fromy = r[x][y].rly + r[x][y].dy; 77 | fromx += 1 + 26*x; fromy += 7*y; 78 | if (!IS_WALL(levl[fromx][fromy].typ)) 79 | impossible("down: no wall at %d,%d?",fromx, 80 | fromy); 81 | dodoor(fromx, fromy, &rooms[r[x][y].nroom]); 82 | levl[fromx][fromy].doormask = D_NODOOR; 83 | fromy++; 84 | } 85 | if(y >= 2) { 86 | impossible("down door from %d,%d going nowhere?",x,y); 87 | return; 88 | } 89 | y++; 90 | r[x][y].doortable &= ~UP; 91 | if (!r[x][y].real) { 92 | tox = r[x][y].rlx; toy = r[x][y].rly; 93 | tox += 1 + 26*x; toy += 7*y; 94 | } else { 95 | tox = r[x][y].rlx + rn2(r[x][y].dx); 96 | toy = r[x][y].rly - 1; 97 | tox += 1 + 26*x; toy += 7*y; 98 | if (!IS_WALL(levl[tox][toy].typ)) 99 | impossible("up: no wall at %d,%d?",tox,toy); 100 | dodoor(tox, toy, &rooms[r[x][y].nroom]); 101 | levl[tox][toy].doormask = D_NODOOR; 102 | toy--; 103 | } 104 | roguejoin(fromx, fromy, tox, toy, FALSE); 105 | return; 106 | } else if (dir == RIGHT) { 107 | r[x][y].doortable &= ~RIGHT; 108 | if (!r[x][y].real) { 109 | fromx = r[x][y].rlx; fromy = r[x][y].rly; 110 | fromx += 1 + 26*x; fromy += 7*y; 111 | } else { 112 | fromx = r[x][y].rlx + r[x][y].dx; 113 | fromy = r[x][y].rly + rn2(r[x][y].dy); 114 | fromx += 1 + 26*x; fromy += 7*y; 115 | if (!IS_WALL(levl[fromx][fromy].typ)) 116 | impossible("down: no wall at %d,%d?",fromx, 117 | fromy); 118 | dodoor(fromx, fromy, &rooms[r[x][y].nroom]); 119 | levl[fromx][fromy].doormask = D_NODOOR; 120 | fromx++; 121 | } 122 | if(x >= 2) { 123 | impossible("right door from %d,%d going nowhere?",x,y); 124 | return; 125 | } 126 | x++; 127 | r[x][y].doortable &= ~LEFT; 128 | if (!r[x][y].real) { 129 | tox = r[x][y].rlx; toy = r[x][y].rly; 130 | tox += 1 + 26*x; toy += 7*y; 131 | } else { 132 | tox = r[x][y].rlx - 1; 133 | toy = r[x][y].rly + rn2(r[x][y].dy); 134 | tox += 1 + 26*x; toy += 7*y; 135 | if (!IS_WALL(levl[tox][toy].typ)) 136 | impossible("left: no wall at %d,%d?",tox,toy); 137 | dodoor(tox, toy, &rooms[r[x][y].nroom]); 138 | levl[tox][toy].doormask = D_NODOOR; 139 | tox--; 140 | } 141 | roguejoin(fromx, fromy, tox, toy, TRUE); 142 | return; 143 | } else impossible("corridor in direction %d?",dir); 144 | } 145 | 146 | /* Modified walkfrom() from mkmaze.c */ 147 | STATIC_OVL 148 | void 149 | miniwalk(x, y) 150 | int x,y; 151 | { 152 | register int q, dir; 153 | int dirs[4]; 154 | 155 | while(1) { 156 | q = 0; 157 | #define doorhere (r[x][y].doortable) 158 | if (x>0 && (!(doorhere & LEFT)) && 159 | (!r[x-1][y].doortable || !rn2(10))) 160 | dirs[q++] = 0; 161 | if (x<2 && (!(doorhere & RIGHT)) && 162 | (!r[x+1][y].doortable || !rn2(10))) 163 | dirs[q++] = 1; 164 | if (y>0 && (!(doorhere & UP)) && 165 | (!r[x][y-1].doortable || !rn2(10))) 166 | dirs[q++] = 2; 167 | if (y<2 && (!(doorhere & DOWN)) && 168 | (!r[x][y+1].doortable || !rn2(10))) 169 | dirs[q++] = 3; 170 | /* Rogue levels aren't just 3 by 3 mazes; they have some extra 171 | * connections, thus that 1/10 chance 172 | */ 173 | if (!q) return; 174 | dir = dirs[rn2(q)]; 175 | switch(dir) { /* Move in direction */ 176 | case 0: doorhere |= LEFT; 177 | x--; 178 | doorhere |= RIGHT; 179 | break; 180 | case 1: doorhere |= RIGHT; 181 | x++; 182 | doorhere |= LEFT; 183 | break; 184 | case 2: doorhere |= UP; 185 | y--; 186 | doorhere |= DOWN; 187 | break; 188 | case 3: doorhere |= DOWN; 189 | y++; 190 | doorhere |= UP; 191 | break; 192 | } 193 | miniwalk(x,y); 194 | } 195 | } 196 | 197 | void 198 | makeroguerooms() { 199 | register int x,y; 200 | /* Rogue levels are structured 3 by 3, with each section containing 201 | * a room or an intersection. The minimum width is 2 each way. 202 | * One difference between these and "real" Rogue levels: real Rogue 203 | * uses 24 rows and NetHack only 23. So we cheat a bit by making the 204 | * second row of rooms not as deep. 205 | * 206 | * Each normal space has 6/7 rows and 25 columns in which a room may 207 | * actually be placed. Walls go from rows 0-5/6 and columns 0-24. 208 | * Not counting walls, the room may go in 209 | * rows 1-5 and columns 1-23 (numbering starting at 0). A room 210 | * coordinate of this type may be converted to a level coordinate 211 | * by adding 1+28*x to the column, and 7*y to the row. (The 1 212 | * is because column 0 isn't used [we only use 1-78]). 213 | * Room height may be 2-4 (2-5 on last row), length 2-23 (not 214 | * counting walls) 215 | */ 216 | #define here r[x][y] 217 | 218 | nroom = 0; 219 | for(y=0; y<3; y++) for(x=0; x<3; x++) { 220 | /* Note: we want to insure at least 1 room. So, if the 221 | * first 8 are all dummies, force the last to be a room. 222 | */ 223 | if (!rn2(5) && (nroom || (x<2 && y<2))) { 224 | /* Arbitrary: dummy rooms may only go where real 225 | * ones do. 226 | */ 227 | here.real = FALSE; 228 | here.rlx = rn1(22, 2); 229 | here.rly = rn1((y==2)?4:3, 2); 230 | } else { 231 | here.real = TRUE; 232 | here.dx = rn1(22, 2); /* 2-23 long, plus walls */ 233 | here.dy = rn1((y==2)?4:3, 2); /* 2-5 high, plus walls */ 234 | 235 | /* boundaries of room floor */ 236 | here.rlx = rnd(23 - here.dx + 1); 237 | here.rly = rnd(((y==2) ? 5 : 4)- here.dy + 1); 238 | nroom++; 239 | } 240 | here.doortable = 0; 241 | } 242 | miniwalk(rn2(3), rn2(3)); 243 | nroom = 0; 244 | for(y=0; y<3; y++) for(x=0; x<3; x++) { 245 | if (here.real) { /* Make a room */ 246 | int lowx, lowy, hix, hiy; 247 | 248 | r[x][y].nroom = nroom; 249 | smeq[nroom] = nroom; 250 | 251 | lowx = 1 + 26*x + here.rlx; 252 | lowy = 7*y + here.rly; 253 | hix = 1 + 26*x + here.rlx + here.dx - 1; 254 | hiy = 7*y + here.rly + here.dy - 1; 255 | /* Strictly speaking, it should be lit only if above 256 | * level 10, but since Rogue rooms are only 257 | * encountered below level 10, use !rn2(7). 258 | */ 259 | add_room(lowx, lowy, hix, hiy, 260 | (boolean) !rn2(7), OROOM, FALSE); 261 | } 262 | } 263 | 264 | /* Now, add connecting corridors. */ 265 | for(y=0; y<3; y++) for(x=0; x<3; x++) { 266 | if (here.doortable & DOWN) 267 | roguecorr(x, y, DOWN); 268 | if (here.doortable & RIGHT) 269 | roguecorr(x, y, RIGHT); 270 | if (here.doortable & LEFT) 271 | impossible ("left end of %d, %d never connected?",x,y); 272 | if (here.doortable & UP) 273 | impossible ("up end of %d, %d never connected?",x,y); 274 | } 275 | } 276 | 277 | void 278 | corr(x,y) 279 | int x, y; 280 | { 281 | if (rn2(50)) { 282 | levl[x][y].typ = CORR; 283 | } else { 284 | levl[x][y].typ = SCORR; 285 | } 286 | } 287 | 288 | void 289 | makerogueghost() 290 | { 291 | register struct monst *ghost; 292 | struct obj *ghostobj; 293 | struct mkroom *croom; 294 | int x,y; 295 | 296 | if (!nroom) return; /* Should never happen */ 297 | croom = &rooms[rn2(nroom)]; 298 | x = somex(croom); y = somey(croom); 299 | if (!(ghost = makemon(&mons[PM_GHOST], x, y, NO_MM_FLAGS))) 300 | return; 301 | ghost->msleeping = 1; 302 | ghost = christen_monst(ghost, roguename()); 303 | 304 | if (rn2(4)) { 305 | ghostobj = mksobj_at(FOOD_RATION,x,y,FALSE); 306 | ghostobj->quan = (long) rnd(7); 307 | ghostobj->owt = weight(ghostobj); 308 | } 309 | if (rn2(2)) { 310 | ghostobj = mksobj_at(MACE,x,y,FALSE); 311 | ghostobj->spe = rnd(3); 312 | if (rn2(4)) curse(ghostobj); 313 | } else { 314 | ghostobj = mksobj_at(TWO_HANDED_SWORD,x,y,FALSE); 315 | ghostobj->spe = rnd(5) - 2; 316 | if (rn2(4)) curse(ghostobj); 317 | } 318 | ghostobj = mksobj_at(BOW,x,y,FALSE); 319 | ghostobj->spe = 1; 320 | if (rn2(4)) curse(ghostobj); 321 | 322 | ghostobj = mksobj_at(ARROW,x,y,FALSE); 323 | ghostobj->spe = 0; 324 | ghostobj->quan = (long) rn1(10,25); 325 | ghostobj->owt = weight(ghostobj); 326 | if (rn2(4)) curse(ghostobj); 327 | 328 | if (rn2(2)) { 329 | ghostobj = mksobj_at(RING_MAIL,x,y,FALSE); 330 | ghostobj->spe = rn2(3); 331 | if (!rn2(3)) ghostobj->oerodeproof = TRUE; 332 | if (rn2(4)) curse(ghostobj); 333 | } else { 334 | ghostobj = mksobj_at(PLATE_MAIL,x,y,FALSE); 335 | ghostobj->spe = rnd(5) - 2; 336 | if (!rn2(3)) ghostobj->oerodeproof = TRUE; 337 | if (rn2(4)) curse(ghostobj); 338 | } 339 | if (rn2(2)) { 340 | ghostobj = mksobj_at(FAKE_AMULET_OF_YENDOR,x,y,TRUE); 341 | ghostobj->known = TRUE; 342 | } 343 | } 344 | #endif /* REINCARNATION */ 345 | 346 | /*extralev.c*/