diff options
Diffstat (limited to 'games/hack/hack.mklev.c')
-rw-r--r-- | games/hack/hack.mklev.c | 741 |
1 files changed, 741 insertions, 0 deletions
diff --git a/games/hack/hack.mklev.c b/games/hack/hack.mklev.c new file mode 100644 index 0000000..8904021 --- /dev/null +++ b/games/hack/hack.mklev.c @@ -0,0 +1,741 @@ +/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ +/* hack.mklev.c - version 1.0.3 */ + +#include "hack.h" + +extern char *getlogin(), *getenv(); +extern struct monst *makemon(); +extern struct obj *mkobj_at(); +extern struct trap *maketrap(); + +#define somex() ((random()%(croom->hx-croom->lx+1))+croom->lx) +#define somey() ((random()%(croom->hy-croom->ly+1))+croom->ly) + +#include "def.mkroom.h" +#define XLIM 4 /* define minimum required space around a room */ +#define YLIM 3 +boolean secret; /* TRUE while making a vault: increase [XY]LIM */ +struct mkroom rooms[MAXNROFROOMS+1]; +int smeq[MAXNROFROOMS+1]; +coord doors[DOORMAX]; +int doorindex; +struct rm zerorm; +int comp(); +schar nxcor; +boolean goldseen; +int nroom; +xchar xdnstair,xupstair,ydnstair,yupstair; + +/* Definitions used by makerooms() and addrs() */ +#define MAXRS 50 /* max lth of temp rectangle table - arbitrary */ +struct rectangle { + xchar rlx,rly,rhx,rhy; +} rs[MAXRS+1]; +int rscnt,rsmax; /* 0..rscnt-1: currently under consideration */ + /* rscnt..rsmax: discarded */ + +makelevel() +{ + register struct mkroom *croom, *troom; + register unsigned tryct; + register x,y; + + nroom = 0; + doorindex = 0; + rooms[0].hx = -1; /* in case we are in a maze */ + + for(x=0; x<COLNO; x++) for(y=0; y<ROWNO; y++) + levl[x][y] = zerorm; + + oinit(); /* assign level dependent obj probabilities */ + + if(dlevel >= rn1(3, 26)) { /* there might be several mazes */ + makemaz(); + return; + } + + /* construct the rooms */ + nroom = 0; + secret = FALSE; + (void) makerooms(); + + /* construct stairs (up and down in different rooms if possible) */ + croom = &rooms[rn2(nroom)]; + xdnstair = somex(); + ydnstair = somey(); + levl[xdnstair][ydnstair].scrsym ='>'; + levl[xdnstair][ydnstair].typ = STAIRS; + if(nroom > 1) { + troom = croom; + croom = &rooms[rn2(nroom-1)]; + if(croom >= troom) croom++; + } + xupstair = somex(); /* %% < and > might be in the same place */ + yupstair = somey(); + levl[xupstair][yupstair].scrsym ='<'; + levl[xupstair][yupstair].typ = STAIRS; + + /* for each room: put things inside */ + for(croom = rooms; croom->hx > 0; croom++) { + + /* put a sleeping monster inside */ + /* Note: monster may be on the stairs. This cannot be + avoided: maybe the player fell through a trapdoor + while a monster was on the stairs. Conclusion: + we have to check for monsters on the stairs anyway. */ + if(!rn2(3)) (void) + makemon((struct permonst *) 0, somex(), somey()); + + /* put traps and mimics inside */ + goldseen = FALSE; + while(!rn2(8-(dlevel/6))) mktrap(0,0,croom); + if(!goldseen && !rn2(3)) mkgold(0L,somex(),somey()); + if(!rn2(3)) { + (void) mkobj_at(0, somex(), somey()); + tryct = 0; + while(!rn2(5)) { + if(++tryct > 100){ + printf("tryct overflow4\n"); + break; + } + (void) mkobj_at(0, somex(), somey()); + } + } + } + + qsort((char *) rooms, nroom, sizeof(struct mkroom), comp); + makecorridors(); + make_niches(); + + /* make a secret treasure vault, not connected to the rest */ + if(nroom <= (2*MAXNROFROOMS/3)) if(rn2(3)) { + troom = &rooms[nroom]; + secret = TRUE; + if(makerooms()) { + troom->rtype = VAULT; /* treasure vault */ + for(x = troom->lx; x <= troom->hx; x++) + for(y = troom->ly; y <= troom->hy; y++) + mkgold((long)(rnd(dlevel*100) + 50), x, y); + if(!rn2(3)) + makevtele(); + } + } + +#ifndef QUEST +#ifdef WIZARD + if(wizard && getenv("SHOPTYPE")) mkshop(); else +#endif WIZARD + if(dlevel > 1 && dlevel < 20 && rn2(dlevel) < 3) mkshop(); + else + if(dlevel > 6 && !rn2(7)) mkzoo(ZOO); + else + if(dlevel > 9 && !rn2(5)) mkzoo(BEEHIVE); + else + if(dlevel > 11 && !rn2(6)) mkzoo(MORGUE); + else + if(dlevel > 18 && !rn2(6)) mkswamp(); +#endif QUEST +} + +makerooms() { +register struct rectangle *rsp; +register int lx, ly, hx, hy, lowx, lowy, hix, hiy, dx, dy; +int tryct = 0, xlim, ylim; + + /* init */ + xlim = XLIM + secret; + ylim = YLIM + secret; + if(nroom == 0) { + rsp = rs; + rsp->rlx = rsp->rly = 0; + rsp->rhx = COLNO-1; + rsp->rhy = ROWNO-1; + rsmax = 1; + } + rscnt = rsmax; + + /* make rooms until satisfied */ + while(rscnt > 0 && nroom < MAXNROFROOMS-1) { + if(!secret && nroom > (MAXNROFROOMS/3) && + !rn2((MAXNROFROOMS-nroom)*(MAXNROFROOMS-nroom))) + return(0); + + /* pick a rectangle */ + rsp = &rs[rn2(rscnt)]; + hx = rsp->rhx; + hy = rsp->rhy; + lx = rsp->rlx; + ly = rsp->rly; + + /* find size of room */ + if(secret) + dx = dy = 1; + else { + dx = 2 + rn2((hx-lx-8 > 20) ? 12 : 8); + dy = 2 + rn2(4); + if(dx*dy > 50) + dy = 50/dx; + } + + /* look whether our room will fit */ + if(hx-lx < dx + dx/2 + 2*xlim || hy-ly < dy + dy/3 + 2*ylim) { + /* no, too small */ + /* maybe we throw this area out */ + if(secret || !rn2(MAXNROFROOMS+1-nroom-tryct)) { + rscnt--; + rs[rsmax] = *rsp; + *rsp = rs[rscnt]; + rs[rscnt] = rs[rsmax]; + tryct = 0; + } else + tryct++; + continue; + } + + lowx = lx + xlim + rn2(hx - lx - dx - 2*xlim + 1); + lowy = ly + ylim + rn2(hy - ly - dy - 2*ylim + 1); + hix = lowx + dx; + hiy = lowy + dy; + + if(maker(lowx, dx, lowy, dy)) { + if(secret) + return(1); + addrs(lowx-1, lowy-1, hix+1, hiy+1); + tryct = 0; + } else + if(tryct++ > 100) + break; + } + return(0); /* failed to make vault - very strange */ +} + +addrs(lowx,lowy,hix,hiy) +register int lowx,lowy,hix,hiy; +{ + register struct rectangle *rsp; + register int lx,ly,hx,hy,xlim,ylim; + boolean discarded; + + xlim = XLIM + secret; + ylim = YLIM + secret; + + /* walk down since rscnt and rsmax change */ + for(rsp = &rs[rsmax-1]; rsp >= rs; rsp--) { + + if((lx = rsp->rlx) > hix || (ly = rsp->rly) > hiy || + (hx = rsp->rhx) < lowx || (hy = rsp->rhy) < lowy) + continue; + if((discarded = (rsp >= &rs[rscnt]))) { + *rsp = rs[--rsmax]; + } else { + rsmax--; + rscnt--; + *rsp = rs[rscnt]; + if(rscnt != rsmax) + rs[rscnt] = rs[rsmax]; + } + if(lowy - ly > 2*ylim + 4) + addrsx(lx,ly,hx,lowy-2,discarded); + if(lowx - lx > 2*xlim + 4) + addrsx(lx,ly,lowx-2,hy,discarded); + if(hy - hiy > 2*ylim + 4) + addrsx(lx,hiy+2,hx,hy,discarded); + if(hx - hix > 2*xlim + 4) + addrsx(hix+2,ly,hx,hy,discarded); + } +} + +addrsx(lx,ly,hx,hy,discarded) +register int lx,ly,hx,hy; +boolean discarded; /* piece of a discarded area */ +{ + register struct rectangle *rsp; + + /* check inclusions */ + for(rsp = rs; rsp < &rs[rsmax]; rsp++) { + if(lx >= rsp->rlx && hx <= rsp->rhx && + ly >= rsp->rly && hy <= rsp->rhy) + return; + } + + /* make a new entry */ + if(rsmax >= MAXRS) { +#ifdef WIZARD + if(wizard) pline("MAXRS may be too small."); +#endif WIZARD + return; + } + rsmax++; + if(!discarded) { + *rsp = rs[rscnt]; + rsp = &rs[rscnt]; + rscnt++; + } + rsp->rlx = lx; + rsp->rly = ly; + rsp->rhx = hx; + rsp->rhy = hy; +} + +comp(x,y) +register struct mkroom *x,*y; +{ + if(x->lx < y->lx) return(-1); + return(x->lx > y->lx); +} + +coord +finddpos(xl,yl,xh,yh) { + coord ff; + register x,y; + + x = (xl == xh) ? xl : (xl + rn2(xh-xl+1)); + y = (yl == yh) ? yl : (yl + rn2(yh-yl+1)); + if(okdoor(x, y)) + goto gotit; + + for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++) + if(okdoor(x, y)) + goto gotit; + + for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++) + if(levl[x][y].typ == DOOR || levl[x][y].typ == SDOOR) + goto gotit; + /* cannot find something reasonable -- strange */ + x = xl; + y = yh; +gotit: + ff.x = x; + ff.y = y; + return(ff); +} + +/* see whether it is allowable to create a door at [x,y] */ +okdoor(x,y) +register x,y; +{ + if(levl[x-1][y].typ == DOOR || levl[x+1][y].typ == DOOR || + levl[x][y+1].typ == DOOR || levl[x][y-1].typ == DOOR || + levl[x-1][y].typ == SDOOR || levl[x+1][y].typ == SDOOR || + levl[x][y-1].typ == SDOOR || levl[x][y+1].typ == SDOOR || + (levl[x][y].typ != HWALL && levl[x][y].typ != VWALL) || + doorindex >= DOORMAX) + return(0); + return(1); +} + +dodoor(x,y,aroom) +register x,y; +register struct mkroom *aroom; +{ + if(doorindex >= DOORMAX) { + impossible("DOORMAX exceeded?"); + return; + } + if(!okdoor(x,y) && nxcor) + return; + dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR); +} + +dosdoor(x,y,aroom,type) +register x,y; +register struct mkroom *aroom; +register type; +{ + register struct mkroom *broom; + register tmp; + + if(!IS_WALL(levl[x][y].typ)) /* avoid SDOORs with '+' as scrsym */ + type = DOOR; + levl[x][y].typ = type; + if(type == DOOR) + levl[x][y].scrsym = '+'; + aroom->doorct++; + broom = aroom+1; + if(broom->hx < 0) tmp = doorindex; else + for(tmp = doorindex; tmp > broom->fdoor; tmp--) + doors[tmp] = doors[tmp-1]; + doorindex++; + doors[tmp].x = x; + doors[tmp].y = y; + for( ; broom->hx >= 0; broom++) broom->fdoor++; +} + +/* Only called from makerooms() */ +maker(lowx,ddx,lowy,ddy) +schar lowx,ddx,lowy,ddy; +{ + register struct mkroom *croom; + register x, y, hix = lowx+ddx, hiy = lowy+ddy; + register xlim = XLIM + secret, ylim = YLIM + secret; + + if(nroom >= MAXNROFROOMS) return(0); + if(lowx < XLIM) lowx = XLIM; + if(lowy < YLIM) lowy = YLIM; + if(hix > COLNO-XLIM-1) hix = COLNO-XLIM-1; + if(hiy > ROWNO-YLIM-1) hiy = ROWNO-YLIM-1; +chk: + if(hix <= lowx || hiy <= lowy) return(0); + + /* check area around room (and make room smaller if necessary) */ + for(x = lowx - xlim; x <= hix + xlim; x++) { + for(y = lowy - ylim; y <= hiy + ylim; y++) { + if(levl[x][y].typ) { +#ifdef WIZARD + if(wizard && !secret) + pline("Strange area [%d,%d] in maker().",x,y); +#endif WIZARD + if(!rn2(3)) return(0); + if(x < lowx) + lowx = x+xlim+1; + else + hix = x-xlim-1; + if(y < lowy) + lowy = y+ylim+1; + else + hiy = y-ylim-1; + goto chk; + } + } + } + + croom = &rooms[nroom]; + + /* on low levels the room is lit (usually) */ + /* secret vaults are always lit */ + if((rnd(dlevel) < 10 && rn2(77)) || (ddx == 1 && ddy == 1)) { + for(x = lowx-1; x <= hix+1; x++) + for(y = lowy-1; y <= hiy+1; y++) + levl[x][y].lit = 1; + croom->rlit = 1; + } else + croom->rlit = 0; + croom->lx = lowx; + croom->hx = hix; + croom->ly = lowy; + croom->hy = hiy; + croom->rtype = croom->doorct = croom->fdoor = 0; + + for(x = lowx-1; x <= hix+1; x++) + for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) { + levl[x][y].scrsym = '-'; + levl[x][y].typ = HWALL; + } + for(x = lowx-1; x <= hix+1; x += (hix-lowx+2)) + for(y = lowy; y <= hiy; y++) { + levl[x][y].scrsym = '|'; + levl[x][y].typ = VWALL; + } + for(x = lowx; x <= hix; x++) + for(y = lowy; y <= hiy; y++) { + levl[x][y].scrsym = '.'; + levl[x][y].typ = ROOM; + } + + smeq[nroom] = nroom; + croom++; + croom->hx = -1; + nroom++; + return(1); +} + +makecorridors() { + register a,b; + + nxcor = 0; + for(a = 0; a < nroom-1; a++) + join(a, a+1); + for(a = 0; a < nroom-2; a++) + if(smeq[a] != smeq[a+2]) + join(a, a+2); + for(a = 0; a < nroom; a++) + for(b = 0; b < nroom; b++) + if(smeq[a] != smeq[b]) + join(a, b); + if(nroom > 2) + for(nxcor = rn2(nroom) + 4; nxcor; nxcor--) { + a = rn2(nroom); + b = rn2(nroom-2); + if(b >= a) b += 2; + join(a, b); + } +} + +join(a,b) +register a,b; +{ + coord cc,tt; + register tx, ty, xx, yy; + register struct rm *crm; + register struct mkroom *croom, *troom; + register dx, dy, dix, diy, cct; + + croom = &rooms[a]; + troom = &rooms[b]; + + /* find positions cc and tt for doors in croom and troom + and direction for a corridor between them */ + + if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return; + if(troom->lx > croom->hx) { + dx = 1; + dy = 0; + xx = croom->hx+1; + tx = troom->lx-1; + cc = finddpos(xx,croom->ly,xx,croom->hy); + tt = finddpos(tx,troom->ly,tx,troom->hy); + } else if(troom->hy < croom->ly) { + dy = -1; + dx = 0; + yy = croom->ly-1; + cc = finddpos(croom->lx,yy,croom->hx,yy); + ty = troom->hy+1; + tt = finddpos(troom->lx,ty,troom->hx,ty); + } else if(troom->hx < croom->lx) { + dx = -1; + dy = 0; + xx = croom->lx-1; + tx = troom->hx+1; + cc = finddpos(xx,croom->ly,xx,croom->hy); + tt = finddpos(tx,troom->ly,tx,troom->hy); + } else { + dy = 1; + dx = 0; + yy = croom->hy+1; + ty = troom->ly-1; + cc = finddpos(croom->lx,yy,croom->hx,yy); + tt = finddpos(troom->lx,ty,troom->hx,ty); + } + xx = cc.x; + yy = cc.y; + tx = tt.x - dx; + ty = tt.y - dy; + if(nxcor && levl[xx+dx][yy+dy].typ) + return; + dodoor(xx,yy,croom); + + cct = 0; + while(xx != tx || yy != ty) { + xx += dx; + yy += dy; + + /* loop: dig corridor at [xx,yy] and find new [xx,yy] */ + if(cct++ > 500 || (nxcor && !rn2(35))) + return; + + if(xx == COLNO-1 || xx == 0 || yy == 0 || yy == ROWNO-1) + return; /* impossible */ + + crm = &levl[xx][yy]; + if(!(crm->typ)) { + if(rn2(100)) { + crm->typ = CORR; + crm->scrsym = CORR_SYM; + if(nxcor && !rn2(50)) + (void) mkobj_at(ROCK_SYM, xx, yy); + } else { + crm->typ = SCORR; + crm->scrsym = ' '; + } + } else + if(crm->typ != CORR && crm->typ != SCORR) { + /* strange ... */ + return; + } + + /* find next corridor position */ + dix = abs(xx-tx); + diy = abs(yy-ty); + + /* do we have to change direction ? */ + if(dy && dix > diy) { + register ddx = (xx > tx) ? -1 : 1; + + crm = &levl[xx+ddx][yy]; + if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) { + dx = ddx; + dy = 0; + continue; + } + } else if(dx && diy > dix) { + register ddy = (yy > ty) ? -1 : 1; + + crm = &levl[xx][yy+ddy]; + if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) { + dy = ddy; + dx = 0; + continue; + } + } + + /* continue straight on? */ + crm = &levl[xx+dx][yy+dy]; + if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) + continue; + + /* no, what must we do now?? */ + if(dx) { + dx = 0; + dy = (ty < yy) ? -1 : 1; + crm = &levl[xx+dx][yy+dy]; + if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) + continue; + dy = -dy; + continue; + } else { + dy = 0; + dx = (tx < xx) ? -1 : 1; + crm = &levl[xx+dx][yy+dy]; + if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) + continue; + dx = -dx; + continue; + } + } + + /* we succeeded in digging the corridor */ + dodoor(tt.x, tt.y, troom); + + if(smeq[a] < smeq[b]) + smeq[b] = smeq[a]; + else + smeq[a] = smeq[b]; +} + +make_niches() +{ + register int ct = rnd(nroom/2 + 1); + while(ct--) makeniche(FALSE); +} + +makevtele() +{ + makeniche(TRUE); +} + +makeniche(with_trap) +boolean with_trap; +{ + register struct mkroom *aroom; + register struct rm *rm; + register int vct = 8; + coord dd; + register dy,xx,yy; + register struct trap *ttmp; + + if(doorindex < DOORMAX) + while(vct--) { + aroom = &rooms[rn2(nroom-1)]; + if(aroom->rtype != 0) continue; /* not an ordinary room */ + if(aroom->doorct == 1 && rn2(5)) continue; + if(rn2(2)) { + dy = 1; + dd = finddpos(aroom->lx,aroom->hy+1,aroom->hx,aroom->hy+1); + } else { + dy = -1; + dd = finddpos(aroom->lx,aroom->ly-1,aroom->hx,aroom->ly-1); + } + xx = dd.x; + yy = dd.y; + if((rm = &levl[xx][yy+dy])->typ) continue; + if(with_trap || !rn2(4)) { + rm->typ = SCORR; + rm->scrsym = ' '; + if(with_trap) { + ttmp = maketrap(xx, yy+dy, TELEP_TRAP); + ttmp->once = 1; + make_engr_at(xx, yy-dy, "ad ae?ar um"); + } + dosdoor(xx, yy, aroom, SDOOR); + } else { + rm->typ = CORR; + rm->scrsym = CORR_SYM; + if(rn2(7)) + dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR); + else { + mksobj_at(SCR_TELEPORTATION, xx, yy+dy); + if(!rn2(3)) (void) mkobj_at(0, xx, yy+dy); + } + } + return; + } +} + +/* make a trap somewhere (in croom if mazeflag = 0) */ +mktrap(num,mazeflag,croom) +register num,mazeflag; +register struct mkroom *croom; +{ + register struct trap *ttmp; + register int kind,nopierc,nomimic,fakedoor,fakegold,tryct = 0; + register xchar mx,my; + extern char fut_geno[]; + + if(!num || num >= TRAPNUM) { + nopierc = (dlevel < 4) ? 1 : 0; + nomimic = (dlevel < 9 || goldseen ) ? 1 : 0; + if(index(fut_geno, 'M')) nomimic = 1; + kind = rn2(TRAPNUM - nopierc - nomimic); + /* note: PIERC = 7, MIMIC = 8, TRAPNUM = 9 */ + } else kind = num; + + if(kind == MIMIC) { + register struct monst *mtmp; + + fakedoor = (!rn2(3) && !mazeflag); + fakegold = (!fakedoor && !rn2(2)); + if(fakegold) goldseen = TRUE; + do { + if(++tryct > 200) return; + if(fakedoor) { + /* note: fakedoor maybe on actual door */ + if(rn2(2)){ + if(rn2(2)) + mx = croom->hx+1; + else mx = croom->lx-1; + my = somey(); + } else { + if(rn2(2)) + my = croom->hy+1; + else my = croom->ly-1; + mx = somex(); + } + } else if(mazeflag) { + extern coord mazexy(); + coord mm; + mm = mazexy(); + mx = mm.x; + my = mm.y; + } else { + mx = somex(); + my = somey(); + } + } while(m_at(mx,my) || levl[mx][my].typ == STAIRS); + if(mtmp = makemon(PM_MIMIC,mx,my)) { + mtmp->mimic = 1; + mtmp->mappearance = + fakegold ? '$' : fakedoor ? '+' : + (mazeflag && rn2(2)) ? AMULET_SYM : + "=/)%?![<>" [ rn2(9) ]; + } + return; + } + + do { + if(++tryct > 200) + return; + if(mazeflag){ + extern coord mazexy(); + coord mm; + mm = mazexy(); + mx = mm.x; + my = mm.y; + } else { + mx = somex(); + my = somey(); + } + } while(t_at(mx, my) || levl[mx][my].typ == STAIRS); + ttmp = maketrap(mx, my, kind); + if(mazeflag && !rn2(10) && ttmp->ttyp < PIERC) + ttmp->tseen = 1; +} |