1/* SCCS Id: @(#)extralev.c 3.4 2001/09/06 */ 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 13struct 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 25static NEARDATA struct rogueroom r[3][3]; 26STATIC_DCL void FDECL(roguejoin,(int,int,int,int,int)); 27STATIC_DCL void FDECL(roguecorr,(int,int,int)); 28STATIC_DCL void FDECL(miniwalk,(int,int)); 29 30STATIC_OVL 31void 32roguejoin(x1,y1,x2,y2, horiz) 33int x1,y1,x2,y2; 34int 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 62STATIC_OVL 63void 64roguecorr(x, y, dir) 65int 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 */ 147STATIC_OVL 148void 149miniwalk(x, y) 150int 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 197void 198makeroguerooms() { 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 277void 278corr(x,y) 279int x, y; 280{ 281 if (rn2(50)) { 282 levl[x][y].typ = CORR; 283 } else { 284 levl[x][y].typ = SCORR; 285 } 286} 287 288void 289makerogueghost() 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, 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, FALSE); 311 ghostobj->spe = rnd(3); 312 if (rn2(4)) curse(ghostobj); 313 } else { 314 ghostobj = mksobj_at(TWO_HANDED_SWORD, x, y, FALSE, FALSE); 315 ghostobj->spe = rnd(5) - 2; 316 if (rn2(4)) curse(ghostobj); 317 } 318 ghostobj = mksobj_at(BOW, x, y, FALSE, FALSE); 319 ghostobj->spe = 1; 320 if (rn2(4)) curse(ghostobj); 321 322 ghostobj = mksobj_at(ARROW, x, y, FALSE, 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, 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, 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, FALSE); 341 ghostobj->known = TRUE; 342 } 343} 344#endif /* REINCARNATION */ 345 346/*extralev.c*/ 347