home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
games
/
volume16
/
nethack31
/
part58
< prev
next >
Wrap
Internet Message Format
|
1993-02-04
|
59KB
Path: uunet!news.tek.com!master!saab!billr
From: billr@saab.CNA.TEK.COM (Bill Randle)
Newsgroups: comp.sources.games
Subject: v16i066: nethack31 - display oriented dungeons & dragons (Ver. 3.1), Part58/108
Message-ID: <4369@master.CNA.TEK.COM>
Date: 1 Feb 93 19:45:05 GMT
Sender: news@master.CNA.TEK.COM
Lines: 2075
Approved: billr@saab.CNA.TEK.COM
Xref: uunet comp.sources.games:1616
Submitted-by: izchak@linc.cis.upenn.edu (Izchak Miller)
Posting-number: Volume 16, Issue 66
Archive-name: nethack31/Part58
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 58 (of 108)."
# Contents: src/vision.c2 sys/amiga/amiwind.c
# Wrapped by billr@saab on Wed Jan 27 16:09:09 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/vision.c2' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/vision.c2'\"
else
echo shar: Extracting \"'src/vision.c2'\" \(33352 characters\)
sed "s/^X//" >'src/vision.c2' <<'END_OF_FILE'
X/*
X * Use vision tables to determine if there is a clear path from
X * (col1,row1) to (col2,row2). This is used by:
X * m_cansee()
X * m_canseeu()
X */
Xboolean
Xclear_path(col1,row1,col2,row2)
X int col1, row1, col2, row2;
X{
X int result;
X
X if(col1 < col2) {
X if(row1 > row2) {
X q1_path(row1,col1,row2,col2,cleardone);
X } else {
X q4_path(row1,col1,row2,col2,cleardone);
X }
X } else {
X if(row1 > row2) {
X q2_path(row1,col1,row2,col2,cleardone);
X } else if(row1 == row2 && col1 == col2) {
X result = 1;
X } else {
X q3_path(row1,col1,row2,col2,cleardone);
X }
X }
Xcleardone:
X return result;
X}
X
X#ifdef VISION_TABLES
X/*===========================================================================*\
X GENERAL LINE OF SIGHT
X Algorithm D
X\*===========================================================================*/
X
X
X/*
X * Indicate caller for the shadow routines.
X */
X#define FROM_RIGHT 0
X#define FROM_LEFT 1
X
X
X/*
X * Include the table definitions.
X */
X#include "vis_tab.h"
X
X
X/* 3D table pointers. */
Xstatic close2d *close_dy[CLOSE_MAX_BC_DY];
Xstatic far2d *far_dy[FAR_MAX_BC_DY];
X
Xstatic void FDECL(right_side, (int,int,int,int,int,int,int,char*));
Xstatic void FDECL(left_side, (int,int,int,int,int,int,int,char*));
Xstatic int FDECL(close_shadow, (int,int,int,int));
Xstatic int FDECL(far_shadow, (int,int,int,int));
X
X/*
X * Initialize algorithm D's table pointers. If we don't have these,
X * then we do 3D table lookups. Verrrry slow.
X */
Xstatic void
Xview_init()
X{
X int i;
X
X for (i = 0; i < CLOSE_MAX_BC_DY; i++)
X close_dy[i] = &close_table[i];
X
X for (i = 0; i < FAR_MAX_BC_DY; i++)
X far_dy[i] = &far_table[i];
X}
X
X
X/*
X * If the far table has an entry of OFF_TABLE, then the far block prevents
X * us from seeing the location just above/below it. I.e. the first visible
X * location is one *before* the block.
X */
X#define OFF_TABLE 0xff
X
Xstatic int
Xclose_shadow(side,this_row,block_row,block_col)
X int side,this_row,block_row,block_col;
X{
X register int sdy, sdx, pdy, offset;
X
X /*
X * If on the same column (block_row = -1), then we can see it.
X */
X if (block_row < 0) return block_col;
X
X /* Take explicit absolute values. Adjust. */
X if ((sdy = (start_row-block_row)) < 0) sdy = -sdy; --sdy; /* src dy */
X if ((sdx = (start_col-block_col)) < 0) sdx = -sdx; /* src dx */
X if ((pdy = (block_row-this_row)) < 0) pdy = -pdy; /* point dy */
X
X if (sdy < 0 || sdy >= CLOSE_MAX_SB_DY || sdx >= CLOSE_MAX_SB_DX ||
X pdy >= CLOSE_MAX_BC_DY) {
X impossible("close_shadow: bad value");
X return block_col;
X }
X offset = close_dy[sdy]->close[sdx][pdy];
X if (side == FROM_RIGHT)
X return block_col + offset;
X
X return block_col - offset;
X}
X
X
Xstatic int
Xfar_shadow(side,this_row,block_row,block_col)
X int side,this_row,block_row,block_col;
X{
X register int sdy, sdx, pdy, offset;
X
X /*
X * Take care of a bug that shows up only on the borders.
X *
X * If the block is beyond the border, then the row is negative. Return
X * the block's column number (should be 0 or COLNO-1).
X *
X * Could easily have the column be -1, but then wouldn't know if it was
X * the left or right border.
X */
X if (block_row < 0) return block_col;
X
X /* Take explicit absolute values. Adjust. */
X if ((sdy = (start_row-block_row)) < 0) sdy = -sdy; /* src dy */
X if ((sdx = (start_col-block_col)) < 0) sdx = -sdx; --sdx; /* src dx */
X if ((pdy = (block_row-this_row)) < 0) pdy = -pdy; --pdy; /* point dy */
X
X if (sdy >= FAR_MAX_SB_DY || sdx < 0 || sdx >= FAR_MAX_SB_DX ||
X pdy < 0 || pdy >= FAR_MAX_BC_DY) {
X impossible("far_shadow: bad value");
X return block_col;
X }
X if ((offset = far_dy[sdy]->far_q[sdx][pdy]) == OFF_TABLE) offset = -1;
X if (side == FROM_RIGHT)
X return block_col + offset;
X
X return block_col - offset;
X}
X
X
X/*
X * right_side()
X *
X * Figure out what could be seen on the right side of the source.
X */
Xstatic void
Xright_side(row, cb_row, cb_col, fb_row, fb_col, left, right_mark, limits)
X int row; /* current row */
X int cb_row, cb_col; /* close block row and col */
X int fb_row, fb_col; /* far block row and col */
X int left; /* left mark of the previous row */
X int right_mark; /* right mark of previous row */
X char *limits; /* points at range limit for current row, or NULL */
X{
X register int i;
X register char *rowp;
X int hit_stone = 0;
X int left_shadow, right_shadow, loc_right;
X int lblock_col; /* local block column (current row) */
X int nrow, deeper;
X char *row_min; /* left most */
X char *row_max; /* right most */
X int lim_max; /* right most limit of circle */
X
X nrow = row + step;
X deeper = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
X if(!vis_func) {
X rowp = cs_rows[row];
X row_min = &cs_left[row];
X row_max = &cs_right[row];
X }
X if(limits) {
X lim_max = start_col + *limits;
X if(lim_max > COLNO-1) lim_max = COLNO-1;
X if(right_mark > lim_max) right_mark = lim_max;
X limits++; /* prepare for next row */
X } else
X lim_max = COLNO-1;
X
X /*
X * Get the left shadow from the close block. This value could be
X * illegal.
X */
X left_shadow = close_shadow(FROM_RIGHT,row,cb_row,cb_col);
X
X /*
X * Mark all stone walls as seen before the left shadow. All this work
X * for a special case.
X *
X * NOTE. With the addition of this code in here, it is now *required*
X * for the algorithm to work correctly. If this is commented out,
X * change the above assignment so that left and not left_shadow is the
X * variable that gets the shadow.
X */
X while (left <= right_mark) {
X loc_right = right_ptrs[row][left];
X if(loc_right > lim_max) loc_right = lim_max;
X if (viz_clear_rows[row][left]) {
X if (loc_right >= left_shadow) {
X left = left_shadow; /* opening ends beyond shadow */
X break;
X }
X left = loc_right;
X loc_right = right_ptrs[row][left];
X if(loc_right > lim_max) loc_right = lim_max;
X if (left == loc_right) return; /* boundary */
X
X /* Shadow covers opening, beyond right mark */
X if (left == right_mark && left_shadow > right_mark) return;
X }
X
X if (loc_right > right_mark) /* can't see stone beyond the mark */
X loc_right = right_mark;
X
X if(vis_func) {
X for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg);
X } else {
X for (i = left; i <= loc_right; i++) set_cs(rowp,i);
X set_min(left); set_max(loc_right);
X }
X
X if (loc_right == right_mark) return; /* all stone */
X if (loc_right >= left_shadow) hit_stone = 1;
X left = loc_right + 1;
X }
X
X /*
X * At this point we are at the first visible clear spot on or beyond
X * the left shadow, unless the left shadow is an illegal value. If we
X * have "hit stone" then we have a stone wall just to our left.
X */
X
X /*
X * Get the right shadow. Make sure that it is a legal value.
X */
X if ((right_shadow = far_shadow(FROM_RIGHT,row,fb_row,fb_col)) >= COLNO)
X right_shadow = COLNO-1;
X /*
X * Make vertical walls work the way we want them. In this case, we
X * note when the close block blocks the column just above/beneath
X * it (right_shadow < fb_col [actually right_shadow == fb_col-1]). If
X * the location is filled, then we want to see it, so we put the
X * right shadow back (same as fb_col).
X */
X if (right_shadow < fb_col && !viz_clear_rows[row][fb_col])
X right_shadow = fb_col;
X if(right_shadow > lim_max) right_shadow = lim_max;
X
X /*
X * Main loop. Within the range of sight of the previous row, mark all
X * stone walls as seen. Follow open areas recursively.
X */
X while (left <= right_mark) {
X /* Get the far right of the opening or wall */
X loc_right = right_ptrs[row][left];
X if(loc_right > lim_max) loc_right = lim_max;
X
X if (!viz_clear_rows[row][left]) {
X hit_stone = 1; /* use stone on this row as close block */
X /*
X * We can see all of the wall until the next open spot or the
X * start of the shadow caused by the far block (right).
X *
X * Can't see stone beyond the right mark.
X */
X if (loc_right > right_mark) loc_right = right_mark;
X
X if(vis_func) {
X for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg);
X } else {
X for (i = left; i <= loc_right; i++) set_cs(rowp,i);
X set_min(left); set_max(loc_right);
X }
X
X if (loc_right == right_mark) return; /* hit the end */
X left = loc_right + 1;
X loc_right = right_ptrs[row][left];
X if(loc_right > lim_max) loc_right = lim_max;
X /* fall through... we know at least one position is visible */
X }
X
X /*
X * We are in an opening.
X *
X * If this is the first open spot since the could see area (this is
X * true if we have hit stone), get the shadow generated by the wall
X * just to our left.
X */
X if (hit_stone) {
X lblock_col = left-1; /* local block column */
X left = close_shadow(FROM_RIGHT,row,row,lblock_col);
X if (left > lim_max) break; /* off the end */
X }
X
X /*
X * Check if the shadow covers the opening. If it does, then
X * move to end of the opening. A shadow generated on from a
X * wall on this row does *not* cover the wall on the right
X * of the opening.
X */
X if (left >= loc_right) {
X if (loc_right == lim_max) { /* boundary */
X if (left == lim_max) {
X if(vis_func) (*vis_func)(lim_max, row, varg);
X else {
X set_cs(rowp,lim_max); /* last pos */
X set_max(lim_max);
X }
X }
X return; /* done */
X }
X left = loc_right;
X continue;
X }
X
X /*
X * If the far wall of the opening (loc_right) is closer than the
X * shadow limit imposed by the far block (right) then use the far
X * wall as our new far block when we recurse.
X *
X * If the limits are the the same, and the far block really exists
X * (fb_row >= 0) then do the same as above.
X *
X * Normally, the check would be for the far wall being closer OR EQUAL
X * to the shadow limit. However, there is a bug that arises from the
X * fact that the clear area pointers end in an open space (if it
X * exists) on a boundary. This then makes a far block exist where it
X * shouldn't --- on a boundary. To get around that, I had to
X * introduce the concept of a non-existent far block (when the
X * row < 0). Next I have to check for it. Here is where that check
X * exists.
X */
X if ((loc_right < right_shadow) ||
X (fb_row >= 0 && loc_right == right_shadow)) {
X if(vis_func) {
X for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg);
X } else {
X for (i = left; i <= loc_right; i++) set_cs(rowp,i);
X set_min(left); set_max(loc_right);
X }
X
X if (deeper) {
X if (hit_stone)
X right_side(nrow,row,lblock_col,row,loc_right,
X left,loc_right,limits);
X else
X right_side(nrow,cb_row,cb_col,row,loc_right,
X left,loc_right,limits);
X }
X
X /*
X * The following line, setting hit_stone, is needed for those
X * walls that are only 1 wide. If hit stone is *not* set and
X * the stone is only one wide, then the close block is the old
X * one instead one on the current row. A way around having to
X * set it here is to make left = loc_right (not loc_right+1) and
X * let the outer loop take care of it. However, if we do that
X * then we then have to check for boundary conditions here as
X * well.
X */
X hit_stone = 1;
X
X left = loc_right+1;
X }
X /*
X * The opening extends beyond the right mark. This means that
X * the next far block is the current far block.
X */
X else {
X if(vis_func) {
X for (i=left; i <= right_shadow; i++) (*vis_func)(i, row, varg);
X } else {
X for (i = left; i <= right_shadow; i++) set_cs(rowp,i);
X set_min(left); set_max(right_shadow);
X }
X
X if (deeper) {
X if (hit_stone)
X right_side(nrow, row,lblock_col,fb_row,fb_col,
X left,right_shadow,limits);
X else
X right_side(nrow,cb_row, cb_col,fb_row,fb_col,
X left,right_shadow,limits);
X }
X
X return; /* we're outta here */
X }
X }
X}
X
X
X/*
X * left_side()
X *
X * This routine is the mirror image of right_side(). Please see right_side()
X * for blow by blow comments.
X */
Xstatic void
Xleft_side(row, cb_row, cb_col, fb_row, fb_col, left_mark, right, limits)
X int row; /* the current row */
X int cb_row, cb_col; /* close block row and col */
X int fb_row, fb_col; /* far block row and col */
X int left_mark; /* left mark of previous row */
X int right; /* right mark of the previous row */
X char *limits;
X{
X register int i;
X register char *rowp;
X int hit_stone = 0;
X int left_shadow, right_shadow, loc_left;
X int lblock_col; /* local block column (current row) */
X int nrow, deeper;
X char *row_min; /* left most */
X char *row_max; /* right most */
X int lim_min;
X
X nrow = row + step;
X deeper = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
X if(!vis_func) {
X rowp = cs_rows[row];
X row_min = &cs_left[row];
X row_max = &cs_right[row];
X }
X if(limits) {
X lim_min = start_col - *limits;
X if(lim_min < 0) lim_min = 0;
X if(left_mark < lim_min) left_mark = lim_min;
X limits++; /* prepare for next row */
X } else
X lim_min = 0;
X
X /* This value could be illegal. */
X right_shadow = close_shadow(FROM_LEFT,row,cb_row,cb_col);
X
X while ( right >= left_mark ) {
X loc_left = left_ptrs[row][right];
X if(loc_left < lim_min) loc_left = lim_min;
X if (viz_clear_rows[row][right]) {
X if (loc_left <= right_shadow) {
X right = right_shadow; /* opening ends beyond shadow */
X break;
X }
X right = loc_left;
X loc_left = left_ptrs[row][right];
X if(loc_left < lim_min) loc_left = lim_min;
X if (right == loc_left) return; /* boundary */
X }
X
X if (loc_left < left_mark) /* can't see beyond the left mark */
X loc_left = left_mark;
X
X if(vis_func) {
X for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg);
X } else {
X for (i = loc_left; i <= right; i++) set_cs(rowp,i);
X set_min(loc_left); set_max(right);
X }
X
X if (loc_left == left_mark) return; /* all stone */
X if (loc_left <= right_shadow) hit_stone = 1;
X right = loc_left - 1;
X }
X
X /* At first visible clear spot on or beyond the right shadow. */
X
X if ((left_shadow = far_shadow(FROM_LEFT,row,fb_row,fb_col)) < 0)
X left_shadow = 0;
X
X /* Do vertical walls as we want. */
X if (left_shadow > fb_col && !viz_clear_rows[row][fb_col])
X left_shadow = fb_col;
X if(left_shadow < lim_min) left_shadow = lim_min;
X
X while (right >= left_mark) {
X loc_left = left_ptrs[row][right];
X
X if (!viz_clear_rows[row][right]) {
X hit_stone = 1; /* use stone on this row as close block */
X
X /* We can only see walls until the left mark */
X if (loc_left < left_mark) loc_left = left_mark;
X
X if(vis_func) {
X for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg);
X } else {
X for (i = loc_left; i <= right; i++) set_cs(rowp,i);
X set_min(loc_left); set_max(right);
X }
X
X if (loc_left == left_mark) return; /* hit end */
X right = loc_left - 1;
X loc_left = left_ptrs[row][right];
X if (loc_left < lim_min) loc_left = lim_min;
X /* fall through...*/
X }
X
X /* We are in an opening. */
X if (hit_stone) {
X lblock_col = right+1; /* stone block (local) */
X right = close_shadow(FROM_LEFT,row,row,lblock_col);
X if (right < lim_min) return; /* off the end */
X }
X
X /* Check if the shadow covers the opening. */
X if (right <= loc_left) {
X /* Make a boundary condition work. */
X if (loc_left == lim_min) { /* at boundary */
X if (right == lim_min) {
X if(vis_func) (*vis_func)(lim_min, row, varg);
X else {
X set_cs(rowp,lim_min); /* caught the last pos */
X set_min(lim_min);
X }
X }
X return; /* and break out the loop */
X }
X
X right = loc_left;
X continue;
X }
X
X /* If the far wall of the opening is closer than the shadow limit. */
X if ((loc_left > left_shadow) ||
X (fb_row >= 0 && loc_left == left_shadow)) {
X if(vis_func) {
X for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg);
X } else {
X for (i = loc_left; i <= right; i++) set_cs(rowp,i);
X set_min(loc_left); set_max(right);
X }
X
X if (deeper) {
X if (hit_stone)
X left_side(nrow,row,lblock_col,row,loc_left,
X loc_left,right,limits);
X else
X left_side(nrow,cb_row,cb_col,row,loc_left,
X loc_left,right,limits);
X }
X
X hit_stone = 1; /* needed for walls of width 1 */
X right = loc_left-1;
X }
X /* The opening extends beyond the left mark. */
X else {
X if(vis_func) {
X for (i=left_shadow; i <= right; i++) (*vis_func)(i, row, varg);
X } else {
X for (i = left_shadow; i <= right; i++) set_cs(rowp,i);
X set_min(left_shadow); set_max(right);
X }
X
X if (deeper) {
X if (hit_stone)
X left_side(nrow,row,lblock_col,fb_row,fb_col,
X left_shadow,right,limits);
X else
X left_side(nrow,cb_row,cb_col,fb_row,fb_col,
X left_shadow,right,limits);
X }
X
X return; /* we're outta here */
X }
X
X }
X}
X
X/*
X * view_from
X *
X * Calculate a view from the given location. Initialize and fill a
X * ROWNOxCOLNO array (could_see) with all the locations that could be
X * seen from the source location. Initialize and fill the left most
X * and right most boundaries of what could be seen.
X */
Xstatic void
Xview_from(srow,scol,loc_cs_rows,left_most,right_most, range, func, arg)
X int srow, scol; /* source row and column */
X char **loc_cs_rows; /* could_see array (row pointers) */
X char *left_most, *right_most; /* limits of what could be seen */
X int range; /* 0 if unlimited */
X void FDECL((*func), (int,int,genericptr_t));
X genericptr_t arg;
X{
X register int i;
X char *rowp;
X int nrow, left, right, left_row, right_row;
X char *limits;
X
X /* Set globals for near_shadow(), far_shadow(), etc. to use. */
X start_col = scol;
X start_row = srow;
X cs_rows = loc_cs_rows;
X cs_left = left_most;
X cs_right = right_most;
X vis_func = func;
X varg = arg;
X
X /* Find the left and right limits of sight on the starting row. */
X if (viz_clear_rows[srow][scol]) {
X left = left_ptrs[srow][scol];
X right = right_ptrs[srow][scol];
X } else {
X left = (!scol) ? 0 :
X (viz_clear_rows[srow][scol-1] ? left_ptrs[srow][scol-1] : scol-1);
X right = (scol == COLNO-1) ? COLNO-1 :
X (viz_clear_rows[srow][scol+1] ? right_ptrs[srow][scol+1] : scol+1);
X }
X
X if(range) {
X if(range > MAX_RADIUS || range < 1)
X panic("view_from called with range %d", range);
X limits = circle_ptr(range) + 1; /* start at next row */
X if(left < scol - range) left = scol - range;
X if(right > scol + range) right = scol + range;
X } else
X limits = (char*) 0;
X
X if(func) {
X for (i = left; i <= right; i++) (*func)(i, srow, arg);
X } else {
X /* Row optimization */
X rowp = cs_rows[srow];
X
X /* We know that we can see our row. */
X for (i = left; i <= right; i++) set_cs(rowp,i);
X cs_left[srow] = left;
X cs_right[srow] = right;
X }
X
X /* The far block has a row number of -1 if we are on an edge. */
X right_row = (right == COLNO-1) ? -1 : srow;
X left_row = (!left) ? -1 : srow;
X
X /*
X * Check what could be seen in quadrants.
X */
X if ( (nrow = srow+1) < ROWNO ) {
X step = 1; /* move down */
X if (scol<COLNO-1)
X right_side(nrow,-1,scol,right_row,right,scol,right,limits);
X if (scol)
X left_side(nrow,-1,scol,left_row, left, left, scol,limits);
X }
X
X if ( (nrow = srow-1) >= 0 ) {
X step = -1; /* move up */
X if (scol<COLNO-1)
X right_side(nrow,-1,scol,right_row,right,scol,right,limits);
X if (scol)
X left_side(nrow,-1,scol,left_row, left, left, scol,limits);
X }
X}
X
X
X#else /*===== End of algorithm D =====*/
X
X
X/*===========================================================================*\
X GENERAL LINE OF SIGHT
X Algorithm C
X\*===========================================================================*/
X
X/*
X * Defines local to Algorithm C.
X */
Xstatic void FDECL(right_side, (int,int,int,char*));
Xstatic void FDECL(left_side, (int,int,int,char*));
X
X/* Initialize algorithm C (nothing). */
Xstatic void
Xview_init()
X{
X}
X
X/*
X * Mark positions as visible on one quadrant of the right side. The
X * quadrant is determined by the value of the global variable step.
X */
Xstatic void
Xright_side(row, left, right_mark, limits)
X int row; /* current row */
X int left; /* first (left side) visible spot on prev row */
X int right_mark; /* last (right side) visible spot on prev row */
X char *limits; /* points at range limit for current row, or NULL */
X{
X int right; /* right limit of "could see" */
X int right_edge; /* right edge of an opening */
X int nrow; /* new row (calculate once) */
X int deeper; /* if TRUE, call self as needed */
X int result; /* set by q?_path() */
X register int i; /* loop counter */
X register char *rowp; /* row optimization */
X char *row_min; /* left most [used by macro set_min()] */
X char *row_max; /* right most [used by macro set_max()] */
X int lim_max; /* right most limit of circle */
X
X#ifdef GCC_WARN
X rowp = row_min = row_max = 0;
X#endif
X nrow = row + step;
X /*
X * Can go deeper if the row is in bounds and the next row is within
X * the circle's limit. We tell the latter by checking to see if the next
X * limit value is the start of a new circle radius (meaning we depend
X * on the structure of circle_data[]).
X */
X deeper = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
X if(!vis_func) {
X rowp = cs_rows[row]; /* optimization */
X row_min = &cs_left[row];
X row_max = &cs_right[row];
X }
X if(limits) {
X lim_max = start_col + *limits;
X if(lim_max > COLNO-1) lim_max = COLNO-1;
X if(right_mark > lim_max) right_mark = lim_max;
X limits++; /* prepare for next row */
X } else
X lim_max = COLNO-1;
X
X while (left <= right_mark) {
X right_edge = right_ptrs[row][left];
X if(right_edge > lim_max) right_edge = lim_max;
X
X if (!is_clear(row,left)) {
X /*
X * Jump to the far side of a stone wall. We can set all
X * the points in between as seen.
X *
X * If the right edge goes beyond the right mark, check to see
X * how much we can see.
X */
X if (right_edge > right_mark) {
X /*
X * If the mark on the previous row was a clear position,
X * the odds are that we can actually see part of the wall
X * beyond the mark on this row. If so, then see one beyond
X * the mark. Otherwise don't. This is a kludge so corners
X * with an adjacent doorway show up in nethack.
X */
X right_edge = is_clear(row-step,right_mark) ?
X right_mark+1 : right_mark;
X }
X if(vis_func) {
X for (i = left; i <= right_edge; i++) (*vis_func)(i, row, varg);
X } else {
X for (i = left; i <= right_edge; i++) set_cs(rowp,i);
X set_min(left); set_max(right_edge);
X }
X left = right_edge + 1; /* no limit check necessary */
X continue;
X }
X
X /* No checking needed if our left side is the start column. */
X if (left != start_col) {
X /*
X * Find the left side. Move right until we can see it or we run
X * into a wall.
X */
X for (; left <= right_edge; left++) {
X if (step < 0) {
X q1_path(start_row,start_col,row,left,rside1);
X } else {
X q4_path(start_row,start_col,row,left,rside1);
X }
Xrside1: /* used if q?_path() is a macro */
X if (result) break;
X }
X
X /*
X * Check for boundary conditions. We *need* check (2) to break
X * an infinite loop where:
X *
X * left == right_edge == right_mark == lim_max.
X *
X */
X if (left > lim_max) return; /* check (1) */
X if (left == lim_max) { /* check (2) */
X if(vis_func) (*vis_func)(lim_max, row, varg);
X else {
X set_cs(rowp,lim_max);
X set_max(lim_max);
X }
X return;
X }
X /*
X * Check if we can see any spots in the opening. We might
X * (left == right_edge) or might not (left == right_edge+1) have
X * been able to see the far wall. Make sure we *can* see the
X * wall (remember, we can see the spot above/below this one)
X * by backing up.
X */
X if (left >= right_edge) {
X left = right_edge; /* for the case left == right_edge+1 */
X continue;
X }
X }
X
X /*
X * Find the right side. If the marker from the previous row is
X * closer than the edge on this row, then we have to check
X * how far we can see around the corner (under the overhang). Stop
X * at the first non-visible spot or we actually hit the far wall.
X *
X * Otherwise, we know we can see the right edge of the current row.
X *
X * This must be a strict less than so that we can always see a
X * horizontal wall, even if it is adjacent to us.
X */
X if (right_mark < right_edge) {
X for (right = right_mark; right <= right_edge; right++) {
X if (step < 0) {
X q1_path(start_row,start_col,row,right,rside2);
X } else {
X q4_path(start_row,start_col,row,right,rside2);
X }
Xrside2: /* used if q?_path() is a macro */
X if (!result) break;
X }
X --right; /* get rid of the last increment */
X }
X else
X right = right_edge;
X
X /*
X * We have the range that we want. Set the bits. Note that
X * there is no else --- we no longer handle splinters.
X */
X if (left <= right) {
X /*
X * An ugly special case. If you are adjacent to a vertical wall
X * and it has a break in it, then the right mark is set to be
X * start_col. We *want* to be able to see adjacent vertical
X * walls, so we have to set it back.
X */
X if (left == right && left == start_col &&
X start_col < (COLNO-1) && !is_clear(row,start_col+1))
X right = start_col+1;
X
X if(right > lim_max) right = lim_max;
X /* set the bits */
X if(vis_func)
X for (i = left; i <= right; i++) (*vis_func)(i, row, varg);
X else {
X for (i = left; i <= right; i++) set_cs(rowp,i);
X set_min(left); set_max(right);
X }
X
X /* recursive call for next finger of light */
X if (deeper) right_side(nrow,left,right,limits);
X left = right + 1; /* no limit check necessary */
X }
X }
X}
X
X
X/*
X * This routine is the mirror image of right_side(). See right_side() for
X * extensive comments.
X */
Xstatic void
Xleft_side(row, left_mark, right, limits)
X int row, left_mark, right;
X char *limits;
X{
X int left, left_edge, nrow, deeper, result;
X register int i;
X register char *rowp;
X char *row_min, *row_max;
X int lim_min;
X
X#ifdef GCC_WARN
X rowp = row_min = row_max = 0;
X#endif
X nrow = row+step;
X deeper = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
X if(!vis_func) {
X rowp = cs_rows[row];
X row_min = &cs_left[row];
X row_max = &cs_right[row];
X }
X if(limits) {
X lim_min = start_col - *limits;
X if(lim_min < 0) lim_min = 0;
X if(left_mark < lim_min) left_mark = lim_min;
X limits++; /* prepare for next row */
X } else
X lim_min = 0;
X
X while (right >= left_mark) {
X left_edge = left_ptrs[row][right];
X if(left_edge < lim_min) left_edge = lim_min;
X
X if (!is_clear(row,right)) {
X /* Jump to the far side of a stone wall. */
X if (left_edge < left_mark) {
X /* Maybe see more (kludge). */
X left_edge = is_clear(row-step,left_mark) ?
X left_mark-1 : left_mark;
X }
X if(vis_func) {
X for (i = left_edge; i <= right; i++) (*vis_func)(i, row, varg);
X } else {
X for (i = left_edge; i <= right; i++) set_cs(rowp,i);
X set_min(left_edge); set_max(right);
X }
X right = left_edge - 1; /* no limit check necessary */
X continue;
X }
X
X if (right != start_col) {
X /* Find the right side. */
X for (; right >= left_edge; right--) {
X if (step < 0) {
X q2_path(start_row,start_col,row,right,lside1);
X } else {
X q3_path(start_row,start_col,row,right,lside1);
X }
Xlside1: /* used if q?_path() is a macro */
X if (result) break;
X }
X
X /* Check for boundary conditions. */
X if (right < lim_min) return;
X if (right == lim_min) {
X if(vis_func) (*vis_func)(lim_min, row, varg);
X else {
X set_cs(rowp,lim_min);
X set_min(lim_min);
X }
X return;
X }
X /* Check if we can see any spots in the opening. */
X if (right <= left_edge) {
X right = left_edge;
X continue;
X }
X }
X
X /* Find the left side. */
X if (left_mark > left_edge) {
X for (left = left_mark; left >= left_edge; --left) {
X if (step < 0) {
X q2_path(start_row,start_col,row,left,lside2);
X } else {
X q3_path(start_row,start_col,row,left,lside2);
X }
Xlside2: /* used if q?_path() is a macro */
X if (!result) break;
X }
X left++; /* get rid of the last decrement */
X }
X else
X left = left_edge;
X
X if (left <= right) {
X /* An ugly special case. */
X if (left == right && right == start_col &&
X start_col > 0 && !is_clear(row,start_col-1))
X left = start_col-1;
X
X if(left < lim_min) left = lim_min;
X if(vis_func)
X for (i = left; i <= right; i++) (*vis_func)(i, row, varg);
X else {
X for (i = left; i <= right; i++) set_cs(rowp,i);
X set_min(left); set_max(right);
X }
X
X /* Recurse */
X if (deeper) left_side(nrow,left,right,limits);
X right = left - 1; /* no limit check necessary */
X }
X }
X}
X
X
X/*
X * Calculate all possible visible locations from the given location
X * (srow,scol). NOTE this is (y,x)! Mark the visible locations in the
X * array provided.
X */
Xstatic void
Xview_from(srow, scol, loc_cs_rows, left_most, right_most, range, func, arg)
X int srow, scol; /* starting row and column */
X char **loc_cs_rows; /* pointers to the rows of the could_see array */
X char *left_most; /* min mark on each row */
X char *right_most; /* max mark on each row */
X int range; /* 0 if unlimited */
X void FDECL((*func), (int,int,genericptr_t));
X genericptr_t arg;
X{
X register int i; /* loop counter */
X char *rowp; /* optimization for setting could_see */
X int nrow; /* the next row */
X int left; /* the left-most visible column */
X int right; /* the right-most visible column */
X char *limits; /* range limit for next row */
X
X /* Set globals for q?_path(), left_side(), and right_side() to use. */
X start_col = scol;
X start_row = srow;
X cs_rows = loc_cs_rows; /* 'could see' rows */
X cs_left = left_most;
X cs_right = right_most;
X vis_func = func;
X varg = arg;
X
X /*
X * Determine extent of sight on the starting row.
X */
X if (is_clear(srow,scol)) {
X left = left_ptrs[srow][scol];
X right = right_ptrs[srow][scol];
X } else {
X /*
X * When in stone, you can only see your adjacent squares, unless
X * you are on an array boundary or a stone/clear boundary.
X */
X left = (!scol) ? 0 :
X (is_clear(srow,scol-1) ? left_ptrs[srow][scol-1] : scol-1);
X right = (scol == COLNO-1) ? COLNO-1 :
X (is_clear(srow,scol+1) ? right_ptrs[srow][scol+1] : scol+1);
X }
X
X if(range) {
X if(range > MAX_RADIUS || range < 1)
X panic("view_from called with range %d", range);
X limits = circle_ptr(range) + 1; /* start at next row */
X if(left < scol - range) left = scol - range;
X if(right > scol + range) right = scol + range;
X } else
X limits = (char*) 0;
X
X if(func) {
X for (i = left; i <= right; i++) (*func)(i, srow, arg);
X } else {
X /* Row pointer optimization. */
X rowp = cs_rows[srow];
X
X /* We know that we can see our row. */
X for (i = left; i <= right; i++) set_cs(rowp,i);
X cs_left[srow] = left;
X cs_right[srow] = right;
X }
X
X /*
X * Check what could be seen in quadrants. We need to check for valid
X * rows here, since we don't do it in the routines right_side() and
X * left_side() [ugliness to remove extra routine calls].
X */
X if ( (nrow = srow+1) < ROWNO ) { /* move down */
X step = 1;
X if (scol < COLNO-1) right_side(nrow, scol, right, limits);
X if (scol) left_side (nrow, left, scol, limits);
X }
X
X if ( (nrow = srow-1) >= 0 ) { /* move up */
X step = -1;
X if (scol < COLNO-1) right_side(nrow, scol, right, limits);
X if (scol) left_side (nrow, left, scol, limits);
X }
X}
X
X#endif /*===== End of algorithm C =====*/
X
X/*
X * AREA OF EFFECT "ENGINE"
X *
X * Calculate all possible visible locations as viewed from the given location
X * (srow,scol) within the range specified. Perform "func" with (x, y) args and
X * additional argument "arg" for each square.
X *
X * If not centered on the hero, just forward arguments to view_from(); it
X * will call "func" when necessary. If the hero is the center, use the
X * vision matrix and reduce extra work.
X */
Xvoid
Xdo_clear_area(scol,srow,range,func,arg)
X int scol, srow, range;
X void FDECL((*func), (int,int,genericptr_t));
X genericptr_t arg;
X{
X /* If not centered on hero, do the hard work of figuring the area */
X if (scol != u.ux || srow != u.uy)
X view_from(srow, scol, (char **)0, NULL, NULL, range, func, arg);
X else {
X register int x;
X int y, min_x, max_x, max_y, offset;
X char *limits;
X
X if (range > MAX_RADIUS || range < 1)
X panic("do_clear_area: illegal range %d", range);
X if(vision_full_recalc)
X vision_recalc(0); /* recalc vision if dirty */
X limits = circle_ptr(range);
X if ((max_y = (srow + range)) >= ROWNO) max_y = ROWNO-1;
X if ((y = (srow - range)) < 0) y = 0;
X for (; y <= max_y; y++) {
X offset = limits[abs(y-srow)];
X if((min_x = (scol - offset)) < 0) min_x = 0;
X if((max_x = (scol + offset)) >= COLNO) max_x = COLNO-1;
X for (x = min_x; x <= max_x; x++)
X if (couldsee(x, y))
X (*func)(x, y, arg);
X }
X }
X}
X
X/*vision.c*/
END_OF_FILE
if test 33352 -ne `wc -c <'src/vision.c2'`; then
echo shar: \"'src/vision.c2'\" unpacked with wrong size!
fi
# end of 'src/vision.c2'
fi
if test -f 'sys/amiga/amiwind.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'sys/amiga/amiwind.c'\"
else
echo shar: Extracting \"'sys/amiga/amiwind.c'\" \(21231 characters\)
sed "s/^X//" >'sys/amiga/amiwind.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)amiwind.c 3.1 93/01/08
X/* Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992 */
X/* Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993 */
X/* NetHack may be freely redistributed. See license for details. */
X
X/*
X * Here is some very Amiga specific stuff, dealing with
X * screens, windows, menus, and input via IntuiMessages.
X */
X
X#include "hack.h"
X#include "winami.h"
X
X/* Have to undef CLOSE as display.h and intuition.h both use it */
X#undef CLOSE
X
X#include <exec/types.h>
X#include <exec/alerts.h>
X#include <exec/io.h>
X#include <exec/devices.h>
X#include <devices/console.h>
X#include <devices/conunit.h>
X#include <intuition/intuition.h>
X#include <intuition/intuitionbase.h>
X#include <libraries/dosextens.h>
X
X#ifdef __SASC
X# undef COUNT
X
X# include <dos.h> /* for __emit */
X# include <string.h>
X# include <proto/dos.h>
X# include <proto/exec.h>
X
X/* kludge - see amirip for why */
X# undef red
X# undef green
X# undef blue
X# undef index
X# include <proto/graphics.h>
X
X# include <proto/intuition.h>
X# include <proto/diskfont.h>
X# include <proto/console.h>
X#endif
X
X#undef NULL
X#define NULL 0L
X
X#include "Amiga:amimenu.c"
X
X/* First, external declarations... */
X
Xstruct Library *ConsoleDevice;
X
X#ifdef AZTEC_50
X# include <functions.h>
X#endif
X
X#ifdef INTUI_NEW_LOOK
X#define NewWindow ExtNewWindow
X#endif
X
X#include "Amiga:winami.p"
X#include "Amiga:amiwind.p"
X#include "Amiga:amidos.p"
X
Xstatic int BufferGetchar(void);
Xstatic void ProcessMessage( register struct IntuiMessage *message );
X
X#ifdef AMIFLUSH
Xstatic struct Message *FDECL(GetFMsg,(struct MsgPort *));
X#endif
X
X/* Now our own variables */
X
Xstruct IntuitionBase *IntuitionBase;
Xstruct Screen *HackScreen;
Xstruct Window *pr_WindowPtr;
Xstruct MsgPort *HackPort;
Xstruct IOStdReq ConsoleIO;
Xchar Initialized = 0;
XWEVENT lastevent;
X
X#ifdef HACKFONT
Xstruct GfxBase *GfxBase;
Xstruct Library *DiskfontBase;
X#endif
X
Xextern struct Library *ConsoleDevice;
X
X#define CSI '\x9b'
X#define NO_CHAR -1
X#define RAWHELP 0x5F /* Rawkey code of the HELP key */
X
X#define KBDBUFFER 10
Xstatic unsigned char KbdBuffer[KBDBUFFER];
Xunsigned char KbdBuffered;
X
X#define BufferQueueChar(ch) (KbdBuffer[KbdBuffered++] = (ch))
X
X/*
X * Define some stuff for our special glyph drawing routines
X */
Xstatic unsigned short glyph_node_index, glyph_buffer_index;
X#define NUMBER_GLYPH_NODES 80
X#define GLYPH_BUFFER_SIZE 512
Xstruct glyph_node {
X short x;
X short y;
X short len;
X unsigned char bg_color;
X unsigned char fg_color;
X char *buffer;
X};
Xstatic struct glyph_node g_nodes[NUMBER_GLYPH_NODES];
Xstatic char glyph_buffer[GLYPH_BUFFER_SIZE];
X
X#ifdef TEXTCOLOR
X/*
X * Map our amiga-specific colormap into the colormap specified in color.h.
X * See amiwind.c for the amiga specific colormap.
X */
X
Xint foreg[16] = { 0, 7, 4, 2, 6, 5, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
Xint backg[16] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 1, 6, 5, 3, 1 };
X#endif
X
X#ifdef HACKFONT
X
Xstruct TextFont *HackFont;
XUBYTE FontName[] = "NetHack:hack.font";
X /* # chars in "NetHack:": */
X#define SIZEOF_DISKNAME 8
X
X#endif
X
Xstruct TextAttr Hack80 = {
X#ifdef HACKFONT
X &FontName[SIZEOF_DISKNAME],
X#else
X (UBYTE *) "topaz.font",
X#endif
X TOPAZ_EIGHTY, FS_NORMAL, FPF_DISKFONT | FPF_ROMFONT
X};
X
X/*
X * Open a window that shares the HackPort IDCMP. Use CloseShWindow()
X * to close.
X */
X
Xstruct Window *OpenShWindow(nw)
Xstruct NewWindow *nw;
X{
X register struct Window *win;
X register ULONG idcmpflags;
X
X if (!HackPort) /* Sanity check */
X return (struct Window *) 0;
X
X idcmpflags = nw->IDCMPFlags;
X nw->IDCMPFlags = 0;
X if (!(win = OpenWindow((void *)nw)))
X return (struct Window *) 0;
X
X win->UserPort = HackPort;
X ModifyIDCMP(win, idcmpflags);
X return win;
X}
X
X
X/*
X * Close a window that shared the HackPort IDCMP port.
X */
X
Xvoid FDECL(CloseShWindow, (struct Window *));
Xvoid CloseShWindow(win)
Xstruct Window *win;
X{
X register struct IntuiMessage *msg, *nxt;
X
X if( !HackPort )
X panic("HackPort NULL in CloseShWindow" );
X if (!win)
X return;
X
X Forbid();
X /* Flush all messages for all windows to avoid typeahead and other
X * similar problems...
X */
X while( msg = (struct IntuiMessage *)GetMsg( win->UserPort ) )
X ReplyMsg( (struct Message *) msg );
X KbdBuffered = 0;
X win->UserPort = (struct MsgPort *) 0;
X ModifyIDCMP(win, 0L);
X Permit();
X CloseWindow(win);
X}
X
Xstatic int BufferGetchar()
X{
X register int c;
X
X if (KbdBuffered > 0) {
X c = KbdBuffer[0];
X KbdBuffered--;
X /* Move the remaining characters */
X if( KbdBuffered < sizeof( KbdBuffer ) )
X memcpy( KbdBuffer, KbdBuffer+1, KbdBuffered );
X return c;
X }
X
X return NO_CHAR;
X}
X
X/*
X * This should remind you remotely of DeadKeyConvert, but we are cheating
X * a bit. We want complete control over the numeric keypad, and no dead
X * keys... (they are assumed to be on Alted keys).
X *
X * Also assumed is that the IntuiMessage is of type RAWKEY. For some
X * reason, IECODE_UP_PREFIX events seem to be lost when they occur while
X * our console window is inactive. This is particulary troublesome with
X * qualifier keys... Is this because I never RawKeyConvert those events???
X */
X
Xint ConvertKey(message)
Xregister struct IntuiMessage *message;
X{
X static struct InputEvent theEvent;
X static char numpad[] = "bjnh.lyku";
X static char ctrl_numpad[] = "\x02\x0A\x0E\x08.\x0C\x19\x0B\x15";
X static char shift_numpad[] = "BJNH.LYKU";
X
X unsigned char buffer[1];
X register int length;
X register ULONG qualifier;
X char numeric_pad, shift, control, alt;
X
X qualifier = message->Qualifier;
X
X control = (qualifier & IEQUALIFIER_CONTROL) != 0;
X shift = (qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) != 0;
X alt = (qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT )) != 0;
X
X /* Allow ALT to function as a META key ... */
X
X qualifier &= ~(IEQUALIFIER_LALT | IEQUALIFIER_RALT);
X numeric_pad = (qualifier & IEQUALIFIER_NUMERICPAD) != 0;
X
X /*
X * Shortcut for HELP and arrow keys. I suppose this is allowed.
X * The defines are in intuition/intuition.h, and the keys don't
X * serve 'text' input, normally. Also, parsing their escape
X * sequences is such a mess...
X */
X
X switch (message->Code) {
X case RAWHELP:
X if( alt )
X {
X EditColor();
X return( -1 );
X }
X return( '?' );
X break;
X case CURSORLEFT:
X length = '4';
X numeric_pad = 1;
X goto arrow;
X case CURSORDOWN:
X length = '2';
X numeric_pad = 1;
X goto arrow;
X case CURSORUP:
X length = '8';
X numeric_pad = 1;
X goto arrow;
X case CURSORRIGHT:
X length = '6';
X numeric_pad = 1;
X goto arrow;
X }
X
X theEvent.ie_Class = IECLASS_RAWKEY;
X theEvent.ie_Code = message->Code;
X theEvent.ie_Qualifier = numeric_pad ? IEQUALIFIER_NUMERICPAD : qualifier;
X theEvent.ie_EventAddress = (APTR) (message->IAddress);
X
X length = RawKeyConvert(&theEvent, (char *)buffer,
X (long) sizeof(buffer), NULL);
X
X if (length == 1) { /* Plain ASCII character */
X length = buffer[0];
X /*
X * If flags.num_pad is set, movement is by 4286.
X * If not set, translate 4286 into hjkl.
X * This way, the numeric pad can /always/ be used
X * for moving, though best results are when it is off.
X */
Xarrow:
X if (!flags.num_pad && numeric_pad && length >= '1' && length <= '9') {
X length -= '1';
X if (control) {
X length = ctrl_numpad[length];
X } else if (shift) {
X length = shift_numpad[length];
X } else {
X length = numpad[length];
X }
X }
X if (alt)
X length |= 0x80;
X return(length);
X } /* else shift, ctrl, alt, amiga, F-key, shift-tab, etc */
X else
X return( -1 );
X}
X
X/*
X * Process an incoming IntuiMessage.
X * It would certainly look nicer if this could be done using a
X * PA_SOFTINT message port, but we cannot call RawKeyConvert()
X * during a software interrupt.
X * Anyway, kbhit() is called often enough, and usually gets
X * ahead of input demands, when the user types ahead.
X */
X
Xstatic void ProcessMessage(message)
Xregister struct IntuiMessage *message;
X{
X int c;
X static int skip_mouse=0; /* need to ignore next mouse event on
X * a window activation */
X switch(message->Class) {
X case ACTIVEWINDOW:
X skip_mouse=1;break;
X case MOUSEBUTTONS:
X {
X if(skip_mouse){
X skip_mouse=0;
X break;
X }
X if( message->Code == SELECTDOWN ){
X lastevent.type = WEMOUSE;
X lastevent.u.mouse.x = message->MouseX;
X lastevent.u.mouse.y = message->MouseY;
X /* With shift equals RUN */
X lastevent.u.mouse.qual = (message->Qualifier &
X (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) != 0;
X }
X }
X break;
X
X case MENUPICK:
X {
X USHORT thismenu;
X struct MenuItem *item;
X
X thismenu = message->Code;
X while (thismenu != MENUNULL) {
X item = ItemAddress(HackMenu, (ULONG) thismenu);
X if (KbdBuffered < KBDBUFFER)
X BufferQueueChar(item->Command); /* Unused: No COMMSEQ */
X thismenu = item->NextSelect;
X }
X }
X break;
X
X case RAWKEY:
X if (!(message->Code & IECODE_UP_PREFIX)){
X /* May queue multiple characters
X * but doesn't do that yet...
X */
X if( ( c = ConvertKey(message) ) > 0 )
X BufferQueueChar( c );
X }
X break;
X }
X ReplyMsg((struct Message *) message);
X}
X
X/*
X * Get all incoming messages and fill up the keyboard buffer,
X * thus allowing Intuition to (maybe) free up the IntuiMessages.
X * Return when no more messages left, or keyboard buffer half full.
X * We need to do this since there is no one-to-one correspondence
X * between characters and incoming messages.
X */
X
Xint kbhit()
X{
X register struct IntuiMessage *message;
X while( KbdBuffered < KBDBUFFER / 2 )
X {
X#ifdef AMIFLUSH
X message = (struct IntuiMessage *) GetFMsg(HackPort);
X#else
X message = (struct IntuiMessage *) GetMsg(HackPort);
X#endif
X if(message)
X {
X ProcessMessage(message);
X if( lastevent.type != WEUNK && lastevent.type != WEKEY )
X break;
X }
X else
X break;
X }
X return ( lastevent.type == WEUNK ) ? KbdBuffered : -1;
X}
X
X/*
X * Get a character from the keyboard buffer, waiting if not available.
X * Ignore other kinds of events that happen in the mean time.
X */
X
Xint WindowGetchar( )
X{
X while ((lastevent.type = WEUNK), kbhit() <= 0) {
X WaitPort(HackPort);
X }
X return BufferGetchar();
X}
X
XWETYPE WindowGetevent()
X{
X lastevent.type = WEUNK;
X while (kbhit() == 0)
X {
X WaitPort(HackPort);
X }
X
X if( KbdBuffered )
X {
X lastevent.type = WEKEY;
X lastevent.u.key = BufferGetchar();
X }
X return( lastevent.type );
X}
X
X/*
X * Clean up everything. But before we do, ask the user to hit return
X * when there is something that s/he should read.
X */
X
Xvoid CleanUp()
X{
X register struct IntuiMessage *msg;
X
X /* Finish closing things up */
X
X amii_raw_print("");
X amii_getret();
X
X ((struct Process *) FindTask(NULL))->pr_WindowPtr = (APTR) pr_WindowPtr;
X if (ConsoleIO.io_Device)
X CloseDevice( (struct IORequest *)&ConsoleIO );
X
X if (HackPort) {
X Forbid();
X while (msg = (struct IntuiMessage *) GetMsg(HackPort))
X ReplyMsg((struct Message *) msg);
X kill_nhwindows( 1 );
X DeletePort( HackPort );
X HackPort = NULL;
X Permit();
X }
X
X if (HackScreen) {
X#ifdef INTUI_NEW_LOOK
X if( IntuitionBase->LibNode.lib_Version >= 37 )
X {
X while( CloseScreen(HackScreen) == FALSE )
X {
X struct EasyStruct easy =
X {
X sizeof( struct EasyStruct ),
X 0,
X "Nethack Problem",
X "Can't Close Screen, Close Remaining Windows",
X "Okay",
X };
X EasyRequest( NULL, &easy, NULL, NULL );
X }
X }
X#else
X CloseScreen(HackScreen);
X#endif
X HackScreen = NULL;
X }
X
X#ifdef HACKFONT
X
X if (HackFont)
X {
X CloseFont(HackFont);
X HackFont = NULL;
X }
X
X if( DiskfontBase )
X {
X CloseLibrary(DiskfontBase);
X DiskfontBase = NULL;
X }
X#endif
X
X if (GfxBase) {
X CloseLibrary((struct Library *)GfxBase);
X GfxBase = NULL;
X }
X
X if (IntuitionBase) {
X CloseLibrary((struct Library *)IntuitionBase);
X IntuitionBase = NULL;
X }
X
X Initialized = 0;
X}
X
Xvoid Abort(rc)
Xlong rc;
X{
X#ifdef CHDIR
X extern char orgdir[];
X chdir(orgdir);
X#endif
X if (Initialized && ConsoleDevice) {
X printf("\n\nAbort with alert code %08lx...\n", rc);
X amii_getret();
X } else
X Alert(rc);
X#ifdef __SASC
X {
X/* __emit(0x4afc); /* illegal instruction */
X __emit(0x40fc); /* divide by */
X __emit(0x0000); /* #0 */
X /* NOTE: don't move CleanUp() above here - */
X /* it is too likely to kill the system */
X /* before it can get the SnapShot out, if */
X /* there is something really wrong. */
X }
X#endif
X CleanUp();
X#undef exit
X#ifdef AZTEC_C
X _abort();
X#endif
X exit((int) rc);
X}
X
X#ifdef AMIFLUSH
X/* This routine adapted from AmigaMail IV-37 by Michael Sinz */
Xstatic struct Message *
XGetFMsg(port)
X struct MsgPort *port;
X {
X struct IntuiMessage *msg,*succ,*succ1;
X
X if(msg=(struct IntuiMessage *)GetMsg(port)){
X if(!flags.amiflush)return((struct Message *)msg);
X if(msg->Class==RAWKEY){
X Forbid();
X succ=(struct IntuiMessage *)(port->mp_MsgList.lh_Head);
X while(succ1=(struct IntuiMessage *)
X (succ->ExecMessage.mn_Node.ln_Succ)){
X if(succ->Class==RAWKEY){
X Remove((struct Node *)succ);
X ReplyMsg((struct Message *)succ);
X }
X succ=succ1;
X }
X Permit();
X }
X }
X return((struct Message *)msg);
X}
X#endif
X
X/*
X * Begin Revamped Text display routines
X *
X * Up until version 3.1, the only method for displaying text on the playing
X * field was by using the console.device. This was nice for a number of
X * reasons, the most signifigant of which was a lot of the nuts and bolts was
X * done for you via escape sequences interpreted by said device. This did
X * not come without a price however. And that price was speed. It has now
X * come to a point where the speed has now been deemed unacceptable.
X *
X * The following series of routines are designed to drop into the current
X * nethack display code, using hooks provided for such a measure. It works
X * on similar principals as the WindowPuts(), buffering I/O internally
X * until either an explicit flush or internal buffering is exceeded, thereby
X * forcing the flush. The output (or glyphs) does not go to the
X * console.device, however. It is driven directly to the rasterport of the
X * nethack window via the low-level Text() calls, increasing the speed by
X * a very signifigant factor.
X */
X/*
X * Routine to simply flush whatever is buffered
X */
Xvoid
Xflush_glyph_buffer( w )
X struct Window *w;
X{
X short i, x, y;
X
X /* If nothing is buffered, return before we do anything */
X if(glyph_node_index == 0)
X return;
X
X cursor_off( WIN_MAP );
X start_glyphout( WIN_MAP );
X /* Set up the drawing mode */
X SetDrMd( w->RPort, JAM2);
X
X /* Go ahead and start dumping the stuff */
X for(i=0; i<glyph_node_index; ++i) {
X /* These coordinate calculations must be synced with the
X * code in curs() in winami.c. curs_on_u() calls curs()
X * to draw the cursor on top of the player
X */
X y = w->BorderTop + (g_nodes[i].y-1) * w->RPort->TxHeight +
X w->RPort->TxBaseline + 1;
X x = g_nodes[i].x * w->RPort->TxWidth + w->BorderLeft;
X
X /* Move pens to correct location */
X Move(w->RPort, (long)x, (long)y);
X
X /* Setup the colors */
X SetAPen(w->RPort, (long)g_nodes[i].fg_color);
X SetBPen(w->RPort, (long)g_nodes[i].bg_color);
X
X /* Do it */
X Text(w->RPort, g_nodes[i].buffer, g_nodes[i].len);
X }
X
X end_glyphout( WIN_MAP );
X /* Clean up */
X glyph_node_index = glyph_buffer_index = 0;
X}
X
X/*
X * Glyph buffering routine. Called instead of WindowPuts().
X */
Xvoid
Xamiga_print_glyph(window,color_index, glyph)
X winid window;
X int color_index, glyph;
X{
X int fg_color, bg_color;
X struct WinDesc *cw;
X struct Window *w;
X int curx;
X int cury;
X
X if( ( cw=wins[window] ) == (struct WinDesc *)NULL )
X panic("bad winid in amiga_print_glyph: %d", window );
X
X w = cw->win;
X curx=cw->curx;
X cury=cw->cury;
X
X#ifdef TEXTCOLOR
X fg_color = foreg[color_index];
X bg_color = backg[color_index];
X#else
X fg_color = 1;
X bg_color = 0;
X#endif /* TEXTCOLOR */
X
X /* See if we have enough character buffer space... */
X if(glyph_buffer_index >= GLYPH_BUFFER_SIZE)
X flush_glyph_buffer( w );
X
X /*
X * See if we can append it to the current active node of glyph buffer. It
X * must satisfy the following conditions:
X *
X * * background colors are the same, AND
X * * foreground colors are the same, AND
X * * they are precisely side by side
X */
X if((glyph_buffer_index != 0) &&
X (fg_color == g_nodes[glyph_node_index-1].fg_color) &&
X (bg_color == g_nodes[glyph_node_index-1].bg_color) &&
X (g_nodes[glyph_node_index-1].x+
X g_nodes[glyph_node_index-1].len == curx) &&
X (g_nodes[glyph_node_index-1].y == cury)) {
X /*
X * Add it to the end of the buffer
X */
X glyph_buffer[glyph_buffer_index++] = glyph;
X g_nodes[glyph_node_index-1].len ++;
X } else {
X /* See if we're out of glyph nodes */
X if(glyph_node_index >= NUMBER_GLYPH_NODES)
X flush_glyph_buffer( w );
X g_nodes[glyph_node_index].len = 1;
X g_nodes[glyph_node_index].x = curx;
X g_nodes[glyph_node_index].y = cury;
X g_nodes[glyph_node_index].fg_color = fg_color;
X g_nodes[glyph_node_index].bg_color = bg_color;
X g_nodes[glyph_node_index].buffer = &glyph_buffer[glyph_buffer_index];
X glyph_buffer[glyph_buffer_index] = glyph;
X ++glyph_buffer_index;
X ++glyph_node_index;
X }
X}
X
X/*
X * Define some variables which will be used to save context when toggling
X * back and forth between low level text and console I/O.
X */
Xstatic long xsave, ysave, modesave, apensave, bpensave;
Xstatic int usecolor;
X
X/*
X * The function is called before any glyphs are driven to the screen. It
X * removes the cursor, saves internal state of the window, then returns.
X */
X
Xvoid
Xstart_glyphout(window)
X winid window;
X{
X struct WinDesc *cw;
X struct Window *w;
X
X if( ( cw=wins[window] ) == (struct WinDesc *)NULL )
X panic( "bad winid %d in start_glyphout()", window );
X
X if( cw->flags & FLMAP_INGLYPH )
X return;
X
X if( !(w = cw->win ) )
X panic( "bad winid %d, no window ptr set", window );
X
X /*
X * Save the context of the window
X */
X xsave = w->RPort->cp_x;
X ysave = w->RPort->cp_y;
X modesave = w->RPort->DrawMode;
X apensave = w->RPort->FgPen;
X bpensave = w->RPort->BgPen;
X
X /*
X * Set the mode, and be done with it
X */
X usecolor = flags.use_color;
X flags.use_color = FALSE;
X cw->flags |= FLMAP_INGLYPH;
X}
X
X/*
X * General cleanup routine -- flushes and restores cursor
X */
Xvoid
Xend_glyphout(window)
X winid window;
X{
X struct WinDesc *cw;
X struct Window *w;
X
X if( ( cw = wins[ window ] ) == (struct WinDesc *)NULL )
X panic("bad window id %d in end_glyphout()", window );
X
X if( ( cw->flags & FLMAP_INGLYPH ) == 0 )
X return;
X cw->flags &= ~(FLMAP_INGLYPH);
X
X if( !(w = cw->win ) )
X panic( "bad winid %d, no window ptr set", window );
X
X /*
X * Clean up whatever is left in the buffer
X */
X flags.use_color = usecolor;
X
X /*
X * Reset internal data structs
X */
X SetAPen(w->RPort, apensave);
X SetBPen(w->RPort, bpensave);
X SetDrMd(w->RPort, modesave);
X
X Move(w->RPort, xsave, ysave);
X}
X
Xstruct NewWindow *
XDupNewWindow( win )
X struct NewWindow *win;
X{
X struct NewWindow *nwin;
X struct Gadget *ngd, *gd, *pgd = NULL;
X struct PropInfo *pip;
X struct StringInfo *sip;
X
X /* Copy the (Ext)NewWindow structure */
X
X nwin = (struct NewWindow *)alloc( sizeof( struct NewWindow ) );
X *nwin = *win;
X
X /* Now do the gadget list */
X
X nwin->FirstGadget = NULL;
X for( gd = win->FirstGadget; gd; gd = gd->NextGadget )
X {
X ngd = (struct Gadget *)alloc( sizeof( struct Gadget ) );
X *ngd = *gd;
X if( gd->GadgetType == STRGADGET )
X {
X sip = (struct StringInfo *)alloc( sizeof( struct StringInfo ) );
X *sip = *((struct StringInfo *)gd->SpecialInfo);
X sip->Buffer = (UBYTE *) alloc( sip->MaxChars );
X *sip->Buffer = 0;
X ngd->SpecialInfo = (APTR)sip;
X }
X else if( gd->GadgetType == PROPGADGET )
X {
X pip = (struct PropInfo *)alloc( sizeof( struct PropInfo ) );
X *pip = *((struct PropInfo *)gd->SpecialInfo);
X ngd->SpecialInfo = (APTR)pip;
X }
X if( pgd )
X pgd->NextGadget = ngd;
X else
X nwin->FirstGadget = ngd;
X pgd = ngd;
X ngd->NextGadget = NULL;
X }
X return( nwin );
X}
X
Xvoid
XFreeNewWindow( win )
X struct NewWindow *win;
X{
X register struct Gadget *gd, *pgd;
X register struct StringInfo *sip;
X
X for( gd = win->FirstGadget; gd; gd = pgd )
X {
X pgd = gd->NextGadget;
X if( gd->GadgetType == STRGADGET )
X {
X sip = (struct StringInfo *)gd->SpecialInfo;
X free( sip->Buffer );
X free( sip );
X }
X else if( gd->GadgetType == PROPGADGET )
X {
X free( (struct PropInfo *)gd->SpecialInfo );
X }
X free( gd );
X }
X free( win );
X}
X
Xvoid
Xbell()
X{
X if (flags.silent) return;
X DisplayBeep(NULL);
X}
X
Xvoid
Xamii_delay_output()
X{
X /* delay 50 ms */
X Delay(2L);
X}
X
Xvoid
Xamii_number_pad(state)
Xint state;
X{
X}
X
X/* fatal error */
X/*VARARGS1*/
Xvoid error VA_DECL(const char *, s)
X VA_START(s);
X VA_INIT(s, char *);
X
X putchar('\n');
X vprintf(s, VA_ARGS);
X putchar('\n');
X
X VA_END();
X Abort(0L);
X}
END_OF_FILE
if test 21231 -ne `wc -c <'sys/amiga/amiwind.c'`; then
echo shar: \"'sys/amiga/amiwind.c'\" unpacked with wrong size!
fi
# end of 'sys/amiga/amiwind.c'
fi
echo shar: End of archive 58 \(of 108\).
cp /dev/null ark58isdone
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