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: 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
-