billr@saab.CNA.TEK.COM (Bill Randle) (07/25/89)
Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
Posting-number: Volume 7, Issue 79
Archive-name: NetHack3/Part24
#! /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 <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 24 (of 38)."
# Contents: Install.dos src/dokick.c src/mondata.c src/pager.c
# Wrapped by billr@saab on Sun Jul 23 21:33:07 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Install.dos' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Install.dos'\"
else
echo shar: Extracting \"'Install.dos'\" \(6416 characters\)
sed "s/^X//" >'Install.dos' <<'END_OF_FILE'
XInstructions for installing NetHack 3.0 on an MS-DOS system
X===========================================================
X
X1. Make sure all the NetHack files are in the appropriate directory structure.
X You should have a main directory with subdirectories src, include, auxil,
X amiga, and others. If you do not follow this structure, the Makefile
X will not function properly. All the UNIX .c files and the source Makefile
X belong in src; all the PC .c files and Makefiles belong in others; all the
X .h files belong in include; other assorted files belong in auxil. The
X PC version does not use any files from the amiga directory.
X
X If you downloaded or ftp'd the sources from a UNIX system, the lines will
X probably end in UNIX-style newlines, instead of DOS-style carriage return
X and line feed pairs. Turbo C in particular does not like these; you will
X have to run a program such as Rahul Dhesi's 'flip' to convert them.
X
X2. Move everything from the others directory to your src directory; you'll
X be needing it, especially pc*.c. PC NetHack needs msdos.c, ST NetHack
X needs tos.c.
X
X3. You should have several Makefiles in your src directory now. If you are
X using Microsoft C, rename Makefile.pc to Makefile; if Turbo C, rename
X Makefile.tcc to Makefile, and also rename Maketcc.ini to Make.ini.
X NDMake can find Make.ini anywhere on your PATH, so you may relocate it
X if you wish. If you are using another compiler, you will have to adapt
X one of the Makefiles and the Make.ini file to your needs. Good luck.
X
X As for the other Makefiles, I would delete them to make space, but you may
X want to keep them around for comparison in case something goes wrong. Two
X other Makefiles we will not be using, Makefile.top and Makefile.auxil,
X reside in the top and auxil directories. We won't need those either.
X
X4. Go to the include subdirectory and edit config.h according to the comments
X to match your system and desired set of features. Similarly edit
X pcconf.h.
X
X The base size of the executable, with no extra features, will be around
X 520K in size. Anything over 540K is likely not to work. With MicroSoft
X C, here is an incomplete list of the costs of various additional features
X in terms of executable size:
X
X ALTARS 4K
X ARMY 1K
X COM_COMPL 1K
X COMPRESS 2K
X DGK 7K
X ENDGAME 2K
X EXPLORE_MODE 1K
X FOUNTAINS 2K
X GOLEMS 2K
X HARD - SEDUCE 5K
X MSDOSCOLOR 1K
X MUSIC 6K
X POLYSELF 31K
X PROBING 0K
X REDO 1K
X REINCARNATION 7K
X SINKS 5K
X SOUNDS 6K
X SPELLS 10K
X STRONGHOLD 13K
X THEOLOGY 11K
X THRONES 3K
X WALKIES 4K
X WALLIFIED_MAZE 0K
X WIZARD 3K
X
X I eked by with just DGK, MSDOSCOLOR, REDO, HARD, MEDUSA, EXPLORE_MODE,
X and WIZARD, to give you an idea of just how little leeway you have for all
X these nifty features. Maybe those of you with overlay linkers can get by
X with more.
X
X5. If you want to, look through system.h. This file attempts to match the
X types for system calls and library routines with various flavors of
X operating systems. Leaving this file alone is unlikely to cause problems,
X but if you're using a different compiler and get compile errors with
X any functions in the standard library, it's worth checking the
X declarations there.
X
X6. If you want to change the high score list behavior, go to the src
X subdirectory and look at the top of topten.c. You may want to change the
X definitions of PERSMAX, POINTSMIN, and ENTRYMAX. I set POINTSMIN of
X 51 and ENTRYMAX of 50 to keep the size of the score list down.
X
X7. Edit the top section of the Makefile. (If you are doing a full
X recompile, or if you got your files from someplace besides the official
X distribution, type 'touch makedefs.c' to make sure certain files (onames.h,
X pm.h) get remade instead of relying on the potentially troublesome
X timestamps.) Be sure the directory you want the game installed in
X actually exists. If you elected to use the high-quality BSD random
X routines by defining RANDOM in pcconf.h, you will have to add random.c
X to the dependency and link macros. If you elected to use Fred Fish's
X termcap library (bundled in as termcap.arc), you will have to generate
X termcap.lib from those sources (follow the comments therein, if you can).
X
X Now, type 'make all', and take a long siesta; your computer will be
X occupied for a long time. If all goes well, you will get an executable.
X If you tried to compile in too many features, you probably will not get
X a working one, and have to start over.
X
X8. Edit NetHack.cnf to reflect your particular setup, following the comments.
X Then move the file to your game directory, along with the termcap file.
X
X If your game directory is not on your PATH, you will want to 'set HACKDIR
X =\games\nethack' (or whatever directory you want to use) now, and add it
X to your autoexec.bat if you'll be playing often.
X
X Make sure the support files data, rumors, cmdhelp, opthelp, help, hh,
X history, and license (and oracles, if you compiled in that feature) got
X copied to the game directory. If not, move them there from the auxil
X directory yourself. rumors can be created manually by typing 'makedefs
X -r'; data by typing 'makedefs -d'.
X
X If you compiled in the special levels, make sure castle, tower?, and
X perhaps endgame are there, too. lev_comp file.des will create these.
X
XNotes:
X
X1. No, your old save files and bones files will not work with NetHack 3.0.
X Don't bother trying to keep them. The old score list will work fine,
X but I recommend you delete it and create a new, empty one ('type record
X >record' will do this nicely). It is a good deal harder to achieve the
X same scores in this version.
X
X2. To install an update of this version of NetHack after changing something,
X type 'make' from the src directory. If you created the new version
X yourself, it should be safe to use 'make update' as long as you did not
X add, delete, or reorder monsters or objects and you did not change
X the format of saved level files. If you did any of these things, you
X should also delete any saved games and bones levels. (Trying to use such
X files often produces amusing but useless confusions on the game's part.)
END_OF_FILE
if test 6416 -ne `wc -c <'Install.dos'`; then
echo shar: \"'Install.dos'\" unpacked with wrong size!
fi
# end of 'Install.dos'
fi
if test -f 'src/dokick.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/dokick.c'\"
else
echo shar: Extracting \"'src/dokick.c'\" \(15059 characters\)
sed "s/^X//" >'src/dokick.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)dokick.c 3.0 89/6/9
X/* Copyright (c) Izchak Miller, Mike Stephenson, Steve Linhart, 1989. */
X/* NetHack may be freely redistributed. See license for details. */
X
X#include "hack.h"
X#include "eshk.h"
X
X#define martial() ((pl_character[0] == 'S' || pl_character[0] == 'P'))
X
X#ifdef KICK
X
X# ifdef WORM
Xextern boolean notonhead;
X# endif
X
Xstatic void
Xkickdmg(mon, clumsy)
Xregister struct monst *mon;
Xregister boolean clumsy;
X{
X register int mdx, mdy;
X register int dmg = (((uarmg &&
X uarmg->otyp == GAUNTLETS_OF_POWER) ?
X 25 : ACURR(A_STR) > 18 ? 18 : ACURR(A_STR))+
X ACURR(A_DEX)+ACURR(A_CON))/15;
X
X /* excessive wt affects dex, so it affects dmg */
X if(clumsy) dmg = dmg/2;
X
X /* kicking a dragon or an elephant will not harm it */
X if(thick_skinned(mon->data)) dmg = 0;
X
X
X /* squeeze some guilt feelings... */
X if(mon->mtame) {
X# ifdef SOUNDS
X if (rn2(10)) yelp(mon);
X else growl(mon); /* give them a moment's worry */
X# endif
X mon->mtame--;
X mon->mflee = mon->mtame ? 1 : 0;
X# ifdef HISX
X mon->mfleetim = mon->mfleetim + (dmg ? rnd(dmg) : 1);
X# else
X mon->mfleetim += (dmg ? rnd(dmg) : 1);
X# endif
X }
X
X mon->mhp -= (!martial() ? rnd(dmg) : rnd(dmg)+rnd(ACURR(A_DEX)/2));
X if(mon->mhp < 1) {
X killed(mon);
X return;
X }
X if(martial() && !bigmonst(mon->data) && !rn2(3) && !mon->mfroz) {
X /* see if the monster has a place to move into */
X mdx = mon->mx + u.dx;
X mdy = mon->my + u.dy;
X if(goodpos(mdx, mdy)) {
X pline("%s reels from the blow.", Monnam(mon));
X levl[mon->mx][mon->my].mmask = 0;
X levl[mdx][mdy].mmask = 1;
X mon->mx = mdx;
X mon->my = mdy;
X pmon(mon);
X set_apparxy(mon);
X }
X }
X
X/* it is unchivalrous to attack the defenseless or from behind */
X if (pl_character[0] == 'K' && u.ualigntyp == U_LAWFUL &&
X u.ualign > -10 && (mon->mfroz || mon->msleep || mon->mflee))
X adjalign(-1);
X
X}
X
Xstatic void
Xkick_monster(x, y)
Xregister int x, y;
X{
X register boolean clumsy = FALSE;
X register struct monst *mon = m_at(x, y);
X register int i, j;
X
X /* no need to check POLYSELF since only ghosts, which you can't turn */
X /* into, are noncorporeal */
X if(noncorporeal(mon->data)) {
X Your("kick passes through!");
X return;
X }
X
X if(special_case(mon)) return;
X
X setmangry(mon);
X
X if(Levitation && !rn2(3) && verysmall(mon->data) &&
X !is_floater(mon->data) && !is_flyer(mon->data)) {
X You("are floating in the air, and miss wildly!");
X return;
X }
X
X i = abs(inv_weight());
X j = weight_cap();
X
X if(i < (j*3)/10) {
X if(!rn2((i < j/10) ? 2 : (i < j/5) ? 3 : 4)) {
X if(martial() && !rn2(2)) goto doit;
X Your("clumsy kick does no damage.");
X return;
X }
X if(i < j/10) clumsy = TRUE;
X else if(!rn2((i < j/5) ? 2 : 3)) clumsy = TRUE;
X }
X
X if(Fumbling) clumsy = TRUE;
X
X else if(uarm && objects[uarm->otyp].oc_bulky && ACURR(A_DEX) < rnd(25))
X clumsy = TRUE;
Xdoit:
X kludge("You kick %s.", mon_nam(mon));
X if(!rn2(clumsy ? 3 : 4) && (clumsy || !bigmonst(mon->data)) &&
X mon->mcansee && !thick_skinned(mon->data) &&
X !mon->mfroz && !mon->mstun && !mon->mconf) {
X mnexto(mon);
X if(mon->mx != x || mon->my != y) {
X kludge("%s jumps, %s evading your %skick.", Monnam(mon),
X clumsy ? "easily" : "nimbly",
X clumsy ? "clumsy " : "");
X return;
X } /* else fall to the next case */
X }
X kickdmg(mon, clumsy);
X}
X#endif /* KICK */
X
X/* return TRUE if caught, FALSE otherwise */
Xboolean
Xghitm(mtmp, amount)
Xregister struct monst *mtmp;
Xregister long amount;
X{
X if(!likes_gold(mtmp->data) && !mtmp->isshk
X#if defined(ALTARS) && defined(THEOLOGY)
X && !mtmp->ispriest
X#endif
X )
X wakeup(mtmp);
X else {
X mtmp->msleep = 0;
X mtmp->meating = 0;
X if(!rn2(4)) setmangry(mtmp); /* not always pleasing */
X
X /* greedy monsters catch gold */
X pline("%s catches the gold.", Monnam(mtmp));
X mtmp->mgold += amount;
X if (mtmp->isshk) {
X long robbed = ESHK(mtmp)->robbed;
X
X if (robbed) {
X robbed -= amount;
X if (robbed < 0) robbed = 0;
X pline("The amount %scovers %s recent losses.",
X !robbed ? "" : "partially ",
X ESHK(mtmp)->ismale ? "his" : "her");
X ESHK(mtmp)->robbed = robbed;
X if(!robbed)
X make_happy_shk(mtmp);
X } else {
X if(mtmp->mpeaceful) {
X ESHK(mtmp)->credit += amount;
X You("have %ld zorkmids in credit.",
X ESHK(mtmp)->credit);
X } else verbalize("Thanks, scum!");
X }
X }
X#if defined(ALTARS) && defined(THEOLOGY)
X else if(mtmp->ispriest) {
X if(mtmp->mpeaceful)
X verbalize("Thank you for your contribution.");
X else verbalize("Thanks, scum!");
X }
X#endif
X return(1);
X }
X return(0);
X
X}
X
Xboolean
Xbad_kick_throw_pos(x,y)
Xxchar x,y;
X{
X register struct rm *lvl = &(levl[x][y]);
X
X return(!ACCESSIBLE(lvl->typ) || lvl->typ == SDOOR ||
X (IS_DOOR(lvl->typ) && (lvl->doormask & (D_CLOSED | D_LOCKED))) );
X}
X
Xstruct monst *
Xghit(ddx, ddy, range)
Xregister int ddx, ddy, range;
X{
X register struct monst *mtmp = (struct monst *) 0;
X
X bhitpos.x = u.ux;
X bhitpos.y = u.uy;
X
X tmp_at(-1, GOLD_SYM); /* open call */
X tmp_at(-3, (int)AT_GLD);
X while(range-- > 0) {
X bhitpos.x += ddx;
X bhitpos.y += ddy;
X if(levl[bhitpos.x][bhitpos.y].mmask) {
X mtmp = m_at(bhitpos.x,bhitpos.y);
X tmp_at(-1, -1); /* close call */
X return(mtmp);
X }
X /* stop on a zorkmid */
X if(levl[bhitpos.x][bhitpos.y].gmask ||
X levl[bhitpos.x][bhitpos.y].omask) {
X tmp_at(-1, -1); /* close call */
X return (struct monst *)0;
X }
X if(bad_kick_throw_pos(bhitpos.x,bhitpos.y)) {
X bhitpos.x -= ddx;
X bhitpos.y -= ddy;
X break;
X }
X tmp_at(bhitpos.x, bhitpos.y);
X }
X tmp_at(-1, -1);
X return(struct monst *)0;
X}
X
X#ifdef KICK
Xstatic int
Xkick_object(x, y)
Xregister int x, y;
X{
X register int range, odx, ody, cnt = 0;
X register struct monst *mon;
X register struct gold *gold;
X register struct obj *otmp, *obj;
X register boolean costly = FALSE;
X
X /* if a pile, the "top" object gets kicked */
X for (otmp = fobj; otmp; otmp = otmp->nobj)
X if(otmp->ox == x && otmp->oy == y)
X if(!otmp->cobj)
X if (otmp != uchain) {
X cnt++;
X if(cnt == 1) obj = otmp;
X }
X
X /* range < 2 means the object will not move. */
X /* maybe dexterity should also figure here. */
X if(cnt) range = (int)((ACURR(A_STR) > 18 ? 20 :
X ACURR(A_STR))/2 - obj->owt/4);
X else range = rnd((int)ACURR(A_STR));
X
X if(range < 1) range = 1; /* safety... */
X if(martial()) range = range + rnd(3);
X
X /* see if the object has a place to move into */
X odx = x + u.dx;
X ody = y + u.dy;
X if(bad_kick_throw_pos(odx,ody))
X range = 1;
X
X if(Fumbling && !rn2(3)) {
X Your("clumsy kick missed.");
X return(1);
X }
X
X if(!cnt && levl[x][y].gmask) {
X long zm;
X gold = g_at(x, y);
X zm = gold->amount;
X if(range < 2 || zm > 300L) /* arbitrary */
X return(0);
X else {
X freegold(gold);
X if(!levl[x][y].mmask) newsym(x, y);
X if(mon = ghit(u.dx, u.dy, range)) {
X setmangry(mon); /* not a means for payment to shk */
X if(ghitm(mon, zm)) /* was it caught? */
X return(1);
X }
X mkgold(zm, bhitpos.x, bhitpos.y);
X if(cansee(bhitpos.x, bhitpos.y)) prl(bhitpos.x,bhitpos.y);
X }
X return(1);
X }
X
X if(obj->otyp == BOULDER || obj == uball)
X return(0);
X
X /* a box gets a chance of breaking open here */
X if(Is_box(obj)) {
X boolean otrp = obj->otrapped;
X
X if (!obj->olocked && (!rn2(3) ||
X (martial() && !rn2(2)))) {
X pline("The lid slams open, then falls shut.");
X if(otrp) goto gotcha;
X return(1);
X } else if (obj->olocked &&
X (!rn2(5) || (martial() && !rn2(2)))) {
X You("break open the lock!");
X obj->olocked = 0;
X if(otrp) {
Xgotcha:
X chest_trap(obj, LEG);
X }
X return(1);
X }
X /* let it fall through to the next cases... */
X }
X
X if(Levitation && !rn2(3)) {
X You("miss."); /* do not identify the object */
X return(1);
X }
X
X /* fragile objects should not be kicked */
X if (breaks(obj, FALSE)) return(1);
X
X costly = costly_spot(x, y);
X
X /* potions get a chance of breaking here */
X if(obj->olet == POTION_SYM) {
X if(rn2(2)) {
X You("smash the %s!", xname(obj));
X if(costly) addtobill(obj, FALSE);
X potionbreathe(obj);
X delobj(obj); /* takes care of omask */
X return(1);
X }
X }
X
X /* too heavy to move. make sure not to call bhit */
X /* in this function when range < 2 (a display bug */
X /* results otherwise). */
X if(range <= 2) {
X if(Is_box(obj)) pline("THUD!");
X else pline("Thump!");
X if(!rn2(3) || martial()) return(1);
X return(0);
X }
X
X if(cnt > 1) {
X /* Needed to fool bhit's display-cleanup to show */
X /* immediately the next object in the pile. We */
X /* know here that the object will move, so there */
X /* is no need to worry about omask. */
X obj->ox = u.ux;
X obj->oy = u.uy;
X } else {
X levl[x][y].omask = 0;
X if(!levl[x][y].gmask) newsym(x, y);
X }
X
X mon = bhit(u.dx, u.dy, range, obj->olet,
X (int (*)()) 0, (int (*)()) 0, obj);
X if(mon) {
X# ifdef WORM
X if (mon->mx != bhitpos.x || mon->my != bhitpos.y)
X notonhead = TRUE;
X# endif
X /* awake monster if sleeping */
X wakeup(mon);
X if(thitmonst(mon, obj)) return(1);
X }
X if(costly && !costly_spot(bhitpos.x,bhitpos.y)) addtobill(obj, FALSE);
X obj->ox = bhitpos.x;
X obj->oy = bhitpos.y;
X levl[obj->ox][obj->oy].omask = 1;
X stackobj(obj);
X return(1);
X}
X#endif /* KICK */
X
X
Xint
Xdokick() { /* try to kick the door down - noisy! */
X register int x, y;
X register struct rm *maploc;
X register int avrg_attrib = (ACURR(A_STR)+ACURR(A_DEX)+ACURR(A_CON))/3;
X
X#ifdef POLYSELF
X if(nolimbs(uasmon)) {
X You("have no legs to kick with.");
X return(0);
X }
X if(verysmall(uasmon)) {
X You("are too small to do any kicking.");
X return(0);
X }
X#endif
X if(Wounded_legs) {
X Your("%s %s in no shape for kicking.",
X ((Wounded_legs & BOTH_SIDES)==BOTH_SIDES)
X ? makeplural(body_part(LEG)) : body_part(LEG),
X ((Wounded_legs & BOTH_SIDES)==BOTH_SIDES) ? "are" : "is");
X return(0);
X }
X
X if(inv_weight() > 0) {
X Your("load is too heavy to balance yourself for a kick.");
X return(0);
X }
X
X if(u.utrap) {
X switch (u.utraptype) {
X case TT_PIT:
X pline("There's nothing to kick down here.");
X case TT_WEB:
X case TT_BEARTRAP:
X You("can't move your %s!", body_part(LEG));
X }
X return(0);
X }
X
X if(!getdir(1)) return(0);
X if(!u.dx && !u.dy) return(0);
X
X x = u.ux + u.dx;
X y = u.uy + u.dy;
X
X if(u.uswallow) {
X switch(rn2(3)) {
X case 0: You("can't move your %s!", body_part(LEG));
X break;
X case 1: pline("%s burps loudly.", Monnam(u.ustuck)); break;
X default: Your("feeble kick has no effect."); break;
X }
X return(1);
X }
X
X wake_nearby();
X u_wipe_engr(2);
X
X maploc = &levl[x][y];
X
X#ifdef KICK
X /* The next four main loops should stay in */
X /* their present order: monsters, objects, */
X /* non-doors, doors. */
X
X if(maploc->mmask) {
X kick_monster(x, y);
X return(1);
X }
X
X if((maploc->omask || maploc->gmask) && !Levitation) {
X if(kick_object(x, y)) return(1);
X else goto ouch;
X }
X
X if(!IS_DOOR(maploc->typ)) {
X if(maploc->typ == SDOOR) {
X if(rn2(30) < avrg_attrib) {
X pline("Crash! You kick open a secret door!");
X maploc->typ = DOOR;
X atl(x, y, (char) DOOR_SYM);
X if(maploc->doormask & D_TRAPPED) {
X b_trapped("door");
X maploc->doormask = D_NODOOR;
X } else
X maploc->doormask = D_ISOPEN;
X return(1);
X } else goto ouch;
X }
X if(maploc->typ == SCORR) {
X if(rn2(30) < avrg_attrib) {
X pline("Crash! You kick open a secret passage!");
X maploc->typ = CORR;
X atl(x, y, (char) CORR_SYM);
X return(1);
X } else goto ouch;
X }
X# ifdef THRONES
X if(IS_THRONE(maploc->typ)) {
X register int i;
X if((u.uluck < 0 || maploc->doormask) && !rn2(3)) {
X pline("CRASH! You destroy the throne.");
X maploc->typ = ROOM;
X maploc->doormask = 0; /* don't leave loose ends.. */
X mkgold((long)rnd(200), x, y);
X prl(x, y);
X return(1);
X } else if(u.uluck && !rn2(3) && !maploc->doormask) {
X You("kick loose some ornamental coins and gems!");
X mkgold((300L+(long)rn2(201)), x, y);
X i = u.uluck + 1;
X if(i > 6) i = 6;
X while(i--) (void) mkobj_at(GEM_SYM, x, y);
X prl(x, y);
X /* prevent endless milking */
X maploc->doormask = T_LOOTED;
X return(1);
X } else if (!rn2(4)) {
X register struct trap *ttmp =
X maketrap(u.ux,u.uy,TRAPDOOR);
X dotrap(ttmp);
X return(1);
X }
X goto ouch;
X }
X# endif
X# ifdef ALTARS
X if(IS_ALTAR(maploc->typ)) {
X You("kick the altar.");
X if(!rn2(3)) goto ouch;
X# ifdef THEOLOGY
X altar_wrath(x, y);
X# endif
X return(1);
X }
X# endif
X# ifdef SINKS
X if(IS_SINK(maploc->typ)) {
X if(rn2(5)) {
X if(flags.soundok)
X pline("Klunk! The pipes vibrate noisily.");
X else pline("Klunk!");
X return(1);
X } else if(!rn2(3) &&
X !(mons[PM_BLACK_PUDDING].geno & G_GENOD)) {
X pline("A %s ooze gushes up from the drain!",
X Hallucination ? hcolor() : black);
X pmon(makemon(&mons[PM_BLACK_PUDDING], x, y));
X return(1);
X# ifdef HARD
X } else if(!rn2(3) &&
X# ifndef POLYSELF
X poly_gender() != 2 &&
X# endif
X !(mons[poly_gender() == 1 ? PM_INCUBUS : PM_SUCCUBUS].geno & G_GENOD)) {
X /* can't resist... */
X pline("The dish washer returns!");
X pmon(makemon(&mons[poly_gender() == 1 ? PM_INCUBUS : PM_SUCCUBUS], x, y));
X return(1);
X# endif
X } else if(!rn2(3)) {
X pline("Flupp! Muddy waste pops up from the drain.");
X if(!maploc->doormask) { /* only once per sink */
X if(!Blind)
X You("see a ring shining in its midst.");
X (void) mkobj_at(RING_SYM, x, y);
X prl(x, y);
X maploc->doormask = T_LOOTED;
X }
X return(1);
X }
X goto ouch;
X }
X# endif
X if(maploc->typ == STAIRS
X# ifdef STRONGHOLD
X || maploc->typ == LADDER
X# endif
X ) goto ouch;
X if(IS_STWALL(maploc->typ)) {
Xouch:
X pline("Ouch! That hurts!");
X if(!rn2(3)) set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
X losehp(rnd(ACURR(A_CON) > 15 ? 3 : 5), "dumb move");
X return(1);
X }
X# ifdef STRONGHOLD
X if (is_drawbridge_wall(x,y) >= 0) {
X pline("The drawbridge is unaffected.");
X return(1);
X }
X# endif
X goto dumb;
X }
X#endif /* KICK */
X
X if(maploc->doormask == D_ISOPEN ||
X maploc->doormask == D_BROKEN ||
X maploc->doormask == D_NODOOR) {
X#ifdef KICK
Xdumb:
X#endif
X if (martial() || ACURR(A_DEX) >= 16) {
X You("kick at empty space.");
X } else {
X pline("Dumb move! You strain a muscle.");
X set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
X }
X return(0);
X }
X
X /* door is known to be CLOSED or LOCKED */
X if(rnl(35) < avrg_attrib + (!martial() ? 0 : ACURR(A_DEX))) {
X /* break the door */
X if(maploc->doormask & D_TRAPPED) {
X pline("As you kick the door, it explodes!");
X b_trapped("door");
X maploc->doormask = D_NODOOR;
X } else if(ACURR(A_STR) > 18 && !rn2(5) && !in_shop(x, y)) {
X pline("As you kick the door, it shatters to pieces!");
X maploc->doormask = D_NODOOR;
X } else {
X pline("As you kick the door, it crashes open!");
X maploc->doormask = D_BROKEN;
X if(in_shop(x, y) && !in_shop(u.ux, u.uy))
X pay_for_door(x, y, "break");
X }
X } else pline("WHAMMM!!!");
X
X return(1);
X}
END_OF_FILE
if test 15059 -ne `wc -c <'src/dokick.c'`; then
echo shar: \"'src/dokick.c'\" unpacked with wrong size!
fi
# end of 'src/dokick.c'
fi
if test -f 'src/mondata.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/mondata.c'\"
else
echo shar: Extracting \"'src/mondata.c'\" \(14444 characters\)
sed "s/^X//" >'src/mondata.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)mondata.c 3.0 89/01/10
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed. See license for details. */
X
X#include "hack.h"
X#include "eshk.h"
X#include "epri.h"
X
X/* These routines provide basic data for any type of monster. */
X
Xboolean
Xattacktype(ptr, atyp)
X register struct permonst *ptr;
X register int atyp;
X{
X int i;
X
X for(i = 0; i < NATTK; i++)
X if(ptr->mattk[i].aatyp == atyp) return(TRUE);
X
X return(FALSE);
X}
X
Xboolean
Xresists_ston(ptr) /* returns TRUE if monster is petrify resistant */
X register struct permonst *ptr;
X{
X return (ptr->mflags1 & M1_STON_RES || dmgtype(ptr, AD_STON) ||
X dmgtype(ptr, AD_ACID));
X}
X
Xboolean
Xresists_drli(ptr) /* returns TRUE if monster is drain-life resistant */
X
X register struct permonst *ptr;
X{
X return(is_undead(ptr) || is_demon(ptr) || is_were(ptr));
X}
X
Xboolean
Xranged_attk(ptr) /* returns TRUE if monster can attack at range */
X register struct permonst *ptr;
X{
X return (attacktype(ptr, AT_BREA) || attacktype(ptr, AT_WEAP) ||
X attacktype(ptr, AT_SPIT) || attacktype(ptr, AT_GAZE) ||
X attacktype(ptr, AT_MAGC));
X}
X
Xboolean
Xcan_track(ptr) /* returns TRUE if monster can track well */
X register struct permonst *ptr;
X{
X#ifdef NAMED_ITEMS
X if(uwep && !strcmp(ONAME(uwep), "Excalibur")) return TRUE;
X#endif
X return(haseyes(ptr));
X}
X
X#ifdef POLYSELF
Xboolean
Xbreakarm(ptr) /* creature will break out of armor */
X register struct permonst *ptr;
X{
X return(bigmonst(ptr) || (!verysmall(ptr) && !humanoid(ptr))
X#ifdef HARD
X || ptr == &mons[PM_MARILITH]
X#endif
X );
X /* Marilith is about the only case of a monster which is otherwise
X * humanoid but cannot wear armor (too many arms). Centaurs would
X * be another except that they are already accounted for by
X * bigmonst.
X */
X}
X
Xboolean
Xsliparm(ptr) /* creature will slide out of armor */
X register struct permonst *ptr;
X{
X return(!bigmonst(ptr) && (verysmall(ptr) || ptr == &mons[PM_GHOST]));
X}
X#endif
X
Xboolean
Xsticks(ptr) /* creature sticks other creatures it hits */
X register struct permonst *ptr;
X{
X return(dmgtype(ptr,AD_STCK) || dmgtype(ptr,AD_WRAP) ||
X attacktype(ptr,AT_HUGS));
X}
X
X/* not one hundred percent correct: now a snake may hide under an
X * invisible object.
X */
Xboolean
Xcanseemon(mtmp)
X register struct monst *mtmp;
X{
X return((!mtmp->minvis || See_invisible)
X && (!mtmp->mhide ||
X (levl[mtmp->mx][mtmp->my].omask == 0 &&
X levl[mtmp->mx][mtmp->my].gmask == 0))
X && cansee(mtmp->mx, mtmp->my));
X}
X
Xboolean
Xdmgtype(ptr, dtyp)
X register struct permonst *ptr;
X register int dtyp;
X{
X int i;
X
X for(i = 0; i < NATTK; i++)
X if(ptr->mattk[i].adtyp == dtyp) return TRUE;
X
X return FALSE;
X}
X
Xint
Xmonsndx(ptr) /* return an index into the mons array */
X struct permonst *ptr;
X{
X register int i;
X register struct permonst *mdat;
X
X if(ptr == &playermon) return(-1);
X
X for(i = 0, mdat = &mons[0]; mdat->mlet; i++)
X if(ptr == mdat++) return(i);
X
X panic("monsndx - could not index monster (%x)", ptr);
X return FALSE; /* will not get here */
X}
X
Xint
Xname_to_mon(str)
Xchar *str;
X{
X /* Be careful. We must check the entire string in case it was
X * something such as "ettin zombie corpse". The calling routine
X * doesn't know about the "corpse" until the monster name has
X * already been taken off the front, so we have to be able to
X * read the name with extraneous stuff such as "corpse" stuck on
X * the end.
X * This causes a problem for names which prefix other names such
X * as "ettin" on "ettin zombie". In this case we want the _longest_
X * name which exists.
X * This also permits plurals created by adding suffixes such as 's'
X * or 'es'. Other plurals must still be handled explicitly.
X */
X register int i;
X register int mntmp = -1;
X register char *s;
X char buf[BUFSZ];
X int len=0;
X
X Strcpy(buf, str);
X str = buf;
X if (!strncmp(str, "a ", 2)) str += 2;
X else if (!strncmp(str, "an ", 3)) str += 3;
X
X /* Some irregular plurals */
X#ifdef HARD
X if (!strncmp(str, "incubi", 6)) return PM_INCUBUS;
X if (!strncmp(str, "succubi", 7)) return PM_SUCCUBUS;
X#endif
X if (!strncmp(str, "violet fungi", 12)) return PM_VIOLET_FUNGUS;
X if (!strncmp(str, "homunculi", 9)) return PM_HOMUNCULUS;
X if (!strncmp(str, "baluchitheria", 13)) return PM_BALUCHITHERIUM;
X if (!strncmp(str, "lurkers above", 13)) return PM_LURKER_ABOVE;
X if (!strncmp(str, "cavemen", 7)) return PM_CAVEMAN;
X if (!strncmp(str, "cavewomen", 9)) return PM_CAVEWOMAN;
X if (!strncmp(str, "zruties", 7)) return PM_ZRUTY;
X if (!strncmp(str, "djinn", 5)) return PM_DJINNI;
X /* be careful with "ies"; "priest", "zombies" */
X for(s=str; *s; s++) {
X if (!strncmp(s, "vortices", 8)) {
X Strcpy(s+4, "ex");
X break;
X }
X if (!strncmp(s, "jellies", 7) || !strncmp(s, "mummies", 7)) {
X Strcpy(s+4, "y");
X break;
X }
X if (!strncmp(s, "ves", 3)) {
X /* luckily no monster names end in fe or ve with ves plurals */
X Strcpy(s, "f");
X break;
X }
X }
X
X for(i = 0; mons[i].mlet; i++) {
X if(!strncmp(mons[i].mname, str, strlen(mons[i].mname))) {
X if (strlen(mons[i].mname) > len) {
X mntmp = i;
X len = strlen(mons[i].mname);
X }
X }
X }
X return mntmp;
X}
X
X#ifdef POLYSELF
Xboolean
Xwebmaker(ptr) /* creature can spin a web */
X register struct permonst *ptr;
X{
X return (ptr->mlet == S_SPIDER && ptr != &mons[PM_SCORPION]);
X}
X#endif
X
Xboolean
Xis_female(mtmp)
X register struct monst *mtmp;
X{
X if (mtmp->isshk) return !ESHK(mtmp)->ismale;
X#if defined(ALTARS) && defined(THEOLOGY)
X if (mtmp->ispriest) return !EPRI(mtmp)->ismale;
X#endif
X return !!(mtmp->data->mflags1 & M1_FEM);
X}
X
X/* Gender function. Differs from is_female() in that 1) It allows the monster
X * type of a polymorphed shopkeeper to override ESHK(mtmp)->ismale, and 2)
X * it returns 3 values (0=male, 1=female, 2=none) instead of 2.
X */
Xint
Xgender(mtmp)
X register struct monst *mtmp;
X{
X if (!humanoid(mtmp->data)) return 2;
X if (mtmp->data->mflags1 & M1_FEM) return 1;
X if (mtmp->data == &mons[PM_CAVEMAN]
X || mtmp->data == &mons[PM_PRIEST]
X#ifdef HARD
X || mtmp->data == &mons[PM_INCUBUS]
X#endif
X ) return 0;
X#if defined(ALTARS) && defined(THEOLOGY)
X if (mtmp->ispriest) return !EPRI(mtmp)->ismale;
X#endif
X if (mtmp->isshk) return !ESHK(mtmp)->ismale;
X return 0;
X}
X
Xboolean
Xlevl_follower(mtmp)
Xregister struct monst *mtmp;
X{
X return (mtmp->mtame || (mtmp->data->mflags1 & M1_STALK) || is_fshk(mtmp)
X || (mtmp->iswiz && !mon_has_amulet(mtmp)));
X}
X
Xstruct permonst *
Xplayer_mon()
X{
X switch (pl_character[0]) {
X case 'A': return &mons[PM_ARCHEOLOGIST];
X case 'B': return &mons[PM_BARBARIAN];
X case 'C': if (flags.female) return &mons[PM_CAVEWOMAN];
X else return &mons[PM_CAVEMAN];
X case 'E': return &mons[PM_ELF];
X case 'H': return &mons[PM_HEALER];
X case 'K': return &mons[PM_KNIGHT];
X case 'P': if (flags.female) return &mons[PM_PRIESTESS];
X else return &mons[PM_PRIEST];
X case 'R': return &mons[PM_ROGUE];
X case 'S': return &mons[PM_SAMURAI];
X case 'T': return &mons[PM_TOURIST];
X case 'V': return &mons[PM_VALKYRIE];
X case 'W': return &mons[PM_WIZARD];
X default: impossible("what are you?");
X return &mons[PM_HUMAN];
X }
X}
X
Xconst int grownups[][2] = { {PM_LITTLE_DOG, PM_DOG}, {PM_DOG, PM_LARGE_DOG},
X {PM_HELL_HOUND_PUP, PM_HELL_HOUND}, {PM_KITTEN, PM_HOUSECAT},
X {PM_HOUSECAT, PM_LARGE_CAT}, {PM_BABY_GREY_DRAGON, PM_GREY_DRAGON},
X {PM_BABY_RED_DRAGON, PM_RED_DRAGON},
X {PM_BABY_WHITE_DRAGON, PM_WHITE_DRAGON},
X {PM_BABY_BLUE_DRAGON, PM_BLUE_DRAGON},
X {PM_BABY_GREEN_DRAGON, PM_GREEN_DRAGON},
X {PM_BABY_ORANGE_DRAGON, PM_ORANGE_DRAGON},
X {PM_BABY_BLACK_DRAGON, PM_BLACK_DRAGON},
X {PM_BABY_YELLOW_DRAGON, PM_YELLOW_DRAGON},
X {PM_RED_NAGA_HATCHLING, PM_RED_NAGA},
X {PM_BLACK_NAGA_HATCHLING, PM_BLACK_NAGA},
X {PM_GOLDEN_NAGA_HATCHLING, PM_GOLDEN_NAGA},
X {PM_GUARDIAN_NAGA_HATCHLING, PM_GUARDIAN_NAGA},
X {PM_BABY_PURPLE_WORM, PM_PURPLE_WORM},
X#ifdef WORM
X {PM_BABY_LONG_WORM, PM_LONG_WORM},
X#endif
X#ifdef ARMY
X {PM_SOLDIER, PM_SERGEANT},
X {PM_SERGEANT, PM_LIEUTENANT},
X {PM_LIEUTENANT, PM_CAPTAIN},
X#endif
X {-1,-1}
X};
X
Xint little_to_big(montype)
Xint montype;
X{
X register int *i;
X
X for(i=grownups[0]; *i >= 0; i++)
X if(montype == *i) return *(i+1);
X return montype;
X}
X
Xint big_to_little(montype)
Xint montype;
X{
X register int *i;
X
X for(i=grownups[0]; *i >= 0; i++)
X if(montype == *(i+1)) return *i;
X return montype;
X}
X
X
X#ifdef STUPID_CPP /* otherwise these functions are macros in mondata.h */
X
Xint
Xbigmonst(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_BIG) != 0L);
X}
X
Xint
Xverysmall(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_VSMALL) != 0L);
X}
X
Xint
Xis_flyer(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_FLY) != 0L);
X}
X
Xint
Xis_floater(ptr) struct permonst *ptr; {
X return(ptr->mlet == S_EYE);
X}
X
Xint
Xis_swimmer(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_SWIM) != 0L);
X}
X
Xint
Xpasses_walls(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_WALLWALK) != 0L);
X}
X
Xint
Xnoncorporeal(ptr) struct permonst *ptr; {
X return(ptr->mlet == S_GHOST);
X}
X
Xint
Xis_animal(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_ANIMAL) != 0L);
X}
X
Xint
Xhumanoid(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_HUMANOID) != 0L);
X}
X
Xint
Xis_undead(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_UNDEAD) != 0L);
X}
X
Xint
Xis_were(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_WERE) != 0L);
X}
X
Xint haseyes(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_NOEYES) == 0L);
X}
X
Xint
Xnohands(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_NOHANDS) != 0L);
X}
X
Xint
Xlays_eggs(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_EGGS) != 0L);
X}
X
Xint
Xpoisonous(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_POIS) != 0L);
X}
X
Xint
Xresists_poison(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & (M1_POIS | M1_POIS_RES)) != 0L);
X}
X
Xint
Xresists_fire(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_FIRE_RES) != 0L);
X}
X
Xint
Xresists_cold(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_COLD_RES) != 0L);
X}
X
Xint
Xresists_acid(ptr) struct permonst *ptr; {
X return(dmgtype(ptr, AD_ACID));
X}
X
Xint
Xresists_elec(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_ELEC_RES) != 0L);
X}
X
Xint
Xresists_sleep(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & (M1_SLEE_RES | M1_UNDEAD)) != 0L);
X}
X
Xint
Xresists_disint(ptr) struct permonst *ptr; {
X return(ptr == &mons[PM_BLACK_DRAGON] ||
X ptr == &mons[PM_BABY_BLACK_DRAGON]);
X}
X
Xint
Xregenerates(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_REGEN) != 0L);
X}
X
Xint
Xperceives(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_SEE_INVIS) != 0L);
X}
X
Xint
Xcan_teleport(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_TPORT) != 0L);
X}
X
Xint
Xcontrol_teleport(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_TPORT_CONTROL) != 0L);
X}
X
Xint
Xis_armed(ptr) struct permonst *ptr; {
X return(attacktype(ptr, AT_WEAP));
X}
X
Xint
Xlikes_gold(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_GREEDY) != 0L);
X}
X
Xint
Xlikes_gems(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_JEWELS) != 0L);
X}
X
Xint
Xlikes_objs(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_COLLECT) != 0L || is_armed(ptr));
X}
X
Xint
Xlikes_magic(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_MAGIC) != 0L);
X}
X
Xint
Xhides_under(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_CONCEAL) != 0L);
X}
X
Xint
Xis_hider(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_HIDE) != 0L);
X}
X
X# ifdef POLYSELF
Xint
Xpolyok(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_NOPOLY) == 0L);
X}
X# endif /* POLYSELF */
X
Xint
Xtunnels(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_TUNNEL) != 0L);
X}
X
Xint
Xneedspick(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_NEEDPICK) != 0L);
X}
X
Xint
Xis_elf(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_ELF) != 0L);
X}
X
Xint
Xis_dwarf(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_DWARF) != 0L);
X}
X
Xint
Xis_giant(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_GIANT) != 0L);
X}
X
X# ifdef GOLEMS
Xint
Xis_golem(ptr) struct permonst *ptr; {
X return(ptr->mlet == S_GOLEM);
X}
X# endif /* GOLEMS */
X
Xint
Xis_orc(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_ORC) != 0L);
X}
X
Xint
Xis_human(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_HUMAN) != 0L);
X}
X
Xint
Xis_demon(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_DEMON) != 0L);
X}
X
Xint
Xis_mercenary(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_MERC) != 0L);
X}
X
Xint
Xthrows_rocks(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_ROCKTHROW) != 0L);
X}
X
Xint
Xis_wanderer(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_WANDER) != 0L);
X}
X
Xint
Xis_lord(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_LORD) != 0L);
X}
X
Xint
Xis_prince(ptr) struct permonst *ptr; {
X return((ptr->mflags1 & M1_PRINCE) != 0L);
X}
X
X# ifdef HARD
Xint
Xis_ndemon(ptr) struct permonst *ptr; {
X return(is_demon(ptr) &&
X (ptr->mflags1 & (M1_LORD | M1_PRINCE)) == 0L);
X}
X# else /* HARD */
Xint
Xis_ndemon(ptr) struct permonst *ptr; {
X return(ptr == &mons[PM_DEMON]);
X}
X# endif /* HARD */
X
Xint
Xis_dlord(ptr) struct permonst *ptr; {
X return(is_demon(ptr) && is_lord(ptr));
X}
X
Xint
Xis_dprince(ptr) struct permonst *ptr; {
X return(is_demon(ptr) && is_prince(ptr));
X}
X
Xint
Xtype_is_pname(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_PNAME) != 0L);
X}
X
Xint
Xalways_hostile(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_HOSTILE) != 0L);
X}
X
Xint
Xalways_peaceful(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_PEACEFUL) != 0L);
X}
X
Xint
Xstrongmonst(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_STRONG) != 0L);
X}
X
Xint
Xextra_nasty(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_NASTY) != 0L);
X}
X
X# ifdef POLYSELF
Xint
Xcan_breathe(ptr) struct permonst *ptr; {
X return(attacktype(ptr, AT_BREA));
X}
X
Xint
Xcantwield(ptr) struct permonst *ptr; {
X return(nohands(ptr) || verysmall(ptr));
X}
X
Xint
Xcantweararm(ptr) struct permonst *ptr; {
X return(breakarm(ptr) || sliparm(ptr));
X}
X
Xint
Xnolimbs(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_NOLIMBS) != 0L);
X}
X# endif /* POLYSELF */
X
Xint
Xcarnivorous(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_CARNIVORE) != 0L);
X}
X
Xint
Xherbivorous(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_HERBIVORE) != 0L);
X}
X
Xint
Xthick_skinned(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_THICK_HIDE) != 0L);
X}
X
Xint
Xamorphous(ptr) struct permonst *ptr; {
X return((ptr->mflags2 & M2_AMORPHOUS) != 0L);
X}
X
X#endif /* STUPID_CPP */
END_OF_FILE
if test 14444 -ne `wc -c <'src/mondata.c'`; then
echo shar: \"'src/mondata.c'\" unpacked with wrong size!
fi
# end of 'src/mondata.c'
fi
if test -f 'src/pager.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/pager.c'\"
else
echo shar: Extracting \"'src/pager.c'\" \(15100 characters\)
sed "s/^X//" >'src/pager.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)pager.c 3.0 88/10/25 */
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed. See license for details. */
X
X/* This file contains the command routine dowhatis() and a pager. */
X/* Also readmail() and doshell(), and generally the things that
X contact the outside world. */
X
X/* block some unused #defines to avoid overloading some cpp's */
X#define MONATTK_H
X#include "hack.h"
X
X#ifndef TOS
X#include <signal.h>
X#endif
X#if defined(BSD) || defined(ULTRIX)
X#include <sys/wait.h>
X#endif
X
Xstatic char hc = 0;
X
Xstatic void page_more();
X
Xint
Xdowhatis()
X{
X FILE *fp;
X char bufr[BUFSZ+6];
X register char *buf = &bufr[6], *ep, q;
X register struct monst *mtmp;
X
X if(!(fp = fopen(DATAFILE, "r")))
X pline("Cannot open data file!");
X else {
X coord cc;
X uchar r;
X
X pline ("Specify unknown object by cursor? ");
X q = ynq();
X cc.x = cc.y = -1;
X if (q == 'q') {
X (void) fclose(fp);
X return 0;
X } else if (q == 'n') {
X pline("Specify what? ");
X r = readchar();
X } else {
X if(flags.verbose)
X pline("Please move the cursor to the unknown object.");
X getpos(&cc, TRUE, "the unknown object");
X r = levl[cc.x][cc.y].scrsym;
X }
X
X if (r == showsyms.stone) q = defsyms.stone;
X else if (r == showsyms.vwall) q = defsyms.vwall;
X else if (r == showsyms.hwall) q = defsyms.hwall;
X else if (r == showsyms.tlcorn) q = defsyms.tlcorn;
X else if (r == showsyms.trcorn) q = defsyms.trcorn;
X else if (r == showsyms.blcorn) q = defsyms.blcorn;
X else if (r == showsyms.brcorn) q = defsyms.brcorn;
X else if (r == showsyms.crwall) q = defsyms.crwall;
X else if (r == showsyms.tuwall) q = defsyms.tuwall;
X else if (r == showsyms.tdwall) q = defsyms.tdwall;
X else if (r == showsyms.tlwall) q = defsyms.tlwall;
X else if (r == showsyms.trwall) q = defsyms.trwall;
X else if (r == showsyms.door) q = defsyms.door;
X else if (r == showsyms.room) q = defsyms.room;
X else if (r == showsyms.corr) q = defsyms.corr;
X else if (r == showsyms.upstair) q = defsyms.upstair;
X else if (r == showsyms.dnstair) q = defsyms.dnstair;
X else if (r == showsyms.trap) q = defsyms.trap;
X#ifdef FOUNTAINS
X else if (r == showsyms.pool) q = defsyms.pool;
X else if (r == showsyms.fountain) q = defsyms.fountain;
X#endif
X#ifdef THRONES
X else if (r == showsyms.throne) q = defsyms.throne;
X#endif
X else if (r == showsyms.web) q = defsyms.web;
X#ifdef SINKS
X else if (r == showsyms.sink) q = defsyms.sink;
X#endif
X#ifdef ALTARS
X else if (r == showsyms.altar) q = defsyms.altar;
X#endif
X else
X q = r;
X if (index(quitchars, q)) {
X (void) fclose(fp); /* sweet@scubed */
X return 0;
X }
X if(q == '%') {
X pline("%% a piece of food");
X (void) fclose(fp);
X return 0;
X }
X
X if(q != '\t')
X while(fgets(buf,BUFSZ,fp))
X if(*buf == q) {
X ep = index(buf, '\n');
X if(ep) *ep = 0;
X /* else: bad data file */
X /* Expand tab 'by hand' */
X if(buf[1] == '\t'){
X buf = bufr;
X buf[0] = r;
X (void) strncpy(buf+1, " ", 7);
X }
X pline(buf);
X if(cc.x != -1 && IS_ALTAR(levl[cc.x][cc.y].typ)) {
X int type = levl[u.ux][u.uy].altarmask & ~A_SHRINE;
X pline("(%s)", (type==0) ? "chaotic" :
X (type==1) ? "neutral" : "lawful");
X }
X if (!Invisible && u.ux==cc.x && u.uy==cc.y) {
X pline("(%s named %s)",
X#ifdef POLYSELF
X u.mtimedone ? mons[u.umonnum].mname :
X#endif
X pl_character, plname);
X } else if((q >= 'A' && q <= 'z') || index(";:& @`",q)) {
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X if(mtmp->mx == cc.x && mtmp->my == cc.y) {
X pline("(%s%s)",
X mtmp->mtame ? "tame " :
X mtmp->mpeaceful ? "peaceful " : "",
X strncmp(lmonnam(mtmp), "the ", 4)
X ? lmonnam(mtmp) : lmonnam(mtmp)+4);
X break;
X }
X }
X if(ep[-1] == ';') {
X pline("More info? ");
X if(yn() == 'y') {
X page_more(fp,1); /* does fclose() */
X return 0;
X }
X }
X (void) fclose(fp); /* kopper@psuvax1 */
X return 0;
X }
X pline("I've never heard of such things.");
X (void) fclose(fp);
X }
X return 0;
X}
X
Xint
Xdowhatdoes()
X{
X FILE *fp;
X char bufr[BUFSZ+6];
X register char *buf = &bufr[6], *ep, q, ctrl;
X
X if(!(fp = fopen(CMDHELPFILE, "r"))) {
X pline("Cannot open data file!");
X return 0;
X }
X pline("What command? ");
X#ifdef UNIX
X introff();
X#endif
X q = readchar();
X#ifdef UNIX
X intron();
X#endif
X if (q == '\033') ctrl = '[';
X else if (q != unctrl(q)) ctrl = q - 1 + 'A';
X else ctrl = 0;
X while(fgets(buf,BUFSZ,fp))
X if ((!ctrl && *buf==q) || (ctrl && *buf=='^' && *(buf+1)==ctrl)) {
X ep = index(buf, '\n');
X if(ep) *ep = 0;
X if(!ctrl && buf[1] == '\t'){
X buf = bufr;
X buf[0] = q;
X (void) strncpy(buf+1, " ", 7);
X } else if (ctrl && buf[2] == '\t'){
X buf = bufr + 1;
X buf[0] = '^';
X buf[1] = ctrl;
X (void) strncpy(buf+2, " ", 6);
X }
X pline(buf);
X (void) fclose(fp);
X return 0;
X }
X pline("I've never heard of such commands.");
X (void) fclose(fp);
X return 0;
X}
X
X/* make the paging of a file interruptible */
Xstatic int got_intrup;
X
X#if !defined(MSDOS) && !defined(TOS)
Xstatic int
Xintruph(){
X (void) signal(SIGINT, (SIG_RET_TYPE) intruph);
X got_intrup++;
X return 0;
X}
X#endif
X
X/* simple pager, also used from dohelp() */
Xstatic void
Xpage_more(fp,strip)
XFILE *fp;
Xint strip; /* nr of chars to be stripped from each line (0 or 1) */
X{
X register char *bufr;
X#if !defined(MSDOS) && !defined(MINIMAL_TERM)
X register char *ep;
X#endif
X#if !defined(MSDOS) && !defined(TOS)
X int (*prevsig)() = (int (*)())signal(SIGINT, (SIG_RET_TYPE) intruph);
X#endif
X#if defined(MSDOS) || defined(MINIMAL_TERM)
X /* There seems to be a bug in ANSI.SYS The first tab character
X * after a clear screen sequence is not expanded correctly. Thus
X * expand the tabs by hand -dgk
X */
X int tabstop = 8, spaces;
X char buf[BUFSIZ], *bufp, *bufrp;
X
X set_pager(0);
X bufr = (char *) alloc((unsigned) COLNO);
X while (fgets(buf, BUFSIZ, fp) && (!strip || *buf == '\t')){
X bufp = buf;
X bufrp = bufr;
X while (*bufp && *bufp != '\n') {
X if (*bufp == '\t') {
X spaces = tabstop - (bufrp - bufr) % tabstop;
X while (spaces--)
X *bufrp++ = ' ';
X bufp++;
X } else
X *bufrp++ = *bufp++;
X }
X *bufrp = '\0';
X#else /* MSDOS /**/
X set_pager(0);
X bufr = (char *) alloc((unsigned) COLNO);
X bufr[COLNO-1] = 0;
X while(fgets(bufr,COLNO-1,fp) && (!strip || *bufr == '\t')){
X ep = index(bufr, '\n');
X if(ep)
X *ep = 0;
X#endif /* MSDOS /**/
X if(got_intrup || page_line(bufr+strip)) {
X set_pager(2);
X goto ret;
X }
X }
X set_pager(1);
Xret:
X free((genericptr_t) bufr);
X (void) fclose(fp);
X#if !defined(MSDOS) && !defined(TOS)
X (void) signal(SIGINT, (SIG_RET_TYPE) prevsig);
X got_intrup = 0;
X#endif
X}
X
Xstatic boolean whole_screen = TRUE;
X#define PAGMIN 12 /* minimum # of lines for page below level map */
X
Xvoid
Xset_whole_screen() { /* called in termcap as soon as LI is known */
X whole_screen = (LI-ROWNO-2 <= PAGMIN || !CD);
X}
X
X#ifdef NEWS
Xint
Xreadnews() {
X register int ret;
X
X whole_screen = TRUE; /* force a docrt(), our first */
X ret = page_file(NEWS, TRUE);
X set_whole_screen();
X return(ret); /* report whether we did docrt() */
X}
X#endif
X
Xvoid
Xset_pager(mode)
Xregister int mode; /* 0: open 1: wait+close 2: close */
X{
X#ifdef LINT /* lint may handle static decl poorly -- static boolean so; */
X boolean so;
X#else
X static boolean so;
X#endif
X if(mode == 0) {
X if(!whole_screen) {
X /* clear topline */
X clrlin();
X /* use part of screen below level map */
X curs(1, ROWNO+4);
X } else {
X cls();
X }
X so = flags.standout;
X flags.standout = 1;
X } else {
X if(mode == 1) {
X curs(1, LI);
X more();
X }
X flags.standout = so;
X if(whole_screen)
X docrt();
X else {
X curs(1, ROWNO+4);
X cl_eos();
X }
X }
X}
X
Xint
Xpage_line(s) /* returns 1 if we should quit */
Xregister char *s;
X{
X if(cury == LI-1) {
X if(!*s)
X return(0); /* suppress blank lines at top */
X (void) putchar('\n');
X cury++;
X cmore("q\033");
X if(morc) {
X morc = 0;
X return(1);
X }
X if(whole_screen)
X cls();
X else {
X curs(1, ROWNO+4);
X cl_eos();
X }
X }
X#ifdef TERMINFO
X xputs(s); xputc('\n');
X#else
X (void) puts(s);
X#endif
X cury++;
X return(0);
X}
X
X/*
X * Flexible pager: feed it with a number of lines and it will decide
X * whether these should be fed to the pager above, or displayed in a
X * corner.
X * Call:
X * cornline(0, title or 0) : initialize
X * cornline(1, text) : add text to the chain of texts
X * cornline(2, morcs) : output everything and cleanup
X * cornline(3, 0) : cleanup
X * cornline(-1,"") : special, for help menu mode only
X */
X
Xvoid
Xcornline(mode, text)
Xint mode;
Xchar *text;
X{
X static struct line {
X struct line *next_line;
X char *line_text;
X } *texthead, *texttail;
X static int maxlen;
X static int linect;
X register struct line *tl;
X register boolean hmenu = FALSE;
X
X if(mode == -1) { /* help menu display only */
X mode = 2;
X hmenu = TRUE;
X }
X if(mode == 0) {
X texthead = 0;
X maxlen = 0;
X linect = 0;
X if(text) {
X cornline(1, text); /* title */
X cornline(1, ""); /* blank line */
X }
X return;
X }
X
X if(mode == 1) {
X register int len;
X
X if(!text) return; /* superfluous, just to be sure */
X linect++;
X len = strlen(text) + 1; /* allow for an extra leading space */
X if(len > maxlen)
X maxlen = len;
X tl = (struct line *)
X alloc((unsigned)(len + sizeof(struct line) + 1));
X tl->next_line = 0;
X tl->line_text = (char *)(tl + 1);
X tl->line_text[0] = ' ';
X tl->line_text[1] = '\0';
X Strcat(tl->line_text, text);
X if(!texthead)
X texthead = tl;
X else
X texttail->next_line = tl;
X texttail = tl;
X return;
X }
X
X /* --- now we really do it --- */
X if(mode == 2 && linect == 1) /* topline only */
X pline(texthead->line_text);
X else
X if(mode == 2) {
X register int curline, lth;
X
X if(flags.toplin == 1) more(); /* ab@unido */
X remember_topl();
X
X lth = CO - maxlen - 2; /* Use full screen width */
X if (linect < LI && lth >= 10) { /* in a corner */
X home ();
X cl_end ();
X flags.toplin = 0;
X curline = 1;
X for (tl = texthead; tl; tl = tl->next_line) {
X#if defined(MSDOS) && !defined(AMIGA)
X cmov (lth, curline);
X#else
X curs (lth, curline);
X#endif
X if(curline > 1)
X cl_end ();
X xputs(tl->line_text);
X curx = curx + strlen(tl->line_text);
X curline++;
X }
X if(hmenu) hc = lowc(readchar()); /* help menu display */
X#if defined(MSDOS) && !defined(AMIGA)
X cmov (lth, curline);
X#else
X curs (lth, curline);
X#endif
X cl_end ();
X if (!hmenu) cmore (text);
X home ();
X cl_end ();
X docorner (lth, curline-1);
X } else { /* feed to pager */
X set_pager(0);
X for (tl = texthead; tl; tl = tl->next_line) {
X if (page_line (tl->line_text)) {
X set_pager(2);
X goto cleanup;
X }
X }
X if(text) {
X cgetret(text);
X set_pager(2);
X } else
X set_pager(1);
X }
X }
X
Xcleanup:
X while(tl = texthead) {
X texthead = tl->next_line;
X free((genericptr_t) tl);
X }
X}
X
X#ifdef WIZARD
Xstatic
Xvoid
Xwiz_help()
X{
X cornline(0, "Wizard-Mode Quick Reference:");
X cornline(1, "^E == detect secret doors and traps.");
X cornline(1, "^F == do magic mapping.");
X cornline(1, "^G == create monster.");
X cornline(1, "^I == identify items in pack.");
X cornline(1, "^O == tell locations of special levels.");
X cornline(1, "^T == do intra-level teleport.");
X cornline(1, "^V == do trans-level teleport.");
X cornline(1, "^W == make wish.");
X cornline(1, "^X == show intrinsic attributes.");
X cornline(1, "");
X cornline(2, "");
X}
X#endif
X
Xstatic void
Xhelp_menu() {
X cornline(0, "Information available:");
X cornline(1, "a. Long description of the game and commands.");
X cornline(1, "b. List of game commands.");
X cornline(1, "c. Concise history of NetHack.");
X cornline(1, "d. Info on a character in the game display.");
X cornline(1, "e. Info on what a given key does.");
X cornline(1, "f. List of game options.");
X cornline(1, "g. Longer explanation of game options.");
X cornline(1, "h. List of extended commands.");
X cornline(1, "i. The NetHack license.");
X#ifdef WIZARD
X if (wizard)
X cornline(1, "j. List of wizard-mode commands.");
X#endif
X cornline(1, "");
X#ifdef WIZARD
X if (wizard)
X cornline(1, "Select one of a,b,c,d,e,f,g,h,i,j or ESC: ");
X else
X#endif
X cornline(1, "Select one of a,b,c,d,e,f,g,h,i or ESC: ");
X cornline(-1,"");
X}
X
Xint
Xdohelp()
X{
X char c;
X
X do {
X help_menu();
X c = hc;
X#ifdef WIZARD
X } while ((c < 'a' || c > (wizard ? 'j' : 'i')) && !index(quitchars,c));
X#else
X } while ((c < 'a' || c > 'i') && !index(quitchars,c));
X#endif
X if (!index(quitchars, c)) {
X switch(c) {
X case 'a': (void) page_file(HELP, FALSE); break;
X case 'b': (void) page_file(SHELP, FALSE); break;
X case 'c': (void) dohistory(); break;
X case 'd': (void) dowhatis(); break;
X case 'e': (void) dowhatdoes(); break;
X case 'f': option_help(); break;
X case 'g': (void) page_file(OPTIONFILE, FALSE); break;
X case 'h': (void) doextlist(); break;
X case 'i': (void) page_file(LICENSE, FALSE); break;
X#ifdef WIZARD
X case 'j': wiz_help(); break;
X#endif
X }
X }
X return 0;
X}
X
Xint
Xdohistory()
X{
X (void) page_file(HISTORY, FALSE);
X return 0;
X}
X
Xint
Xpage_file(fnam, silent) /* return: 0 - cannot open fnam; 1 - otherwise */
Xregister char *fnam;
Xboolean silent;
X{
X#ifdef DEF_PAGER /* this implies that UNIX is defined */
X {
X /* use external pager; this may give security problems */
X
X register int fd = open(fnam, 0);
X
X if(fd < 0) {
X if(!silent) pline("Cannot open %s.", fnam);
X return(0);
X }
X if(child(1)){
X /* Now that child() does a setuid(getuid()) and a chdir(),
X we may not be able to open file fnam anymore, so make
X it stdin. */
X (void) close(0);
X if(dup(fd)) {
X if(!silent) Printf("Cannot open %s as stdin.\n", fnam);
X } else {
X (void) execl(catmore, "page", NULL);
X if(!silent) Printf("Cannot exec %s.\n", catmore);
X }
X exit(1);
X }
X (void) close(fd);
X }
X#else
X {
X FILE *f; /* free after Robert Viduya */
X
X if ((f = fopen (fnam, "r")) == (FILE *) 0) {
X if(!silent) {
X home(); perror (fnam); flags.toplin = 1;
X pline ("Cannot open %s.", fnam);
X }
X return(0);
X }
X page_more(f, 0);
X }
X#endif /* DEF_PAGER /**/
X
X return(1);
X}
X
X#ifdef UNIX
X#ifdef SHELL
Xint
Xdosh(){
Xregister char *str;
X if(child(0)) {
X if(str = getenv("SHELL"))
X (void) execl(str, str, NULL);
X else
X (void) execl("/bin/sh", "sh", NULL);
X pline("sh: cannot execute.");
X exit(1);
X }
X return 0;
X}
X#endif /* SHELL /**/
X
Xint
Xchild(wt)
Xint wt;
X{
Xregister int f = fork();
X if(f == 0){ /* child */
X settty(NULL); /* also calls end_screen() */
X (void) setgid(getgid());
X (void) setuid(getuid());
X#ifdef CHDIR
X (void) chdir(getenv("HOME"));
X#endif
X return(1);
X }
X if(f == -1) { /* cannot fork */
X pline("Fork failed. Try again.");
X return(0);
X }
X /* fork succeeded; wait for child to exit */
X (void) signal(SIGINT,SIG_IGN);
X (void) signal(SIGQUIT,SIG_IGN);
X (void) wait(
X#if defined(BSD) || defined(ULTRIX)
X (union wait *)
X#else
X (int *)
X#endif
X 0);
X gettty();
X setftty();
X (void) signal(SIGINT, (SIG_RET_TYPE) done1);
X#ifdef WIZARD
X if(wizard) (void) signal(SIGQUIT,SIG_DFL);
X#endif
X if(wt) getret();
X docrt();
X return(0);
X}
X#endif /* UNIX /**/
END_OF_FILE
if test 15100 -ne `wc -c <'src/pager.c'`; then
echo shar: \"'src/pager.c'\" unpacked with wrong size!
fi
# end of 'src/pager.c'
fi
echo shar: End of archive 24 \(of 38\).
cp /dev/null ark24isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 38 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0