Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!uunet!tektronix!tekgen!tekred!games-request
From: games-request@tekred.TEK.COM
Newsgroups: comp.sources.games
Subject: v03i007: NetHack2.2 - display oriented dungeons and dragons, Part07/20
Message-ID: <1890@tekred.TEK.COM>
Date: Tue, 1-Dec-87 19:40:42 EST
Article-I.D.: tekred.1890
Posted: Tue Dec 1 19:40:42 1987
Date-Received: Sat, 5-Dec-87 09:31:13 EST
Sender: billr@tekred.TEK.COM
Lines: 2251
Approved: billr@tekred.TEK.COM
Submitted by: mike@genat.UUCP (Mike Stephenson)
Comp.sources.games: Volume 3, Issue 7
Archive-name: nethack2.2/Part07
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh mklev.c <<'END_OF_mklev.c'
X/* SCCS Id: @(#)mklev.c 2.1 87/09/23
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X
X#include "hack.h"
X
Xextern char *getlogin(), *getenv();
Xextern struct monst *makemon();
Xextern struct obj *mkobj_at();
Xextern struct trap *maketrap();
X
X#ifdef RPH
Xextern struct permonst pm_medusa;
X#endif
X
X#define somex() ((rand()%(croom->hx-croom->lx+1))+croom->lx)
X#define somey() ((rand()%(croom->hy-croom->ly+1))+croom->ly)
X
X#include "mkroom.h"
X#define XLIM 4 /* define minimum required space around a room */
X#define YLIM 3
Xboolean secret; /* TRUE while making a vault: increase [XY]LIM */
Xextern struct mkroom rooms[MAXNROFROOMS+1];
Xint smeq[MAXNROFROOMS+1];
Xextern coord doors[DOORMAX];
Xint doorindex;
Xstruct rm zerorm;
Xint comp();
Xschar nxcor;
Xboolean goldseen;
Xint nroom;
Xextern xchar xdnstair,xupstair,ydnstair,yupstair;
X
X/* Definitions used by makerooms() and addrs() */
X#define MAXRS 50 /* max lth of temp rectangle table - arbitrary */
Xstruct rectangle {
X xchar rlx,rly,rhx,rhy;
X} rs[MAXRS+1];
Xint rscnt,rsmax; /* 0..rscnt-1: currently under consideration */
X /* rscnt..rsmax: discarded */
X
Xmakelevel()
X{
X register struct mkroom *croom, *troom;
X register unsigned tryct;
X#ifndef REGBUG
X register
X#endif
X int x,y;
X#ifdef SPIDERS /* always put a web with a spider */
X struct monst *tmonst;
X#endif
X
X nroom = 0;
X doorindex = 0;
X rooms[0].hx = -1; /* in case we are in a maze */
X
X for(x=0; x u.medusa_level) {
X makemaz();
X return;
X }
X#else
X if(dlevel >= rn1(3, 26)) { /* there might be several mazes */
X makemaz();
X return;
X }
X#endif
X /* construct the rooms */
X nroom = 0;
X secret = FALSE;
X (void) makerooms();
X
X /* construct stairs (up and down in different rooms if possible) */
X croom = &rooms[rn2(nroom)];
X xdnstair = somex();
X ydnstair = somey();
X levl[xdnstair][ydnstair].scrsym = DN_SYM;
X levl[xdnstair][ydnstair].typ = STAIRS;
X#ifdef RPH
X { struct monst *mtmp;
X if (dlevel == u.medusa_level)
X if (mtmp = makemon(PM_MEDUSA, xdnstair, ydnstair))
X mtmp->msleep = 1;
X }
X#endif
X if(nroom > 1) {
X troom = croom;
X croom = &rooms[rn2(nroom-1)];
X if(croom >= troom) croom++;
X }
X xupstair = somex(); /* %% < and > might be in the same place */
X yupstair = somey();
X levl[xupstair][yupstair].scrsym = UP_SYM;
X levl[xupstair][yupstair].typ = STAIRS;
X
X /* for each room: put things inside */
X for(croom = rooms; croom->hx > 0; croom++) {
X
X /* put a sleeping monster inside */
X /* Note: monster may be on the stairs. This cannot be
X avoided: maybe the player fell through a trapdoor
X while a monster was on the stairs. Conclusion:
X we have to check for monsters on the stairs anyway. */
X#ifdef BVH
X if(has_amulet() || !rn2(3))
X#else
X if (!rn2(3))
X#endif
X#ifndef SPIDERS
X (void)makemon((struct permonst *) 0, somex(), somey());
X#else
X {
X x = somex(); y = somey();
X tmonst=makemon((struct permonst *) 0, x,y);
X if (tmonst && tmonst->data->mlet == 's')
X (void) maketrap (x,y,WEB);
X }
X#endif
X /* put traps and mimics inside */
X goldseen = FALSE;
X while(!rn2(8-(dlevel/6))) mktrap(0,0,croom);
X if(!goldseen && !rn2(3)) mkgold(0L,somex(),somey());
X#ifdef FOUNTAINS
X if(!rn2(10)) mkfount(0,croom);
X#endif
X if(!rn2(3)) {
X (void) mkobj_at(0, somex(), somey());
X tryct = 0;
X while(!rn2(5)) {
X if(++tryct > 100){
X printf("tryct overflow4\n");
X break;
X }
X (void) mkobj_at(0, somex(), somey());
X }
X }
X }
X
X qsort((char *) rooms, nroom, sizeof(struct mkroom), comp);
X makecorridors();
X make_niches();
X
X /* make a secret treasure vault, not connected to the rest */
X if(nroom <= (2*MAXNROFROOMS/3)) if(rn2(3)) {
X troom = &rooms[nroom];
X secret = TRUE;
X if(makerooms()) {
X troom->rtype = VAULT; /* treasure vault */
X for(x = troom->lx; x <= troom->hx; x++)
X for(y = troom->ly; y <= troom->hy; y++)
X mkgold((long)(rnd(dlevel*100) + 50), x, y);
X if(!rn2(3))
X makevtele();
X }
X }
X
X#ifdef WIZARD
X if(wizard && getenv("SHOPTYPE")) mkshop(); else
X#endif
X if(dlevel > 1 && dlevel < 20 && rn2(dlevel) < 3) mkshop();
X else
X#ifdef NEWCLASS
X if(dlevel > 4 && !rn2(6)) mkzoo(COURT);
X#endif
X if(dlevel > 6 && !rn2(7)) mkzoo(ZOO);
X else
X if(dlevel > 9 && !rn2(5)) mkzoo(BEEHIVE);
X else
X if(dlevel > 11 && !rn2(6)) mkzoo(MORGUE);
X else
X if(dlevel > 18 && !rn2(6)) mkswamp();
X}
X
Xmakerooms() {
Xregister struct rectangle *rsp;
Xregister int lx, ly, hx, hy, lowx, lowy, hix, hiy, dx, dy;
Xint tryct = 0, xlim, ylim;
X
X /* init */
X xlim = XLIM + secret;
X ylim = YLIM + secret;
X if(nroom == 0) {
X rsp = rs;
X rsp->rlx = rsp->rly = 0;
X rsp->rhx = COLNO-1;
X rsp->rhy = ROWNO-1;
X rsmax = 1;
X }
X rscnt = rsmax;
X
X /* make rooms until satisfied */
X while(rscnt > 0 && nroom < MAXNROFROOMS-1) {
X if(!secret && nroom > (MAXNROFROOMS/3) &&
X !rn2((MAXNROFROOMS-nroom)*(MAXNROFROOMS-nroom)))
X return(0);
X
X /* pick a rectangle */
X rsp = &rs[rn2(rscnt)];
X hx = rsp->rhx;
X hy = rsp->rhy;
X lx = rsp->rlx;
X ly = rsp->rly;
X
X /* find size of room */
X if(secret)
X dx = dy = 1;
X else {
X dx = 2 + rn2((hx-lx-8 > 20) ? 12 : 8);
X dy = 2 + rn2(4);
X if(dx*dy > 50)
X dy = 50/dx;
X }
X
X /* look whether our room will fit */
X if(hx-lx < dx + dx/2 + 2*xlim || hy-ly < dy + dy/3 + 2*ylim) {
X /* no, too small */
X /* maybe we throw this area out */
X if(secret || !rn2(MAXNROFROOMS+1-nroom-tryct)) {
X rscnt--;
X rs[rsmax] = *rsp;
X *rsp = rs[rscnt];
X rs[rscnt] = rs[rsmax];
X tryct = 0;
X } else
X tryct++;
X continue;
X }
X
X lowx = lx + xlim + rn2(hx - lx - dx - 2*xlim + 1);
X lowy = ly + ylim + rn2(hy - ly - dy - 2*ylim + 1);
X hix = lowx + dx;
X hiy = lowy + dy;
X
X if(maker(lowx, dx, lowy, dy)) {
X if(secret) return(1);
X addrs(lowx-1, lowy-1, hix+1, hiy+1);
X tryct = 0;
X } else
X if(tryct++ > 100)
X break;
X }
X return(0); /* failed to make vault - very strange */
X}
X
Xaddrs(lowx,lowy,hix,hiy)
Xregister int lowx,lowy,hix,hiy;
X{
X register struct rectangle *rsp;
X register int lx,ly,hx,hy,xlim,ylim;
X boolean discarded;
X
X xlim = XLIM + secret;
X ylim = YLIM + secret;
X
X /* walk down since rscnt and rsmax change */
X for(rsp = &rs[rsmax-1]; rsp >= rs; rsp--) {
X
X if((lx = rsp->rlx) > hix || (ly = rsp->rly) > hiy ||
X (hx = rsp->rhx) < lowx || (hy = rsp->rhy) < lowy)
X continue;
X if((discarded = (rsp >= &rs[rscnt]))) {
X *rsp = rs[--rsmax];
X } else {
X rsmax--;
X rscnt--;
X *rsp = rs[rscnt];
X if(rscnt != rsmax)
X rs[rscnt] = rs[rsmax];
X }
X if(lowy - ly > 2*ylim + 4)
X addrsx(lx,ly,hx,lowy-2,discarded);
X if(lowx - lx > 2*xlim + 4)
X addrsx(lx,ly,lowx-2,hy,discarded);
X if(hy - hiy > 2*ylim + 4)
X addrsx(lx,hiy+2,hx,hy,discarded);
X if(hx - hix > 2*xlim + 4)
X addrsx(hix+2,ly,hx,hy,discarded);
X }
X}
X
Xaddrsx(lx,ly,hx,hy,discarded)
Xregister int lx,ly,hx,hy;
Xboolean discarded; /* piece of a discarded area */
X{
X register struct rectangle *rsp;
X
X /* check inclusions */
X for(rsp = rs; rsp < &rs[rsmax]; rsp++) {
X if(lx >= rsp->rlx && hx <= rsp->rhx &&
X ly >= rsp->rly && hy <= rsp->rhy)
X return;
X }
X
X /* make a new entry */
X if(rsmax >= MAXRS) {
X#ifdef WIZARD
X if(wizard) pline("MAXRS may be too small.");
X#endif
X return;
X }
X rsmax++;
X if(!discarded) {
X *rsp = rs[rscnt];
X rsp = &rs[rscnt];
X rscnt++;
X }
X rsp->rlx = lx;
X rsp->rly = ly;
X rsp->rhx = hx;
X rsp->rhy = hy;
X}
X
Xcomp(x,y)
Xregister struct mkroom *x,*y;
X{
X if(x->lx < y->lx) return(-1);
X return(x->lx > y->lx);
X}
X
Xfinddpos(cc, xl,yl,xh,yh)
Xcoord *cc;
Xint xl,yl,xh,yh;
X{
X register x,y;
X
X x = (xl == xh) ? xl : (xl + rn2(xh-xl+1));
X y = (yl == yh) ? yl : (yl + rn2(yh-yl+1));
X if(okdoor(x, y))
X goto gotit;
X
X for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
X if(okdoor(x, y))
X goto gotit;
X
X for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
X if(levl[x][y].typ == DOOR || levl[x][y].typ == SDOOR)
X goto gotit;
X /* cannot find something reasonable -- strange */
X x = xl;
X y = yh;
Xgotit:
X cc->x = x;
X cc->y = y;
X return(0);
X}
X
X/* see whether it is allowable to create a door at [x,y] */
Xokdoor(x,y)
Xregister x,y;
X{
X if(levl[x-1][y].typ == DOOR || levl[x+1][y].typ == DOOR ||
X levl[x][y+1].typ == DOOR || levl[x][y-1].typ == DOOR ||
X levl[x-1][y].typ == SDOOR || levl[x+1][y].typ == SDOOR ||
X levl[x][y-1].typ == SDOOR || levl[x][y+1].typ == SDOOR ||
X (levl[x][y].typ != HWALL && levl[x][y].typ != VWALL) ||
X doorindex >= DOORMAX)
X return(0);
X return(1);
X}
X
Xdodoor(x,y,aroom)
Xregister x,y;
Xregister struct mkroom *aroom;
X{
X if(doorindex >= DOORMAX) {
X impossible("DOORMAX exceeded?");
X return;
X }
X if(!okdoor(x,y) && nxcor)
X return;
X dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR);
X}
X
Xdosdoor(x,y,aroom,type)
Xregister x,y;
Xregister struct mkroom *aroom;
Xregister type;
X{
X register struct mkroom *broom;
X register tmp;
X
X if(!IS_WALL(levl[x][y].typ)) /* avoid SDOORs with DOOR_SYM as scrsym */
X type = DOOR;
X levl[x][y].typ = type;
X if(type == DOOR)
X levl[x][y].scrsym = DOOR_SYM;
X aroom->doorct++;
X broom = aroom+1;
X if(broom->hx < 0) tmp = doorindex; else
X for(tmp = doorindex; tmp > broom->fdoor; tmp--)
X doors[tmp] = doors[tmp-1];
X doorindex++;
X doors[tmp].x = x;
X doors[tmp].y = y;
X for( ; broom->hx >= 0; broom++) broom->fdoor++;
X}
X
X/* Only called from makerooms() */
Xmaker(lowx,ddx,lowy,ddy)
Xschar lowx,ddx,lowy,ddy;
X{
X register struct mkroom *croom;
X register x, y, hix = lowx+ddx, hiy = lowy+ddy;
X register xlim = XLIM + secret, ylim = YLIM + secret;
X
X if(nroom >= MAXNROFROOMS) return(0);
X if(lowx < XLIM) lowx = XLIM;
X if(lowy < YLIM) lowy = YLIM;
X if(hix > COLNO-XLIM-1) hix = COLNO-XLIM-1;
X if(hiy > ROWNO-YLIM-1) hiy = ROWNO-YLIM-1;
Xchk:
X if(hix <= lowx || hiy <= lowy) return(0);
X
X /* check area around room (and make room smaller if necessary) */
X for(x = lowx - xlim; x <= hix + xlim; x++) {
X for(y = lowy - ylim; y <= hiy + ylim; y++) {
X if(levl[x][y].typ) {
X#ifdef WIZARD
X if(wizard && !secret)
X pline("Strange area [%d,%d] in maker().",x,y);
X#endif
X if(!rn2(3)) return(0);
X if(x < lowx)
X lowx = x+xlim+1;
X else
X hix = x-xlim-1;
X if(y < lowy)
X lowy = y+ylim+1;
X else
X hiy = y-ylim-1;
X goto chk;
X }
X }
X }
X
X croom = &rooms[nroom];
X
X /* on low levels the room is lit (usually) */
X /* secret vaults are always lit */
X if((rnd(dlevel) < 10 && rn2(77)) || (ddx == 1 && ddy == 1)) {
X for(x = lowx-1; x <= hix+1; x++)
X for(y = lowy-1; y <= hiy+1; y++)
X levl[x][y].lit = 1;
X croom->rlit = 1;
X } else
X croom->rlit = 0;
X croom->lx = lowx;
X croom->hx = hix;
X croom->ly = lowy;
X croom->hy = hiy;
X croom->rtype = OROOM;
X croom->doorct = croom->fdoor = 0;
X
X for(x = lowx-1; x <= hix+1; x++)
X for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
X levl[x][y].scrsym = HWALL_SYM;
X levl[x][y].typ = HWALL;
X }
X for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
X for(y = lowy; y <= hiy; y++) {
X levl[x][y].scrsym = VWALL_SYM;
X levl[x][y].typ = VWALL;
X }
X for(x = lowx; x <= hix; x++)
X for(y = lowy; y <= hiy; y++) {
X levl[x][y].scrsym = ROOM_SYM;
X levl[x][y].typ = ROOM;
X }
X levl[lowx-1][lowy-1].scrsym = TLCORN_SYM;
X levl[hix+1][lowy-1].scrsym = TRCORN_SYM;
X levl[lowx-1][hiy+1].scrsym = BLCORN_SYM;
X levl[hix+1][hiy+1].scrsym = BRCORN_SYM;
X
X smeq[nroom] = nroom;
X croom++;
X croom->hx = -1;
X nroom++;
X return(1);
X}
X
Xmakecorridors() {
X register a,b;
X
X nxcor = 0;
X for(a = 0; a < nroom-1; a++)
X join(a, a+1);
X for(a = 0; a < nroom-2; a++)
X if(smeq[a] != smeq[a+2])
X join(a, a+2);
X for(a = 0; a < nroom; a++)
X for(b = 0; b < nroom; b++)
X if(smeq[a] != smeq[b])
X join(a, b);
X if(nroom > 2)
X for(nxcor = rn2(nroom) + 4; nxcor; nxcor--) {
X a = rn2(nroom);
X b = rn2(nroom-2);
X if(b >= a) b += 2;
X join(a, b);
X }
X}
X
Xjoin(a,b)
Xregister a,b;
X{
X coord cc,tt;
X register tx, ty, xx, yy;
X register struct rm *crm;
X register struct mkroom *croom, *troom;
X register dx, dy, dix, diy, cct;
X
X croom = &rooms[a];
X troom = &rooms[b];
X
X /* find positions cc and tt for doors in croom and troom
X and direction for a corridor between them */
X
X if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return;
X if(troom->lx > croom->hx) {
X dx = 1;
X dy = 0;
X xx = croom->hx+1;
X tx = troom->lx-1;
X finddpos(&cc, xx, croom->ly, xx, croom->hy);
X finddpos(&tt, tx, troom->ly, tx, troom->hy);
X } else if(troom->hy < croom->ly) {
X dy = -1;
X dx = 0;
X yy = croom->ly-1;
X finddpos(&cc, croom->lx, yy, croom->hx, yy);
X ty = troom->hy+1;
X finddpos(&tt, troom->lx, ty, troom->hx, ty);
X } else if(troom->hx < croom->lx) {
X dx = -1;
X dy = 0;
X xx = croom->lx-1;
X tx = troom->hx+1;
X finddpos(&cc, xx, croom->ly, xx, croom->hy);
X finddpos(&tt, tx, troom->ly, tx, troom->hy);
X } else {
X dy = 1;
X dx = 0;
X yy = croom->hy+1;
X ty = troom->ly-1;
X finddpos(&cc, croom->lx, yy, croom->hx, yy);
X finddpos(&tt, troom->lx, ty, troom->hx, ty);
X }
X xx = cc.x;
X yy = cc.y;
X tx = tt.x - dx;
X ty = tt.y - dy;
X if(nxcor && levl[xx+dx][yy+dy].typ)
X return;
X dodoor(xx,yy,croom);
X
X cct = 0;
X while(xx != tx || yy != ty) {
X xx += dx;
X yy += dy;
X
X /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
X if(cct++ > 500 || (nxcor && !rn2(35)))
X return;
X
X if(xx == COLNO-1 || xx == 0 || yy == 0 || yy == ROWNO-1)
X return; /* impossible */
X
X crm = &levl[xx][yy];
X if(!(crm->typ)) {
X if(rn2(100)) {
X crm->typ = CORR;
X crm->scrsym = CORR_SYM;
X if(nxcor && !rn2(50))
X (void) mkobj_at(ROCK_SYM, xx, yy);
X } else {
X crm->typ = SCORR;
X crm->scrsym = STONE_SYM;
X }
X } else
X if(crm->typ != CORR && crm->typ != SCORR) {
X /* strange ... */
X return;
X }
X
X /* find next corridor position */
X dix = abs(xx-tx);
X diy = abs(yy-ty);
X
X /* do we have to change direction ? */
X if(dy && dix > diy) {
X register ddx = (xx > tx) ? -1 : 1;
X
X crm = &levl[xx+ddx][yy];
X if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) {
X dx = ddx;
X dy = 0;
X continue;
X }
X } else if(dx && diy > dix) {
X register ddy = (yy > ty) ? -1 : 1;
X
X crm = &levl[xx][yy+ddy];
X if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) {
X dy = ddy;
X dx = 0;
X continue;
X }
X }
X
X /* continue straight on? */
X crm = &levl[xx+dx][yy+dy];
X if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
X continue;
X
X /* no, what must we do now?? */
X if(dx) {
X dx = 0;
X dy = (ty < yy) ? -1 : 1;
X crm = &levl[xx+dx][yy+dy];
X if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
X continue;
X dy = -dy;
X continue;
X } else {
X dy = 0;
X dx = (tx < xx) ? -1 : 1;
X crm = &levl[xx+dx][yy+dy];
X if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
X continue;
X dx = -dx;
X continue;
X }
X }
X
X /* we succeeded in digging the corridor */
X dodoor(tt.x, tt.y, troom);
X
X if(smeq[a] < smeq[b])
X smeq[b] = smeq[a];
X else
X smeq[a] = smeq[b];
X}
X
Xmake_niches()
X{
X register int ct = rnd(nroom/2 + 1);
X#ifdef NEWCLASS
X boolean ltptr = TRUE,
X vamp = TRUE;
X
X while(ct--) {
X
X if(dlevel > 15 && !rn2(6) && ltptr) {
X
X ltptr = FALSE;
X makeniche(LEVEL_TELEP);
X } else if (dlevel > 5 && dlevel < 25
X && !rn2(6) && vamp) {
X
X vamp = FALSE;
X makeniche(TRAPDOOR);
X } else makeniche(NO_TRAP);
X }
X#else
X while(ct--) makeniche(NO_TRAP);
X#endif
X}
X
Xmakevtele()
X{
X makeniche(TELEP_TRAP);
X}
X
X/* there should be one of these per trap */
Xchar *engravings[] = { "", "", "", "", "",
X "ad ae?ar um", "?la? ?as ?er?",
X "", "", ""
X#ifdef NEWTRAPS
X ,"", ""
X#endif
X#ifdef SPIDERS
X ,""
X#endif
X#ifdef NEWCLASS
X , "", "ad ae?ar um"
X#endif
X#ifdef SPELLS
X ,""
X#endif
X };
X
Xmakeniche(trap_type)
Xint trap_type;
X{
X register struct mkroom *aroom;
X register struct rm *rm;
X register int vct = 8;
X coord dd;
X register dy,xx,yy;
X register struct trap *ttmp;
X
X if(doorindex < DOORMAX)
X while(vct--) {
X aroom = &rooms[rn2(nroom-1)];
X if(aroom->rtype != OROOM) continue; /* not an ordinary room */
X if(aroom->doorct == 1 && rn2(5)) continue;
X if(rn2(2)) {
X dy = 1;
X finddpos(&dd, aroom->lx, aroom->hy+1, aroom->hx, aroom->hy+1);
X } else {
X dy = -1;
X finddpos(&dd, aroom->lx, aroom->ly-1, aroom->hx, aroom->ly-1);
X }
X xx = dd.x;
X yy = dd.y;
X if((rm = &levl[xx][yy+dy])->typ) continue;
X if(trap_type || !rn2(4)) {
X
X rm->typ = SCORR;
X rm->scrsym = STONE_SYM;
X if(trap_type) {
X ttmp = maketrap(xx, yy+dy, trap_type);
X ttmp->once = 1;
X if (strlen(engravings[trap_type]) > 0)
X make_engr_at(xx, yy-dy, engravings[trap_type]);
X }
X dosdoor(xx, yy, aroom, SDOOR);
X } else {
X rm->typ = CORR;
X rm->scrsym = CORR_SYM;
X if(rn2(7))
X dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
X else {
X mksobj_at(SCR_TELEPORTATION, xx, yy+dy);
X if(!rn2(3)) (void) mkobj_at(0, xx, yy+dy);
X }
X }
X return;
X }
X}
X
X/* make a trap somewhere (in croom if mazeflag = 0) */
Xmktrap(num, mazeflag, croom)
X#ifndef REGBUG
Xregister
X#endif
X int num, mazeflag;
X#ifndef REGBUG
Xregister
X#endif
X struct mkroom *croom;
X{
X#ifndef REGBUG
X register
X#endif
X struct trap *ttmp;
X#ifndef REGBUG
X register
X#endif
X int kind,nopierc,nomimic,fakedoor,fakegold,
X#ifdef SPIDERS
X nospider,
X#endif
X#ifdef NEWCLASS
X nospikes, nolevltp,
X#endif
X tryct = 0;
X
X xchar mx,my;
X extern char fut_geno[];
X
X if(!num || num >= TRAPNUM) {
X nopierc = (dlevel < 4) ? 1 : 0;
X#ifdef NEWCLASS
X nolevltp = (dlevel < 5) ? 1 : 0;
X nospikes = (dlevel < 6) ? 1 : 0;
X#endif
X#ifdef SPIDERS
X nospider = (dlevel < 7) ? 1 : 0;
X#endif
X nomimic = (dlevel < 9 || goldseen ) ? 1 : 0;
X if(index(fut_geno, 'M')) nomimic = 1;
X
X do {
X kind = rnd(TRAPNUM-1);
X if((kind == PIERC && nopierc) ||
X (kind == MIMIC && nomimic)
X#ifdef SPIDERS
X || ((kind == WEB) && nospider)
X#endif
X#ifdef NEWCLASS
X || (kind == SPIKED_PIT && nospikes)
X || (kind == LEVEL_TELEP && nolevltp)
X#endif
X ) kind = NO_TRAP;
X } while(kind == NO_TRAP);
X } else kind = num;
X
X if(kind == MIMIC) {
X register struct monst *mtmp;
X
X fakedoor = (!rn2(3) && !mazeflag);
X fakegold = (!fakedoor && !rn2(2));
X if(fakegold) goldseen = TRUE;
X do {
X if(++tryct > 200) return;
X if(fakedoor) {
X /* note: fakedoor maybe on actual door */
X if(rn2(2)){
X if(rn2(2)) mx = croom->hx+1;
X else mx = croom->lx-1;
X my = somey();
X } else {
X if(rn2(2)) my = croom->hy+1;
X else my = croom->ly-1;
X mx = somex();
X }
X } else if(mazeflag) {
X coord mm;
X mazexy(&mm);
X mx = mm.x;
X my = mm.y;
X } else {
X mx = somex();
X my = somey();
X }
X } while(m_at(mx,my) || levl[mx][my].typ == STAIRS);
X if(mtmp = makemon(PM_MIMIC,mx,my)) {
X mtmp->mimic = 1;
X mtmp->mappearance =
X fakegold ? '$' : fakedoor ? DOOR_SYM :
X (mazeflag && rn2(2)) ? AMULET_SYM :
X#ifdef SPELLS
X "=/)%?![<>+" [ rn2(10) ];
X#else
X "=/)%?![<>" [ rn2(9) ];
X#endif
X }
X return;
X }
X
X do {
X if(++tryct > 200)
X return;
X if(mazeflag){
X coord mm;
X mazexy(&mm);
X mx = mm.x;
X my = mm.y;
X } else {
X mx = somex();
X my = somey();
X }
X } while(t_at(mx, my) || levl[mx][my].typ == STAIRS);
X ttmp = maketrap(mx, my, kind);
X#ifdef SPIDERS
X if (kind == WEB) mkmon_at ('s', mx, my);
X#endif
X if(mazeflag && !rn2(10) && ttmp->ttyp < PIERC)
X ttmp->tseen = 1;
X}
X
X#ifdef FOUNTAINS
Xmkfount(mazeflag,croom)
Xregister struct mkroom *croom;
Xregister mazeflag;
X{
X register xchar mx,my;
X register int tryct = 0;
X
X do {
X if(++tryct > 200)
X return;
X if(mazeflag){
X coord mm;
X mazexy(&mm);
X mx = mm.x;
X my = mm.y;
X } else {
X mx = somex();
X my = somey();
X }
X } while(t_at(mx, my) || levl[mx][my].typ == STAIRS
X#ifdef NEWCLASS
X || IS_THRONE(levl[mx][my].typ)
X#endif
X );
X
X /* Put a fountain at mx, my */
X
X levl[mx][my].typ = FOUNTAIN;
X levl[mx][my].scrsym = FOUNTAIN_SYM;
X
X}
X#endif /* FOUNTAINS /**/
X
END_OF_mklev.c
if test 20060 -ne `wc -c mon.c <<'END_OF_mon.c'
X/* SCCS Id: @(#)mon.c 2.1 87/10/17
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X
X#include "hack.h"
X#include "mfndpos.h"
Xextern struct monst *mkmon_at();
Xextern struct trap *maketrap();
Xextern struct obj *mkobj_at(), *mksobj_at();
Xextern char *hcolor();
X#ifdef KAA
Xextern boolean stoned;
Xextern char mlarge[];
X#endif
X#ifdef RPH
Xextern struct obj *mk_named_obj_at();
X#endif
X
Xint warnlevel; /* used by movemon and dochugw */
Xlong lastwarntime;
Xint lastwarnlev;
Xchar *warnings[] = { "white", "pink", "red", "ruby", "purple", "black" };
X
Xmovemon()
X{
X register struct monst *mtmp;
X register int fr;
X
X warnlevel = 0;
X
X while(1) {
X /* find a monster that we haven't treated yet */
X /* note that mtmp or mtmp->nmon might get killed
X while mtmp moves, so we cannot just walk down the
X chain (even new monsters might get created!) */
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X if(mtmp->mlstmv < moves) goto next_mon;
X /* treated all monsters */
X break;
X
X next_mon:
X mtmp->mlstmv = moves;
X
X /* most monsters drown in pools */
X { boolean inpool, iseel;
X
X inpool = (levl[mtmp->mx][mtmp->my].typ == POOL);
X iseel = (mtmp->data->mlet == ';');
X if(inpool && !iseel) {
X if(cansee(mtmp->mx,mtmp->my))
X pline("%s drowns.", Monnam(mtmp));
X mondead(mtmp);
X continue;
X }
X /* but eels have a difficult time outside */
X if(iseel && !inpool) {
X if(mtmp->mhp > 1) mtmp->mhp--;
X mtmp->mflee = 1;
X mtmp->mfleetim += 2;
X }
X }
X if(mtmp->mblinded && !--mtmp->mblinded)
X mtmp->mcansee = 1;
X if(mtmp->mfleetim && !--mtmp->mfleetim)
X mtmp->mflee = 0;
X#ifdef HARD
X /* unwatched mimics and piercers may hide again [MRS] */
X if(restrap(mtmp)) continue;
X#endif
X if(mtmp->mimic) continue;
X if(mtmp->mspeed != MSLOW || !(moves%2)){
X /* continue if the monster died fighting */
X fr = -1;
X if(Conflict && cansee(mtmp->mx,mtmp->my)
X && (fr = fightm(mtmp)) == 2)
X continue;
X if(fr<0 && dochugw(mtmp))
X continue;
X }
X if(mtmp->mspeed == MFAST && dochugw(mtmp))
X continue;
X }
X
X warnlevel -= u.ulevel;
X if(warnlevel >= SIZE(warnings))
X warnlevel = SIZE(warnings)-1;
X if(warnlevel >= 0)
X if(warnlevel > lastwarnlev || moves > lastwarntime + 5){
X register char *rr;
X switch((int) (Warning & (LEFT_RING | RIGHT_RING))){
X case LEFT_RING:
X rr = "Your left ring glows";
X break;
X case RIGHT_RING:
X rr = "Your right ring glows";
X break;
X case LEFT_RING | RIGHT_RING:
X rr = "Both your rings glow";
X break;
X default:
X rr = "Your fingertips glow";
X break;
X }
X pline("%s %s!", rr, Hallucination ? hcolor() : warnings[warnlevel]);
X lastwarntime = moves;
X lastwarnlev = warnlevel;
X }
X
X dmonsfree(); /* remove all dead monsters */
X}
X
Xjustswld(mtmp,name)
Xregister struct monst *mtmp;
Xchar *name;
X{
X
X mtmp->mx = u.ux;
X mtmp->my = u.uy;
X u.ustuck = mtmp;
X pmon(mtmp);
X kludge("%s swallows you!",name);
X more();
X seeoff(1);
X u.uswallow = 1;
X u.uswldtim = 0;
X swallowed();
X}
X
Xyouswld(mtmp,dam,die,name)
Xregister struct monst *mtmp;
Xregister dam,die;
Xchar *name;
X{
X if(mtmp != u.ustuck) return;
X kludge("%s digests you!",name);
X u.uhp -= dam;
X if(u.uswldtim++ >= die){ /* a3 */
X pline("It totally digests you!");
X u.uhp = -1;
X }
X if(u.uhp < 1) done_in_by(mtmp);
X /* flags.botlx = 1; /* should we show status line ? */
X}
X
X#ifdef ROCKMOLE
Xmeatgold(mtmp) register struct monst *mtmp; {
Xregister struct gold *gold;
Xregister int pile;
Xregister struct obj *otmp;
X#ifdef KJSMODS
X if(dlevel < 4) return;
X#endif
X /* Eats gold if it is there */
X while(gold = g_at(mtmp->mx, mtmp->my)){
X freegold(gold);
X /* Left behind a pile? */
X pile = rnd(25);
X if(pile < 3) mksobj_at(ROCK, mtmp->mx, mtmp->my);
X newsym(mtmp->mx, mtmp->my);
X }
X /* Eats armor if it is there */
X otmp = o_at(mtmp->mx,mtmp->my);
X if((otmp) && (otmp->otyp >= PLATE_MAIL) && (otmp->otyp <= RING_MAIL)){
X freeobj(otmp);
X /* Left behind a pile? */
X pile = rnd(25);
X if(pile < 3) mksobj_at(ROCK, mtmp->mx, mtmp->my);
X newsym(mtmp->mx, mtmp->my);
X }
X}
X#endif /* ROCKMOLE /**/
X
Xmpickgold(mtmp) register struct monst *mtmp; {
Xregister struct gold *gold;
X while(gold = g_at(mtmp->mx, mtmp->my)){
X mtmp->mgold += gold->amount;
X freegold(gold);
X if(levl[mtmp->mx][mtmp->my].scrsym == GOLD_SYM)
X newsym(mtmp->mx, mtmp->my);
X }
X}
X
X/* Now includes giants which pick up enormous rocks. KAA */
Xmpickgems(mtmp) register struct monst *mtmp; {
Xregister struct obj *otmp;
X for(otmp = fobj; otmp; otmp = otmp->nobj)
X if(otmp->olet ==
X#ifdef KAA
X (mtmp->data->mlet=='9' ? ROCK_SYM : GEM_SYM))
X#else
X GEM_SYM)
X#endif
X if(otmp->ox == mtmp->mx && otmp->oy == mtmp->my)
X if(mtmp->data->mlet != 'u' || objects[otmp->otyp].g_val != 0){
X freeobj(otmp);
X mpickobj(mtmp, otmp);
X#ifndef KAA
X if(levl[mtmp->mx][mtmp->my].scrsym == GEM_SYM)
X#endif
X newsym(mtmp->mx, mtmp->my); /* %% */
X return; /* pick only one object */
X }
X}
X
X/* return number of acceptable neighbour positions */
Xmfndpos(mon,poss,info,flag)
Xregister struct monst *mon;
Xcoord poss[9];
Xlong info[9], flag;
X{
X register int x,y,nx,ny,cnt = 0,ntyp;
X register struct monst *mtmp;
X int nowtyp;
X boolean pool;
X
X x = mon->mx;
X y = mon->my;
X nowtyp = levl[x][y].typ;
X
X pool = (mon->data->mlet == ';');
Xnexttry: /* eels prefer the water, but if there is no water nearby,
X they will crawl over land */
X if(mon->mconf) {
X flag |= ALLOW_ALL;
X flag &= ~NOTONL;
X }
X for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++)
X if(nx != x || ny != y) if(isok(nx,ny))
X#ifdef ROCKMOLE
X if(!IS_ROCK(ntyp = levl[nx][ny].typ) || (flag & ALLOW_WALL))
X#else
X if(!IS_ROCK(ntyp = levl[nx][ny].typ))
X#endif
X if(!(nx != x && ny != y && (nowtyp == DOOR || ntyp == DOOR)))
X if((ntyp == POOL) == pool) {
X info[cnt] = 0;
X if(nx == u.ux && ny == u.uy){
X if(!(flag & ALLOW_U)) continue;
X info[cnt] = ALLOW_U;
X } else if(mtmp = m_at(nx,ny)){
X if(!(flag & ALLOW_M)) continue;
X info[cnt] = ALLOW_M;
X if(mtmp->mtame){
X if(!(flag & ALLOW_TM)) continue;
X info[cnt] |= ALLOW_TM;
X }
X }
X if(sobj_at(CLOVE_OF_GARLIC, nx, ny)) {
X if(flag & NOGARLIC) continue;
X info[cnt] |= NOGARLIC;
X }
X if(sobj_at(SCR_SCARE_MONSTER, nx, ny) ||
X (!mon->mpeaceful && sengr_at("Elbereth", nx, ny))) {
X if(!(flag & ALLOW_SSM)) continue;
X info[cnt] |= ALLOW_SSM;
X }
X if(sobj_at(ENORMOUS_ROCK, nx, ny)) {
X if(!(flag & ALLOW_ROCK)) continue;
X info[cnt] |= ALLOW_ROCK;
X }
X if(!Invis && online(nx,ny)){
X if(flag & NOTONL) continue;
X info[cnt] |= NOTONL;
X }
X /* we cannot avoid traps of an unknown kind */
X { register struct trap *ttmp = t_at(nx, ny);
X register long tt;
X if(ttmp) {
X tt = 1L << ttmp->ttyp;
X /* below if added by GAN 02/06/87 to avoid
X * traps out of range
X */
X if(!(tt & ALLOW_TRAPS)) {
X impossible("A monster looked at a very strange trap");
X continue;
X }
X if(mon->mtrapseen & tt){
X if(!(flag & tt)) continue;
X info[cnt] |= tt;
X }
X }
X }
X poss[cnt].x = nx;
X poss[cnt].y = ny;
X cnt++;
X }
X if(!cnt && pool && nowtyp != POOL) {
X pool = FALSE;
X goto nexttry;
X }
X return(cnt);
X}
X
Xdist(x,y) int x,y; {
X return((x-u.ux)*(x-u.ux) + (y-u.uy)*(y-u.uy));
X}
X
Xpoisoned(string, pname)
Xregister char *string, *pname;
X{
X register i, plural;
X
X plural = (string[strlen(string) - 1] == 's')? 1 : 0;
X if(Blind) {
X if (plural) pline("They were poisoned.");
X else pline("It was poisoned.");
X } else {
X if (plural) pline("The %s were poisoned!", string);
X else pline("The %s was poisoned!", string);
X }
X
X if(Poison_resistance) {
X pline("The poison doesn't seem to affect you.");
X return;
X }
X i = rn2(10);
X if(i == 0) {
X u.uhp = -1;
X pline("I am afraid the poison was deadly ...");
X } else if(i <= 5) {
X losestr(rn1(3,3));
X } else {
X losehp(rn1(10,6), pname);
X }
X if(u.uhp < 1) {
X killer = pname;
X done("died");
X }
X}
X
Xmondead(mtmp)
Xregister struct monst *mtmp;
X{
X relobj(mtmp,1);
X unpmon(mtmp);
X relmon(mtmp);
X unstuck(mtmp);
X#ifdef KOPS
X if(mtmp->data->mlet == 'K' &&
X !strcmp(mtmp->data->mname,"Keystone Kop")) {
X /* When a Kop dies, he probably comes back. */
X switch(rnd(3)) {
X
X case 1: /* returns near the stairs */
X mkmon_at('K',xdnstair,ydnstair);
X break;
X case 2: /* randomly */
X mkmon_at('K',0,0);
X break;
X default:
X break;
X }
X }
X#endif
X if(mtmp->isshk) shkdead(mtmp);
X if(mtmp->isgd) gddead();
X#ifndef NOWORM
X if(mtmp->wormno) wormdead(mtmp);
X#endif
X#ifdef HARD
X if(mtmp->data->mlet == '1') wizdead(mtmp);
X#endif
X monfree(mtmp);
X}
X
X/* called when monster is moved to larger structure */
Xreplmon(mtmp,mtmp2)
Xregister struct monst *mtmp, *mtmp2;
X{
X relmon(mtmp);
X monfree(mtmp);
X mtmp2->nmon = fmon;
X fmon = mtmp2;
X if(u.ustuck == mtmp) u.ustuck = mtmp2;
X if(mtmp2->isshk) replshk(mtmp,mtmp2);
X if(mtmp2->isgd) replgd(mtmp,mtmp2);
X}
X
Xrelmon(mon)
Xregister struct monst *mon;
X{
X register struct monst *mtmp;
X
X if (fmon == 0) panic ("relmon: no fmon available.");
X
X if(mon == fmon) fmon = fmon->nmon;
X else {
X for(mtmp = fmon; mtmp->nmon != mon; mtmp = mtmp->nmon) ;
X mtmp->nmon = mon->nmon;
X }
X}
X
X/* we do not free monsters immediately, in order to have their name
X available shortly after their demise */
Xstruct monst *fdmon; /* chain of dead monsters, need not to be saved */
X
Xmonfree(mtmp) register struct monst *mtmp; {
X mtmp->nmon = fdmon;
X fdmon = mtmp;
X}
X
Xdmonsfree(){
Xregister struct monst *mtmp;
X while(mtmp = fdmon){
X fdmon = mtmp->nmon;
X free((char *) mtmp);
X }
X}
X
Xunstuck(mtmp)
Xregister struct monst *mtmp;
X{
X if(u.ustuck == mtmp) {
X if(u.uswallow){
X u.ux = mtmp->mx;
X u.uy = mtmp->my;
X u.uswallow = 0;
X setsee();
X docrt();
X }
X u.ustuck = 0;
X }
X}
X
Xkilled(mtmp)
Xregister struct monst *mtmp;
X{
X xkilled(mtmp, 1);
X}
X
Xxkilled(mtmp, dest)
Xregister struct monst *mtmp;
Xint dest;
X/* Dest=1, normal; dest=0, don't print message; dest=2, don't drop corpse
X either; dest=3, message but no corpse */
X{
X#ifdef LINT
X#define NEW_SCORING
X#endif
X register int tmp,tmp2,nk,x,y;
X register struct permonst *mdat = mtmp->data;
X extern long newuexp();
X#ifdef RPH
X int old_nlth;
X char old_name[BUFSZ];
X#endif
X
X if(mtmp->cham) mdat = PM_CHAMELEON;
X if (dest & 1) {
X if(Blind) pline("You destroy it!");
X else {
X pline("You destroy %s!",
X mtmp->mtame ? amonnam(mtmp, "poor") : monnam(mtmp));
X }
X }
X if(u.umconf) {
X if(!Blind)
X {
X pline("Your hands stop glowing %s.",
X Hallucination ? hcolor() : "blue");
X }
X u.umconf = 0;
X }
X
X /* count killed monsters */
X#define MAXMONNO 100
X nk = 1; /* in case we cannot find it in mons */
X tmp = mdat - mons; /* index in mons array (if not 'd', '@', ...) */
X if(tmp >= 0 && tmp < CMNUM+2) {
X extern char fut_geno[];
X u.nr_killed[tmp]++;
X if((nk = u.nr_killed[tmp]) > MAXMONNO &&
X#ifdef HARD
X# ifdef KOPS
X !index("KkO&", mdat->mlet) &&
X# else
X !index("kO&", mdat->mlet) &&
X# endif
X#endif
X !index(fut_geno, mdat->mlet))
X charcat(fut_geno, mdat->mlet);
X }
X
X /* punish bad behaviour */
X if(mdat->mlet == '@') {
X HTelepat = 0;
X u.uluck -= 2;
X }
X if(mtmp->mpeaceful || mtmp->mtame) u.uluck--;
X if(mdat->mlet == 'u') u.uluck -= 5;
X if((int)u.uluck < LUCKMIN) u.uluck = LUCKMIN;
X
X /* give experience points */
X tmp = 1 + mdat->mlevel * mdat->mlevel;
X if(mdat->ac < 3) tmp += 2*(7 - mdat->ac);
X if(index(
X#ifdef RPH
X# ifdef KAA
X "AcsSDXaeRTVWU&In:P89",
X# else
X "AcsSDXaeRTVWU&In:P8",
X# endif
X#else
X# ifdef KAA
X "AcsSDXaeRTVWU&In:P9",
X# else
X "AcsSDXaeRTVWU&In:P",
X# endif
X#endif
X mdat->mlet)) tmp += 2*mdat->mlevel;
X
X if(index("DeV&P",mdat->mlet)) tmp += (7*mdat->mlevel);
X if(mdat->mlevel > 6) tmp += 50;
X if(mdat->mlet == ';') tmp += 1000;
X
X#ifdef NEW_SCORING
X /* ------- recent addition: make nr of points decrease
X when this is not the first of this kind */
X { int ul = u.ulevel;
X int ml = mdat->mlevel;
X
X if(ul < 14) /* points are given based on present and future level */
X for(tmp2 = 0; !tmp2 || ul + tmp2 <= ml; tmp2++)
X if(u.uexp + 1 + (tmp + ((tmp2 <= 0) ? 0 : 4<<(tmp2-1)))/nk
X >= 10*pow((unsigned)(ul-1)))
X if(++ul == 14) break;
X
X tmp2 = ml - ul -1;
X tmp = (tmp + ((tmp2 < 0) ? 0 : 4<= newuexp()){
X#ifdef RPH
X /* make experience gaining simiar to d&d, whereby you */
X /* can at most go up by one level at a time, extra expr */
X /* possibly helping you along. Afterall, how much real */
X /* experience does one get shooting a wand of death at */
X /* a dragon created w/ a poymorph?? */
X u.ulevel++;
X if (u.uexp >= newuexp())
X u.uexp = newuexp() - 1;
X pline("Welcome to experience level %u.", u.ulevel);
X#else
X pline("Welcome to experience level %u.", ++u.ulevel);
X#endif
X tmp = rnd(10);
X if(tmp < 3) tmp = rnd(10);
X u.uhpmax += tmp;
X u.uhp += tmp;
X#ifdef SPELLS
X tmp = rnd(u.ulevel/2+1) + 1; /* M. Stephenson */
X u.uenmax += tmp;
X u.uen += tmp;
X#endif
X flags.botl = 1;
X }
X
X /* dispose of monster and make cadaver */
X x = mtmp->mx; y = mtmp->my;
X#ifdef RPH
X old_nlth = mtmp->mnamelth;
X if (old_nlth > 0) (void) strcpy (old_name, NAME(mtmp));
X#endif
X mondead(mtmp);
X tmp = mdat->mlet;
X if(tmp == 'm') { /* he killed a minotaur, give him a wand of digging */
X /* note: the dead minotaur will be on top of it! */
X mksobj_at(WAN_DIGGING, x, y);
X /* if(cansee(x,y)) atl(x,y,fobj->olet); */
X stackobj(fobj);
X } else
X#ifndef NOWORM
X if(tmp == 'w') {
X mksobj_at(WORM_TOOTH, x, y);
X stackobj(fobj);
X } else
X#endif
X#ifdef KJSMODS
X if(tmp == 'N') {
X mksobj_at(POT_OBJECT_DETECTION, x, y);
X stackobj(fobj);
X } else
X#endif
X#ifdef KAA
X if(tmp == '&') (void) mkobj_at(0, x, y);
X else
X if(stoned == FALSE && (!letter(tmp) || (!index("9&1", tmp) && !rn2(3)))) tmp = 0;
X if(dest & 2) {
X newsym(x,y);
X return;
X }
X#else
X if(!letter(tmp) || (!index("mw", tmp) && !rn2(3))) tmp = 0;
X#endif
X tmp2 = rn2(5);
X#ifdef KJSMODS
X /* if a kobold or a giant rat does not become treasure, do
X * not make a corpse. */
X# ifdef KOPS
X if(mdat->mlet == 'K'
X && !strcmp(mdat->mname,"kobold") && tmp) tmp2 = 0;
X# endif
X# ifdef ROCKMOLE
X if((mdat->mlet == 'r' && dlevel < 4) && tmp) tmp2 = 0;
X# endif
X#endif
X if(!ACCESSIBLE(levl[x][y].typ)) {
X /* might be mimic in wall or dead eel*/
X newsym(x,y);
X } else if(x != u.ux || y != u.uy) {
X /* might be here after swallowed */
X#ifdef KAA
X if(stoned) {
X register int typetmp;
X if(index(mlarge, tmp)) typetmp = ENORMOUS_ROCK;
X else typetmp = ROCK;
X mksobj_at(typetmp, x, y);
X if(cansee(x,y))
X atl(x, y, Hallucination ? rndobjsym() :
X objects[typetmp].oc_olet);
X } else
X#endif
X if(index("NTVm&w",mdat->mlet) || tmp2) {
X#ifndef RPH
X register struct obj *obj2 = mkobj_at(tmp,x,y);
X#else
X register struct obj *obj2;
X if (letter(tmp))
X obj2 = mk_named_obj_at(tmp, x, y,
X old_name, old_nlth);
X# ifdef KOPS
X else if (mdat->mlet == 'K')
X obj2 = mksobj_at((rn2(4) ? CLUB : WHISTLE), x, y);
X# endif
X else
X obj2 = mkobj_at(tmp,x,y);
X#endif /* RPH /**/
X if(cansee(x,y))
X atl(x, y, Hallucination ? rndobjsym() : obj2->olet);
X stackobj(obj2);
X }
X }
X}
X
Xkludge(str,arg)
Xregister char *str,*arg;
X{
X if(Blind) {
X if(*str == '%') pline(str,"It");
X else pline(str,"it");
X } else pline(str,arg);
X}
X
Xrescham() /* force all chameleons to become normal */
X{
X register struct monst *mtmp;
X
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X if(mtmp->cham) {
X mtmp->cham = 0;
X (void) newcham(mtmp, PM_CHAMELEON);
X }
X}
X
X#ifdef DGKMOD
X/* Let the chameleons change again -dgk */
Xrestartcham()
X{
X register struct monst *mtmp;
X
X for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X if (mtmp->data->mlet == ':')
X mtmp->cham = 1;
X}
X#endif
X
Xnewcham(mtmp,mdat) /* make a chameleon look like a new monster */
X /* returns 1 if the monster actually changed */
Xregister struct monst *mtmp;
Xregister struct permonst *mdat;
X{
X register mhp, hpn, hpd;
X
X if(mdat == mtmp->data) return(0); /* still the same monster */
X#ifndef NOWORM
X if(mtmp->wormno) wormdead(mtmp); /* throw tail away */
X#endif
X hpn = mtmp->mhp;
X hpd = (mtmp->data->mlevel)*8; if(!hpd) hpd = 4;
X mhp = (mdat->mlevel)*8; if(!mhp) mhp = 4;
X
X /* new hp: same fraction of max as before */
X mtmp->mhp = (hpn*mhp)/hpd;
X if (mhp > hpd && mtmp->mhp < hpn) mtmp->mhp = 127;
X/* Not totally foolproof. A 2HD monster with 80 HP that changes into a 6HD
X monster that really should have 240 and actually should have 127, the
X maximum possible, will wind up having 113. */
X if (!mtmp->mhp) mtmp->mhp = 1;
X/* Unlikely but not impossible; a 1HD creature with 1HP that changes into a
X 0HD creature will require this statement */
X mtmp->data = mdat;
X/* and the same for maximum hit points */
X hpn = mtmp->mhpmax;
X mtmp->mhpmax = (hpn*mhp)/hpd;
X if (mhp > hpd && mtmp->mhpmax < hpn) mtmp->mhp = 127;
X if (!mtmp->mhp) mtmp->mhp = 1;
X
X mtmp->minvis = (mdat->mlet == 'I') ? 1 : 0;
X /* only snakes and scorpions can hide under things -dgk */
X /* also generated by GAN */
X mtmp->mhide = (mdat->mlet == 'S' || mdat->mlet == 's') ? 1 : 0;
X if (!mtmp->mhide) mtmp->mundetected = 0;
X#ifndef NOWORM
X if(mdat->mlet == 'w' && getwn(mtmp)) initworm(mtmp);
X /* perhaps we should clear mtmp->mtame here? */
X#endif
X unpmon(mtmp); /* necessary for 'I' and to force pmon */
X pmon(mtmp);
X return(1);
X}
X
Xmnexto(mtmp) /* Make monster mtmp next to you (if possible) */
Xstruct monst *mtmp;
X{
X coord mm;
X enexto(&mm, u.ux, u.uy);
X mtmp->mx = mm.x;
X mtmp->my = mm.y;
X pmon(mtmp);
X}
X
Xishuman(mtmp) register struct monst *mtmp; {
X return(mtmp->data->mlet == '@');
X}
X
Xsetmangry(mtmp) register struct monst *mtmp; {
X if(!mtmp->mpeaceful) return;
X if(mtmp->mtame) return;
X mtmp->mpeaceful = 0;
X if(ishuman(mtmp)) pline("%s gets angry!", Monnam(mtmp));
X}
X
X/* not one hundred procent correct: now a snake may hide under an
X invisible object */
Xcanseemon(mtmp)
Xregister struct monst *mtmp;
X{
X return((!mtmp->minvis || See_invisible)
X && (!mtmp->mhide || !o_at(mtmp->mx,mtmp->my))
X && cansee(mtmp->mx, mtmp->my));
X}
X
Xdisturb(mtmp) /* awaken monsters while in the same room.
X * return a 1 if they have been woken.
X */
Xregister struct monst *mtmp;
X{
X /* wake up, or get out of here. */
X /* ettins are hard to surprise */
X /* Nymphs and Leprechauns do not easily wake up */
X if(cansee(mtmp->mx,mtmp->my) &&
X (!Stealth || (mtmp->data->mlet == 'e' && rn2(10))) &&
X (!index("NL",mtmp->data->mlet) || !rn2(50)) &&
X#ifdef RPH
X (Aggravate_monster || index("8d1", mtmp->data->mlet)
X#else
X (Aggravate_monster || index("d1", mtmp->data->mlet)
X#endif
X || (!rn2(7) && !mtmp->mimic))) {
X mtmp->msleep = 0;
X return(1);
X }
X if(Hallucination) pmon(mtmp);
X return(0);
X}
X
X#ifdef HARD
Xrestrap(mtmp) /* unwatched mimics and piercers may hide again,
X * if so, a 1 is returned.
X */
Xregister struct monst *mtmp;
X{
X if(mtmp->data->mlet == 'M' && !mtmp->mimic && !mtmp->cham
X && !mtmp->mcan && !cansee(mtmp->mx, mtmp->my)
X && !rn2(3)) {
X mtmp->mimic = 1;
X mtmp->mappearance = (levl[mtmp->mx][mtmp->my].typ == DOOR) ? DOOR_SYM : GOLD_SYM;
X return(1);
X }
X
X if(mtmp->data->mlet == 'p' && !mtmp->cham
X && !mtmp->mcan && !cansee(mtmp->mx, mtmp->my)
X && !rn2(3)) {
X
X if(levl[mtmp->mx][mtmp->my].typ == ROOM) {
X
X maketrap(mtmp->mx, mtmp->my, PIERC);
X mondead(mtmp);
X return(1);
X }
X }
X return(0);
X}
X#endif
END_OF_mon.c
if test 19391 -ne `wc -c topten.c <<'END_OF_topten.c'
X/* SCCS Id: @(#)topten.c 2.1 87/09/28
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X
X#include
X#include "hack.h"
X#ifdef GENIX
X#define void int /* jhn - mod to prevent compiler from bombing */
X#endif
X
X#define Sprintf (void) sprintf
Xextern char plname[], pl_character[];
Xextern char *itoa(), *ordin(), *eos();
Xextern int done_hup, done_stopprint;
X
X#define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry))
X#define NAMSZ 10
X#define DTHSZ 60
X#define PERSMAX 3 /* entries per name/uid per char. allowed */
X#define POINTSMIN 1 /* must be > 0 */
X#define ENTRYMAX 100 /* must be >= 10 */
X#ifndef MSDOS
X#define PERS_IS_UID /* delete for PERSMAX per name; now per uid */
X#endif
Xstruct toptenentry {
X struct toptenentry *tt_next;
X long int points;
X int level,maxlvl,hp,maxhp;
X int uid;
X char plchar;
X char sex;
X char name[NAMSZ+1];
X char death[DTHSZ+1];
X char date[7]; /* yymmdd */
X} *tt_head;
X
Xtopten(){
X int uid = getuid();
X int rank, rank0 = -1, rank1 = 0;
X int occ_cnt = PERSMAX;
X register struct toptenentry *t0, *t1, *tprev;
X char *recfile = RECORD;
X#ifdef UNIX
X char *reclock = "record_lock";
X#endif
X int sleepct = 300;
X FILE *rfile;
X register flg = 0;
X extern char *getdate();
X#ifndef DGK
X#define HUP if(!done_hup)
X#else
X#define HUP
X#endif
X#ifdef UNIX
X while(link(recfile, reclock) == -1) {
X HUP perror(reclock);
X if(!sleepct--) {
X HUP puts("I give up. Sorry.");
X HUP puts("Perhaps there is an old record_lock around?");
X return;
X }
X HUP printf("Waiting for access to record file. (%d)\n",
X sleepct);
X HUP (void) fflush(stdout);
X sleep(1);
X }
X#endif
X if(!(rfile = fopen(recfile,"r"))){
X HUP puts("Cannot open record file!");
X goto unlock;
X }
X HUP (void) putchar('\n');
X
X /* create a new 'topten' entry */
X t0 = newttentry();
X t0->level = dlevel;
X t0->maxlvl = maxdlevel;
X t0->hp = u.uhp;
X t0->maxhp = u.uhpmax;
X t0->points = u.urexp;
X t0->plchar = pl_character[0];
X t0->sex = (flags.female ? 'F' : 'M');
X t0->uid = uid;
X (void) strncpy(t0->name, plname, NAMSZ);
X (t0->name)[NAMSZ] = 0;
X (void) strncpy(t0->death, killer, DTHSZ);
X (t0->death)[DTHSZ] = 0;
X (void) strcpy(t0->date, getdate());
X
X /* assure minimum number of points */
X if(t0->points < POINTSMIN)
X t0->points = 0;
X
X t1 = tt_head = newttentry();
X tprev = 0;
X /* rank0: -1 undefined, 0 not_on_list, n n_th on list */
X for(rank = 1; ; ) {
X if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]",
X t1->date, &t1->uid,
X &t1->level, &t1->maxlvl,
X &t1->hp, &t1->maxhp, &t1->points,
X &t1->plchar, &t1->sex, t1->name, t1->death) != 11
X || t1->points < POINTSMIN)
X t1->points = 0;
X if(rank0 < 0 && t1->points < t0->points) {
X rank0 = rank++;
X if(tprev == 0)
X tt_head = t0;
X else
X tprev->tt_next = t0;
X t0->tt_next = t1;
X occ_cnt--;
X flg++; /* ask for a rewrite */
X } else
X tprev = t1;
X if(t1->points == 0) break;
X if(
X#ifdef PERS_IS_UID
X t1->uid == t0->uid &&
X#else
X strncmp(t1->name, t0->name, NAMSZ) == 0 &&
X#endif
X t1->plchar == t0->plchar && --occ_cnt <= 0){
X if(rank0 < 0){
X rank0 = 0;
X rank1 = rank;
X HUP printf("You didn't beat your previous score of %ld points.\n\n",
X t1->points);
X }
X if(occ_cnt < 0){
X flg++;
X continue;
X }
X }
X if(rank <= ENTRYMAX){
X t1 = t1->tt_next = newttentry();
X rank++;
X }
X if(rank > ENTRYMAX){
X t1->points = 0;
X break;
X }
X }
X if(flg) { /* rewrite record file */
X (void) fclose(rfile);
X if(!(rfile = fopen(recfile,"w"))){
X HUP puts("Cannot write record file\n");
X goto unlock;
X }
X
X if(!done_stopprint) if(rank0 > 0){
X if(rank0 <= 10)
X puts("You made the top ten list!\n");
X else
X printf("You reached the %d%s place on the top %d list.\n\n",
X rank0, ordin(rank0), ENTRYMAX);
X }
X }
X if(rank0 == 0) rank0 = rank1;
X if(rank0 <= 0) rank0 = rank;
X if(!done_stopprint) outheader();
X t1 = tt_head;
X for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
X if(flg) fprintf(rfile,"%6s %d %d %d %d %d %ld %c%c %s,%s\n",
X t1->date, t1->uid,
X t1->level, t1->maxlvl,
X t1->hp, t1->maxhp, t1->points,
X t1->plchar, t1->sex, t1->name, t1->death);
X if(done_stopprint) continue;
X if(rank > flags.end_top &&
X (rank < rank0-flags.end_around || rank > rank0+flags.end_around)
X && (!flags.end_own ||
X#ifdef PERS_IS_UID
X t1->uid != t0->uid
X#else
X strncmp(t1->name, t0->name, NAMSZ)
X#endif
X )) continue;
X if(rank == rank0-flags.end_around &&
X rank0 > flags.end_top+flags.end_around+1 &&
X !flags.end_own)
X (void) putchar('\n');
X if(rank != rank0)
X (void) outentry(rank, t1, 0);
X else if(!rank1)
X (void) outentry(rank, t1, 1);
X else {
X int t0lth = outentry(0, t0, -1);
X int t1lth = outentry(rank, t1, t0lth);
X if(t1lth > t0lth) t0lth = t1lth;
X (void) outentry(0, t0, t0lth);
X }
X }
X if(rank0 >= rank) if(!done_stopprint)
X (void) outentry(0, t0, 1);
X (void) fclose(rfile);
Xunlock: ;
X#ifdef UNIX
X (void) unlink(reclock);
X#endif
X}
X
Xoutheader() {
Xchar linebuf[BUFSZ];
Xregister char *bp;
X#ifdef KJSMODS
X (void) strcpy(linebuf, " No Points Name");
X#else
X (void) strcpy(linebuf, "Number Points Name");
X#endif
X bp = eos(linebuf);
X while(bp < linebuf + COLNO - 9) *bp++ = ' ';
X (void) strcpy(bp, "Hp [max]");
X puts(linebuf);
X}
X
X/* so>0: standout line; so=0: ordinary line; so<0: no output, return lth */
Xint
Xoutentry(rank,t1,so) register struct toptenentry *t1; {
Xboolean quit = FALSE, killed = FALSE, starv = FALSE;
Xchar linebuf[BUFSZ];
X linebuf[0] = 0;
X if(rank) Sprintf(eos(linebuf), "%3d", rank);
X else Sprintf(eos(linebuf), " ");
X#ifdef KJSMODS
X Sprintf(eos(linebuf), " %7ld %10s", t1->points, t1->name);
X#else
X# ifdef DGKMOD
X Sprintf(eos(linebuf), " %6ld %10s", t1->points, t1->name);
X# else
X Sprintf(eos(linebuf), " %6ld %8s", t1->points, t1->name);
X# endif
X#endif
X if(t1->plchar == 'X') Sprintf(eos(linebuf), " ");
X else Sprintf(eos(linebuf), "-%c ", t1->plchar);
X if(!strncmp("escaped", t1->death, 7)) {
X if(!strcmp(" (with amulet)", t1->death+7))
X Sprintf(eos(linebuf), "escaped the dungeon with amulet");
X else
X Sprintf(eos(linebuf), "escaped the dungeon [max level %d]",
X t1->maxlvl);
X } else {
X if(!strncmp(t1->death,"quit",4)) {
X quit = TRUE;
X#ifndef KJSMODS
X if(t1->maxhp < 3*t1->hp && t1->maxlvl < 4)
X Sprintf(eos(linebuf), "cravenly gave up");
X else
X#endif
X Sprintf(eos(linebuf), "quit");
X }
X else if(!strcmp(t1->death,"choked"))
X Sprintf(eos(linebuf), "choked on %s food",
X (t1->sex == 'F') ? "her" : "his");
X else if(!strncmp(t1->death,"starv",5))
X Sprintf(eos(linebuf), "starved to death"), starv = TRUE;
X else Sprintf(eos(linebuf), "was killed"), killed = TRUE;
X Sprintf(eos(linebuf), " on%s level %d",
X (killed || starv) ? "" : " dungeon", t1->level);
X if(t1->maxlvl != t1->level)
X Sprintf(eos(linebuf), " [max %d]", t1->maxlvl);
X if(quit && t1->death[4]) Sprintf(eos(linebuf), t1->death + 4);
X }
X if(killed) Sprintf(eos(linebuf), " by %s%s",
X (!strncmp(t1->death, "trick", 5) || !strncmp(t1->death, "the ", 4))
X ? "" :
X index(vowels,*t1->death) ? "an " : "a ",
X t1->death);
X Sprintf(eos(linebuf), ".");
X if(t1->maxhp) {
X register char *bp = eos(linebuf);
X char hpbuf[10];
X int hppos;
X#ifdef KJSMODS
X int lngr = strlen(linebuf);
X#endif
X Sprintf(hpbuf, (t1->hp > 0) ? itoa(t1->hp) : "-");
X hppos = COLNO - 7 - strlen(hpbuf);
X#ifdef KJSMODS
X if (lngr >= hppos) hppos = (2*COLNO) - 7 - strlen(hpbuf);
X#endif
X if(bp <= linebuf + hppos) {
X /* pad any necessary blanks to the hit point entry */
X while(bp < linebuf + hppos) *bp++ = ' ';
X (void) strcpy(bp, hpbuf);
X Sprintf(eos(bp), " [%d]", t1->maxhp);
X }
X }
X if(so == 0) puts(linebuf);
X else if(so > 0) {
X register char *bp = eos(linebuf);
X if(so >= COLNO) so = COLNO-1;
X while(bp < linebuf + so) *bp++ = ' ';
X *bp = 0;
X standoutbeg();
X fputs(linebuf,stdout);
X standoutend();
X (void) putchar('\n');
X }
X return(strlen(linebuf));
X}
X
Xchar *
Xitoa(a) int a; {
Xstatic char buf[12];
X Sprintf(buf,"%d",a);
X return(buf);
X}
X
Xchar *
Xordin(n) int n; {
Xregister int d = n%10;
X return((d==0 || d>3 || n/10==1) ? "th" : (d==1) ? "st" :
X (d==2) ? "nd" : "rd");
X}
X
Xchar *
Xeos(s)
Xregister char *s;
X{
X while(*s) s++;
X return(s);
X}
X
X/*
X * Called with args from main if argc >= 0. In this case, list scores as
X * requested. Otherwise, find scores for the current player (and list them
X * if argc == -1).
X */
Xprscore(argc,argv) int argc; char **argv; {
X extern char *hname;
X char **players;
X int playerct;
X int rank;
X register struct toptenentry *t1, *t2;
X char *recfile = RECORD;
X FILE *rfile;
X register flg = 0;
X register int i;
X#ifdef nonsense
X long total_score = 0L;
X char totchars[10];
X int totcharct = 0;
X#endif
X int outflg = (argc >= -1);
X#ifdef PERS_IS_UID
X int uid = -1;
X#else
X char *player0;
X#endif
X
X if(!(rfile = fopen(recfile,"r"))){
X puts("Cannot open record file!");
X return;
X }
X
X if(argc > 1 && !strncmp(argv[1], "-s", 2)){
X if(!argv[1][2]){
X argc--;
X argv++;
X } else if(!argv[1][3] && index("CFKSTWX", argv[1][2])) {
X argv[1]++;
X argv[1][0] = '-';
X } else argv[1] += 2;
X }
X if(argc <= 1){
X#ifdef PERS_IS_UID
X uid = getuid();
X playerct = 0;
X#else
X player0 = plname;
X if(!*player0)
X player0 = "hackplayer";
X playerct = 1;
X players = &player0;
X#endif
X } else {
X playerct = --argc;
X players = ++argv;
X }
X if(outflg) putchar('\n');
X
X t1 = tt_head = newttentry();
X for(rank = 1; ; rank++) {
X if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]",
X t1->date, &t1->uid,
X &t1->level, &t1->maxlvl,
X &t1->hp, &t1->maxhp, &t1->points,
X &t1->plchar, &t1->sex, t1->name, t1->death) != 11)
X t1->points = 0;
X if(t1->points == 0) break;
X#ifdef PERS_IS_UID
X if(!playerct && t1->uid == uid)
X flg++;
X else
X#endif
X for(i = 0; i < playerct; i++){
X if(strcmp(players[i], "all") == 0 ||
X strncmp(t1->name, players[i], NAMSZ) == 0 ||
X (players[i][0] == '-' &&
X players[i][1] == t1->plchar &&
X players[i][2] == 0) ||
X (digit(players[i][0]) && rank <= atoi(players[i])))
X flg++;
X }
X t1 = t1->tt_next = newttentry();
X }
X (void) fclose(rfile);
X if(!flg) {
X if(outflg) {
X printf("Cannot find any entries for ");
X if(playerct < 1) printf("you.\n");
X else {
X if(playerct > 1) printf("any of ");
X for(i=0; ipoints != 0; rank++, t1 = t2) {
X t2 = t1->tt_next;
X#ifdef PERS_IS_UID
X if(!playerct && t1->uid == uid)
X goto outwithit;
X else
X#endif
X for(i = 0; i < playerct; i++){
X if(strcmp(players[i], "all") == 0 ||
X strncmp(t1->name, players[i], NAMSZ) == 0 ||
X (players[i][0] == '-' &&
X players[i][1] == t1->plchar &&
X players[i][2] == 0) ||
X (digit(players[i][0]) && rank <= atoi(players[i]))){
X outwithit:
X if(outflg)
X (void) outentry(rank, t1, 0);
X#ifdef nonsense
X total_score += t1->points;
X if(totcharct < sizeof(totchars)-1)
X totchars[totcharct++] = t1->plchar;
X#endif
X break;
X }
X }
X free((char *) t1);
X }
X#ifdef nonsense
X totchars[totcharct] = 0;
X
X /* We would like to determine whether he is experienced. However,
X the information collected here only tells about the scores/roles
X that got into the topten (top 100?). We should maintain a
X .hacklog or something in his home directory. */
X flags.beginner = (total_score < 6000);
X for(i=0; i<6; i++)
X if(!index(totchars, "CFKSTWX"[i])) {
X flags.beginner = 1;
X if(!pl_character[0]) pl_character[0] = "CFKSTWX"[i];
X break;
X }
X#endif /* nonsense /**/
X}
END_OF_topten.c
if test 11629 -ne `wc -c