diff --git a/src/extralev.c b/src/extralev.c new file mode 100644 index 000000000..4d7149320 --- /dev/null +++ b/src/extralev.c @@ -0,0 +1,346 @@ +/* SCCS Id: @(#)extralev.c 3.3 2001/09/06 */ +/* Copyright 1988, 1989 by Ken Arromdee */ +/* NetHack may be freely redistributed. See license for details. */ + +/* + * Support code for "rogue"-style level. + */ + +#include "hack.h" + +#ifdef REINCARNATION + +struct rogueroom { + xchar rlx, rly; + xchar dx, dy; + boolean real; + uchar doortable; + int nroom; /* Only meaningful for "real" rooms */ +}; +#define UP 1 +#define DOWN 2 +#define LEFT 4 +#define RIGHT 8 + +static NEARDATA struct rogueroom r[3][3]; +STATIC_DCL void FDECL(roguejoin,(int,int,int,int,int)); +STATIC_DCL void FDECL(roguecorr,(int,int,int)); +STATIC_DCL void FDECL(miniwalk,(int,int)); + +STATIC_OVL +void +roguejoin(x1,y1,x2,y2, horiz) +int x1,y1,x2,y2; +int horiz; +{ + register int x,y,middle; +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + if (horiz) { + middle = x1 + rn2(x2-x1+1); + for(x=MIN(x1,middle); x<=MAX(x1,middle); x++) + corr(x, y1); + for(y=MIN(y1,y2); y<=MAX(y1,y2); y++) + corr(middle,y); + for(x=MIN(middle,x2); x<=MAX(middle,x2); x++) + corr(x, y2); + } else { + middle = y1 + rn2(y2-y1+1); + for(y=MIN(y1,middle); y<=MAX(y1,middle); y++) + corr(x1, y); + for(x=MIN(x1,x2); x<=MAX(x1,x2); x++) + corr(x, middle); + for(y=MIN(middle,y2); y<=MAX(middle,y2); y++) + corr(x2,y); + } +} + +STATIC_OVL +void +roguecorr(x, y, dir) +int x,y,dir; +{ + register int fromx, fromy, tox, toy; + + if (dir==DOWN) { + r[x][y].doortable &= ~DOWN; + if (!r[x][y].real) { + fromx = r[x][y].rlx; fromy = r[x][y].rly; + fromx += 1 + 26*x; fromy += 7*y; + } else { + fromx = r[x][y].rlx + rn2(r[x][y].dx); + fromy = r[x][y].rly + r[x][y].dy; + fromx += 1 + 26*x; fromy += 7*y; + if (!IS_WALL(levl[fromx][fromy].typ)) + impossible("down: no wall at %d,%d?",fromx, + fromy); + dodoor(fromx, fromy, &rooms[r[x][y].nroom]); + levl[fromx][fromy].doormask = D_NODOOR; + fromy++; + } + if(y >= 2) { + impossible("down door from %d,%d going nowhere?",x,y); + return; + } + y++; + r[x][y].doortable &= ~UP; + if (!r[x][y].real) { + tox = r[x][y].rlx; toy = r[x][y].rly; + tox += 1 + 26*x; toy += 7*y; + } else { + tox = r[x][y].rlx + rn2(r[x][y].dx); + toy = r[x][y].rly - 1; + tox += 1 + 26*x; toy += 7*y; + if (!IS_WALL(levl[tox][toy].typ)) + impossible("up: no wall at %d,%d?",tox,toy); + dodoor(tox, toy, &rooms[r[x][y].nroom]); + levl[tox][toy].doormask = D_NODOOR; + toy--; + } + roguejoin(fromx, fromy, tox, toy, FALSE); + return; + } else if (dir == RIGHT) { + r[x][y].doortable &= ~RIGHT; + if (!r[x][y].real) { + fromx = r[x][y].rlx; fromy = r[x][y].rly; + fromx += 1 + 26*x; fromy += 7*y; + } else { + fromx = r[x][y].rlx + r[x][y].dx; + fromy = r[x][y].rly + rn2(r[x][y].dy); + fromx += 1 + 26*x; fromy += 7*y; + if (!IS_WALL(levl[fromx][fromy].typ)) + impossible("down: no wall at %d,%d?",fromx, + fromy); + dodoor(fromx, fromy, &rooms[r[x][y].nroom]); + levl[fromx][fromy].doormask = D_NODOOR; + fromx++; + } + if(x >= 2) { + impossible("right door from %d,%d going nowhere?",x,y); + return; + } + x++; + r[x][y].doortable &= ~LEFT; + if (!r[x][y].real) { + tox = r[x][y].rlx; toy = r[x][y].rly; + tox += 1 + 26*x; toy += 7*y; + } else { + tox = r[x][y].rlx - 1; + toy = r[x][y].rly + rn2(r[x][y].dy); + tox += 1 + 26*x; toy += 7*y; + if (!IS_WALL(levl[tox][toy].typ)) + impossible("left: no wall at %d,%d?",tox,toy); + dodoor(tox, toy, &rooms[r[x][y].nroom]); + levl[tox][toy].doormask = D_NODOOR; + tox--; + } + roguejoin(fromx, fromy, tox, toy, TRUE); + return; + } else impossible("corridor in direction %d?",dir); +} + +/* Modified walkfrom() from mkmaze.c */ +STATIC_OVL +void +miniwalk(x, y) +int x,y; +{ + register int q, dir; + int dirs[4]; + + while(1) { + q = 0; +#define doorhere (r[x][y].doortable) + if (x>0 && (!(doorhere & LEFT)) && + (!r[x-1][y].doortable || !rn2(10))) + dirs[q++] = 0; + if (x<2 && (!(doorhere & RIGHT)) && + (!r[x+1][y].doortable || !rn2(10))) + dirs[q++] = 1; + if (y>0 && (!(doorhere & UP)) && + (!r[x][y-1].doortable || !rn2(10))) + dirs[q++] = 2; + if (y<2 && (!(doorhere & DOWN)) && + (!r[x][y+1].doortable || !rn2(10))) + dirs[q++] = 3; + /* Rogue levels aren't just 3 by 3 mazes; they have some extra + * connections, thus that 1/10 chance + */ + if (!q) return; + dir = dirs[rn2(q)]; + switch(dir) { /* Move in direction */ + case 0: doorhere |= LEFT; + x--; + doorhere |= RIGHT; + break; + case 1: doorhere |= RIGHT; + x++; + doorhere |= LEFT; + break; + case 2: doorhere |= UP; + y--; + doorhere |= DOWN; + break; + case 3: doorhere |= DOWN; + y++; + doorhere |= UP; + break; + } + miniwalk(x,y); + } +} + +void +makeroguerooms() { + register int x,y; + /* Rogue levels are structured 3 by 3, with each section containing + * a room or an intersection. The minimum width is 2 each way. + * One difference between these and "real" Rogue levels: real Rogue + * uses 24 rows and NetHack only 23. So we cheat a bit by making the + * second row of rooms not as deep. + * + * Each normal space has 6/7 rows and 25 columns in which a room may + * actually be placed. Walls go from rows 0-5/6 and columns 0-24. + * Not counting walls, the room may go in + * rows 1-5 and columns 1-23 (numbering starting at 0). A room + * coordinate of this type may be converted to a level coordinate + * by adding 1+28*x to the column, and 7*y to the row. (The 1 + * is because column 0 isn't used [we only use 1-78]). + * Room height may be 2-4 (2-5 on last row), length 2-23 (not + * counting walls) + */ +#define here r[x][y] + + nroom = 0; + for(y=0; y<3; y++) for(x=0; x<3; x++) { + /* Note: we want to insure at least 1 room. So, if the + * first 8 are all dummies, force the last to be a room. + */ + if (!rn2(5) && (nroom || (x<2 && y<2))) { + /* Arbitrary: dummy rooms may only go where real + * ones do. + */ + here.real = FALSE; + here.rlx = rn1(22, 2); + here.rly = rn1((y==2)?4:3, 2); + } else { + here.real = TRUE; + here.dx = rn1(22, 2); /* 2-23 long, plus walls */ + here.dy = rn1((y==2)?4:3, 2); /* 2-5 high, plus walls */ + + /* boundaries of room floor */ + here.rlx = rnd(23 - here.dx + 1); + here.rly = rnd(((y==2) ? 5 : 4)- here.dy + 1); + nroom++; + } + here.doortable = 0; + } + miniwalk(rn2(3), rn2(3)); + nroom = 0; + for(y=0; y<3; y++) for(x=0; x<3; x++) { + if (here.real) { /* Make a room */ + int lowx, lowy, hix, hiy; + + r[x][y].nroom = nroom; + smeq[nroom] = nroom; + + lowx = 1 + 26*x + here.rlx; + lowy = 7*y + here.rly; + hix = 1 + 26*x + here.rlx + here.dx - 1; + hiy = 7*y + here.rly + here.dy - 1; + /* Strictly speaking, it should be lit only if above + * level 10, but since Rogue rooms are only + * encountered below level 10, use !rn2(7). + */ + add_room(lowx, lowy, hix, hiy, + (boolean) !rn2(7), OROOM, FALSE); + } + } + + /* Now, add connecting corridors. */ + for(y=0; y<3; y++) for(x=0; x<3; x++) { + if (here.doortable & DOWN) + roguecorr(x, y, DOWN); + if (here.doortable & RIGHT) + roguecorr(x, y, RIGHT); + if (here.doortable & LEFT) + impossible ("left end of %d, %d never connected?",x,y); + if (here.doortable & UP) + impossible ("up end of %d, %d never connected?",x,y); + } +} + +void +corr(x,y) +int x, y; +{ + if (rn2(50)) { + levl[x][y].typ = CORR; + } else { + levl[x][y].typ = SCORR; + } +} + +void +makerogueghost() +{ + register struct monst *ghost; + struct obj *ghostobj; + struct mkroom *croom; + int x,y; + + if (!nroom) return; /* Should never happen */ + croom = &rooms[rn2(nroom)]; + x = somex(croom); y = somey(croom); + if (!(ghost = makemon(&mons[PM_GHOST], x, y, NO_MM_FLAGS))) + return; + ghost->msleeping = 1; + ghost = christen_monst(ghost, roguename()); + + if (rn2(4)) { + ghostobj = mksobj_at(FOOD_RATION, x, y, FALSE, FALSE); + ghostobj->quan = (long) rnd(7); + ghostobj->owt = weight(ghostobj); + } + if (rn2(2)) { + ghostobj = mksobj_at(MACE, x, y, FALSE, FALSE); + ghostobj->spe = rnd(3); + if (rn2(4)) curse(ghostobj); + } else { + ghostobj = mksobj_at(TWO_HANDED_SWORD, x, y, FALSE, FALSE); + ghostobj->spe = rnd(5) - 2; + if (rn2(4)) curse(ghostobj); + } + ghostobj = mksobj_at(BOW, x, y, FALSE, FALSE); + ghostobj->spe = 1; + if (rn2(4)) curse(ghostobj); + + ghostobj = mksobj_at(ARROW, x, y, FALSE, FALSE); + ghostobj->spe = 0; + ghostobj->quan = (long) rn1(10,25); + ghostobj->owt = weight(ghostobj); + if (rn2(4)) curse(ghostobj); + + if (rn2(2)) { + ghostobj = mksobj_at(RING_MAIL, x, y, FALSE, FALSE); + ghostobj->spe = rn2(3); + if (!rn2(3)) ghostobj->oerodeproof = TRUE; + if (rn2(4)) curse(ghostobj); + } else { + ghostobj = mksobj_at(PLATE_MAIL, x, y, FALSE, FALSE); + ghostobj->spe = rnd(5) - 2; + if (!rn2(3)) ghostobj->oerodeproof = TRUE; + if (rn2(4)) curse(ghostobj); + } + if (rn2(2)) { + ghostobj = mksobj_at(FAKE_AMULET_OF_YENDOR, x, y, TRUE, FALSE); + ghostobj->known = TRUE; + } +} +#endif /* REINCARNATION */ + +/*extralev.c*/