billr@saab.CNA.TEK.COM (Bill Randle) (07/12/90)
Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu> Posting-number: Volume 10, Issue 79 Archive-name: nethack3p9/Part34 Supersedes: NetHack3: Volume 7, Issue 56-93 #! /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 34 (of 56)." # Contents: src/dbridge.c src/pager.c src/sit.c # Wrapped by billr@saab on Wed Jul 11 17:11:42 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'src/dbridge.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/dbridge.c'\" else echo shar: Extracting \"'src/dbridge.c'\" \(20980 characters\) sed "s/^X//" >'src/dbridge.c' <<'END_OF_FILE' X/* SCCS Id: @(#)dbridge.c 3.0 88/18/12 X/* Copyright (c) 1989 by Jean-Christophe Collet */ X/* NetHack may be freely redistributed. See license for details. */ X X/* X * This file contains the drawbridge manipulation (create, open, close, X * destroy). X * X * Added comprehensive monster-handling, and the "entity" structure to X * deal with players as well. - 11/89 X */ X X#include "hack.h" X X#ifdef STRONGHOLD X# ifdef OVLB Xstatic void FDECL(redosym, (int, int)); Xstatic void FDECL(get_wall_for_db, (int *, int *)); Xstatic struct entity *FDECL(e_at, (int, int)); Xstatic void FDECL(m_to_e, (struct monst *, struct entity *)); Xstatic void FDECL(u_to_e, (struct entity *)); Xstatic void FDECL(set_entity, (int, int, struct entity *)); Xstatic char *FDECL(e_nam, (struct entity *)); X/* static char *FDECL(Enam, (struct entity *)); */ /* unused */ Xstatic char *FDECL(E_phrase, (struct entity *, const char *)); Xstatic boolean FDECL(e_survives_at, (struct entity *, int, int)); Xstatic void FDECL(e_died, (struct entity *, int, int)); Xstatic boolean FDECL(automiss, (struct entity *)); Xstatic boolean FDECL(e_missed, (struct entity *, BOOLEAN_P)); Xstatic boolean FDECL(e_jumps, (struct entity *)); Xstatic void FDECL(do_entity, (struct entity *)); X# endif /* OVLB */ X#endif /* STRONGHOLD */ X X#ifdef OVL0 X Xboolean Xis_pool(x,y) Xint x,y; X{ X if(levl[x][y].typ == POOL || levl[x][y].typ == MOAT) return TRUE; X#ifdef STRONGHOLD X if(levl[x][y].typ == DRAWBRIDGE_UP && X (levl[x][y].drawbridgemask & DB_UNDER) == DB_MOAT) return TRUE; X#endif X return FALSE; X} X X#endif /* OVL0 */ X X#ifdef STRONGHOLD X X#ifdef OVL1 X Xvoid Xinitsym(x,y) Xint x,y; X{ X char oldseen; X struct rm *crm = &levl[x][y]; X X oldseen = crm->seen; X crm->seen = 1; X crm->scrsym = news0(x,y); X crm->seen = oldseen; X} X X#endif /* OVL1 */ X#ifdef OVLB X Xstatic void Xredosym(x,y) Xint x,y; X{ X if(cansee(x,y)) { X levl[x][y].seen = 0; /* force prl */ X prl(x, y); X } else { X initsym(x,y); X levl[x][y].seen = 0; X } X} X X#endif /* OVLB */ X#ifdef OVL1 X X/* X * We want to know whether a wall (or a door) is the portcullis (passageway) X * of an eventual drawbridge. X * X * Return value: the direction of the drawbridge. X */ X Xint Xis_drawbridge_wall(x,y) Xint x,y; X{ X struct rm *lev; X X lev = &levl[x][y]; X if (lev->typ != DOOR && !(lev->diggable & W_GATEWAY)) X return (-1); X switch (lev->typ) { X case DOOR: X case VWALL: X if (IS_DRAWBRIDGE(levl[x+1][y].typ) && X (levl[x+1][y].drawbridgemask & DB_DIR) == DB_WEST) X return (DB_WEST); X if (IS_DRAWBRIDGE(levl[x-1][y].typ) && X (levl[x-1][y].drawbridgemask & DB_DIR) == DB_EAST) X return (DB_EAST); X if (lev->typ == VWALL) break; X case HWALL: X if (IS_DRAWBRIDGE(levl[x][y-1].typ) && X (levl[x][y-1].drawbridgemask & DB_DIR) == DB_SOUTH) X return (DB_SOUTH); X if (IS_DRAWBRIDGE(levl[x][y+1].typ) && X (levl[x][y+1].drawbridgemask & DB_DIR) == DB_NORTH) X return (DB_NORTH); X } X return (-1); X} X X/* X * Use is_db_wall where you want to verify that a X * drawbridge "wall" is UP in the location x, y X * (instead of UP or DOWN, as with is_drawbridge_wall). X */ Xboolean Xis_db_wall(x,y) Xint x,y; X{ X return( (levl[x][y].typ == VWALL || levl[x][y].typ == HWALL) && X levl[x][y].diggable & W_GATEWAY); X} X X X/* X * Return true with x,y pointing to the drawbridge if x,y initially indicate X * a drawbridge or drawbridge wall. X */ Xboolean Xfind_drawbridge(x,y) Xint *x,*y; X{ X int dir; X X if (IS_DRAWBRIDGE(levl[*x][*y].typ)) X return TRUE; X dir = is_drawbridge_wall(*x,*y); X if (dir >= 0) { X switch(dir) { X case DB_NORTH: (*y)++; break; X case DB_SOUTH: (*y)--; break; X case DB_EAST: (*x)--; break; X case DB_WEST: (*x)++; break; X } X return TRUE; X } X return FALSE; X} X X#endif /* OVL1 */ X#ifdef OVLB X X/* X * Find the drawbridge wall associated with a drawbridge. X */ Xstatic void Xget_wall_for_db(x,y) Xint *x,*y; X{ X switch (levl[*x][*y].drawbridgemask & DB_DIR) { X case DB_NORTH: (*y)--; break; X case DB_SOUTH: (*y)++; break; X case DB_EAST: (*x)++; break; X case DB_WEST: (*x)--; break; X } X} X X/* X * Creation of a drawbridge at pos x,y. X * dir is the direction. X * flag must be put to TRUE if we want the drawbridge to be opened. X */ X Xboolean Xcreate_drawbridge(x,y,dir,flag) Xint x,y,dir; Xboolean flag; X{ X int x2,y2; X uchar wall; X X x2 = x; y2 = y; X switch(dir) { X case DB_NORTH: X wall = HWALL; X y2--; X break; X case DB_SOUTH: X wall = HWALL; X y2++; X break; X case DB_EAST: X wall = VWALL; X x2++; X break; X default: X impossible("bad direction in create_drawbridge"); X /* fall through */ X case DB_WEST: X wall = VWALL; X x2--; X break; X } X if (!IS_WALL(levl[x2][y2].typ)) X return(FALSE); X if (flag) { /* We want the bridge open */ X levl[x][y].typ = DRAWBRIDGE_DOWN; X levl[x2][y2].typ = DOOR; X levl[x2][y2].doormask = D_NODOOR; X } else { X levl[x][y].typ = DRAWBRIDGE_UP; X levl[x2][y2].typ = wall; X /* Beware, drawbridges are non-diggable. */ X levl[x2][y2].diggable = (W_NONDIGGABLE | W_GATEWAY); X } X levl[x][y].drawbridgemask = dir; /* always have DB_MOAT */ X initsym(x,y); X initsym(x2,y2); X return(TRUE); X} X Xstruct entity { X struct monst *emon; /* youmonst for the player */ X struct permonst *edata; /* must be non-zero for record to be valid */ X int ex, ey; X}; X X#define ENTITIES 2 X Xstatic struct entity NEARDATA occupants[ENTITIES]; X Xstatic Xstruct entity * Xe_at(x, y) Xint x, y; X{ X int entitycnt; X X for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++) X if ((occupants[entitycnt].edata) && X (occupants[entitycnt].ex == x) && X (occupants[entitycnt].ey == y)) X break; X#ifdef D_DEBUG X pline("entitycnt = %d", entitycnt); X fflush(stdout); X#endif X return((entitycnt == ENTITIES)? X (struct entity *)0 : &(occupants[entitycnt])); X} X Xstatic void Xm_to_e(mtmp, etmp) Xstruct monst *mtmp; Xstruct entity *etmp; X{ X etmp->emon = mtmp; X if (mtmp) { X etmp->ex = mtmp->mx; X etmp->ey = mtmp->my; X etmp->edata = mtmp->data; X } else X etmp->edata = (struct permonst *)0; X} X Xstatic void Xu_to_e(etmp) Xstruct entity *etmp; X{ X etmp->emon = &youmonst; X etmp->ex = u.ux; X etmp->ey = u.uy; X etmp->edata = uasmon; X} X Xstatic void Xset_entity(x, y, etmp) Xint x, y; Xstruct entity *etmp; X{ X if ((x == u.ux) && (y == u.uy)) X u_to_e(etmp); X else X if (MON_AT(x, y)) X m_to_e(m_at(x, y), etmp); X else X etmp->edata = (struct permonst *)0; X} X X#ifdef POLYSELF X#define is_u(etmp) (etmp->emon == &youmonst) X#else X#define is_u(x) FALSE X#endif X X/* X * WARNING! THE FOLLOWING IS ONLY USEFUL FOR CANSEEMON, OR OTHER FUNCS WHICH X * ALWAYS RETURN TRUE FOR U. X */ X X#define e_boolean(etmp, func) (is_u(etmp)? (boolean)TRUE : func(etmp->emon)) X X/* X * e_strg is a utility routine which is not actually in use anywhere, since X * the specialized routines below suffice for all current purposes. X */ X X/* #define e_strg(etmp, func) (is_u(etmp)? (char *)0 : func(etmp->emon)) */ X Xstatic char * Xe_nam(etmp) Xstruct entity *etmp; X{ X return(is_u(etmp)? "you" : mon_nam(etmp->emon)); X} X X/* X * Enam is another unused utility routine: E_phrase is preferable. X */ X X/* Xstatic char * XEnam(etmp) Xstruct entity *etmp; X{ X return(is_u(etmp)? "You" : Monnam(etmp->emon)); X} X*/ X X/* X * Generates capitalized entity name, makes 2nd -> 3rd person conversion on X * verb, where necessary. X */ X Xstatic char * XE_phrase(etmp, verb) Xstruct entity *etmp; Xconst char *verb; X{ X char wholebuf[80], verbbuf[30]; X X if (is_u(etmp)) X Strcpy(wholebuf, "You"); X else X Strcpy(wholebuf, Monnam(etmp->emon)); X if (!*verb) X return(wholebuf); X Strcat(wholebuf, " "); X verbbuf[0] = '\0'; X if (is_u(etmp)) X Strcpy(verbbuf, verb); X else { X if (!strcmp(verb, "are")) X Strcpy(verbbuf, "is"); X if (!strcmp(verb, "have")) X Strcpy(verbbuf, "has"); X if (!verbbuf[0]) { X Strcpy(verbbuf, verb); X switch (verbbuf[strlen(verbbuf) - 1]) { X case 'y': X verbbuf[strlen(verbbuf) - 1] = '\0'; X Strcat(verbbuf, "ies"); X break; X case 'h': X case 'o': X case 's': X Strcat(verbbuf, "es"); X break; X default: X Strcat(verbbuf, "s"); X break; X } X } X } X Strcat(wholebuf, verbbuf); X return(wholebuf); X} X X/* X * Simple-minded "can it be here?" routine X */ X Xstatic boolean Xe_survives_at(etmp, x, y) Xstruct entity *etmp; Xint x, y; X{ X if (noncorporeal(etmp->edata)) X return(TRUE); X if (is_pool(x, y)) X return((is_u(etmp) && (Wwalking || Levitation)) || X is_swimmer(etmp->edata) || is_flyer(etmp->edata) || X is_floater(etmp->edata)); X if (is_db_wall(x, y)) X return(passes_walls(etmp->edata)); X return(TRUE); X} X Xstatic void Xe_died(etmp, dest, how) Xstruct entity *etmp; Xint dest, how; X{ X if (is_u(etmp)) { X if (how == DROWNING) X drown(); X else { X coord xy; X X killer_format = KILLED_BY_AN; X killer = "falling drawbridge"; X done(how); X /* So, you didn't die */ X if (!e_survives_at(etmp, etmp->ex, etmp->ey)) { X pline("A %s force teleports you away...", X Hallucination ? "normal" : "strange"); X (void) enexto(&xy, etmp->ex, etmp->ey, X etmp->edata); X teleds(xy.x, xy.y); X } X } X } else { X xkilled(etmp->emon, dest); X etmp->edata = (struct permonst *)0; X } X} X X X/* X * These are never directly affected by a bridge or portcullis. X */ X Xstatic boolean Xautomiss(etmp) Xstruct entity *etmp; X{ X return(passes_walls(etmp->edata) || noncorporeal(etmp->edata)); X} X X/* X * Does falling drawbridge or portcullis miss etmp? X */ X Xstatic boolean Xe_missed(etmp, chunks) Xstruct entity *etmp; Xboolean chunks; X{ X int misses; X X#ifdef D_DEBUG X if (chunks) X pline("Do chunks miss?"); X#endif X if (automiss(etmp)) X return(TRUE); X X if (is_flyer(etmp->edata) && X (is_u(etmp)? !Sleeping : X (etmp->emon->mcanmove && !etmp->emon->msleep))) X /* flying requires mobility */ X misses = 5; /* out of 8 */ X else X if (is_floater(etmp->edata) || X (is_u(etmp) && Levitation)) /* doesn't require mobility */ X misses = 3; X else X if (chunks && is_pool(etmp->ex, etmp->ey)) X misses = 2; /* sitting ducks */ X else X misses = 0; X X if (is_db_wall(etmp->ex, etmp->ey)) X misses -= 3; /* less airspace */ X X#ifdef D_DEBUG X pline("Miss chance = %d (out of 8)", misses); X#endif X X return((misses >= rnd(8))? TRUE : FALSE); X} X X/* X * Can etmp jump from death? X */ X Xstatic boolean Xe_jumps(etmp) Xstruct entity *etmp; X{ X int tmp = 4; /* out of 10 */ X X if (is_u(etmp)? (Sleeping || Fumbling) : X (!etmp->emon->mcanmove || etmp->emon->msleep || X !etmp->edata->mmove)) X return(FALSE); X X if (is_u(etmp)? Confusion : etmp->emon->mconf) X tmp -= 2; X X if (is_u(etmp)? Stunned : etmp->emon->mstun) X tmp -= 3; X X if (is_db_wall(etmp->ex, etmp->ey)) X tmp -= 2; /* less room to maneuver */ X X#ifdef D_DEBUG X pline("%s to jump (%d chances in 10)", E_phrase(etmp, "try"), tmp); X#endif X return((tmp >= rnd(10))? TRUE : FALSE); X} X Xstatic void Xdo_entity(etmp) Xstruct entity *etmp; X{ X int newx, newy, at_portcullis, oldx, oldy; X boolean must_jump = FALSE, relocates = FALSE, e_inview; X struct rm *crm; X X if (!etmp->edata) X return; X X e_inview = e_boolean(etmp, canseemon); X X oldx = etmp->ex; X oldy = etmp->ey; X X at_portcullis = is_db_wall(oldx, oldy); X X crm = &levl[oldx][oldy]; X X if (automiss(etmp) && e_survives_at(etmp, oldx, oldy)) { X char edifice[20]; X X if (e_inview) { X *edifice = '\0'; X if ((crm->typ == DRAWBRIDGE_DOWN) || X (crm->typ == DRAWBRIDGE_UP)) X Strcpy(edifice, "drawbridge"); X else X if (at_portcullis) X Strcpy(edifice, "portcullis"); X if (*edifice) X pline("The %s passes through %s!", edifice, X e_nam(etmp)); X } X return; X } X if (e_missed(etmp, FALSE)) { X if (at_portcullis) X pline("The portcullis misses %s!", X e_nam(etmp)); X#ifdef D_DEBUG X else X pline("The drawbridge misses %s!", X e_nam(etmp)); X#endif X if (e_survives_at(etmp, oldx, oldy)) X return; X else { X#ifdef D_DEBUG X pline("Mon can't survive here"); X#endif X if (at_portcullis) X must_jump = TRUE; X else X relocates = TRUE; /* just ride drawbridge in */ X } X } else { X if (crm->typ == DRAWBRIDGE_DOWN) { X pline("%s crushed underneath the drawbridge.", X E_phrase(etmp, "are")); /* no jump */ X e_died(etmp, e_inview? 2 : 3, CRUSHING); /* no corpse */ X return; /* Note: Beyond this point, we know we're */ X } /* not at an opened drawbridge, since all */ X must_jump = TRUE; /* *missable* creatures survive on the */ X } /* square, and all the unmissed ones die. */ X if (must_jump) X if (at_portcullis) { X if (e_jumps(etmp)) { X relocates = TRUE; X#ifdef D_DEBUG X pline("Jump succeeds!"); X#endif X } else { X if (e_inview) X pline("%s crushed by the falling portcullis!", X E_phrase(etmp, "are")); X else X if (flags.soundok) X You("hear a crushing sound."); X e_died(etmp, e_inview? 1 : 0, CRUSHING); X /* corpse */ X return; X } X } else { /* tries to jump off bridge to original square */ X relocates = !e_jumps(etmp); X#ifdef D_DEBUG X pline("Jump %s!", (relocates)? "fails" : "succeeds"); X#endif X } X X/* X * Here's where we try to do relocation. Assumes that etmp is not arriving X * at the portcullis square while the drawbridge is falling, since this square X * would be inaccessible (i.e. etmp started on drawbridge square) or X * unnecessary (i.e. etmp started here) in such a situation. X */ X#ifdef D_DEBUG X pline("Doing relocation"); X#endif X newx = oldx; X newy = oldy; X (void)find_drawbridge(&newx, &newy); X if ((newx == oldx) && (newy == oldy)) X get_wall_for_db(&newx, &newy); X#ifdef D_DEBUG X pline("Checking new square for occupancy"); X#endif X if (relocates && (e_at(newx, newy))) { X X/* X * Standoff problem: one or both entities must die, and/or both switch X * places. Avoid infinite recursion by checking first whether the other X * entity is staying put. Clean up if we happen to move/die in recursion. X */ X struct entity *other; X X other = e_at(newx, newy); X#ifdef D_DEBUG X pline("New square is occupied by %s", e_nam(other)); X#endif X if (e_survives_at(other, newx, newy) && automiss(other)) { X relocates = FALSE; /* "other" won't budge */ X#ifdef D_DEBUG X pline("%s suicide.", E_phrase(etmp, "commit")); X#endif X } else { X X#ifdef D_DEBUG X pline("Handling %s", e_nam(other)); X#endif X while ((e_at(newx, newy)) && X (e_at(newx, newy) != etmp)) X do_entity(other); X#ifdef D_DEBUG X pline("Checking existence of %s", X e_nam(etmp)); X fflush(stdout); X#endif X if (e_at(oldx, oldy) != etmp) { X#ifdef D_DEBUG X pline("%s moved or died in recursion somewhere", X E_phrase(etmp, "have")); X fflush(stdout); X#endif X return; X } X } X } X if (relocates) { X#ifdef D_DEBUG X pline("Moving %s", e_nam(etmp)); X#endif X if (!is_u(etmp)) { X remove_monster(etmp->ex, etmp->ey); X place_monster(etmp->emon, newx, newy); X } else { X u.ux = newx; X u.uy = newy; X } X etmp->ex = newx; X etmp->ey = newy; X e_inview = e_boolean(etmp, canseemon); X } X#ifdef D_DEBUG X pline("Final disposition of %s", e_nam(etmp)); X fflush(stdout); X#endif X if (is_db_wall(etmp->ex, etmp->ey)) { X#ifdef D_DEBUG X pline("%s in portcullis chamber", E_phrase(etmp, "are")); X fflush(stdout); X#endif X if (e_inview) X if (is_u(etmp)) { X You("tumble towards the closed portcullis!"); X if (automiss(etmp)) X You("pass through it!"); X else X pline("The drawbridge closes in..."); X } else X pline("%s behind the drawbridge.", X E_phrase(etmp, "disappear")); X if (!e_survives_at(etmp, etmp->ex, etmp->ey)) { X killer_format = KILLED_BY_AN; X killer = "closing drawbridge"; X e_died(etmp, 0, CRUSHING); /* no message */ X return; X } X#ifdef D_DEBUG X pline("%s in here", E_phrase(etmp, "survive")); X#endif X } else { X#ifdef D_DEBUG X pline("%s on drawbridge square", E_phrase(etmp, "are")); X#endif X if (is_pool(etmp->ex, etmp->ey) && !e_inview) X if (flags.soundok) X You("hear a splash."); X if (e_survives_at(etmp, etmp->ex, etmp->ey)) { X if (e_inview && !is_flyer(etmp->edata) && X !is_floater(etmp->edata)) X pline("%s from the bridge.", X E_phrase(etmp, "fall")); X return; X } X#ifdef D_DEBUG X pline("%s cannot survive on the drawbridge square", Enam(etmp)); X#endif X if (is_pool(etmp->ex, etmp->ey)) X if (e_inview && X !is_u(etmp)) /* drown() will supply msgs if nec. */ X if (Hallucination) X pline("%s the moat and disappears.", X E_phrase(etmp, "drink")); X else X pline("%s into the moat.", X E_phrase(etmp, "fall")); X killer_format = NO_KILLER_PREFIX; X killer = "fell from a drawbridge"; X e_died(etmp, e_inview? 1 : 0, /* CRUSHING is arbitrary */ X (is_pool(etmp->ex, etmp->ey))? DROWNING : CRUSHING); X /* corpse */ X return; X } X} X X/* X * Close the drawbridge located at x,y X */ X Xvoid Xclose_drawbridge(x,y) Xint x,y; X{ X register struct rm *lev1, *lev2; X struct obj *otmp, *otmp2; X int x2, y2; X X lev1 = &levl[x][y]; X if (lev1->typ != DRAWBRIDGE_DOWN) return; X x2 = x; y2 = y; X get_wall_for_db(&x2,&y2); X if (cansee(x,y)) /* change msgs if you are a w-walker at portcullis */ X You("see a drawbridge %s up!", X ((u.ux == x2) && (u.uy == y2))? "coming" : "going"); X lev1->typ = DRAWBRIDGE_UP; X lev2 = &levl[x2][y2]; X switch (lev1->drawbridgemask & DB_DIR) { X case DB_NORTH: X case DB_SOUTH: X lev2->typ = HWALL; X break; X case DB_WEST: X case DB_EAST: X lev2->typ = VWALL; X break; X } X lev2->diggable = (W_NONDIGGABLE | W_GATEWAY); X set_entity(x, y, &(occupants[0])); X set_entity(x2, y2, &(occupants[1])); X do_entity(&(occupants[0])); X do_entity(&(occupants[1])); X redosym(x, y); X for (otmp = level.objects[x][y]; otmp; otmp = otmp2) { X otmp2 = otmp->nexthere; X delobj(otmp); X } X for (otmp = level.objects[x2][y2]; otmp; otmp = otmp2) { X otmp2 = otmp->nexthere; X delobj(otmp); X } X redosym(x2, y2); X} X X/* X * Open the drawbridge located at x,y X */ X Xvoid Xopen_drawbridge(x,y) Xint x,y; X{ X register struct rm *lev1, *lev2; X int x2, y2; X X lev1 = &levl[x][y]; X if (lev1->typ != DRAWBRIDGE_UP) return; X x2 = x; y2 = y; X get_wall_for_db(&x2,&y2); X if (cansee(x,y)) /* change msgs if you are a w-walker at portcullis */ X You("see a drawbridge %s down!", X ((x2 == u.ux) && (y2 == u.uy))? "going" : "coming"); X lev1->typ = DRAWBRIDGE_DOWN; X lev2 = &levl[x2][y2]; X lev2->typ = DOOR; X lev2->doormask = D_NODOOR; X set_entity(x, y, &(occupants[0])); X set_entity(x2, y2, &(occupants[1])); X do_entity(&(occupants[0])); X do_entity(&(occupants[1])); X redosym(x, y); X redosym(x2, y2); X} X X/* X * Let's destroy the drawbridge located at x,y X */ X Xvoid Xdestroy_drawbridge(x,y) Xint x,y; X{ X register struct rm *lev1, *lev2; X int x2, y2; X boolean e_inview; X struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]); X X lev1 = &levl[x][y]; X if (!IS_DRAWBRIDGE(lev1->typ)) X return; X x2 = x; y2 = y; X get_wall_for_db(&x2,&y2); X lev2 = &levl[x2][y2]; X if ((lev1->drawbridgemask & DB_UNDER) == DB_MOAT) { X if (lev1->typ == DRAWBRIDGE_UP) { X if (cansee(x2,y2)) X pline("The portcullis of the drawbridge falls into the moat!"); X else if (flags.soundok) X You("hear a loud *SPLASH*!"); X } else { X if (cansee(x,y)) X pline("The drawbridge collapses into the moat!"); X else if (flags.soundok) X You("hear a loud *SPLASH*!"); X } X lev1->typ = MOAT; X lev1->drawbridgemask = 0; X } else { X if (cansee(x,y)) X pline("The drawbridge disintegrates!"); X else X You("hear a loud *CRASH*!"); X lev1->typ = ROOM; X lev1->icedpool = X ((lev1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0); X } X set_entity(x2, y2, etmp2); /* currently, only automissers can be here */ X if (etmp2->edata) { X e_inview = e_boolean(etmp2, canseemon); X if (!automiss(etmp2)) { /* i.e. no-one yet */ X if (e_inview) X pline("%s blown apart by flying debris", X E_phrase(etmp2, "are")); X killer_format = KILLED_BY_AN; X killer = "exploding drawbridge"; X e_died(etmp2, e_inview? 2 : 3, CRUSHING);/* no corpse */ X } /* nothing which is vulnerable can survive this */ X } X lev2->typ = DOOR; X lev2->doormask = D_NODOOR; X set_entity(x, y, etmp1); X if (etmp1->edata) { X e_inview = e_boolean(etmp1, canseemon); X if (e_missed(etmp1, TRUE)) { X#ifdef D_DEBUG X pline("%s spared!", E_phrase(etmp1, "are")); X#endif X } else { X if (e_inview) X if (!is_u(etmp1) && Hallucination) X pline("%s into some heavy metal", X E_phrase(etmp1, "get")); X else X pline("%s hit by a huge chunk of metal!", X E_phrase(etmp1, "are")); X else X if (flags.soundok && !is_u(etmp1) && X !is_pool(x, y)) X You("hear a crushing sound"); X#ifdef D_DEBUG X else X pline("%s from shrapnel", X E_phrase(etmp1, "die")); X#endif X killer_format = KILLED_BY_AN; X killer = "collapsing drawbridge"; X e_died(etmp1, e_inview? 0 : 1, CRUSHING); /* corpse */ X } X } X redosym(x,y); X redosym(x2,y2); X} X X X#endif /* OVLB */ X X#endif /* STRONGHOLD /**/ END_OF_FILE if test 20980 -ne `wc -c <'src/dbridge.c'`; then echo shar: \"'src/dbridge.c'\" unpacked with wrong size! fi # end of 'src/dbridge.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'\" \(28788 characters\) sed "s/^X//" >'src/pager.c' <<'END_OF_FILE' X/* SCCS Id: @(#)pager.c 3.0 89/11/19 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#define MONATTK_H /* comment line for pre-compiled headers */ X/* block some unused #defines to avoid overloading some cpp's */ X#include "hack.h" X X#include <ctype.h> X#ifndef NO_SIGNAL X#include <signal.h> X#endif X#if defined(BSD) || defined(ULTRIX) X#include <sys/wait.h> X#endif X#ifdef MACOS Xextern WindowPtr HackWindow; Xextern short macflags; X#endif X X#ifndef SEEK_SET X#define SEEK_SET 0 X#endif X XSTATIC_DCL boolean FDECL(clear_help, (CHAR_P)); XSTATIC_DCL boolean FDECL(valid_help, (CHAR_P)); X X#ifndef OVLB XSTATIC_DCL char hc; X#else /* OVLB */ XSTATIC_OVL char NEARDATA hc = 0; X Xstatic void FDECL(page_more, (FILE *,int)); Xstatic boolean FDECL(is_swallow_sym, (UCHAR_P)); Xstatic boolean FDECL(pmatch,(const char *,const char *)); Xstatic boolean FDECL(outspec,(const char *,int)); Xstatic const char *FDECL(lookat,(int,int,UCHAR_P)); X#ifdef WIZARD Xstatic void NDECL(wiz_help); X#endif Xstatic void NDECL(help_menu); X X/* X * simple pattern matcher: '*' matches 0 or more characters X * returns TRUE if strng matches patrn X */ X Xstatic boolean Xpmatch(patrn, strng) X const char *patrn, *strng; X{ X char s, p; X X s = *strng; X p = *patrn; X X if (!p) { X return (s == 0); X } X X if (p == '*') { X if (!patrn[1] || pmatch(patrn+1, strng)) { X return TRUE; X } X return (s ? pmatch(patrn, strng+1) : FALSE); X } X X return (p == s) ? pmatch(patrn+1, strng+1) : FALSE; X} X X/* X * returns "true" for characters that could represent a monster's stomach X */ X Xstatic boolean Xis_swallow_sym(c) Xuchar c; X{ X return (index(" /-\\|", (char)c) != 0); X} X X/* X * print out another possibility for dowhatis. "new" is the possible new X * string; "out_flag" indicates whether we really want output, and if X * so what kind of output: 0 == no output, 1 == "(or %s)" output. X * Returns TRUE if this new string wasn't the last string printed. X */ X Xstatic boolean Xoutspec(new, out_flag) Xconst char *new; Xint out_flag; X{ X static char NEARDATA old[50]; X X if (!strcmp(old, new)) X return FALSE; /* don't print the same thing twice */ X X if (out_flag) X pline("(or %s)", an(new)); X X Strcpy(old, new); X return 1; X} X X/* X * return the name of the character ch found at (x,y) X */ X Xstatic Xconst char * Xlookat(x, y, ch) Xint x,y; Xuchar ch; X{ X register struct monst *mtmp; X register struct obj *otmp; X struct trap *trap; X static char NEARDATA answer[50]; X register char *s, *t; X uchar typ; X X answer[0] = 0; X X if(MON_AT(x,y)) { X mtmp = m_at(x,y); X if (!showmon(mtmp) || Hallucination) X mtmp = (struct monst *)0; X } else X mtmp = (struct monst *) 0; X typ = levl[x][y].typ; X if (!Invisible X#ifdef POLYSELF X && !u.uundetected X#endif X && u.ux==x && u.uy==y) { X Sprintf(answer, "%s named %s", X#ifdef POLYSELF X u.mtimedone ? mons[u.umonnum].mname : X#endif X pl_character, plname); X } else if (u.uswallow && is_swallow_sym(ch)) { X Sprintf(answer, "interior of %s", defmonnam(u.ustuck)); X } else if (mtmp && !mtmp->mimic) X Sprintf(answer, "%s%s", X mtmp->mtame ? "tame " : X mtmp->mpeaceful ? "peaceful " : "", X strncmp(lmonnam(mtmp), "the ", 4) X ? lmonnam(mtmp) : lmonnam(mtmp)+4); X else if (!levl[x][y].seen) X Strcpy(answer,"dark part of a room"); X else if (mtmp && mtmp->mimic) { X if (mtmp->m_ap_type == M_AP_FURNITURE) { X if (mtmp->mappearance == S_altar) X Strcpy(answer, "neutral altar"); X else X Strcpy(answer, explainsyms[mtmp->mappearance]); X } X else if (mtmp->m_ap_type == M_AP_OBJECT) { X if (mtmp->mappearance == STRANGE_OBJECT) X Strcpy(answer, "strange object"); X else { X int oindx = mtmp->mappearance; X otmp = mksobj(oindx,FALSE ); X if(oindx == STATUE || oindx == FIGURINE) X otmp->corpsenm = PM_KOBOLD; X else if (oindx == DRAGON_SCALE_MAIL) X otmp->corpsenm = PM_RED_DRAGON; X Strcpy(answer, distant_name(otmp, xname)); X free((genericptr_t) otmp); X } X } X else if (mtmp->m_ap_type == M_AP_GOLD) X Strcpy(answer, "pile of gold"); X } X else if (OBJ_AT(x, y)) { X otmp = level.objects[x][y]; X Strcpy(answer, distant_name(otmp, xname)); X } X else if (ch == GOLD_SYM) { X Strcpy(answer, "pile of gold"); X } X#ifdef ALTARS X else if (ch == ALTAR_SYM && IS_ALTAR(typ)) { X int kind = levl[x][y].altarmask & ~A_SHRINE; X Sprintf( answer, "%s altar", X (kind == A_CHAOS) ? "chaotic" : X (kind == A_NEUTRAL) ? "neutral" : X "lawful" ); X } X#endif X#ifdef STRONGHOLD X else if ((ch == DB_VWALL_SYM || ch == DB_HWALL_SYM) && is_db_wall(x,y)) X Strcpy(answer,"raised drawbridge"); X#endif X#ifdef THRONES X else if ((ch == THRONE_SYM) && IS_THRONE(typ)) X Strcpy(answer, "throne"); X#endif X else if ( (ch==H_OPEN_DOOR_SYM || X ch==V_OPEN_DOOR_SYM || X ch==CLOSED_DOOR_SYM || X ch==NO_DOOR_SYM) && X IS_DOOR(typ) ) { X switch(levl[x][y].doormask & ~D_TRAPPED) { X case D_NODOOR: Strcpy(answer,"doorway"); break; X case D_BROKEN: Strcpy(answer,"broken door"); break; X case D_ISOPEN: Strcpy(answer,"open door"); break; X default: Strcpy(answer,"closed door"); break; X /* locked or not */ X } X } X#ifdef SINKS X else if (ch == SINK_SYM && IS_SINK(levl[x][y].typ)) X Strcpy(answer,"sink"); X#endif X else if ((ch == TRAP_SYM || ch == WEB_SYM) && (trap = t_at(x, y))) { X if (trap->ttyp == WEB && ch == WEB_SYM) X Strcpy(answer, "web"); X else if (trap->ttyp != MONST_TRAP && ch == TRAP_SYM) { X Strcpy(answer, traps[ Hallucination ? X rn2(TRAPNUM-3)+3 : trap->ttyp]); X /* strip leading garbage */ X for (s = answer; *s && *s != ' '; s++) ; X if (*s) ++s; X for (t = answer; *t++ = *s++; ) ; X } X } X else if (ch == UP_SYM && x == xupstair && y == yupstair) X Strcpy(answer, "staircase up"); X else if (ch == DN_SYM && x == xdnstair && y == ydnstair) X Strcpy(answer, "staircase down"); X#ifdef STRONGHOLD X else if (ch == UPLADDER_SYM && x && x == xupladder && y == ydnladder) X Strcpy(answer, "ladder up"); X else if (ch == DNLADDER_SYM && x && x == xdnladder && y == ydnladder) X Strcpy(answer, "ladder down"); X#endif X else if (IS_ROOM(typ)) { X if (ch == ROOM_SYM) { X if (levl[x][y].icedpool) X Strcpy(answer,"iced pool"); X else X Strcpy(answer,"floor of a room"); X } X else if (ch == STONE_SYM || ch == ' ') X Strcpy(answer,"dark part of a room"); X } X else if (ch == CORR_SYM && SPACE_POS(typ)) X Strcpy(answer,"corridor"); X else if (!ACCESSIBLE(typ)) { X if (ch == STONE_SYM || ch == ' ') X Strcpy(answer,"dark part of a room"); X else X Strcpy(answer,"wall"); X } X return answer; X} X X Xint Xdowhatis() X{ X FILE *fp; X char buf[BUFSZ], inpbuf[BUFSZ]; X register char *ep, *inp = inpbuf; X char *alt = 0; /* alternate description */ X#ifdef __GNULINT__ X const char *firstmatch = 0; X#else X const char *firstmatch; X#endif X uchar q; X register int i; X coord cc; X boolean oldverb = flags.verbose; X boolean found_in_file = FALSE, need_to_print = FALSE; X int found = 0; X static const char *mon_interior = "the interior of a monster"; X X#ifdef OS2_CODEVIEW X char tmp[PATHLEN]; X X Strcpy(tmp,hackdir); X append_slash(tmp); X Strcat(tmp,DATAFILE); X fp = fopen(tmp,"r")); X#else X fp = fopen(DATAFILE, "r"); X#endif X if(!fp) { X#ifdef MACOS X fp = openFile(DATAFILE, "r"); X } X if (!fp) { X#endif X pline("Cannot open data file!"); X return 0; X } X X pline ("Specify unknown object by cursor? "); X q = ynq(); X if (q == 'q') { X (void) fclose(fp); X return 0; X } else if (q == 'n') { X cc.x = cc.y = -1; X pline("Specify what? (type the word) "); X getlin(inp); X if (inp[0] == '\033' || !inp[0]) { X (void)fclose(fp); X return 0; X } X if (!inp[1]) X q = inp[0]; X else X q = 0; X } else { X cc.x = u.ux; X cc.y = u.uy; Xselobj: X need_to_print = found_in_file = FALSE; X found = 0; X inp = inpbuf; X alt = 0; X (void) outspec("", 0); /* reset output */ X if(flags.verbose) X pline("Please move the cursor to an unknown object."); X else X pline("Pick an object."); X getpos(&cc, FALSE, "an unknown object"); X if (cc.x < 0) { X (void) fclose(fp); /* sweet@scubed */ X flags.verbose = oldverb; X return 0; X } X flags.verbose = FALSE; X if (!u.uswallow) { X q = levl[cc.x][cc.y].scrsym; X if (!q || (!levl[cc.x][cc.y].seen && !MON_AT(cc.x,cc.y))) X q = ' '; X } X else if (cc.x == u.ux && cc.y == u.uy) X q = u.usym; X else { X i = (u.uy - cc.y)+1; X if (i < 0 || i > 2) X q = ' '; X else { X firstmatch = (i == 0) ? "/-\\" : X (i == 1) ? "| |" : "\\-/"; X i = (u.ux - cc.x)+1; X if (i < 0 || i > 2) X q = ' '; X else X q = firstmatch[i]; X } X } X } X X if (!q) X goto checkfile; /* user typed in a complete string */ X X if (q != ' ' && index(quitchars, (char)q)) { X (void) fclose(fp); /* sweet@scubed */ X flags.verbose = oldverb; X return 0; X } X/* X * if the user just typed one letter, or we're identifying from the X * screen, then we have to check all the possibilities and print them X * out for him/her. X */ X X/* Check for monsters */ X for (i = 0; monsyms[i]; i++) { X if (q == monsyms[i]) { X need_to_print = TRUE; X pline("%c %s",q,an(monexplain[i])); X (void) outspec(firstmatch = monexplain[i], 0); X found++; X break; X } X } X X/* Special case: if identifying from the screen, and X * we're swallowed, and looking at something other than our own symbol, X * then just say "the interior of a monster". X */ X if (u.uswallow && is_swallow_sym(q)) { X if (!found) { X pline("%c %s", q, mon_interior); X (void)outspec(firstmatch=mon_interior, 0); X } X else X (void)outspec(mon_interior, 1); X found++; need_to_print = TRUE; X } X X/* Now check for objects */ X for (i = 0; objsyms[i]; i++) { X if (q == objsyms[i]) { X need_to_print = TRUE; X if (!found) { X pline("%c %s",q,an(objexplain[i])); X (void)outspec(firstmatch = objexplain[i], 0); X found++; X } X else if (outspec(objexplain[i], 1)) X found++; X } X } X X/* Now check for graphics symbols */ X for (i = 0; i < MAXPCHARS; i++) { X if ( q == showsyms[i] && (*explainsyms[i])) { X if (!found) { X pline("%c %s",q,an(explainsyms[i])); X (void)outspec(firstmatch = explainsyms[i], 0); X found++; X } X else if (outspec(explainsyms[i], 1)) X found++; X if (i == S_altar || i == S_trap || i == S_web) X need_to_print = TRUE; X } X } X X if (!found) X pline("I've never heard of such things."); X else if (cc.x != -1) { /* a specific object on screen */ X if (found > 1 || need_to_print) { X Strcpy(inp, lookat(cc.x, cc.y, q)); X if (*inp) X pline("(%s)", inp); X } X else { X Strcpy(inp, firstmatch); X } X } X else if (found == 1) { X Strcpy(inp, firstmatch); X } X else X found = FALSE; /* abort the 'More info?' stuff */ X X/* check the data file for information about this thing */ X Xcheckfile: X X if (!strncmp(inp, "interior of ", 12)) X inp += 12; X if (!strncmp(inp, "a ", 2)) X inp += 2; X else if (!strncmp(inp, "an ", 3)) X inp += 3; X else if (!strncmp(inp, "the ", 4)) X inp += 4; X if (!strncmp(inp, "tame ", 5)) X inp += 5; X else if (!strncmp(inp, "peaceful ", 9)) X inp += 9; X if (!strncmp(inp, "invisible ", 10)) X inp += 10; X X/* X * look in the file for more info if: X * the user typed in the whole name (!q) X * OR we've found a possible match with the character q (found) and X * flags.help is TRUE X * and, of course, the name to look for must be non-empty. X */ X if ((!q || (found && flags.help)) && *inp) { X/* adjust the input to remove "named " and convert to lower case */ X for (ep = inp; *ep; ) { X if ((!strncmp(ep, " named ", 7) && (alt = ep + 7)) || X !strncmp(ep, " called ", 8)) X *ep = 0; X else { X if(isupper(*ep)) *ep = tolower(*ep); X ep++; X } X } X X/* X * If the object is named, then the name is the alternate search string; X * otherwise, the result of makesingular() applied to the name is. This X * isn't strictly optimal, but named objects of interest to the user X * will usually be found under their name, rather than under their X * object type, so looking for a singular form is pointless. X */ X X if (!alt) X alt = makesingular(inp); X else X for (ep = alt; *ep; ep++) X if(isupper(*ep)) *ep = tolower(*ep); X X while(fgets(buf,BUFSZ,fp)) { X if(*buf != '\t') { X ep = index(buf, '\n'); X if(ep) *ep = 0; X else impossible("bad data file"); X if (pmatch(buf, inp)||(alt && pmatch(buf, alt))) { X found_in_file = TRUE; X break; X } X } X } X } X X if(found_in_file) { X/* skip over other possible matches for the info */ X for(;;) { X if ( (i = getc(fp)) == '\t' ) { X (void) ungetc(i, fp); X break; X } X if (!fgets(buf, BUFSZ, fp)) { X break; X } X } X if (q) { X pline("More info? "); X if(yn() == 'y') { X page_more(fp,1); /* does fclose() */ X flags.verbose = oldverb; X return 0; X } X } X else { X page_more(fp, 1); X flags.verbose = oldverb; X return 0; X } X } X else if (!q) X pline("I don't have any information on those things."); X X/* if specified by cursor, keep going */ X if(cc.x != -1) { X more(); X rewind(fp); X goto selobj; X } X (void) fclose(fp); /* kopper@psuvax1 */ X flags.verbose = oldverb; 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, meta; X#ifdef OS2_CODEVIEW X char tmp[PATHLEN]; X X Strcpy(tmp,hackdir); X append_slash(tmp); X Strcat(tmp,CMDHELPFILE); X if(!(fp = fopen(tmp,"r"))) { X#else X# ifdef MACOS X if(!(fp = fopen(CMDHELPFILE, "r"))) X fp = openFile(CMDHELPFILE, "r"); X if (!fp) { X# else X if(!(fp = fopen(CMDHELPFILE, "r"))) { X# endif X#endif X pline("Cannot open data file!"); X return 0; X } X X pline("What command? "); X#if defined(UNIX) || defined(VMS) X introff(); X#endif X q = readchar(); X#if defined(UNIX) || defined(VMS) X intron(); X#endif X ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0); X meta = ((0x80 & q) ? (0x7f & q) : 0); X while(fgets(buf,BUFSZ,fp)) X if ((ctrl && *buf=='^' && *(buf+1)==ctrl) || X (meta && *buf=='M' && *(buf+1)=='-' && *(buf+2)==meta) || X *buf==q) { X ep = index(buf, '\n'); X if(ep) *ep = 0; X if (ctrl && buf[2] == '\t'){ X buf = bufr + 1; X (void) strncpy(buf, "^? ", 8); X buf[1] = ctrl; X } else if (meta && buf[3] == '\t'){ X buf = bufr + 2; X (void) strncpy(buf, "M-? ", 8); X buf[2] = meta; X } else if(buf[1] == '\t'){ X buf = bufr; X buf[0] = q; X (void) strncpy(buf+1, " ", 7); X } X pline("%s", 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 volatile int NEARDATA got_intrup; X X#if !defined(MSDOS) && !defined(TOS) && !defined(MACOS) 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#ifdef MACOS X short tmpflags; X X tmpflags = macflags; X macflags &= ~fDoUpdate; X if(!mac_more(fp, strip)) { X macflags |= (tmpflags & fDoUpdate); X return; X } X macflags |= (tmpflags & fDoUpdate); X#else 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 if (strip && *bufp && *bufp != '\n') X *bufrp++ = *bufp++; 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#endif /* MACOS */ X} X X#endif /* OVLB */ X X#define PAGMIN 12 /* minimum # of lines for page below level map */ X X#ifndef OVLB X XSTATIC_DCL boolean whole_screen; X X#else /* OVLB */ X XSTATIC_OVL boolean NEARDATA whole_screen = TRUE; 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 NEARDATA 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 X#endif /* OVLB */ X#ifdef OVL0 X Xint Xpage_line(s) /* returns 1 if we should quit */ Xregister const char *s; X{ X#ifdef CLIPPING X/* we assume here that no data files have more than 80 chars/line */ X static char tmp[81], *t; X#endif 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 CLIPPING X/* if lines are too long for the screen, first try stripping leading blanks */ X if (strlen(s) >= CO) { X while (*s == ' ' || *s == '\t') s++; X } X X/* if it's still too long, try compressing blanks */ X if (strlen(s) >= CO) { X t = tmp; X while ( (*t = *s) != 0) { X if (*t == ' ') { X while (*s == ' ') X s++; X } X else X s++; X t++; X } X s = tmp; X } X#endif /* CLIPPING */ X X#ifdef TERMINFO X xputs(s); xputc('\n'); X#else X (void) puts(s); X# ifdef MACOS X (void) putchar('\n'); X# endif 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; Xconst char *text; X{ X static struct line { X struct line *next_line; X char *line_text; X } NEARDATA *texthead, NEARDATA *texttail; X static int NEARDATA maxlen; X static int NEARDATA 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("%s", 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) { /* help menu display */ X do X hc = lowc(readchar()); X while (!valid_help(hc)); X } X#if defined(MSDOS) && !defined(AMIGA) X cmov (lth, curline); X#else X curs (lth, curline); X#endif X cl_end (); X if (!hmenu) { X cmore (text); X } X if (!hmenu || clear_help(hc)) { X home (); X cl_end (); X docorner (lth, curline-1); X } X } else { /* feed to pager */ X#ifdef MACOS X short tmpflags; X X tmpflags = macflags; X macflags &= ~fDoNonKeyEvt; X#endif 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#ifdef MACOS X macflags = tmpflags; X#endif X while(tl = texthead) { X texthead = tl->next_line; X free((genericptr_t) tl); X } X return; X } X } X if(text) { X cgetret(text); X set_pager(2); X } else X set_pager(1); X#ifdef MACOS X macflags = tmpflags; X#endif X } X } X X while(tl = texthead) { X texthead = tl->next_line; X free((genericptr_t) tl); X } X} X X#endif /* OVL0 */ X#ifdef OVLB 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 MACOS X cornline(1, "j. Macintosh primer."); X#endif X#ifdef WIZARD X if (wizard) X# ifdef MACOS X cornline(1, "k. List of wizard-mode commands."); X# else X cornline(1, "j. List of wizard-mode commands."); X# endif X#endif X cornline(1, ""); X#ifdef WIZARD X if (wizard) X# ifdef MACOS X cornline(1, "Select one of a,b,c,d,e,f,g,h,i,j,k or ESC: "); X# else X cornline(1, "Select one of a,b,c,d,e,f,g,h,i,j or ESC: "); X# endif X else X#endif X#ifdef MACOS X cornline(1, "Select one of a,b,c,d,e,f,g,h,i,j or ESC: "); X#else X cornline(1, "Select one of a,b,c,d,e,f,g,h,i or ESC: "); X#endif X cornline(-1,""); X} X XSTATIC_OVL boolean Xclear_help(c) Xchar c; X{ X /* those valid_help characters which do not correspond to help routines X * that redraw the whole screen on their own. if we always clear the X * help menu, we end up restoring the part of the maze underneath the X * help menu when the last page of a long help file is displayed with X * an external pager. X * X * When whole_screen is FALSE and the internal pager is used, the X * screen is big enough so that the maze is left in place during paging X * and the paging occurs in the lower part of the screen. In this case X * the pager clears out the part it wrote over when it exits but it X * doesn't redraw the whole screen. So all characters require that X * the help menu be cleared. X * X * When an external pager is used, the screen is always cleared. X * However, the "f" and "h" help options always use the internal X * pager even if DEF_PAGER is defined. X * - Bob Wilber wilber@homxb.att.com 10/20/89 X */ X return(index(quitchars,c) || c == 'd' || c == 'e' X#ifdef DEF_PAGER X || (!whole_screen && (c == 'f' || c == 'h')) X#else X || !whole_screen X#endif X#ifdef WIZARD X# ifdef MACOS X || c == 'k' X# else X || c == 'j' X# endif X#endif X ); X} X XSTATIC_OVL boolean Xvalid_help(c) Xchar c; X{ X#ifdef WIZARD X# ifdef MACOS X return ((c >= 'a' && c <= (wizard ? 'k' : 'j')) || index(quitchars,c)); X# else X return ((c >= 'a' && c <= (wizard ? 'j' : 'i')) || index(quitchars,c)); X# endif X#else X# ifdef MACOS X return ((c >= 'a' && c <= 'j') || index(quitchars,c)); X# else X return ((c >= 'a' && c <= 'i') || index(quitchars,c)); X# endif X#endif X} X Xint Xdohelp() X{ X#ifdef MACOS X term_info *t; X X macflags &= ~fDoNonKeyEvt; X t = (term_info *)GetWRefCon(HackWindow); X SetVol((StringPtr)NULL, X (t->auxFileVRefNum) ? t->auxFileVRefNum : t->recordVRefNum); X#endif X help_menu(); X if (!index(quitchars, hc)) { X switch(hc) { 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# ifdef MACOS X case 'j': (void) page_file(MACHELP, FALSE); break; X case 'k': wiz_help(); break; X# else X case 'j': wiz_help(); break; X# endif X#endif X } X } X#ifdef MACOS X SetVol((StringPtr)NULL, t->recordVRefNum); X macflags |= fDoNonKeyEvt; X#endif 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 const 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#ifdef OS2_CODEVIEW X char tmp[PATHLEN]; X X Strcpy(tmp,hackdir); X append_slash(tmp); X Strcat(tmp,fnam); X if ((f = fopen (tmp, "r")) == (FILE *) 0) { X#else X# ifdef MACOS X if ((f = fopen (fnam, "r")) == (FILE *) 0) X f = openFile(fnam, "r"); X if (!f) { X# else X if ((f = fopen (fnam, "r")) == (FILE *) 0) { X# endif X#endif 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 X#if defined(SHELL) || defined(DEF_PAGER) || defined(DEF_MAILREADER) 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) { X boolean so; X X cmov(1, LI); /* get prompt in reasonable place */ X so = flags.standout; X flags.standout = 1; X more(); X flags.standout = so; X } X docrt(); X return(0); X} X#endif X#endif /* UNIX /**/ X X#endif /* OVLB */ END_OF_FILE if test 28788 -ne `wc -c <'src/pager.c'`; then echo shar: \"'src/pager.c'\" unpacked with wrong size! fi # end of 'src/pager.c' fi if test -f 'src/sit.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/sit.c'\" else echo shar: Extracting \"'src/sit.c'\" \(5549 characters\) sed "s/^X//" >'src/sit.c' <<'END_OF_FILE' X/* SCCS Id: @(#)sit.c 3.0 89/06/12 X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ X/* NetHack may be freely redistributed. See license for details. */ X X#include "hack.h" X X#if defined(THRONES) || defined(SPELLS) Xvoid Xtake_gold() X{ X if (u.ugold <= 0) { X You("feel a strange sensation."); X } else { X You("notice you have no gold!"); X u.ugold = 0; X flags.botl = 1; X } X} X#endif X Xint Xdosit() { X#ifdef THRONES X register int cnt; X#endif X X if(Levitation) { X pline("There's nothing to sit on up here."); X#ifdef THRONES X } else if(IS_THRONE(levl[u.ux][u.uy].typ)) { X X if (rnd(6) > 4) { X switch (rnd(13)) { X case 1: X adjattrib(rn2(A_MAX), -rn1(4,3), FALSE); X losehp(rnd(10), "cursed throne", KILLED_BY_AN); X break; X case 2: X adjattrib(rn2(A_MAX), 1, FALSE); X break; X case 3: X pline("A%s charge of electricity shoots through your body!", X (Shock_resistance) ? "" : " massive"); X if(Shock_resistance) X losehp(rnd(6), "electric chair", KILLED_BY_AN); X else losehp(rnd(30), "electric chair", KILLED_BY_AN); X break; X case 4: X You("feel much, much better!"); X if(u.uhp >= (u.uhpmax - 5)) u.uhpmax += 4; X u.uhp = u.uhpmax; X make_blinded(0L,TRUE); X make_sick(0L,FALSE); X heal_legs(); X flags.botl = 1; X break; X case 5: X take_gold(); X break; X case 6: X if(u.uluck + rn2(5) < 0) { X You("feel your luck is changing."); X change_luck(1); X } else makewish(); X break; X case 7: X cnt = rnd(10); X You("hear a voice echo:"); X pline("\"Thy audience hath been summoned, Sire!\""); X while(cnt--) X (void) makemon(courtmon(), u.ux, u.uy); X break; X case 8: X You("hear a voice echo:"); X pline("\"By thy Imperious order, Sire...\""); X do_genocide(1); X break; X case 9: X You("hear a voice echo:"); X pline("\"A curse upon thee for sitting upon this most holy throne!\""); X if (Luck > 0) { X make_blinded(Blinded + rn1(100,250),TRUE); X } else rndcurse(); X break; X case 10: X if (Luck < 0 || (HSee_invisible & INTRINSIC)) { X pline("An image forms in your mind."); X do_mapping(); X } else { X Your("vision clarifies."); X HSee_invisible |= INTRINSIC; X } X break; X case 11: X if (Luck < 0) { X You("feel threatened."); X aggravate(); X } else { X X You("feel a wrenching sensation."); X tele(); /* teleport him */ X } X break; X case 12: X You("are granted a gift of insight!"); X while (!ggetobj("identify", identify, rn2(5)) X && invent); X break; X case 13: X Your("mind turns into a pretzel!"); X make_confused(HConfusion + rn1(7,16),FALSE); X break; X default: impossible("throne effect"); X break; X } X } else You("feel somehow out of place..."); X X if (!rn2(3) && IS_THRONE(levl[u.ux][u.uy].typ)) { X pline("The throne vanishes in a puff of logic."); X/* levl[u.ux][u.uy].scrsym = ROOM_SYM; */ X levl[u.ux][u.uy].typ = ROOM; X if(Invisible) newsym(u.ux,u.uy); X } X#endif X#ifdef POLYSELF X } else if (lays_eggs(uasmon) || u.umonnum == PM_QUEEN_BEE) { X struct obj *uegg; X X if (u.uhunger < objects[EGG].nutrition) { X You("are too weak to lay an egg."); X return 0; X } X X uegg = mksobj(EGG, 0); X uegg->spe = 1; X uegg->quan = 1; X uegg->owt = weight(uegg); X uegg->corpsenm = X (u.umonnum==PM_QUEEN_BEE ? PM_KILLER_BEE : monsndx(uasmon)); X uegg->known = uegg->dknown = 1; X You("lay an egg."); X dropy(uegg); X stackobj(uegg); X morehungry(objects[EGG].nutrition); X#endif X } else X pline("Having fun sitting on the floor?"); X return(1); X} X Xvoid Xrndcurse() { /* curse a few inventory items at random! */ X X int nobj = 0; X int cnt, onum; X struct obj *otmp; X X if(Antimagic) { X shieldeff(u.ux, u.uy); X You("feel a malignant aura surround you."); X } X X for (otmp = invent; otmp; otmp = otmp->nobj) nobj++; X X if (nobj) X for (cnt = rnd(6/((!!Antimagic) + 1)); cnt > 0; cnt--) { X onum = rn2(nobj); X for(otmp = invent; onum != 0; onum--) X otmp = otmp->nobj; X if(otmp->blessed) X otmp->blessed = 0; X else X otmp->cursed++; X } X} X Xvoid Xattrcurse() { /* remove a random INTRINSIC ability */ X switch(rnd(10)) { X case 1 : if (HFire_resistance & INTRINSIC) { X HFire_resistance &= ~INTRINSIC; X if (Inhell && !Fire_resistance) { X You("burn to a crisp."); X killer_format = NO_KILLER_PREFIX; X killer = self_pronoun("a gremlin stole %s fire resistance in hell", "his"); X done(BURNING); X } else You("feel warmer."); X break; X } X case 2 : if (HTeleportation & INTRINSIC) { X HTeleportation &= ~INTRINSIC; X You("feel less jumpy."); X break; X } X case 3 : if (HPoison_resistance & INTRINSIC) { X HPoison_resistance &= ~INTRINSIC; X You("feel a little sick!"); X break; X } X case 4 : if (HTelepat & INTRINSIC) { X HTelepat &= ~INTRINSIC; X Your("senses fail!"); X break; X } X case 5 : if (HCold_resistance & INTRINSIC) { X HCold_resistance &= ~INTRINSIC; X You("feel cooler."); X break; X } X case 6 : if (HInvis & INTRINSIC) { X HInvis &= ~INTRINSIC; X You("feel paranoid."); X break; X } X case 7 : if (HSee_invisible & INTRINSIC) { X HSee_invisible &= ~INTRINSIC; X You("thought you saw something!"); X break; X } X case 8 : if (Fast & INTRINSIC) { X Fast &= ~INTRINSIC; X You("feel slower."); X break; X } X case 9 : if (Stealth & INTRINSIC) { X Stealth &= ~INTRINSIC; X You("feel clumsy."); X break; X } X case 10: if (Protection & INTRINSIC) { X Protection &= ~INTRINSIC; X You("feel vulnerable."); X break; X } X default: break; X } X} END_OF_FILE if test 5549 -ne `wc -c <'src/sit.c'`; then echo shar: \"'src/sit.c'\" unpacked with wrong size! fi # end of 'src/sit.c' fi echo shar: End of archive 34 \(of 56\). cp /dev/null ark34isdone 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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 56 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