home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!news.tek.com!master!saab!billr
- From: billr@saab.CNA.TEK.COM (Bill Randle)
- Newsgroups: comp.sources.games
- Subject: v16i052: nethack31 - display oriented dungeons & dragons (Ver. 3.1), Part44/108
- Message-ID: <4346@master.CNA.TEK.COM>
- Date: 30 Jan 93 01:13:37 GMT
- Sender: news@master.CNA.TEK.COM
- Lines: 2104
- Approved: billr@saab.CNA.TEK.COM
- Xref: uunet comp.sources.games:1601
-
- Submitted-by: izchak@linc.cis.upenn.edu (Izchak Miller)
- Posting-number: Volume 16, Issue 52
- Archive-name: nethack31/Part44
- Supersedes: nethack3p9: Volume 10, Issue 46-102
- Environment: Amiga, Atari, Mac, MS-DOS, OS2, Unix, VMS, X11
-
-
-
- #! /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 44 (of 108)."
- # Contents: src/vision.c1 src/wizard.c
- # Wrapped by billr@saab on Wed Jan 27 16:09:03 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'src/vision.c1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/vision.c1'\"
- else
- echo shar: Extracting \"'src/vision.c1'\" \(38940 characters\)
- sed "s/^X//" >'src/vision.c1' <<'END_OF_FILE'
- X/* SCCS Id: @(#)vision.c 3.1 92/11/14 */
- X/* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990. */
- X/* NetHack may be freely redistributed. See license for details. */
- X#include "hack.h"
- X
- X/* Circles ==================================================================*/
- X
- X/*
- X * These numbers are limit offsets for one quadrant of a circle of a given
- X * radius (the first number of each line) from the source. The number in
- X * the comment is the element number (so pointers can be set up). Each
- X * "circle" has as many elements as its radius+1. The radius is the number
- X * of points away from the source that the limit exists. The radius of the
- X * offset on the same row as the source *is* included so we don't have to
- X * make an extra check. For example, a circle of radius 4 has offsets:
- X *
- X * XXX +2
- X * ...X +3
- X * ....X +4
- X * ....X +4
- X * @...X +4
- X *
- X */
- Xstatic char circle_data[] = {
- X/* 0*/ 1, 1,
- X/* 2*/ 2, 2, 1,
- X/* 5*/ 3, 3, 2, 1,
- X/* 9*/ 4, 4, 4, 3, 2,
- X/* 14*/ 5, 5, 5, 4, 3, 2,
- X/* 20*/ 6, 6, 6, 5, 5, 4, 2,
- X/* 27*/ 7, 7, 7, 6, 6, 5, 4, 2,
- X/* 35*/ 8, 8, 8, 7, 7, 6, 6, 4, 2,
- X/* 44*/ 9, 9, 9, 9, 8, 8, 7, 6, 5, 3,
- X/* 54*/ 10,10,10,10, 9, 9, 8, 7, 6, 5, 3,
- X/* 65*/ 11,11,11,11,10,10, 9, 9, 8, 7, 5, 3,
- X/* 77*/ 12,12,12,12,11,11,10,10, 9, 8, 7, 5, 3,
- X/* 90*/ 13,13,13,13,12,12,12,11,10,10, 9, 7, 6, 3,
- X/*104*/ 14,14,14,14,13,13,13,12,12,11,10, 9, 8, 6, 3,
- X/*119*/ 15,15,15,15,14,14,14,13,13,12,11,10, 9, 8, 6, 3,
- X/*135*/ 16 /* should be MAX_RADIUS+1; used to terminate range loops -dlc */
- X};
- X
- X/*
- X * These are the starting indexes into the circle_data[] array for a
- X * circle of a given radius.
- X */
- Xstatic char circle_start[] = {
- X/* */ 0, /* circles of radius zero are not used */
- X/* 1*/ 0,
- X/* 2*/ 2,
- X/* 3*/ 5,
- X/* 4*/ 9,
- X/* 5*/ 14,
- X/* 6*/ 20,
- X/* 7*/ 27,
- X/* 8*/ 35,
- X/* 9*/ 44,
- X/*10*/ 54,
- X/*11*/ 65,
- X/*12*/ 77,
- X/*13*/ 90,
- X/*14*/ 104,
- X/*15*/ 119,
- X};
- X
- X
- X/*===========================================================================*/
- X/* Vision (arbitrary line of sight) =========================================*/
- X
- X/*------ global variables ------*/
- X
- X#if 0 /* (moved to decl.c) */
- X/* True if we need to run a full vision recalculation. */
- Xboolean vision_full_recalc = 0;
- X
- X/* Pointers to the current vision array. */
- Xchar **viz_array;
- X#endif
- Xchar *viz_rmin, *viz_rmax; /* current vision cs bounds */
- X
- X
- X/*------ local variables ------*/
- X
- X
- Xstatic char could_see[2][ROWNO][COLNO]; /* vision work space */
- Xstatic char *cs_rows0[ROWNO], *cs_rows1[ROWNO];
- Xstatic char cs_rmin0[ROWNO], cs_rmax0[ROWNO];
- Xstatic char cs_rmin1[ROWNO], cs_rmax1[ROWNO];
- X
- Xstatic char viz_clear[ROWNO][COLNO]; /* vision clear/blocked map */
- Xstatic char *viz_clear_rows[ROWNO];
- X
- Xstatic char left_ptrs[ROWNO][COLNO]; /* LOS algorithm helpers */
- Xstatic char right_ptrs[ROWNO][COLNO];
- X
- X/* Forward declarations. */
- Xstatic void FDECL(fill_point, (int,int));
- Xstatic void FDECL(dig_point, (int,int));
- Xstatic void NDECL(view_init);
- Xstatic void FDECL(view_from,(int,int,char **,char *,char *,int,
- X void (*)(int,int,genericptr_t),genericptr_t));
- Xstatic void FDECL(get_unused_cs, (char ***,char **,char **));
- X#ifdef REINCARNATION
- Xstatic void FDECL(rogue_vision, (char **,char *,char *));
- X#endif
- X
- X/* Macro definitions that I can't find anywhere. */
- X#define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0 ))
- X#define abs(z) ((z) < 0 ? -(z) : (z))
- X
- X/*
- X * vision_init()
- X *
- X * The one-time vision initialization routine.
- X *
- X * This must be called before mklev() is called in newgame() [allmain.c],
- X * or before a game restore. Else we die a horrible death.
- X */
- Xvoid
- Xvision_init()
- X{
- X int i;
- X
- X /* Set up the pointers. */
- X for (i = 0; i < ROWNO; i++) {
- X cs_rows0[i] = could_see[0][i];
- X cs_rows1[i] = could_see[1][i];
- X viz_clear_rows[i] = viz_clear[i];
- X }
- X
- X /* Start out with cs0 as our current array */
- X viz_array = cs_rows0;
- X viz_rmin = cs_rmin0;
- X viz_rmax = cs_rmax0;
- X
- X vision_full_recalc = 0;
- X (void) memset((genericptr_t) could_see, 0, sizeof(could_see));
- X
- X /* Initialize the vision algorithm (currently C or D). */
- X view_init();
- X
- X#ifdef VISION_TABLES
- X /* Note: this initializer doesn't do anything except guarantee that
- X we're linked properly.
- X */
- X vis_tab_init();
- X#endif
- X}
- X
- X/*
- X * does_block()
- X *
- X * Returns true if the level feature, object, or monster at (x,y) blocks
- X * sight.
- X */
- Xint
- Xdoes_block(x,y,lev)
- X int x, y;
- X register struct rm *lev;
- X{
- X struct obj *obj;
- X struct monst *mon;
- X
- X /* Features that block . . */
- X if (IS_ROCK(lev->typ) || (IS_DOOR(lev->typ) &&
- X (lev->doormask & (D_CLOSED|D_LOCKED|D_TRAPPED) )))
- X return 1;
- X
- X if (lev->typ == CLOUD || lev->typ == WATER ||
- X (lev->typ == MOAT && Underwater))
- X return 1;
- X
- X /* Boulders block light. */
- X for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
- X if (obj->otyp == BOULDER) return 1;
- X
- X /* Mimics mimicing a door or boulder block light. */
- X if ((mon = m_at(x,y)) && (!mon->minvis || See_invisible) &&
- X ((mon->m_ap_type == M_AP_FURNITURE &&
- X (mon->mappearance == S_hcdoor || mon->mappearance == S_vcdoor)) ||
- X (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER)))
- X return 1;
- X
- X return 0;
- X}
- X
- X/*
- X * vision_reset()
- X *
- X * This must be called *after* the levl[][] structure is set with the new
- X * level and the level monsters and objects are in place.
- X */
- Xvoid
- Xvision_reset()
- X{
- X int y;
- X register int x, i, dig_left, block;
- X register struct rm *lev;
- X
- X /* Start out with cs0 as our current array */
- X viz_array = cs_rows0;
- X viz_rmin = cs_rmin0;
- X viz_rmax = cs_rmax0;
- X
- X (void) memset((genericptr_t) could_see, 0, sizeof(could_see));
- X
- X /* Reset the pointers and clear so that we have a "full" dungeon. */
- X (void) memset((genericptr_t) viz_clear, 0, sizeof(viz_clear));
- X
- X /* Dig the level */
- X for (y = 0; y < ROWNO; y++) {
- X dig_left = 0;
- X block = TRUE; /* location (0,y) is always stone; it's !isok() */
- X lev = &levl[1][y];
- X for (x = 1; x < COLNO; x++, lev += ROWNO)
- X if (block != (IS_ROCK(lev->typ) || does_block(x,y,lev))) {
- X if(block) {
- X for(i=dig_left; i<x; i++) {
- X left_ptrs [y][i] = dig_left;
- X right_ptrs[y][i] = x-1;
- X }
- X } else {
- X i = dig_left;
- X if(dig_left) dig_left--; /* point at first blocked point */
- X for(; i<x; i++) {
- X left_ptrs [y][i] = dig_left;
- X right_ptrs[y][i] = x;
- X viz_clear[y][i] = 1;
- X }
- X }
- X dig_left = x;
- X block = !block;
- X }
- X /* handle right boundary; almost identical for blocked/unblocked */
- X i = dig_left;
- X if(!block && dig_left) dig_left--; /* point at first blocked point */
- X for(; i<COLNO; i++) {
- X left_ptrs [y][i] = dig_left;
- X right_ptrs[y][i] = (COLNO-1);
- X viz_clear[y][i] = !block;
- X }
- X }
- X
- X vision_full_recalc = 1; /* we want to run vision_recalc() */
- X}
- X
- X
- X/*
- X * get_unused_cs()
- X *
- X * Called from vision_recalc() and at least one light routine. Get pointers
- X * to the unused vision work area.
- X */
- Xstatic void
- Xget_unused_cs(rows, rmin, rmax)
- X char ***rows;
- X char **rmin, **rmax;
- X{
- X register int row;
- X register char *nrmin, *nrmax;
- X
- X if (viz_array == cs_rows0) {
- X *rows = cs_rows1;
- X *rmin = cs_rmin1;
- X *rmax = cs_rmax1;
- X } else {
- X *rows = cs_rows0;
- X *rmin = cs_rmin0;
- X *rmax = cs_rmax0;
- X }
- X
- X /* return an initialized, unused work area */
- X nrmin = *rmin;
- X nrmax = *rmax;
- X
- X (void) memset((genericptr_t)**rows, 0, ROWNO*COLNO); /* we see nothing */
- X for (row = 0; row < ROWNO; row++) { /* set row min & max */
- X *nrmin++ = COLNO-1;
- X *nrmax++ = 0;
- X }
- X}
- X
- X
- X#ifdef REINCARNATION
- X/*
- X * rogue_vision()
- X *
- X * Set the "could see" and in sight bits so vision acts just like the old
- X * rogue game:
- X *
- X * + If in a room, the hero can see to the room boundaries.
- X * + The hero can always see adjacent squares.
- X *
- X * We set the in_sight bit here as well to escape a bug that shows up
- X * due to the one-sided lit wall hack.
- X */
- Xstatic void
- Xrogue_vision(next, rmin, rmax)
- X char **next; /* could_see array pointers */
- X char *rmin, *rmax;
- X{
- X int rnum = levl[u.ux][u.uy].roomno - ROOMOFFSET; /* no SHARED... */
- X int start, stop, in_door;
- X register int zx, zy;
- X
- X /* If in a lit room, we are able to see to its boundaries. */
- X /* If dark, set COULD_SEE so various spells work -dlc */
- X if (rnum >= 0) {
- X for (zy = rooms[rnum].ly-1; zy <= rooms[rnum].hy+1; zy++) {
- X rmin[zy] = start = rooms[rnum].lx-1;
- X rmax[zy] = stop = rooms[rnum].hx+1;
- X
- X for (zx = start; zx <= stop; zx++) {
- X if (rooms[rnum].rlit) {
- X next[zy][zx] = COULD_SEE | IN_SIGHT;
- X levl[zx][zy].seen = 1; /* see the walls */
- X } else
- X next[zy][zx] = COULD_SEE;
- X }
- X }
- X }
- X
- X in_door = levl[u.ux][u.uy].typ == DOOR;
- X
- X /* Can always see adjacent. */
- X for (zy = u.uy-1; zy <= u.uy+1; zy++) {
- X rmin[zy] = min(rmin[zy],u.ux-1);
- X rmax[zy] = max(rmax[zy],u.ux+1);
- X
- X for (zx = u.ux-1; zx <= u.ux+1; zx++) {
- X next[zy][zx] = COULD_SEE | IN_SIGHT;
- X /*
- X * Yuck, update adjacent non-diagonal positions when in a doorway.
- X * We need to do this to catch the case when we first step into
- X * a room. The room's walls were not seen from the outside, but
- X * now are seen (the seen bit is set just above). However, the
- X * positions are not updated because they were already in sight.
- X * So, we have to do it here.
- X */
- X if (in_door && (zx == u.ux || zy == u.uy)) newsym(zx,zy);
- X }
- X }
- X}
- X#endif /* REINCARNATION */
- X
- X
- X/*
- X * vision_recalc()
- X *
- X * Do all of the heavy vision work. Recalculate all locations that could
- X * possibly be seen by the hero --- if the location were lit, etc. Note
- X * which locations are actually seen because of lighting. Then add to
- X * this all locations that be seen by hero due to night vision and x-ray
- X * vision. Finally, compare with what the hero was able to see previously.
- X * Update the difference.
- X *
- X * This function is usually called only when the variable 'vision_full_recalc'
- X * is set. The following is a list of places where this function is called,
- X * with three valid values for the control flag parameter:
- X *
- X * Control flag = 0. A complete vision recalculation. Generate the vision
- X * tables from scratch. This is necessary to correctly set what the hero
- X * can see. (1) and (2) call this routine for synchronization purposes, (3)
- X * calls this routine so it can operate correctly.
- X *
- X * + After the monster move, before input from the player. [moveloop()]
- X * + At end of moveloop. [moveloop() ??? not sure why this is here]
- X * + Right before something is printed. [pline()]
- X * + Right before we do a vision based operation. [do_clear_area()]
- X * + screen redraw, so we can renew all positions in sight. [docrt()]
- X *
- X * Control flag = 1. An adjacent vision recalculation. The hero has moved
- X * one square. Knowing this, it might be possible to optimize the vision
- X * recalculation using the current knowledge. This is presently unimplemented
- X * and is treated as a control = 0 call.
- X *
- X * + Right after the hero moves. [domove()]
- X *
- X * Control flag = 2. Turn off the vision system. Nothing new will be
- X * displayed, since nothing is seen. This is usually done when you need
- X * a newsym() run on all locations in sight, or on some locations but you
- X * don't know which ones.
- X *
- X * + Before a screen redraw, so all positions are renewed. [docrt()]
- X * + Right before the hero arrives on a new level. [goto_level()]
- X * + Right after a scroll of light is read. [litroom()]
- X * + After an option has changed that affects vision [parseoptions()]
- X * + Right after the hero is swallowed. [gulpmu()]
- X * + Just before bubbles are moved. [movebubbles()]
- X */
- Xvoid
- Xvision_recalc(control)
- X int control;
- X{
- X char **temp_array; /* points to the old vision array */
- X char **next_array; /* points to the new vision array */
- X char *next_row; /* row pointer for the new array */
- X char *old_row; /* row pointer for the old array */
- X char *next_rmin; /* min pointer for the new array */
- X char *next_rmax; /* max pointer for the new array */
- X char *ranges; /* circle ranges -- used for xray & night vision */
- X int row; /* row counter (outer loop) */
- X int start, stop; /* inner loop starting/stopping index */
- X int dx, dy; /* one step from a lit door or lit wall (see below) */
- X register int col; /* inner loop counter */
- X register struct rm *lev; /* pointer to current pos */
- X struct rm *flev; /* pointer to position in "front" of current pos */
- X
- X vision_full_recalc = 0; /* reset flag */
- X
- X#ifdef GCC_WARN
- X row = 0;
- X#endif
- X
- X /*
- X * Either the light sources have been taken care of, or we must
- X * recalculate them here.
- X */
- X
- X /* Get the unused could see, row min, and row max arrays. */
- X get_unused_cs(&next_array, &next_rmin, &next_rmax);
- X
- X /* You see nothing, nothing can see you --- if swallowed or refreshing. */
- X if (u.uswallow || control == 2) {
- X /* do nothing -- get_unused_cs() nulls out the new work area */
- X
- X } else if (Blind) {
- X /*
- X * Calculate the could_see array even when blind so that monsters
- X * can see you, even if you can't see them. Note that the current
- X * setup allows:
- X *
- X * + Monsters to see with the "new" vision, even on the rogue
- X * level.
- X *
- X * + Monsters to see you even when you're in a pit.
- X */
- X view_from(u.uy, u.ux, next_array, next_rmin, next_rmax,
- X 0,(void(*)())0,(genericptr_t)0);
- X
- X /*
- X * Our own version of the update loop below. We know we can't see
- X * anything, so we only need update positions we used to be able
- X * to see.
- X */
- X temp_array = viz_array; /* set viz_array so newsym() will work */
- X viz_array = next_array;
- X
- X for (row = 0; row < ROWNO; row++) {
- X old_row = temp_array[row];
- X
- X /* Find the min and max positions on the row. */
- X start = min(viz_rmin[row], next_rmin[row]);
- X stop = max(viz_rmax[row], next_rmax[row]);
- X
- X for (col = start; col <= stop; col++)
- X if (old_row[col] & IN_SIGHT) newsym(col,row);
- X }
- X
- X /* skip the normal update loop */
- X goto skip;
- X }
- X#ifdef REINCARNATION
- X else if (Is_rogue_level(&u.uz)) {
- X rogue_vision(next_array,next_rmin,next_rmax);
- X }
- X#endif
- X else {
- X int has_night_vision = 1; /* hero has night vision */
- X
- X if (Underwater && !Is_waterlevel(&u.uz)) {
- X /*
- X * The hero is under water. Only see surrounding locations if
- X * they are also underwater. This overrides night vision but
- X * does not override x-ray vision.
- X */
- X has_night_vision = 0;
- X
- X for (row = u.uy-1; row <= u.uy+1; row++)
- X for (col = u.ux-1; col <= u.ux+1; col++) {
- X if (!isok(col,row) || !is_pool(col,row)) continue;
- X
- X next_rmin[row] = min(next_rmin[row], col);
- X next_rmax[row] = max(next_rmax[row], col);
- X next_array[row][col] = IN_SIGHT;
- X }
- X }
- X
- X /* if in a pit, just update for immediate locations */
- X else if (u.utrap && u.utraptype == TT_PIT) {
- X for (row = u.uy-1; row <= u.uy+1; row++) {
- X if (row < 0) continue; if (row >= ROWNO) break;
- X
- X next_rmin[row] = max( 0, u.ux - 1);
- X next_rmax[row] = min(COLNO-1, u.ux + 1);
- X next_row = next_array[row];
- X
- X for(col=next_rmin[row]; col <= next_rmax[row]; col++)
- X next_row[col] = IN_SIGHT;
- X }
- X } else
- X view_from(u.uy, u.ux, next_array, next_rmin, next_rmax,
- X 0,(void(*)())0,(genericptr_t)0);
- X
- X /*
- X * Set the IN_SIGHT bit for xray and night vision.
- X */
- X if (u.xray_range >= 0) {
- X if (u.xray_range) {
- X ranges = circle_ptr(u.xray_range);
- X
- X for (row = u.uy-u.xray_range; row <= u.uy+u.xray_range; row++) {
- X if (row < 0) continue; if (row >= ROWNO) break;
- X dy = abs(u.uy-row); next_row = next_array[row];
- X
- X start = max( 0, u.ux - ranges[dy]);
- X stop = min(COLNO-1, u.ux + ranges[dy]);
- X
- X for (col = start; col <= stop; col++) {
- X next_row[col] |= IN_SIGHT;
- X levl[col][row].seen = 1; /* we see walls */
- X }
- X
- X next_rmin[row] = min(start, next_rmin[row]);
- X next_rmax[row] = max(stop, next_rmax[row]);
- X }
- X
- X } else { /* range is 0 */
- X next_array[u.uy][u.ux] |= IN_SIGHT;
- X levl[u.ux][u.uy].seen = 1;
- X next_rmin[u.uy] = min(u.ux, next_rmin[u.uy]);
- X next_rmax[u.uy] = max(u.ux, next_rmax[u.uy]);
- X }
- X }
- X
- X if (has_night_vision && u.xray_range < u.nv_range) {
- X if (!u.nv_range) { /* range is 0 */
- X next_array[u.uy][u.ux] |= IN_SIGHT;
- X levl[u.ux][u.uy].seen = 1;
- X next_rmin[u.uy] = min(u.ux, next_rmin[u.uy]);
- X next_rmax[u.uy] = max(u.ux, next_rmax[u.uy]);
- X } else if (u.nv_range > 0) {
- X ranges = circle_ptr(u.nv_range);
- X
- X for (row = u.uy-u.nv_range; row <= u.uy+u.nv_range; row++) {
- X if (row < 0) continue; if (row >= ROWNO) break;
- X dy = abs(u.uy-row); next_row = next_array[row];
- X
- X start = max( 0, u.ux - ranges[dy]);
- X stop = min(COLNO-1, u.ux + ranges[dy]);
- X
- X for (col = start; col <= stop; col++)
- X if (next_row[col]) next_row[col] |= IN_SIGHT;
- X
- X next_rmin[row] = min(start, next_rmin[row]);
- X next_rmax[row] = max(stop, next_rmax[row]);
- X }
- X }
- X }
- X }
- X
- X
- X /*
- X * Make the viz_array the new array so that cansee() will work correctly.
- X */
- X temp_array = viz_array;
- X viz_array = next_array;
- X
- X /*
- X * The main update loop. Here we do two things:
- X *
- X * + Set the IN_SIGHT bit for places that we could see and are lit.
- X * + Reset changed places.
- X *
- X * There are two things that make deciding what the hero can see
- X * difficult:
- X *
- X * 1. Walls. Walls are only seen as walls from the inside of a room.
- X * On the outside they look like stone. The "seen" bit in the rm
- X * structure is used in the display system to decide what to
- X * display, but it is here where we decide to set the seen bit.
- X * In this case the wall must already be in sight (either by night
- X * vision or could be seen and lit) *and* we must see the wall
- X * from across a room-typ square.
- X *
- X * 2. Directional lighting. Items that block light create problems.
- X * The worst offenders are doors. Suppose a door to a lit room
- X * is closed. It is lit on one side, but not on the other. How
- X * do you know? You have to check the closest adjacent position.
- X * Even so, that is not entirely correct. But it seems close
- X * enough for now.
- X */
- X for (row = 0; row < ROWNO; row++) {
- X dy = u.uy - row; dy = sign(dy);
- X next_row = next_array[row]; old_row = temp_array[row];
- X
- X /* Find the min and max positions on the row. */
- X start = min(viz_rmin[row], next_rmin[row]);
- X stop = max(viz_rmax[row], next_rmax[row]);
- X lev = &levl[start][row];
- X
- X for (col = start; col <= stop; col++, lev += ROWNO) {
- X if (next_row[col] & IN_SIGHT) {
- X /*
- X * We see this position because of night- or xray-vision.
- X *
- X * Check for "unseen" walls.
- X */
- X if ( (!lev->seen || (lev->diggable & W_REPAIRED)) &&
- X (IS_WALL(lev->typ) || lev->typ == SDOOR) ) {
- X /* Check the closest adjacent position. */
- X dx = u.ux - col; dx = sign(dx);
- X flev = &(levl[col+dx][row+dy]);
- X
- X /* If it was a non-corridor "open" area, we see the wall */
- X if ((ZAP_POS(flev->typ) && (flev->typ != CORR)) ||
- X (lev->diggable & W_REPAIRED)) {
- X lev->seen = 1; /* we've seen it */
- X lev->diggable &= ~W_REPAIRED;
- X
- X /* Make sure newly "seen" walls show up */
- X newsym(col,row);
- X }
- X
- X /* Update position if it was not in sight before. */
- X else if (!(old_row[col]&IN_SIGHT)) newsym(col,row);
- X }
- X
- X /* Update position if it was not in sight before. */
- X else if ( !(old_row[col] & IN_SIGHT) ) {
- X lev->seen = 1;
- X newsym(col,row);
- X }
- X }
- X
- X else if ( next_row[col] && lev->lit ) {
- X /*
- X * We see this position because it is lit.
- X *
- X * It is assumed here that lit walls are lit from the
- X * inside of the room, Hence, walls are not "seen"
- X * unless we can see them from across a lit room square.
- X */
- X if (IS_WALL(lev->typ) || lev->typ == SDOOR) {
- X
- X /* Check the closest adjacent position. */
- X dx = u.ux - col; dx = sign(dx);
- X flev = &(levl[col+dx][row+dy]);
- X /*
- X * If it is a non-corridor "open" area, and it is lit,
- X * then we see the wall as a wall.
- X *
- X * What happens when the hero is standing on this
- X * location (dx == dy == 0)?
- X */
- X if (ZAP_POS(flev->typ) && (flev->typ != CORR) &&
- X flev->lit) {
- X next_row[col] |= IN_SIGHT; /* we see it */
- X if (!lev->seen || (lev->diggable & W_REPAIRED)) {
- X lev->seen = 1; /* see it as a wall */
- X lev->diggable &= ~W_REPAIRED;
- X /*
- X * Force an update on the position, even if it
- X * was previously in sight. Reason: the hero
- X * could have been in a corridor or outside of
- X * an undiscovered wall and then teleported into
- X * the room. The wall was in sight before, but
- X * seen as stone. Now we need to see it as a
- X * wall.
- X */
- X newsym(col,row);
- X }
- X } else
- X goto not_in_sight; /* we don't see it */
- X
- X } else if (IS_DOOR(lev->typ) && !viz_clear[row][col]) {
- X /*
- X * Make sure doors, boulders or mimics don't show up
- X * at the end of dark hallways. We do this by checking
- X * the adjacent position. If it is lit, then we can see
- X * the door, otherwise we can't.
- X */
- X dx = u.ux - col; dx = sign(dx);
- X flev = &(levl[col+dx][row+dy]);
- X if (flev->lit) {
- X next_row[col] |= IN_SIGHT; /* we see it */
- X
- X /* Update position if it was not in sight before. */
- X if (!(old_row[col] & IN_SIGHT)) newsym(col,row);
- X } else
- X goto not_in_sight; /* we don't see it */
- X
- X } else {
- X next_row[col] |= IN_SIGHT; /* we see it */
- X
- X /* Update position if it was not in sight before. */
- X if ( !(old_row[col] & IN_SIGHT) ) {
- X lev->seen = 1;
- X newsym(col,row);
- X }
- X }
- X } else if (next_row[col] && lev->waslit ) {
- X /*
- X * If we make it here, the hero _could see_ the location
- X * (next_row[col] is true), but doesn't see it (lit is false).
- X * However, the hero _remembers_ it as lit (waslit is true).
- X * The hero can now see that it is not lit, so change waslit
- X * and update the location.
- X */
- X lev->waslit = 0; /* remember lit condition */
- X newsym(col,row);
- X }
- X /*
- X * At this point we know that the row position is *not* in
- X * sight. If the old one *was* in sight, then clean up the
- X * position.
- X */
- X else {
- Xnot_in_sight:
- X if (old_row[col] & IN_SIGHT) newsym(col,row);
- X }
- X
- X } /* end for col . . */
- X } /* end for row . . */
- X
- Xskip:
- X newsym(u.ux,u.uy); /* Make sure the hero shows up! */
- X
- X /* Set the new min and max pointers. */
- X viz_rmin = next_rmin;
- X viz_rmax = next_rmax;
- X}
- X
- X
- X/*
- X * block_point()
- X *
- X * Make the location opaque to light.
- X */
- Xvoid
- Xblock_point(x,y)
- X int x, y;
- X{
- X fill_point(y,x);
- X
- X /* recalc light sources here? */
- X
- X /*
- X * We have to do a full vision recalculation if we "could see" the
- X * location. Why? Suppose some monster opened a way so that the
- X * hero could see a lit room. However, the position of the opening
- X * was out of night-vision range of the hero. Suddenly the hero should
- X * see the lit room.
- X */
- X if (viz_array[y][x]) vision_full_recalc = 1;
- X}
- X
- X/*
- X * unblock_point()
- X *
- X * Make the location transparent to light.
- X */
- Xvoid
- Xunblock_point(x,y)
- X int x, y;
- X{
- X dig_point(y,x);
- X
- X /* recalc light sources here? */
- X
- X if (viz_array[y][x]) vision_full_recalc = 1;
- X}
- X
- X
- X/*===========================================================================*\
- X | |
- X | Everything below this line uses (y,x) instead of (x,y) --- the |
- X | algorithms are faster if they are less recursive and can scan |
- X | on a row longer. |
- X | |
- X\*===========================================================================*/
- X
- X
- X/* ========================================================================= *\
- X Left and Right Pointer Updates
- X\* ========================================================================= */
- X
- X/*
- X * LEFT and RIGHT pointer rules
- X *
- X *
- X * **NOTE** The rules changed on 4/4/90. This comment reflects the
- X * new rules. The change was so that the stone-wall optimization
- X * would work.
- X *
- X * OK, now the tough stuff. We must maintain our left and right
- X * row pointers. The rules are as follows:
- X *
- X * Left Pointers:
- X * ______________
- X *
- X * + If you are a clear spot, your left will point to the first
- X * stone to your left. If there is none, then point the first
- X * legal position in the row (0).
- X *
- X * + If you are a blocked spot, then your left will point to the
- X * left-most blocked spot to your left that is connected to you.
- X * This means that a left-edge (a blocked spot that has an open
- X * spot on its left) will point to itself.
- X *
- X *
- X * Right Pointers:
- X * ---------------
- X * + If you are a clear spot, your right will point to the first
- X * stone to your right. If there is none, then point the last
- X * legal position in the row (COLNO-1).
- X *
- X * + If you are a blocked spot, then your right will point to the
- X * right-most blocked spot to your right that is connected to you.
- X * This means that a right-edge (a blocked spot that has an open
- X * spot on its right) will point to itself.
- X */
- Xstatic void
- Xdig_point(row,col)
- X int row,col;
- X{
- X int i;
- X
- X if (viz_clear[row][col]) return; /* already done */
- X
- X viz_clear[row][col] = 1;
- X
- X /*
- X * Boundary cases first.
- X */
- X if (col == 0) { /* left edge */
- X if (viz_clear[row][1]) {
- X right_ptrs[row][0] = right_ptrs[row][1];
- X } else {
- X right_ptrs[row][0] = 1;
- X for (i = 1; i <= right_ptrs[row][1]; i++)
- X left_ptrs[row][i] = 1;
- X }
- X } else if (col == (COLNO-1)) { /* right edge */
- X
- X if (viz_clear[row][COLNO-2]) {
- X left_ptrs[row][COLNO-1] = left_ptrs[row][COLNO-2];
- X } else {
- X left_ptrs[row][COLNO-1] = COLNO-2;
- X for (i = left_ptrs[row][COLNO-2]; i < COLNO-1; i++)
- X right_ptrs[row][i] = COLNO-2;
- X }
- X }
- X
- X /*
- X * At this point, we know we aren't on the boundaries.
- X */
- X else if (viz_clear[row][col-1] && viz_clear[row][col+1]) {
- X /* Both sides clear */
- X for (i = left_ptrs[row][col-1]; i <= col; i++) {
- X if (!viz_clear[row][i]) continue; /* catch non-end case */
- X right_ptrs[row][i] = right_ptrs[row][col+1];
- X }
- X for (i = col; i <= right_ptrs[row][col+1]; i++) {
- X if (!viz_clear[row][i]) continue; /* catch non-end case */
- X left_ptrs[row][i] = left_ptrs[row][col-1];
- X }
- X
- X } else if (viz_clear[row][col-1]) {
- X /* Left side clear, right side blocked. */
- X for (i = col+1; i <= right_ptrs[row][col+1]; i++)
- X left_ptrs[row][i] = col+1;
- X
- X for (i = left_ptrs[row][col-1]; i <= col; i++) {
- X if (!viz_clear[row][i]) continue; /* catch non-end case */
- X right_ptrs[row][i] = col+1;
- X }
- X left_ptrs[row][col] = left_ptrs[row][col-1];
- X
- X } else if (viz_clear[row][col+1]) {
- X /* Right side clear, left side blocked. */
- X for (i = left_ptrs[row][col-1]; i < col; i++)
- X right_ptrs[row][i] = col-1;
- X
- X for (i = col; i <= right_ptrs[row][col+1]; i++) {
- X if (!viz_clear[row][i]) continue; /* catch non-end case */
- X left_ptrs[row][i] = col-1;
- X }
- X right_ptrs[row][col] = right_ptrs[row][col+1];
- X
- X } else {
- X /* Both sides blocked */
- X for (i = left_ptrs[row][col-1]; i < col; i++)
- X right_ptrs[row][i] = col-1;
- X
- X for (i = col+1; i <= right_ptrs[row][col+1]; i++)
- X left_ptrs[row][i] = col+1;
- X
- X left_ptrs[row][col] = col-1;
- X right_ptrs[row][col] = col+1;
- X }
- X}
- X
- Xstatic void
- Xfill_point(row,col)
- X int row, col;
- X{
- X int i;
- X
- X if (!viz_clear[row][col]) return;
- X
- X viz_clear[row][col] = 0;
- X
- X if (col == 0) {
- X if (viz_clear[row][1]) { /* adjacent is clear */
- X right_ptrs[row][0] = 0;
- X } else {
- X right_ptrs[row][0] = right_ptrs[row][1];
- X for (i = 1; i <= right_ptrs[row][1]; i++)
- X left_ptrs[row][i] = 0;
- X }
- X } else if (col == COLNO-1) {
- X if (viz_clear[row][COLNO-2]) { /* adjacent is clear */
- X left_ptrs[row][COLNO-1] = COLNO-1;
- X } else {
- X left_ptrs[row][COLNO-1] = left_ptrs[row][COLNO-2];
- X for (i = left_ptrs[row][COLNO-2]; i < COLNO-1; i++)
- X right_ptrs[row][i] = COLNO-1;
- X }
- X }
- X
- X /*
- X * Else we know that we are not on an edge.
- X */
- X else if (viz_clear[row][col-1] && viz_clear[row][col+1]) {
- X /* Both sides clear */
- X for (i = left_ptrs[row][col-1]+1; i <= col; i++)
- X right_ptrs[row][i] = col;
- X
- X if (!left_ptrs[row][col-1]) /* catch the end case */
- X right_ptrs[row][0] = col;
- X
- X for (i = col; i < right_ptrs[row][col+1]; i++)
- X left_ptrs[row][i] = col;
- X
- X if (right_ptrs[row][col+1] == COLNO-1) /* catch the end case */
- X left_ptrs[row][COLNO-1] = col;
- X
- X } else if (viz_clear[row][col-1]) {
- X /* Left side clear, right side blocked. */
- X for (i = col; i <= right_ptrs[row][col+1]; i++)
- X left_ptrs[row][i] = col;
- X
- X for (i = left_ptrs[row][col-1]+1; i < col; i++)
- X right_ptrs[row][i] = col;
- X
- X if (!left_ptrs[row][col-1]) /* catch the end case */
- X right_ptrs[row][i] = col;
- X
- X right_ptrs[row][col] = right_ptrs[row][col+1];
- X
- X } else if (viz_clear[row][col+1]) {
- X /* Right side clear, left side blocked. */
- X for (i = left_ptrs[row][col-1]; i <= col; i++)
- X right_ptrs[row][i] = col;
- X
- X for (i = col+1; i < right_ptrs[row][col+1]; i++)
- X left_ptrs[row][i] = col;
- X
- X if (right_ptrs[row][col+1] == COLNO-1) /* catch the end case */
- X left_ptrs[row][i] = col;
- X
- X left_ptrs[row][col] = left_ptrs[row][col-1];
- X
- X } else {
- X /* Both sides blocked */
- X for (i = left_ptrs[row][col-1]; i <= col; i++)
- X right_ptrs[row][i] = right_ptrs[row][col+1];
- X
- X for (i = col; i <= right_ptrs[row][col+1]; i++)
- X left_ptrs[row][i] = left_ptrs[row][col-1];
- X }
- X}
- X
- X
- X/*===========================================================================*/
- X/*===========================================================================*/
- X/* Use either algorithm C or D. See the config.h for more details. =========*/
- X
- X/*
- X * Variables local to both Algorithms C and D.
- X */
- Xstatic int start_row;
- Xstatic int start_col;
- Xstatic int step;
- Xstatic char **cs_rows;
- Xstatic char *cs_left;
- Xstatic char *cs_right;
- X
- Xstatic void FDECL((*vis_func), (int,int,genericptr_t));
- Xstatic genericptr_t varg;
- X
- X/*
- X * Both Algorithms C and D use the following macros.
- X *
- X * good_row(z) - Return TRUE if the argument is a legal row.
- X * set_cs(rowp,col) - Set the local could see array.
- X * set_min(z) - Save the min value of the argument and the current
- X * row minimum.
- X * set_max(z) - Save the max value of the argument and the current
- X * row maximum.
- X *
- X * The last three macros depend on having local pointers row_min, row_max,
- X * and rowp being set correctly.
- X */
- X#define set_cs(rowp,col) (rowp[col] = COULD_SEE)
- X#define good_row(z) ((z) >= 0 && (z) < ROWNO)
- X#define set_min(z) if (*row_min > (z)) *row_min = (z)
- X#define set_max(z) if (*row_max < (z)) *row_max = (z)
- X#define is_clear(row,col) viz_clear_rows[row][col]
- X
- X/*
- X * clear_path() expanded into 4 macros/functions:
- X *
- X * q1_path()
- X * q2_path()
- X * q3_path()
- X * q4_path()
- X *
- X * "Draw" a line from the start to the given location. Stop if we hit
- X * something that blocks light. The start and finish points themselves are
- X * not checked, just the points between them. These routines do _not_
- X * expect to be called with the same starting and stopping point.
- X *
- X * These routines use the generalized integer Bresenham's algorithm (fast
- X * line drawing) for all quadrants. The algorithm was taken from _Procedural
- X * Elements for Computer Graphics_, by David F. Rogers. McGraw-Hill, 1985.
- X */
- X#ifdef MACRO_CPATH /* quadrant calls are macros */
- X
- X/*
- X * When called, the result is in "result".
- X * The first two arguments (srow,scol) are one end of the path. The next
- X * two arguments (row,col) are the destination. The last argument is
- X * used as a C language label. This means that it must be different
- X * in each pair of calls.
- X */
- X
- X/*
- X * Quadrant I (step < 0).
- X */
- X#define q1_path(srow,scol,y2,x2,label) \
- X{ \
- X int dx, dy; \
- X register int k, err, x, y, dxs, dys; \
- X \
- X x = (scol); y = (srow); \
- X dx = (x2) - x; dy = y - (y2); \
- X \
- X result = 0; /* default to a blocked path */\
- X \
- X dxs = dx << 1; /* save the shifted values */\
- X dys = dy << 1; \
- X if (dy > dx) { \
- X err = dxs - dy; \
- X \
- X for (k = dy-1; k; k--) { \
- X if (err >= 0) { \
- X x++; \
- X err -= dys; \
- X } \
- X y--; \
- X err += dxs; \
- X if (!is_clear(y,x)) goto label;/* blocked */\
- X } \
- X } else { \
- X err = dys - dx; \
- X \
- X for (k = dx-1; k; k--) { \
- X if (err >= 0) { \
- X y--; \
- X err -= dxs; \
- X } \
- X x++; \
- X err += dys; \
- X if (!is_clear(y,x)) goto label;/* blocked */\
- X } \
- X } \
- X \
- X result = 1; \
- X}
- X
- X/*
- X * Quadrant IV (step > 0).
- X */
- X#define q4_path(srow,scol,y2,x2,label) \
- X{ \
- X int dx, dy; \
- X register int k, err, x, y, dxs, dys; \
- X \
- X x = (scol); y = (srow); \
- X dx = (x2) - x; dy = (y2) - y; \
- X \
- X result = 0; /* default to a blocked path */\
- X \
- X dxs = dx << 1; /* save the shifted values */\
- X dys = dy << 1; \
- X if (dy > dx) { \
- X err = dxs - dy; \
- X \
- X for (k = dy-1; k; k--) { \
- X if (err >= 0) { \
- X x++; \
- X err -= dys; \
- X } \
- X y++; \
- X err += dxs; \
- X if (!is_clear(y,x)) goto label;/* blocked */\
- X } \
- X \
- X } else { \
- X err = dys - dx; \
- X \
- X for (k = dx-1; k; k--) { \
- X if (err >= 0) { \
- X y++; \
- X err -= dxs; \
- X } \
- X x++; \
- X err += dys; \
- X if (!is_clear(y,x)) goto label;/* blocked */\
- X } \
- X } \
- X \
- X result = 1; \
- X}
- X
- X/*
- X * Quadrant II (step < 0).
- X */
- X#define q2_path(srow,scol,y2,x2,label) \
- X{ \
- X int dx, dy; \
- X register int k, err, x, y, dxs, dys; \
- X \
- X x = (scol); y = (srow); \
- X dx = x - (x2); dy = y - (y2); \
- X \
- X result = 0; /* default to a blocked path */\
- X \
- X dxs = dx << 1; /* save the shifted values */\
- X dys = dy << 1; \
- X if (dy > dx) { \
- X err = dxs - dy; \
- X \
- X for (k = dy-1; k; k--) { \
- X if (err >= 0) { \
- X x--; \
- X err -= dys; \
- X } \
- X y--; \
- X err += dxs; \
- X if (!is_clear(y,x)) goto label;/* blocked */\
- X } \
- X } else { \
- X err = dys - dx; \
- X \
- X for (k = dx-1; k; k--) { \
- X if (err >= 0) { \
- X y--; \
- X err -= dxs; \
- X } \
- X x--; \
- X err += dys; \
- X if (!is_clear(y,x)) goto label;/* blocked */\
- X } \
- X } \
- X \
- X result = 1; \
- X}
- X
- X/*
- X * Quadrant III (step > 0).
- X */
- X#define q3_path(srow,scol,y2,x2,label) \
- X{ \
- X int dx, dy; \
- X register int k, err, x, y, dxs, dys; \
- X \
- X x = (scol); y = (srow); \
- X dx = x - (x2); dy = (y2) - y; \
- X \
- X result = 0; /* default to a blocked path */\
- X \
- X dxs = dx << 1; /* save the shifted values */\
- X dys = dy << 1; \
- X if (dy > dx) { \
- X err = dxs - dy; \
- X \
- X for (k = dy-1; k; k--) { \
- X if (err >= 0) { \
- X x--; \
- X err -= dys; \
- X } \
- X y++; \
- X err += dxs; \
- X if (!is_clear(y,x)) goto label;/* blocked */\
- X } \
- X \
- X } else { \
- X err = dys - dx; \
- X \
- X for (k = dx-1; k; k--) { \
- X if (err >= 0) { \
- X y++; \
- X err -= dxs; \
- X } \
- X x--; \
- X err += dys; \
- X if (!is_clear(y,x)) goto label;/* blocked */\
- X } \
- X } \
- X \
- X result = 1; \
- X}
- X
- X#else /* quadrants are really functions */
- X
- Xstatic int FDECL(_q1_path, (int,int,int,int));
- Xstatic int FDECL(_q2_path, (int,int,int,int));
- Xstatic int FDECL(_q3_path, (int,int,int,int));
- Xstatic int FDECL(_q4_path, (int,int,int,int));
- X
- X#define q1_path(sy,sx,y,x,dummy) result = _q1_path(sy,sx,y,x)
- X#define q2_path(sy,sx,y,x,dummy) result = _q2_path(sy,sx,y,x)
- X#define q3_path(sy,sx,y,x,dummy) result = _q3_path(sy,sx,y,x)
- X#define q4_path(sy,sx,y,x,dummy) result = _q4_path(sy,sx,y,x)
- X
- X/*
- X * Quadrant I (step < 0).
- X */
- Xstatic int
- X_q1_path(srow,scol,y2,x2)
- X int scol, srow, y2, x2;
- X{
- X int dx, dy;
- X register int k, err, x, y, dxs, dys;
- X
- X x = scol; y = srow;
- X dx = x2 - x; dy = y - y2;
- X
- X dxs = dx << 1; /* save the shifted values */
- X dys = dy << 1;
- X if (dy > dx) {
- X err = dxs - dy;
- X
- X for (k = dy-1; k; k--) {
- X if (err >= 0) {
- X x++;
- X err -= dys;
- X }
- X y--;
- X err += dxs;
- X if (!is_clear(y,x)) return 0; /* blocked */
- X }
- X } else {
- X err = dys - dx;
- X
- X for (k = dx-1; k; k--) {
- X if (err >= 0) {
- X y--;
- X err -= dxs;
- X }
- X x++;
- X err += dys;
- X if (!is_clear(y,x)) return 0;/* blocked */
- X }
- X }
- X
- X return 1;
- X}
- X
- X/*
- X * Quadrant IV (step > 0).
- X */
- Xstatic int
- X_q4_path(srow,scol,y2,x2)
- X int scol, srow, y2, x2;
- X{
- X int dx, dy;
- X register int k, err, x, y, dxs, dys;
- X
- X x = scol; y = srow;
- X dx = x2 - x; dy = y2 - y;
- X
- X dxs = dx << 1; /* save the shifted values */
- X dys = dy << 1;
- X if (dy > dx) {
- X err = dxs - dy;
- X
- X for (k = dy-1; k; k--) {
- X if (err >= 0) {
- X x++;
- X err -= dys;
- X }
- X y++;
- X err += dxs;
- X if (!is_clear(y,x)) return 0; /* blocked */
- X }
- X } else {
- X err = dys - dx;
- X
- X for (k = dx-1; k; k--) {
- X if (err >= 0) {
- X y++;
- X err -= dxs;
- X }
- X x++;
- X err += dys;
- X if (!is_clear(y,x)) return 0;/* blocked */
- X }
- X }
- X
- X return 1;
- X}
- X
- X/*
- X * Quadrant II (step < 0).
- X */
- Xstatic int
- X_q2_path(srow,scol,y2,x2)
- X int scol, srow, y2, x2;
- X{
- X int dx, dy;
- X register int k, err, x, y, dxs, dys;
- X
- X x = scol; y = srow;
- X dx = x - x2; dy = y - y2;
- X
- X dxs = dx << 1; /* save the shifted values */
- X dys = dy << 1;
- X if (dy > dx) {
- X err = dxs - dy;
- X
- X for (k = dy-1; k; k--) {
- X if (err >= 0) {
- X x--;
- X err -= dys;
- X }
- X y--;
- X err += dxs;
- X if (!is_clear(y,x)) return 0; /* blocked */
- X }
- X } else {
- X err = dys - dx;
- X
- X for (k = dx-1; k; k--) {
- X if (err >= 0) {
- X y--;
- X err -= dxs;
- X }
- X x--;
- X err += dys;
- X if (!is_clear(y,x)) return 0;/* blocked */
- X }
- X }
- X
- X return 1;
- X}
- X
- X/*
- X * Quadrant III (step > 0).
- X */
- Xstatic int
- X_q3_path(srow,scol,y2,x2)
- X int scol, srow, y2, x2;
- X{
- X int dx, dy;
- X register int k, err, x, y, dxs, dys;
- X
- X x = scol; y = srow;
- X dx = x - x2; dy = y2 - y;
- X
- X dxs = dx << 1; /* save the shifted values */
- X dys = dy << 1;
- X if (dy > dx) {
- X err = dxs - dy;
- X
- X for (k = dy-1; k; k--) {
- X if (err >= 0) {
- X x--;
- X err -= dys;
- X }
- X y++;
- X err += dxs;
- X if (!is_clear(y,x)) return 0; /* blocked */
- X }
- X } else {
- X err = dys - dx;
- X
- X for (k = dx-1; k; k--) {
- X if (err >= 0) {
- X y++;
- X err -= dxs;
- X }
- X x--;
- X err += dys;
- X if (!is_clear(y,x)) return 0;/* blocked */
- X }
- X }
- X
- X return 1;
- X}
- X
- X#endif /* quadrants are functions */
- X
- END_OF_FILE
- if test 38940 -ne `wc -c <'src/vision.c1'`; then
- echo shar: \"'src/vision.c1'\" unpacked with wrong size!
- fi
- # end of 'src/vision.c1'
- fi
- if test -f 'src/wizard.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/wizard.c'\"
- else
- echo shar: Extracting \"'src/wizard.c'\" \(15887 characters\)
- sed "s/^X//" >'src/wizard.c' <<'END_OF_FILE'
- X/* SCCS Id: @(#)wizard.c 3.1 92/11/13 */
- X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
- X/* NetHack may be freely redistributed. See license for details. */
- X
- X/* wizard code - inspired by rogue code from Merlyn Leroy (digi-g!brian) */
- X/* - heavily modified to give the wiz balls. (genat!mike) */
- X/* - dewimped and given some maledictions. -3. */
- X/* - generalized for 3.1 (mike@bullns.on01.bull.ca) */
- X
- X#include "hack.h"
- X#ifdef MULDGN
- X#include "qtext.h"
- X#endif
- X
- X#ifdef OVLB
- X
- Xstatic short FDECL(which_arti, (UCHAR_P));
- Xstatic boolean FDECL(mon_has_arti, (struct monst *,SHORT_P));
- Xstatic struct monst *FDECL(other_mon_has_arti, (struct monst *,SHORT_P));
- Xstatic struct obj *FDECL(on_ground, (SHORT_P));
- Xstatic boolean FDECL(you_have, (UCHAR_P));
- Xstatic long FDECL(target_on, (UCHAR_P,struct monst *));
- Xstatic long FDECL(strategy, (struct monst *));
- X
- X/* TODO: Expand this list. */
- Xstatic const int NEARDATA nasties[] = {
- X PM_COCKATRICE, PM_ETTIN, PM_STALKER, PM_MINOTAUR, PM_RED_DRAGON,
- X PM_GREEN_DRAGON, PM_OWLBEAR, PM_PURPLE_WORM, PM_ROCK_TROLL, PM_XAN,
- X PM_GREMLIN, PM_UMBER_HULK, PM_VAMPIRE_LORD, PM_XORN, PM_ZRUTY,
- X PM_ELF_LORD, PM_ELVENKING, PM_YELLOW_DRAGON, PM_LEOCROTTA,
- X PM_CARNIVOROUS_APE, PM_FIRE_GIANT, PM_COUATL,
- X#ifdef ARMY
- X PM_CAPTAIN,
- X#endif
- X };
- X
- Xstatic const unsigned NEARDATA wizapp[] = {
- X PM_HUMAN, PM_WATER_DEMON, PM_VAMPIRE,
- X PM_RED_DRAGON, PM_TROLL, PM_UMBER_HULK,
- X PM_XORN, PM_XAN, PM_COCKATRICE,
- X PM_FLOATING_EYE,
- X PM_GUARDIAN_NAGA,
- X PM_TRAPPER
- X};
- X
- X#endif /* OVLB */
- X#ifdef OVL0
- X
- X/* If you've found the Amulet, make the Wizard appear after some time */
- X/* Also, give hints about portal locations, if amulet is worn/wielded -dlc */
- Xvoid
- Xamulet()
- X{
- X register struct monst *mtmp;
- X struct obj *amu;
- X
- X if ((((amu = uamul) && uamul->otyp == AMULET_OF_YENDOR) ||
- X ((amu = uwep) && uwep->otyp == AMULET_OF_YENDOR)) && !rn2(15)) {
- X register struct trap *ttmp;
- X for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
- X if(ttmp->ttyp == MAGIC_PORTAL) {
- X int du = distu(ttmp->tx, ttmp->ty);
- X if (du <= 9)
- X pline("%s feels hot!", The(xname(amu)));
- X else if (du <= 64)
- X pline("%s feels very warm.", The(xname(amu)));
- X else if (du <= 144)
- X pline("%s feels warm.", The(xname(amu)));
- X /* else, the amulet feels normal */
- X break;
- X }
- X }
- X }
- X
- X if (!flags.no_of_wizards || !u.uhave.amulet)
- X return;
- X /* find Wizard, and wake him if necessary */
- X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- X if(mtmp->iswiz && mtmp->msleep && !rn2(40)) {
- X mtmp->msleep = 0;
- X if (distu(mtmp->mx,mtmp->my) > 2)
- X You(
- X "get the creepy feeling that somebody noticed your taking the Amulet."
- X );
- X return;
- X }
- X}
- X
- X#endif /* OVL0 */
- X#ifdef OVLB
- X
- Xint
- Xmon_has_amulet(mtmp)
- Xregister struct monst *mtmp;
- X{
- X register struct obj *otmp;
- X
- X for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
- X if(otmp->otyp == AMULET_OF_YENDOR) return(1);
- X return(0);
- X}
- X
- Xint
- Xmon_has_special(mtmp)
- Xregister struct monst *mtmp;
- X{
- X register struct obj *otmp;
- X
- X for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
- X if(otmp->otyp == AMULET_OF_YENDOR ||
- X#ifdef MULDGN
- X is_quest_artifact(otmp) ||
- X#endif
- X otmp->otyp == BELL_OF_OPENING ||
- X otmp->otyp == CANDELABRUM_OF_INVOCATION ||
- X otmp->otyp == SPE_BOOK_OF_THE_DEAD) return(1);
- X return(0);
- X}
- X
- X/*
- X * New for 3.1 Strategy / Tactics for the wiz, as well as other
- X * monsters that are "after" something (defined via mflag3).
- X *
- X * The strategy section decides *what* the monster is going
- X * to attempt, the tactics section implements the decision.
- X */
- X#define STRAT(w, x, y, typ) (w | ((long)(x)<<16) | ((long)(y)<<8) | (long)typ)
- X#define ST_NONE 0L
- X#define ST_HEAL -1L
- X#define ST_GROUND 0x04000000
- X#define ST_MONSTR 0x02000000
- X#define ST_PLAYER 0x01000000
- X
- X#define M_Wants(mask) (mtmp->data->mflags3 & (mask))
- X
- Xstatic short
- Xwhich_arti(mask)
- X register uchar mask;
- X{
- X switch(mask) {
- X case M3_WANTSAMUL: return(AMULET_OF_YENDOR);
- X case M3_WANTSBELL: return(BELL_OF_OPENING);
- X case M3_WANTSCAND: return(CANDELABRUM_OF_INVOCATION);
- X case M3_WANTSBOOK: return(SPE_BOOK_OF_THE_DEAD);
- X default: break; /* 0 signifies quest artifact */
- X }
- X return(0);
- X}
- X
- X/*
- X * If "otyp" is zero, it triggers a check for the quest_artifact,
- X * since bell, book, candle, and amulet are all objects, not really
- X * artifacts right now. [MRS]
- X */
- Xstatic boolean
- Xmon_has_arti(mtmp, otyp)
- X register struct monst *mtmp;
- X register short otyp;
- X{
- X register struct obj *otmp;
- X
- X for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
- X if(otyp) {
- X if(otmp->otyp == otyp)
- X return(1);
- X }
- X#ifdef MULDGN
- X else if(is_quest_artifact(otmp)) return(1);
- X#endif
- X }
- X return(0);
- X
- X}
- X
- Xstatic struct monst *
- Xother_mon_has_arti(mtmp, otyp)
- X register struct monst *mtmp;
- X register short otyp;
- X{
- X register struct monst *mtmp2;
- X
- X for(mtmp2 = fmon; mtmp2; mtmp2 = mtmp2->nmon)
- X if(mtmp2 != mtmp)
- X if(mon_has_arti(mtmp2, otyp)) return(mtmp2);
- X
- X return((struct monst *)0);
- X}
- X
- Xstatic struct obj *
- Xon_ground(otyp)
- X register short otyp;
- X{
- X register struct obj *otmp;
- X
- X for(otmp = fobj; otmp; otmp = otmp->nobj)
- X if(otyp) {
- X if(otmp->otyp == otyp)
- X return(otmp);
- X }
- X#ifdef MULDGN
- X else if(is_quest_artifact(otmp)) return(otmp);
- X#endif
- X return((struct obj *)0);
- X}
- X
- Xstatic boolean
- Xyou_have(mask)
- X register uchar mask;
- X{
- X switch(mask) {
- X case M3_WANTSAMUL: return(u.uhave.amulet);
- X case M3_WANTSBELL: return(u.uhave.bell);
- X case M3_WANTSCAND: return(u.uhave.menorah);
- X case M3_WANTSBOOK: return(u.uhave.book);
- X#ifdef MULDGN
- X case M3_WANTSARTI: return(u.uhave.questart);
- X#endif
- X default: break;
- X }
- X return(0);
- X}
- X
- Xstatic long
- Xtarget_on(mask, mtmp)
- X register uchar mask;
- X register struct monst *mtmp;
- X{
- X register short otyp;
- X register struct obj *otmp;
- X register struct monst *mtmp2;
- X
- X if(!M_Wants(mask)) return(ST_NONE);
- X
- X otyp = which_arti(mask);
- X if(!mon_has_arti(mtmp, otyp)) {
- X if(you_have(mask))
- X return(STRAT(ST_PLAYER, u.ux, u.uy, mask));
- X else if((otmp = on_ground(otyp)))
- X return(STRAT(ST_GROUND, otmp->ox, otmp->oy, mask));
- X else if((mtmp2 = other_mon_has_arti(mtmp, otyp)))
- X return(STRAT(ST_MONSTR, mtmp2->mx, mtmp2->my, mask));
- X }
- X return(ST_NONE);
- X}
- X
- Xstatic long
- Xstrategy(mtmp)
- X register struct monst *mtmp;
- X{
- X long strat, dstrat;
- X
- X if(!is_covetous(mtmp->data)) return(ST_NONE);
- X
- X switch((mtmp->mhp*3)/mtmp->mhpmax) { /* 0-3 */
- X
- X default:
- X case 0: /* panic time - mtmp is almost snuffed */
- X return(ST_HEAL);
- X
- X case 1: /* the wiz is less cautious */
- X if(mtmp->data != &mons[PM_WIZARD_OF_YENDOR])
- X return(ST_HEAL);
- X /* else fall through */
- X
- X case 2: dstrat = ST_HEAL;
- X break;
- X
- X case 3: dstrat = ST_NONE;
- X break;
- X }
- X
- X if(flags.made_amulet)
- X if((strat = target_on(M3_WANTSAMUL, mtmp)) != ST_NONE)
- X return(strat);
- X
- X if(u.uevent.invoked) { /* priorities change once gate opened */
- X
- X#ifdef MULDGN
- X if((strat = target_on(M3_WANTSARTI, mtmp)) != ST_NONE)
- X return(strat);
- X#endif
- X if((strat = target_on(M3_WANTSBOOK, mtmp)) != ST_NONE)
- X return(strat);
- X if((strat = target_on(M3_WANTSBELL, mtmp)) != ST_NONE)
- X return(strat);
- X if((strat = target_on(M3_WANTSCAND, mtmp)) != ST_NONE)
- X return(strat);
- X } else {
- X
- X if((strat = target_on(M3_WANTSBOOK, mtmp)) != ST_NONE)
- X return(strat);
- X if((strat = target_on(M3_WANTSBELL, mtmp)) != ST_NONE)
- X return(strat);
- X if((strat = target_on(M3_WANTSCAND, mtmp)) != ST_NONE)
- X return(strat);
- X#ifdef MULDGN
- X if((strat = target_on(M3_WANTSARTI, mtmp)) != ST_NONE)
- X return(strat);
- X#endif
- X }
- X return(dstrat);
- X}
- X
- Xint
- Xtactics(mtmp)
- X register struct monst *mtmp;
- X{
- X mtmp->mstrategy = strategy(mtmp);
- X
- X switch (mtmp->mstrategy) {
- X case ST_HEAL: /* hide and recover */
- X /* if wounded, hole up on or near the stairs (to block them) */
- X /* unless, of course, there are no stairs (e.g. endlevel */
- X if((xupstair || yupstair))
- X if (mtmp->mx != xupstair || mtmp->my != yupstair)
- X (void) mnearto(mtmp, xupstair, yupstair, TRUE);
- X
- X /* if you're not around, cast healing spells */
- X if (distu(mtmp->mx,mtmp->my) > (BOLT_LIM * BOLT_LIM))
- X if(mtmp->mhp <= mtmp->mhpmax - 8) {
- X mtmp->mhp += rnd(8);
- X return(1);
- X }
- X /* fall through :-) */
- X
- X case ST_NONE: /* harrass */
- X if(!rn2(5)) mnexto(mtmp);
- X return(0);
- X
- X default: /* kill, maim, pillage! */
- X {
- X long where = (mtmp->mstrategy & 0xff000000);
- X xchar tx = (xchar)((mtmp->mstrategy >> 16) & 0xff),
- X ty = (xchar)((mtmp->mstrategy >> 8) & 0xff);
- X uchar targ = (xchar)(mtmp->mstrategy & 0xff);
- X struct obj *otmp;
- X
- X if(!targ) { /* simply wants you to close */
- X return(0);
- X }
- X if((u.ux == tx && u.uy == ty) || where == ST_PLAYER) {
- X /* player is standing on it (or has it) */
- X mnexto(mtmp);
- X return(0);
- X }
- X if(where == ST_GROUND) {
- X if(!MON_AT(tx, ty) || (mtmp->mx == tx && mtmp->my == ty)) {
- X
- X /* teleport to it and pick it up */
- X rloc_to(mtmp, tx, ty); /* clean old pos */
- X
- X if((otmp = on_ground(which_arti(targ)))) {
- X
- X if (cansee(mtmp->mx, mtmp->my))
- X pline("%s picks up %s.",
- X Monnam(mtmp), the(xname(otmp)));
- X freeobj(otmp);
- X mpickobj(mtmp, otmp);
- X return(1);
- X } else return(0);
- X }
- X } else { /* a monster has it - 'port beside it. */
- X (void) mnearto(mtmp, tx, ty, TRUE);
- X return(0);
- X }
- X }
- X }
- X /* NOTREACHED */
- X return(0);
- X}
- X
- Xvoid
- Xaggravate()
- X{
- X register struct monst *mtmp;
- X
- X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
- X mtmp->msleep = 0;
- X if(!mtmp->mcanmove && !rn2(5)) {
- X mtmp->mfrozen = 0;
- X mtmp->mcanmove = 1;
- X }
- X }
- X}
- X
- Xvoid
- Xclonewiz()
- X{
- X register struct monst *mtmp2;
- X
- X if(mtmp2 = makemon(&mons[PM_WIZARD_OF_YENDOR], u.ux, u.uy)) {
- X mtmp2->msleep = mtmp2->mtame = mtmp2->mpeaceful = 0;
- X if (!u.uhave.amulet && rn2(2)) { /* give clone a fake */
- X mtmp2->minvent = mksobj(FAKE_AMULET_OF_YENDOR, TRUE, FALSE);
- X }
- X mtmp2->m_ap_type = M_AP_MONSTER;
- X mtmp2->mappearance = wizapp[rn2(SIZE(wizapp))];
- X newsym(mtmp2->mx,mtmp2->my);
- X }
- X}
- X
- X/* create some nasty monsters, aligned or neutral with the caster */
- X/* a null caster defaults to a chaotic caster (e.g. the wizard) */
- Xvoid
- Xnasty(mcast)
- X struct monst *mcast;
- X{
- X register struct monst *mtmp;
- X register int i, j, tmp;
- X int castalign = (mcast ? mcast->data->maligntyp : -1);
- X
- X if(!rn2(10) && Inhell) msummon(&mons[PM_WIZARD_OF_YENDOR]);
- X else {
- X tmp = (u.ulevel > 3) ? u.ulevel/3 : 1; /* just in case -- rph */
- X
- X for(i = rnd(tmp); i > 0; --i)
- X for(j=0; j<20; j++) {
- X if((mtmp = makemon(&mons[nasties[rn2(SIZE(nasties))]],
- X u.ux, u.uy))) {
- X mtmp->msleep = mtmp->mpeaceful = mtmp->mtame = 0;
- X set_malign(mtmp);
- X } else /* GENOD? */
- X mtmp = makemon((struct permonst *)0, u.ux, u.uy);
- X if(mtmp->data->maligntyp == 0 ||
- X sgn(mtmp->data->maligntyp) == sgn(castalign))
- X break;
- X }
- X }
- X return;
- X}
- X
- X/* Let's resurrect the wizard, for some unexpected fun. */
- Xvoid
- Xresurrect()
- X{
- X register struct monst *mtmp;
- X
- X if(mtmp = makemon(&mons[PM_WIZARD_OF_YENDOR], u.ux, u.uy)) {
- X mtmp->msleep = mtmp->mtame = mtmp->mpeaceful = 0;
- X set_malign(mtmp);
- X pline("A voice booms out...");
- X verbalize("So thou thought thou couldst kill me, fool.");
- X }
- X
- X}
- X
- X/* Here, we make trouble for the poor shmuck who actually */
- X/* managed to do in the Wizard. */
- Xvoid
- Xintervene() {
- X
- X switch(rn2(6)) {
- X
- X case 0:
- X case 1: You("feel vaguely nervous.");
- X break;
- X case 2: if (!Blind)
- X You("notice a %s glow surrounding you.",
- X Hallucination ? hcolor() : Black);
- X rndcurse();
- X break;
- X case 3: aggravate();
- X break;
- X case 4: nasty((struct monst *)0);
- X break;
- X case 5: if (!flags.no_of_wizards) resurrect();
- X break;
- X }
- X}
- X
- Xvoid
- Xwizdead(mtmp)
- Xregister struct monst *mtmp;
- X{
- X flags.no_of_wizards--;
- X if (!u.uevent.udemigod) {
- X u.uevent.udemigod = TRUE;
- X u.udg_cnt = rn1(250, 50);
- X
- X /* Make the wizard meaner the next time he appears */
- X mtmp->data->mlevel++;
- X mtmp->data->ac--;
- X } else
- X mtmp->data->mlevel++;
- X}
- X
- Xconst char *random_insult[] = {
- X "antic",
- X "blackguard",
- X "caitiff",
- X "chucklehead",
- X "coistrel",
- X "craven",
- X "cretin",
- X "cur",
- X "dastard",
- X "demon fodder",
- X "dimwit",
- X "dolt",
- X "fool",
- X "footpad",
- X "imbecile",
- X "knave",
- X "maledict",
- X "miscreant",
- X "niddering",
- X "poltroon",
- X "rattlepate",
- X "reprobate",
- X "scapegrace",
- X "varlet",
- X "villein", /* (sic.) */
- X "wittol",
- X "worm",
- X "wretch",
- X};
- X
- Xconst char *random_malediction[] = {
- X "Hell shall soon claim thy remains,",
- X "I chortle at thee, thou pathetic",
- X "Prepare to die, thou",
- X "Resistance is useless,",
- X "Surrender or die, thou",
- X "There shall be no mercy, thou",
- X "Thou shalt repent of thy cunning,",
- X "Thou art as a flea to me,",
- X "Thou art doomed,",
- X "Thy fate is sealed,",
- X "Verily, thou shalt be one dead"
- X};
- X
- X#ifdef SOUNDS
- X# ifndef MULDGN
- X/* Any %s will be filled in by the appropriate diety's name */
- Xconst char *angelic_malediction[] = {
- X "Repent, and thou shalt be saved!",
- X "Thou shalt pay for thine insolence!",
- X "Very soon, my child, thou shalt meet thy maker.",
- X "%s has sent me to make you pay for your sins!",
- X "The wrath of %s is now upon you!",
- X "Thy life belongs to %s now!",
- X "Dost thou wish to receive thy final blessing?",
- X "Thou art but a godless void.",
- X "Thou art not worthy to seek the Amulet.",
- X "No one expects the Spanish Inquisition!",
- X};
- X
- Xconst char *demonic_malediction[] = {
- X "I first mistook thee for a statue, when I regarded thy head of stone.",
- X "Come here often?",
- X "Dost pain excite thee? Wouldst thou prefer the whip?",
- X "Thinkest thou it shall tickle as I rip out thy lungs?",
- X "Eat slime and die!",
- X "Go ahead, fetch thy mama! I shall wait.",
- X "Go play leapfrog with a herd of unicorns!",
- X "Hast thou been drinking, or art thou always so clumsy?",
- X "This time I shall let thee off with a spanking, but let it not happen again.",
- X "I've met smarter (and prettier) acid blobs.",
- X "Look! Thy bootlace is undone!",
- X "Mercy! Dost thou wish me to die of laughter?",
- X "Run away! Live to flee another day!",
- X "Thou hadst best fight better than thou canst dress!",
- X "Twixt thy cousin and thee, Medusa is the prettier.",
- X "Methinks thou wert unnaturally interested in yon corpse back there, eh, varlet?",
- X "Up thy nose with a rubber hose!",
- X "Verily, thy corpse could not smell worse!",
- X "Wait! I shall polymorph into a grid bug to give thee a fighting chance!",
- X "Why search for the Amulet? Thou wouldst but lose it, cretin.",
- X};
- X# endif /* MULDGN */
- X#endif
- X
- X/* Insult or intimidate the player */
- Xvoid
- Xcuss(mtmp)
- Xregister struct monst *mtmp;
- X{
- X#ifdef SOUNDS
- X if (mtmp->iswiz) {
- X#endif
- X if (!rn2(5)) /* typical bad guy action */
- X pline("%s laughs fiendishly.", Monnam(mtmp));
- X else
- X if (u.uhave.amulet && !rn2(SIZE(random_insult)))
- X verbalize("Relinquish the amulet, %s!",
- X random_insult[rn2(SIZE(random_insult))]);
- X else if (u.uhp < 5 && !rn2(2)) /* Panic */
- X verbalize(rn2(2) ?
- X "Even now thy life force ebbs, %s!" :
- X "Savor thy breath, %s, it be thine last!",
- X random_insult[rn2(SIZE(random_insult))]);
- X else if (mtmp->mhp < 5 && !rn2(2)) /* Parthian shot */
- X verbalize(rn2(2) ?
- X "I shall return." :
- X "I'll be back.");
- X else
- X verbalize("%s %s!",
- X random_malediction[rn2(SIZE(random_malediction))],
- X random_insult[rn2(SIZE(random_insult))]);
- X#ifdef SOUNDS
- X } else if(is_lminion(mtmp->data)) {
- X#ifndef MULDGN
- X verbalize(angelic_malediction[rn2(SIZE(angelic_malediction) - 1
- X + (Hallucination ? 1 : 0))],
- X align_gname(A_LAWFUL));
- X#else
- X com_pager(rn2(QTN_ANGELIC - 1 + (Hallucination ? 1 : 0)) +
- X QT_ANGELIC);
- X#endif
- X } else {
- X if (!rn2(5))
- X pline("%s casts aspersions on your ancestry.", Monnam(mtmp));
- X else
- X#ifndef MULDGN
- X verbalize(demonic_malediction[rn2(SIZE(demonic_malediction))]);
- X#else
- X com_pager(rn2(QTN_DEMONIC) + QT_DEMONIC);
- X#endif
- X }
- X#endif
- X}
- X
- X#endif /* OVLB */
- X
- X/*wizard.c*/
- END_OF_FILE
- if test 15887 -ne `wc -c <'src/wizard.c'`; then
- echo shar: \"'src/wizard.c'\" unpacked with wrong size!
- fi
- # end of 'src/wizard.c'
- fi
- echo shar: End of archive 44 \(of 108\).
- cp /dev/null ark44isdone
- 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 57 58 59 60 \
- 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
- 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 \
- 101 102 103 104 105 106 107 108 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 108 archives.
- echo "Now execute 'rebuild.sh'"
- rm -f ark10[0-8]isdone 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
-