home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / games / volume16 / nethack31 / part58 < prev    next >
Internet Message Format  |  1993-02-04  |  59KB

  1. Path: uunet!news.tek.com!master!saab!billr
  2. From: billr@saab.CNA.TEK.COM (Bill Randle)
  3. Newsgroups: comp.sources.games
  4. Subject: v16i066:  nethack31 - display oriented dungeons & dragons (Ver. 3.1), Part58/108
  5. Message-ID: <4369@master.CNA.TEK.COM>
  6. Date: 1 Feb 93 19:45:05 GMT
  7. Sender: news@master.CNA.TEK.COM
  8. Lines: 2075
  9. Approved: billr@saab.CNA.TEK.COM
  10. Xref: uunet comp.sources.games:1616
  11.  
  12. Submitted-by: izchak@linc.cis.upenn.edu (Izchak Miller)
  13. Posting-number: Volume 16, Issue 66
  14. Archive-name: nethack31/Part58
  15. Supersedes: nethack3p9: Volume 10, Issue 46-102
  16. Environment: Amiga, Atari, Mac, MS-DOS, OS2, Unix, VMS, X11
  17.  
  18.  
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of archive 58 (of 108)."
  27. # Contents:  src/vision.c2 sys/amiga/amiwind.c
  28. # Wrapped by billr@saab on Wed Jan 27 16:09:09 1993
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'src/vision.c2' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'src/vision.c2'\"
  32. else
  33. echo shar: Extracting \"'src/vision.c2'\" \(33352 characters\)
  34. sed "s/^X//" >'src/vision.c2' <<'END_OF_FILE'
  35. X/*
  36. X * Use vision tables to determine if there is a clear path from
  37. X * (col1,row1) to (col2,row2).  This is used by:
  38. X *        m_cansee()
  39. X *        m_canseeu()
  40. X */
  41. Xboolean
  42. Xclear_path(col1,row1,col2,row2)
  43. X    int col1, row1, col2, row2;
  44. X{
  45. X    int result;
  46. X
  47. X    if(col1 < col2) {
  48. X    if(row1 > row2) {
  49. X        q1_path(row1,col1,row2,col2,cleardone);
  50. X    } else {
  51. X        q4_path(row1,col1,row2,col2,cleardone);
  52. X    }
  53. X    } else {
  54. X    if(row1 > row2) {
  55. X        q2_path(row1,col1,row2,col2,cleardone);
  56. X    } else if(row1 == row2 && col1 == col2) {
  57. X        result = 1;
  58. X    } else {
  59. X        q3_path(row1,col1,row2,col2,cleardone);
  60. X    }
  61. X    }
  62. Xcleardone:
  63. X    return result;
  64. X}
  65. X
  66. X#ifdef VISION_TABLES
  67. X/*===========================================================================*\
  68. X                GENERAL LINE OF SIGHT
  69. X                Algorithm D
  70. X\*===========================================================================*/
  71. X
  72. X
  73. X/*
  74. X * Indicate caller for the shadow routines.
  75. X */
  76. X#define FROM_RIGHT 0
  77. X#define FROM_LEFT  1
  78. X
  79. X
  80. X/*
  81. X * Include the table definitions.
  82. X */
  83. X#include "vis_tab.h"
  84. X
  85. X
  86. X/* 3D table pointers. */
  87. Xstatic close2d *close_dy[CLOSE_MAX_BC_DY];
  88. Xstatic far2d   *far_dy[FAR_MAX_BC_DY];
  89. X
  90. Xstatic void FDECL(right_side, (int,int,int,int,int,int,int,char*));
  91. Xstatic void FDECL(left_side, (int,int,int,int,int,int,int,char*));
  92. Xstatic int FDECL(close_shadow, (int,int,int,int));
  93. Xstatic int FDECL(far_shadow, (int,int,int,int));
  94. X
  95. X/*
  96. X * Initialize algorithm D's table pointers.  If we don't have these,
  97. X * then we do 3D table lookups.  Verrrry slow.
  98. X */
  99. Xstatic void
  100. Xview_init()
  101. X{
  102. X    int i;
  103. X
  104. X    for (i = 0; i < CLOSE_MAX_BC_DY; i++)
  105. X    close_dy[i] = &close_table[i];
  106. X
  107. X    for (i = 0; i < FAR_MAX_BC_DY; i++)
  108. X    far_dy[i] = &far_table[i];
  109. X}
  110. X
  111. X
  112. X/*
  113. X * If the far table has an entry of OFF_TABLE, then the far block prevents
  114. X * us from seeing the location just above/below it.  I.e. the first visible
  115. X * location is one *before* the block.
  116. X */
  117. X#define OFF_TABLE 0xff
  118. X
  119. Xstatic int
  120. Xclose_shadow(side,this_row,block_row,block_col)
  121. X    int side,this_row,block_row,block_col;
  122. X{
  123. X    register int sdy, sdx, pdy, offset;
  124. X
  125. X    /*
  126. X     * If on the same column (block_row = -1), then we can see it.
  127. X     */
  128. X    if (block_row < 0) return block_col;
  129. X
  130. X    /* Take explicit absolute values.  Adjust. */
  131. X    if ((sdy = (start_row-block_row)) < 0) sdy = -sdy; --sdy;    /* src   dy */
  132. X    if ((sdx = (start_col-block_col)) < 0) sdx = -sdx;        /* src   dx */
  133. X    if ((pdy = (block_row-this_row))  < 0) pdy = -pdy;        /* point dy */
  134. X
  135. X    if (sdy < 0 || sdy >= CLOSE_MAX_SB_DY || sdx >= CLOSE_MAX_SB_DX ||
  136. X                            pdy >= CLOSE_MAX_BC_DY) {
  137. X    impossible("close_shadow:  bad value");
  138. X    return block_col;
  139. X    }
  140. X    offset = close_dy[sdy]->close[sdx][pdy];
  141. X    if (side == FROM_RIGHT)
  142. X    return block_col + offset;
  143. X
  144. X    return block_col - offset;
  145. X}
  146. X
  147. X
  148. Xstatic int
  149. Xfar_shadow(side,this_row,block_row,block_col)
  150. X    int side,this_row,block_row,block_col;
  151. X{
  152. X    register int sdy, sdx, pdy, offset;
  153. X
  154. X    /*
  155. X     * Take care of a bug that shows up only on the borders.
  156. X     *
  157. X     * If the block is beyond the border, then the row is negative.  Return
  158. X     * the block's column number (should be 0 or COLNO-1).
  159. X     *
  160. X     * Could easily have the column be -1, but then wouldn't know if it was
  161. X     * the left or right border.
  162. X     */
  163. X    if (block_row < 0) return block_col;
  164. X
  165. X    /* Take explicit absolute values.  Adjust. */
  166. X    if ((sdy = (start_row-block_row)) < 0) sdy = -sdy;        /* src   dy */
  167. X    if ((sdx = (start_col-block_col)) < 0) sdx = -sdx; --sdx;    /* src   dx */
  168. X    if ((pdy = (block_row-this_row))  < 0) pdy = -pdy; --pdy;    /* point dy */
  169. X
  170. X    if (sdy >= FAR_MAX_SB_DY || sdx < 0 || sdx >= FAR_MAX_SB_DX ||
  171. X                        pdy < 0 || pdy >= FAR_MAX_BC_DY) {
  172. X    impossible("far_shadow:  bad value");
  173. X    return block_col;
  174. X    }
  175. X    if ((offset = far_dy[sdy]->far_q[sdx][pdy]) == OFF_TABLE) offset = -1;
  176. X    if (side == FROM_RIGHT)
  177. X    return block_col + offset;
  178. X
  179. X    return block_col - offset;
  180. X}
  181. X
  182. X
  183. X/*
  184. X * right_side()
  185. X *
  186. X * Figure out what could be seen on the right side of the source.
  187. X */
  188. Xstatic void
  189. Xright_side(row, cb_row, cb_col, fb_row, fb_col, left, right_mark, limits)
  190. X    int row;        /* current row */
  191. X    int    cb_row, cb_col;    /* close block row and col */
  192. X    int    fb_row, fb_col;    /* far block row and col */
  193. X    int left;        /* left mark of the previous row */
  194. X    int    right_mark;    /* right mark of previous row */
  195. X    char *limits;    /* points at range limit for current row, or NULL */
  196. X{
  197. X    register int  i;
  198. X    register char *rowp;
  199. X    int  hit_stone = 0;
  200. X    int  left_shadow, right_shadow, loc_right;
  201. X    int  lblock_col;        /* local block column (current row) */
  202. X    int  nrow, deeper;
  203. X    char *row_min;        /* left most */
  204. X    char *row_max;        /* right most */
  205. X    int          lim_max;    /* right most limit of circle */
  206. X
  207. X    nrow    = row + step;
  208. X    deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
  209. X    if(!vis_func) {
  210. X    rowp    = cs_rows[row];
  211. X    row_min = &cs_left[row];
  212. X    row_max = &cs_right[row];
  213. X    }
  214. X    if(limits) {
  215. X    lim_max = start_col + *limits;
  216. X    if(lim_max > COLNO-1) lim_max = COLNO-1;
  217. X    if(right_mark > lim_max) right_mark = lim_max;
  218. X    limits++; /* prepare for next row */
  219. X    } else
  220. X    lim_max = COLNO-1;
  221. X
  222. X    /*
  223. X     * Get the left shadow from the close block.  This value could be
  224. X     * illegal.
  225. X     */
  226. X    left_shadow = close_shadow(FROM_RIGHT,row,cb_row,cb_col);
  227. X
  228. X    /*
  229. X     * Mark all stone walls as seen before the left shadow.  All this work
  230. X     * for a special case.
  231. X     *
  232. X     * NOTE.  With the addition of this code in here, it is now *required* 
  233. X     * for the algorithm to work correctly.  If this is commented out,
  234. X     * change the above assignment so that left and not left_shadow is the
  235. X     * variable that gets the shadow.
  236. X     */
  237. X    while (left <= right_mark) {
  238. X    loc_right = right_ptrs[row][left];
  239. X    if(loc_right > lim_max) loc_right = lim_max;
  240. X    if (viz_clear_rows[row][left]) {
  241. X        if (loc_right >= left_shadow) {
  242. X        left = left_shadow;    /* opening ends beyond shadow */
  243. X        break;
  244. X        }
  245. X        left = loc_right;
  246. X        loc_right = right_ptrs[row][left];
  247. X        if(loc_right > lim_max) loc_right = lim_max;
  248. X        if (left == loc_right) return;    /* boundary */
  249. X
  250. X        /* Shadow covers opening, beyond right mark */
  251. X        if (left == right_mark && left_shadow > right_mark) return;
  252. X    }
  253. X
  254. X    if (loc_right > right_mark)    /* can't see stone beyond the mark */
  255. X        loc_right = right_mark;
  256. X
  257. X    if(vis_func) {
  258. X        for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg);
  259. X    } else {
  260. X        for (i = left; i <= loc_right; i++) set_cs(rowp,i);
  261. X        set_min(left);    set_max(loc_right);
  262. X    }
  263. X
  264. X    if (loc_right == right_mark) return;    /* all stone */
  265. X    if (loc_right >= left_shadow) hit_stone = 1;
  266. X    left = loc_right + 1;
  267. X    }
  268. X
  269. X    /*
  270. X     * At this point we are at the first visible clear spot on or beyond
  271. X     * the left shadow, unless the left shadow is an illegal value.  If we
  272. X     * have "hit stone" then we have a stone wall just to our left.
  273. X     */
  274. X
  275. X    /*
  276. X     * Get the right shadow.  Make sure that it is a legal value.
  277. X     */
  278. X    if ((right_shadow = far_shadow(FROM_RIGHT,row,fb_row,fb_col)) >= COLNO)
  279. X    right_shadow = COLNO-1;
  280. X    /*
  281. X     * Make vertical walls work the way we want them.  In this case, we
  282. X     * note when the close block blocks the column just above/beneath
  283. X     * it (right_shadow < fb_col [actually right_shadow == fb_col-1]).  If
  284. X     * the location is filled, then we want to see it, so we put the
  285. X     * right shadow back (same as fb_col).
  286. X     */
  287. X    if (right_shadow < fb_col && !viz_clear_rows[row][fb_col])
  288. X    right_shadow = fb_col;
  289. X    if(right_shadow > lim_max) right_shadow = lim_max;
  290. X
  291. X    /*
  292. X     * Main loop.  Within the range of sight of the previous row, mark all
  293. X     * stone walls as seen.  Follow open areas recursively.
  294. X     */
  295. X    while (left <= right_mark) {
  296. X    /* Get the far right of the opening or wall */
  297. X    loc_right = right_ptrs[row][left];
  298. X    if(loc_right > lim_max) loc_right = lim_max;
  299. X
  300. X    if (!viz_clear_rows[row][left]) {
  301. X        hit_stone = 1;    /* use stone on this row as close block */
  302. X        /*
  303. X         * We can see all of the wall until the next open spot or the
  304. X         * start of the shadow caused by the far block (right).
  305. X         *
  306. X         * Can't see stone beyond the right mark.
  307. X         */
  308. X        if (loc_right > right_mark) loc_right = right_mark;
  309. X
  310. X        if(vis_func) {
  311. X        for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg);
  312. X        } else {
  313. X        for (i = left; i <= loc_right; i++) set_cs(rowp,i);
  314. X        set_min(left);    set_max(loc_right);
  315. X        }
  316. X
  317. X        if (loc_right == right_mark) return;    /* hit the end */
  318. X        left = loc_right + 1;
  319. X        loc_right = right_ptrs[row][left];
  320. X        if(loc_right > lim_max) loc_right = lim_max;
  321. X        /* fall through... we know at least one position is visible */
  322. X    }
  323. X
  324. X    /*
  325. X     * We are in an opening.
  326. X     *
  327. X     * If this is the first open spot since the could see area  (this is
  328. X     * true if we have hit stone), get the shadow generated by the wall
  329. X     * just to our left.
  330. X     */
  331. X    if (hit_stone) {
  332. X        lblock_col = left-1;    /* local block column */
  333. X        left = close_shadow(FROM_RIGHT,row,row,lblock_col);
  334. X        if (left > lim_max) break;        /* off the end */
  335. X    }
  336. X
  337. X    /*
  338. X     * Check if the shadow covers the opening.  If it does, then
  339. X     * move to end of the opening.  A shadow generated on from a
  340. X     * wall on this row does *not* cover the wall on the right
  341. X     * of the opening.
  342. X     */
  343. X    if (left >= loc_right) {
  344. X        if (loc_right == lim_max) {        /* boundary */
  345. X        if (left == lim_max) {
  346. X            if(vis_func) (*vis_func)(lim_max, row, varg);
  347. X            else {
  348. X            set_cs(rowp,lim_max);    /* last pos */
  349. X            set_max(lim_max);
  350. X            }
  351. X        }
  352. X        return;                    /* done */
  353. X        }
  354. X        left = loc_right;
  355. X        continue;
  356. X    }
  357. X
  358. X    /*
  359. X     * If the far wall of the opening (loc_right) is closer than the
  360. X     * shadow limit imposed by the far block (right) then use the far
  361. X     * wall as our new far block when we recurse.
  362. X     *
  363. X     * If the limits are the the same, and the far block really exists
  364. X     * (fb_row >= 0) then do the same as above.
  365. X     *
  366. X     * Normally, the check would be for the far wall being closer OR EQUAL
  367. X     * to the shadow limit.  However, there is a bug that arises from the
  368. X     * fact that the clear area pointers end in an open space (if it
  369. X     * exists) on a boundary.  This then makes a far block exist where it
  370. X     * shouldn't --- on a boundary.  To get around that, I had to
  371. X     * introduce the concept of a non-existent far block (when the
  372. X     * row < 0).  Next I have to check for it.  Here is where that check
  373. X     * exists.
  374. X     */
  375. X    if ((loc_right < right_shadow) ||
  376. X                (fb_row >= 0 && loc_right == right_shadow)) {
  377. X        if(vis_func) {
  378. X        for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg);
  379. X        } else {
  380. X        for (i = left; i <= loc_right; i++) set_cs(rowp,i);
  381. X        set_min(left);    set_max(loc_right);
  382. X        }
  383. X
  384. X        if (deeper) {
  385. X        if (hit_stone)
  386. X            right_side(nrow,row,lblock_col,row,loc_right,
  387. X                            left,loc_right,limits);
  388. X        else
  389. X            right_side(nrow,cb_row,cb_col,row,loc_right,
  390. X                            left,loc_right,limits);
  391. X        }
  392. X
  393. X        /*
  394. X         * The following line, setting hit_stone, is needed for those
  395. X         * walls that are only 1 wide.  If hit stone is *not* set and
  396. X         * the stone is only one wide, then the close block is the old
  397. X         * one instead one on the current row.  A way around having to
  398. X         * set it here is to make left = loc_right (not loc_right+1) and
  399. X         * let the outer loop take care of it.  However, if we do that
  400. X         * then we then have to check for boundary conditions here as
  401. X         * well.
  402. X         */
  403. X        hit_stone = 1;
  404. X
  405. X        left = loc_right+1;
  406. X    }
  407. X    /*
  408. X     * The opening extends beyond the right mark.  This means that
  409. X     * the next far block is the current far block.
  410. X     */
  411. X    else {
  412. X        if(vis_func) {
  413. X        for (i=left; i <= right_shadow; i++) (*vis_func)(i, row, varg);
  414. X        } else {
  415. X        for (i = left; i <= right_shadow; i++) set_cs(rowp,i);
  416. X        set_min(left);    set_max(right_shadow);
  417. X        }
  418. X
  419. X        if (deeper) {
  420. X        if (hit_stone)
  421. X            right_side(nrow,   row,lblock_col,fb_row,fb_col,
  422. X                             left,right_shadow,limits);
  423. X        else
  424. X            right_side(nrow,cb_row,    cb_col,fb_row,fb_col,
  425. X                             left,right_shadow,limits);
  426. X        }
  427. X
  428. X        return;    /* we're outta here */
  429. X    }
  430. X    }
  431. X}
  432. X
  433. X
  434. X/*
  435. X * left_side()
  436. X *
  437. X * This routine is the mirror image of right_side().  Please see right_side()
  438. X * for blow by blow comments.
  439. X */
  440. Xstatic void
  441. Xleft_side(row, cb_row, cb_col, fb_row, fb_col, left_mark, right, limits)
  442. X    int row;        /* the current row */
  443. X    int    cb_row, cb_col;    /* close block row and col */
  444. X    int    fb_row, fb_col;    /* far block row and col */
  445. X    int    left_mark;    /* left mark of previous row */
  446. X    int right;        /* right mark of the previous row */
  447. X    char *limits;
  448. X{
  449. X    register int  i;
  450. X    register char *rowp;
  451. X    int  hit_stone = 0;
  452. X    int  left_shadow, right_shadow, loc_left;
  453. X    int  lblock_col;        /* local block column (current row) */
  454. X    int  nrow, deeper;
  455. X    char *row_min;        /* left most */
  456. X    char *row_max;        /* right most */
  457. X    int          lim_min;
  458. X
  459. X    nrow    = row + step;
  460. X    deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
  461. X    if(!vis_func) {
  462. X    rowp    = cs_rows[row];
  463. X    row_min = &cs_left[row];
  464. X    row_max = &cs_right[row];
  465. X    }
  466. X    if(limits) {
  467. X    lim_min = start_col - *limits;
  468. X    if(lim_min < 0) lim_min = 0;
  469. X    if(left_mark < lim_min) left_mark = lim_min;
  470. X    limits++; /* prepare for next row */
  471. X    } else
  472. X    lim_min = 0;
  473. X
  474. X    /* This value could be illegal. */
  475. X    right_shadow = close_shadow(FROM_LEFT,row,cb_row,cb_col);
  476. X
  477. X    while ( right >= left_mark ) {
  478. X    loc_left = left_ptrs[row][right];
  479. X    if(loc_left < lim_min) loc_left = lim_min;
  480. X    if (viz_clear_rows[row][right]) {
  481. X        if (loc_left <= right_shadow) {
  482. X        right = right_shadow;    /* opening ends beyond shadow */
  483. X        break;
  484. X        }
  485. X        right = loc_left;
  486. X        loc_left = left_ptrs[row][right];
  487. X        if(loc_left < lim_min) loc_left = lim_min;
  488. X        if (right == loc_left) return;    /* boundary */
  489. X    }
  490. X
  491. X    if (loc_left < left_mark)    /* can't see beyond the left mark */
  492. X        loc_left = left_mark;
  493. X
  494. X    if(vis_func) {
  495. X        for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg);
  496. X    } else {
  497. X        for (i = loc_left; i <= right; i++) set_cs(rowp,i);
  498. X        set_min(loc_left);    set_max(right);
  499. X    }
  500. X
  501. X    if (loc_left == left_mark) return;    /* all stone */
  502. X    if (loc_left <= right_shadow) hit_stone = 1;
  503. X    right = loc_left - 1;
  504. X    }
  505. X
  506. X    /* At first visible clear spot on or beyond the right shadow. */
  507. X
  508. X    if ((left_shadow = far_shadow(FROM_LEFT,row,fb_row,fb_col)) < 0)
  509. X    left_shadow = 0;
  510. X    
  511. X    /* Do vertical walls as we want. */
  512. X    if (left_shadow > fb_col && !viz_clear_rows[row][fb_col])
  513. X    left_shadow = fb_col;
  514. X    if(left_shadow < lim_min) left_shadow = lim_min;
  515. X
  516. X    while (right >= left_mark) {
  517. X    loc_left = left_ptrs[row][right];
  518. X
  519. X    if (!viz_clear_rows[row][right]) {
  520. X        hit_stone = 1;    /* use stone on this row as close block */
  521. X
  522. X        /* We can only see walls until the left mark */
  523. X        if (loc_left < left_mark) loc_left = left_mark;
  524. X
  525. X        if(vis_func) {
  526. X        for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg);
  527. X        } else {
  528. X        for (i = loc_left; i <= right; i++) set_cs(rowp,i);
  529. X        set_min(loc_left);    set_max(right);
  530. X        }
  531. X
  532. X        if (loc_left == left_mark) return;    /* hit end */
  533. X        right = loc_left - 1;
  534. X        loc_left = left_ptrs[row][right];
  535. X        if (loc_left < lim_min) loc_left = lim_min;
  536. X        /* fall through...*/
  537. X    }
  538. X
  539. X    /* We are in an opening. */
  540. X    if (hit_stone) {
  541. X        lblock_col = right+1;    /* stone block (local) */
  542. X        right = close_shadow(FROM_LEFT,row,row,lblock_col);
  543. X        if (right < lim_min) return;    /* off the end */
  544. X    }
  545. X
  546. X    /*  Check if the shadow covers the opening. */
  547. X    if (right <= loc_left) {
  548. X        /*  Make a boundary condition work. */
  549. X        if (loc_left == lim_min) {    /* at boundary */
  550. X        if (right == lim_min) {
  551. X            if(vis_func) (*vis_func)(lim_min, row, varg);
  552. X            else {
  553. X            set_cs(rowp,lim_min);    /* caught the last pos */
  554. X            set_min(lim_min);
  555. X            }
  556. X        }
  557. X        return;            /* and break out the loop */
  558. X        }
  559. X
  560. X        right = loc_left;
  561. X        continue;
  562. X    }
  563. X
  564. X    /* If the far wall of the opening is closer than the shadow limit. */
  565. X    if ((loc_left > left_shadow) ||
  566. X                    (fb_row >= 0 && loc_left == left_shadow)) {
  567. X        if(vis_func) {
  568. X        for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg);
  569. X        } else {
  570. X        for (i = loc_left; i <= right; i++) set_cs(rowp,i);
  571. X        set_min(loc_left);    set_max(right);
  572. X        }
  573. X
  574. X        if (deeper) {
  575. X        if (hit_stone)
  576. X            left_side(nrow,row,lblock_col,row,loc_left,
  577. X                            loc_left,right,limits);
  578. X        else
  579. X            left_side(nrow,cb_row,cb_col,row,loc_left,
  580. X                            loc_left,right,limits);
  581. X        }
  582. X
  583. X        hit_stone = 1;    /* needed for walls of width 1 */
  584. X        right = loc_left-1;
  585. X    }
  586. X    /*  The opening extends beyond the left mark. */
  587. X    else {
  588. X        if(vis_func) {
  589. X        for (i=left_shadow; i <= right; i++) (*vis_func)(i, row, varg);
  590. X        } else {
  591. X        for (i = left_shadow; i <= right; i++) set_cs(rowp,i);
  592. X        set_min(left_shadow);    set_max(right);
  593. X        }
  594. X
  595. X        if (deeper) {
  596. X        if (hit_stone)
  597. X            left_side(nrow,row,lblock_col,fb_row,fb_col,
  598. X                             left_shadow,right,limits);
  599. X        else
  600. X            left_side(nrow,cb_row,cb_col,fb_row,fb_col,
  601. X                             left_shadow,right,limits);
  602. X        }
  603. X
  604. X        return;    /* we're outta here */
  605. X    }
  606. X
  607. X    }
  608. X}
  609. X
  610. X/*
  611. X * view_from
  612. X *  
  613. X * Calculate a view from the given location.  Initialize and fill a
  614. X * ROWNOxCOLNO array (could_see) with all the locations that could be
  615. X * seen from the source location.  Initialize and fill the left most
  616. X * and right most boundaries of what could be seen.
  617. X */
  618. Xstatic void
  619. Xview_from(srow,scol,loc_cs_rows,left_most,right_most, range, func, arg)
  620. X    int  srow, scol;            /* source row and column */
  621. X    char **loc_cs_rows;            /* could_see array (row pointers) */
  622. X    char *left_most, *right_most;    /* limits of what could be seen */
  623. X    int range;        /* 0 if unlimited */
  624. X    void FDECL((*func), (int,int,genericptr_t));
  625. X    genericptr_t arg;
  626. X{
  627. X    register int i;
  628. X    char     *rowp;
  629. X    int         nrow, left, right, left_row, right_row;
  630. X    char     *limits;
  631. X
  632. X    /* Set globals for near_shadow(), far_shadow(), etc. to use. */
  633. X    start_col = scol;
  634. X    start_row = srow;
  635. X    cs_rows   = loc_cs_rows;
  636. X    cs_left   = left_most;
  637. X    cs_right  = right_most;
  638. X    vis_func = func;
  639. X    varg = arg;
  640. X
  641. X    /*  Find the left and right limits of sight on the starting row. */
  642. X    if (viz_clear_rows[srow][scol]) {
  643. X    left  = left_ptrs[srow][scol];
  644. X    right = right_ptrs[srow][scol];
  645. X    } else {
  646. X    left  = (!scol) ? 0 :
  647. X        (viz_clear_rows[srow][scol-1] ?  left_ptrs[srow][scol-1] : scol-1);
  648. X    right = (scol == COLNO-1) ? COLNO-1 :
  649. X        (viz_clear_rows[srow][scol+1] ? right_ptrs[srow][scol+1] : scol+1);
  650. X    }
  651. X
  652. X    if(range) {
  653. X    if(range > MAX_RADIUS || range < 1)
  654. X        panic("view_from called with range %d", range);
  655. X    limits = circle_ptr(range) + 1; /* start at next row */
  656. X    if(left < scol - range) left = scol - range;
  657. X    if(right > scol + range) right = scol + range;
  658. X    } else
  659. X    limits = (char*) 0;
  660. X
  661. X    if(func) {
  662. X    for (i = left; i <= right; i++) (*func)(i, srow, arg);
  663. X    } else {
  664. X    /* Row optimization */
  665. X    rowp = cs_rows[srow];
  666. X
  667. X    /* We know that we can see our row. */
  668. X    for (i = left; i <= right; i++) set_cs(rowp,i);
  669. X    cs_left[srow]  = left;
  670. X    cs_right[srow] = right;
  671. X    }
  672. X
  673. X    /* The far block has a row number of -1 if we are on an edge. */
  674. X    right_row = (right == COLNO-1) ? -1 : srow;
  675. X    left_row  = (!left)           ? -1 : srow;
  676. X
  677. X    /*
  678. X     *  Check what could be seen in quadrants.
  679. X     */
  680. X    if ( (nrow = srow+1) < ROWNO ) {
  681. X    step =  1;    /* move down */
  682. X    if (scol<COLNO-1)
  683. X        right_side(nrow,-1,scol,right_row,right,scol,right,limits);
  684. X    if (scol)
  685. X        left_side(nrow,-1,scol,left_row, left, left, scol,limits);
  686. X    }
  687. X
  688. X    if ( (nrow = srow-1) >= 0 ) {
  689. X    step = -1;    /* move up */
  690. X    if (scol<COLNO-1)
  691. X        right_side(nrow,-1,scol,right_row,right,scol,right,limits);
  692. X    if (scol)
  693. X        left_side(nrow,-1,scol,left_row, left, left, scol,limits);
  694. X    }
  695. X}
  696. X
  697. X
  698. X#else    /*===== End of algorithm D =====*/
  699. X
  700. X
  701. X/*===========================================================================*\
  702. X                GENERAL LINE OF SIGHT
  703. X                Algorithm C
  704. X\*===========================================================================*/
  705. X
  706. X/*
  707. X * Defines local to Algorithm C.  
  708. X */
  709. Xstatic void FDECL(right_side, (int,int,int,char*));
  710. Xstatic void FDECL(left_side, (int,int,int,char*));
  711. X
  712. X/* Initialize algorithm C (nothing). */
  713. Xstatic void
  714. Xview_init()
  715. X{
  716. X}
  717. X
  718. X/*
  719. X * Mark positions as visible on one quadrant of the right side.  The
  720. X * quadrant is determined by the value of the global variable step.
  721. X */
  722. Xstatic void
  723. Xright_side(row, left, right_mark, limits)
  724. X    int row;        /* current row */
  725. X    int left;        /* first (left side) visible spot on prev row */
  726. X    int right_mark;    /* last (right side) visible spot on prev row */
  727. X    char *limits;    /* points at range limit for current row, or NULL */
  728. X{
  729. X    int          right;    /* right limit of "could see" */
  730. X    int          right_edge;    /* right edge of an opening */
  731. X    int          nrow;        /* new row (calculate once) */
  732. X    int          deeper;    /* if TRUE, call self as needed */
  733. X    int          result;    /* set by q?_path() */
  734. X    register int  i;        /* loop counter */
  735. X    register char *rowp;    /* row optimization */
  736. X    char      *row_min;    /* left most  [used by macro set_min()] */
  737. X    char      *row_max;    /* right most [used by macro set_max()] */
  738. X    int          lim_max;    /* right most limit of circle */
  739. X
  740. X#ifdef GCC_WARN
  741. X    rowp = row_min = row_max = 0;
  742. X#endif
  743. X    nrow    = row + step;
  744. X    /*
  745. X     * Can go deeper if the row is in bounds and the next row is within
  746. X     * the circle's limit.  We tell the latter by checking to see if the next
  747. X     * limit value is the start of a new circle radius (meaning we depend
  748. X     * on the structure of circle_data[]).
  749. X     */
  750. X    deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
  751. X    if(!vis_func) {
  752. X    rowp    = cs_rows[row];    /* optimization */
  753. X    row_min = &cs_left[row];
  754. X    row_max = &cs_right[row];
  755. X    }
  756. X    if(limits) {
  757. X    lim_max = start_col + *limits;
  758. X    if(lim_max > COLNO-1) lim_max = COLNO-1;
  759. X    if(right_mark > lim_max) right_mark = lim_max;
  760. X    limits++; /* prepare for next row */
  761. X    } else
  762. X    lim_max = COLNO-1;
  763. X
  764. X    while (left <= right_mark) {
  765. X    right_edge = right_ptrs[row][left];
  766. X    if(right_edge > lim_max) right_edge = lim_max;
  767. X
  768. X    if (!is_clear(row,left)) {
  769. X        /*
  770. X         * Jump to the far side of a stone wall.  We can set all
  771. X         * the points in between as seen.
  772. X         *
  773. X         * If the right edge goes beyond the right mark, check to see
  774. X         * how much we can see.
  775. X         */
  776. X        if (right_edge > right_mark) {
  777. X        /*
  778. X         * If the mark on the previous row was a clear position, 
  779. X         * the odds are that we can actually see part of the wall
  780. X         * beyond the mark on this row.  If so, then see one beyond
  781. X         * the mark.  Otherwise don't.  This is a kludge so corners
  782. X         * with an adjacent doorway show up in nethack.
  783. X         */
  784. X        right_edge = is_clear(row-step,right_mark) ?
  785. X                            right_mark+1 : right_mark;
  786. X        }
  787. X        if(vis_func) {
  788. X        for (i = left; i <= right_edge; i++) (*vis_func)(i, row, varg);
  789. X        } else {
  790. X        for (i = left; i <= right_edge; i++) set_cs(rowp,i);
  791. X        set_min(left);      set_max(right_edge);
  792. X        }
  793. X        left = right_edge + 1; /* no limit check necessary */
  794. X        continue;
  795. X    }
  796. X
  797. X    /* No checking needed if our left side is the start column. */
  798. X    if (left != start_col) { 
  799. X        /*
  800. X         * Find the left side.  Move right until we can see it or we run
  801. X         * into a wall.
  802. X         */
  803. X        for (; left <= right_edge; left++) {
  804. X        if (step < 0) {
  805. X            q1_path(start_row,start_col,row,left,rside1);
  806. X        } else {
  807. X            q4_path(start_row,start_col,row,left,rside1);
  808. X        }
  809. Xrside1:                    /* used if q?_path() is a macro */
  810. X        if (result) break;
  811. X        }
  812. X
  813. X        /*
  814. X         * Check for boundary conditions.  We *need* check (2) to break
  815. X         * an infinite loop where:
  816. X         *
  817. X         *        left == right_edge == right_mark == lim_max.
  818. X         * 
  819. X         */
  820. X        if (left > lim_max) return;    /* check (1) */
  821. X        if (left == lim_max) {    /* check (2) */
  822. X        if(vis_func) (*vis_func)(lim_max, row, varg);
  823. X        else {
  824. X            set_cs(rowp,lim_max);
  825. X            set_max(lim_max);
  826. X        }
  827. X        return;
  828. X        }
  829. X        /*
  830. X         * Check if we can see any spots in the opening.  We might
  831. X         * (left == right_edge) or might not (left == right_edge+1) have
  832. X         * been able to see the far wall.  Make sure we *can* see the
  833. X         * wall (remember, we can see the spot above/below this one)
  834. X         * by backing up.
  835. X         */
  836. X        if (left >= right_edge) {
  837. X        left = right_edge;    /* for the case left == right_edge+1 */
  838. X        continue;
  839. X        }
  840. X    }
  841. X
  842. X    /*
  843. X     * Find the right side.  If the marker from the previous row is
  844. X     * closer than the edge on this row, then we have to check
  845. X     * how far we can see around the corner (under the overhang).  Stop
  846. X     * at the first non-visible spot or we actually hit the far wall.
  847. X     *
  848. X     * Otherwise, we know we can see the right edge of the current row.
  849. X     *
  850. X     * This must be a strict less than so that we can always see a
  851. X     * horizontal wall, even if it is adjacent to us.
  852. X     */
  853. X    if (right_mark < right_edge) {
  854. X        for (right = right_mark; right <= right_edge; right++) {
  855. X        if (step < 0) {
  856. X            q1_path(start_row,start_col,row,right,rside2);
  857. X        } else {
  858. X            q4_path(start_row,start_col,row,right,rside2);
  859. X        }
  860. Xrside2:                    /* used if q?_path() is a macro */
  861. X        if (!result) break;
  862. X        }
  863. X        --right;    /* get rid of the last increment */
  864. X    }
  865. X    else
  866. X        right = right_edge;
  867. X
  868. X    /*
  869. X     * We have the range that we want.  Set the bits.  Note that
  870. X     * there is no else --- we no longer handle splinters.
  871. X     */
  872. X    if (left <= right) {
  873. X        /*
  874. X         * An ugly special case.  If you are adjacent to a vertical wall
  875. X         * and it has a break in it, then the right mark is set to be
  876. X         * start_col.  We *want* to be able to see adjacent vertical
  877. X         * walls, so we have to set it back.
  878. X         */
  879. X        if (left == right && left == start_col &&
  880. X            start_col < (COLNO-1) && !is_clear(row,start_col+1))
  881. X        right = start_col+1;
  882. X
  883. X        if(right > lim_max) right = lim_max;
  884. X        /* set the bits */
  885. X        if(vis_func)
  886. X        for (i = left; i <= right; i++) (*vis_func)(i, row, varg);
  887. X        else {
  888. X        for (i = left; i <= right; i++) set_cs(rowp,i);
  889. X        set_min(left);      set_max(right);
  890. X        }
  891. X
  892. X        /* recursive call for next finger of light */
  893. X        if (deeper) right_side(nrow,left,right,limits);
  894. X        left = right + 1; /* no limit check necessary */
  895. X    }
  896. X    }
  897. X}
  898. X
  899. X
  900. X/*
  901. X * This routine is the mirror image of right_side().  See right_side() for
  902. X * extensive comments.
  903. X */
  904. Xstatic void
  905. Xleft_side(row, left_mark, right, limits)
  906. X    int row, left_mark, right;
  907. X    char *limits;
  908. X{
  909. X    int          left, left_edge, nrow, deeper, result;
  910. X    register int  i;
  911. X    register char *rowp;
  912. X    char      *row_min, *row_max;
  913. X    int          lim_min;
  914. X
  915. X#ifdef GCC_WARN
  916. X    rowp = row_min = row_max = 0;
  917. X#endif
  918. X    nrow    = row+step;
  919. X    deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
  920. X    if(!vis_func) {
  921. X    rowp    = cs_rows[row];
  922. X    row_min = &cs_left[row];
  923. X    row_max = &cs_right[row];
  924. X    }
  925. X    if(limits) {
  926. X    lim_min = start_col - *limits;
  927. X    if(lim_min < 0) lim_min = 0;
  928. X    if(left_mark < lim_min) left_mark = lim_min;
  929. X    limits++; /* prepare for next row */
  930. X    } else
  931. X    lim_min = 0;
  932. X
  933. X    while (right >= left_mark) {
  934. X    left_edge = left_ptrs[row][right];
  935. X    if(left_edge < lim_min) left_edge = lim_min;
  936. X
  937. X    if (!is_clear(row,right)) {
  938. X        /* Jump to the far side of a stone wall. */
  939. X        if (left_edge < left_mark) {
  940. X        /* Maybe see more (kludge). */
  941. X        left_edge = is_clear(row-step,left_mark) ?
  942. X                            left_mark-1 : left_mark;
  943. X        }
  944. X        if(vis_func) {
  945. X        for (i = left_edge; i <= right; i++) (*vis_func)(i, row, varg);
  946. X        } else {
  947. X        for (i = left_edge; i <= right; i++) set_cs(rowp,i);
  948. X        set_min(left_edge); set_max(right);
  949. X        }
  950. X        right = left_edge - 1; /* no limit check necessary */
  951. X        continue;
  952. X    }
  953. X
  954. X    if (right != start_col) {
  955. X        /* Find the right side. */
  956. X        for (; right >= left_edge; right--) {
  957. X        if (step < 0) {
  958. X            q2_path(start_row,start_col,row,right,lside1);
  959. X        } else {
  960. X            q3_path(start_row,start_col,row,right,lside1);
  961. X        }
  962. Xlside1:                    /* used if q?_path() is a macro */
  963. X        if (result) break;
  964. X        }
  965. X
  966. X        /* Check for boundary conditions. */
  967. X        if (right < lim_min) return;
  968. X        if (right == lim_min) {
  969. X        if(vis_func) (*vis_func)(lim_min, row, varg);
  970. X        else {
  971. X            set_cs(rowp,lim_min);
  972. X            set_min(lim_min);
  973. X        }
  974. X        return;
  975. X        }
  976. X        /* Check if we can see any spots in the opening. */
  977. X        if (right <= left_edge) {
  978. X        right = left_edge;
  979. X        continue;
  980. X        }
  981. X    }
  982. X
  983. X    /* Find the left side. */
  984. X    if (left_mark > left_edge) {
  985. X        for (left = left_mark; left >= left_edge; --left) {
  986. X        if (step < 0) {
  987. X            q2_path(start_row,start_col,row,left,lside2);
  988. X        } else {
  989. X            q3_path(start_row,start_col,row,left,lside2);
  990. X        }
  991. Xlside2:                    /* used if q?_path() is a macro */
  992. X        if (!result) break;
  993. X        }
  994. X        left++;    /* get rid of the last decrement */
  995. X    }
  996. X    else
  997. X        left = left_edge;
  998. X
  999. X    if (left <= right) {
  1000. X        /* An ugly special case. */
  1001. X        if (left == right && right == start_col &&
  1002. X                start_col > 0 && !is_clear(row,start_col-1))
  1003. X        left = start_col-1;
  1004. X
  1005. X        if(left < lim_min) left = lim_min;
  1006. X        if(vis_func)
  1007. X        for (i = left; i <= right; i++) (*vis_func)(i, row, varg);
  1008. X        else {
  1009. X        for (i = left; i <= right; i++) set_cs(rowp,i);
  1010. X        set_min(left);      set_max(right);
  1011. X        }
  1012. X
  1013. X        /* Recurse */
  1014. X        if (deeper) left_side(nrow,left,right,limits);
  1015. X        right = left - 1; /* no limit check necessary */
  1016. X    }
  1017. X    }
  1018. X}
  1019. X
  1020. X
  1021. X/*
  1022. X * Calculate all possible visible locations from the given location
  1023. X * (srow,scol).  NOTE this is (y,x)!  Mark the visible locations in the
  1024. X * array provided.
  1025. X */
  1026. Xstatic void
  1027. Xview_from(srow, scol, loc_cs_rows, left_most, right_most, range, func, arg)
  1028. X    int  srow, scol;    /* starting row and column */
  1029. X    char **loc_cs_rows;    /* pointers to the rows of the could_see array */
  1030. X    char *left_most;    /* min mark on each row */
  1031. X    char *right_most;    /* max mark on each row */
  1032. X    int range;        /* 0 if unlimited */
  1033. X    void FDECL((*func), (int,int,genericptr_t));
  1034. X    genericptr_t arg;
  1035. X{
  1036. X    register int i;        /* loop counter */
  1037. X    char         *rowp;        /* optimization for setting could_see */
  1038. X    int         nrow;        /* the next row */
  1039. X    int         left;        /* the left-most visible column */
  1040. X    int         right;        /* the right-most visible column */
  1041. X    char     *limits;    /* range limit for next row */
  1042. X
  1043. X    /* Set globals for q?_path(), left_side(), and right_side() to use. */
  1044. X    start_col = scol;
  1045. X    start_row = srow;
  1046. X    cs_rows   = loc_cs_rows;    /* 'could see' rows */
  1047. X    cs_left   = left_most;
  1048. X    cs_right  = right_most;
  1049. X    vis_func = func;
  1050. X    varg = arg;
  1051. X
  1052. X    /*
  1053. X     * Determine extent of sight on the starting row.
  1054. X     */
  1055. X    if (is_clear(srow,scol)) {
  1056. X    left =  left_ptrs[srow][scol];
  1057. X    right = right_ptrs[srow][scol];
  1058. X    } else {
  1059. X    /*
  1060. X     * When in stone, you can only see your adjacent squares, unless
  1061. X     * you are on an array boundary or a stone/clear boundary.
  1062. X     */
  1063. X    left  = (!scol) ? 0 :
  1064. X        (is_clear(srow,scol-1) ? left_ptrs[srow][scol-1] : scol-1);
  1065. X    right = (scol == COLNO-1) ? COLNO-1 :
  1066. X        (is_clear(srow,scol+1) ? right_ptrs[srow][scol+1] : scol+1);
  1067. X    }
  1068. X
  1069. X    if(range) {
  1070. X    if(range > MAX_RADIUS || range < 1)
  1071. X        panic("view_from called with range %d", range);
  1072. X    limits = circle_ptr(range) + 1; /* start at next row */
  1073. X    if(left < scol - range) left = scol - range;
  1074. X    if(right > scol + range) right = scol + range;
  1075. X    } else
  1076. X    limits = (char*) 0;
  1077. X
  1078. X    if(func) {
  1079. X    for (i = left; i <= right; i++) (*func)(i, srow, arg);
  1080. X    } else {
  1081. X    /* Row pointer optimization. */
  1082. X    rowp = cs_rows[srow];
  1083. X
  1084. X    /* We know that we can see our row. */
  1085. X    for (i = left; i <= right; i++) set_cs(rowp,i);
  1086. X    cs_left[srow]  = left;
  1087. X    cs_right[srow] = right;
  1088. X    }
  1089. X
  1090. X    /*
  1091. X     * Check what could be seen in quadrants.  We need to check for valid
  1092. X     * rows here, since we don't do it in the routines right_side() and
  1093. X     * left_side() [ugliness to remove extra routine calls].
  1094. X     */
  1095. X    if ( (nrow = srow+1) < ROWNO ) {    /* move down */
  1096. X    step =  1;
  1097. X    if (scol < COLNO-1) right_side(nrow, scol, right, limits);
  1098. X    if (scol)        left_side (nrow, left,  scol, limits);
  1099. X    }
  1100. X
  1101. X    if ( (nrow = srow-1) >= 0 ) {    /* move up */
  1102. X    step = -1;
  1103. X    if (scol < COLNO-1) right_side(nrow, scol, right, limits);
  1104. X    if (scol)        left_side (nrow, left,  scol, limits);
  1105. X    }
  1106. X}
  1107. X
  1108. X#endif    /*===== End of algorithm C =====*/
  1109. X
  1110. X/*
  1111. X * AREA OF EFFECT "ENGINE"
  1112. X *
  1113. X * Calculate all possible visible locations as viewed from the given location
  1114. X * (srow,scol) within the range specified. Perform "func" with (x, y) args and
  1115. X * additional argument "arg" for each square.
  1116. X *
  1117. X * If not centered on the hero, just forward arguments to view_from(); it
  1118. X * will call "func" when necessary.  If the hero is the center, use the
  1119. X * vision matrix and reduce extra work.
  1120. X */
  1121. Xvoid
  1122. Xdo_clear_area(scol,srow,range,func,arg)
  1123. X    int scol, srow, range;
  1124. X    void FDECL((*func), (int,int,genericptr_t));
  1125. X    genericptr_t arg;
  1126. X{
  1127. X    /* If not centered on hero, do the hard work of figuring the area */
  1128. X    if (scol != u.ux || srow != u.uy)
  1129. X        view_from(srow, scol, (char **)0, NULL, NULL, range, func, arg);
  1130. X    else {
  1131. X        register int x;
  1132. X        int y, min_x, max_x, max_y, offset;
  1133. X        char *limits;
  1134. X
  1135. X        if (range > MAX_RADIUS || range < 1)
  1136. X        panic("do_clear_area:  illegal range %d", range);
  1137. X        if(vision_full_recalc)
  1138. X        vision_recalc(0);    /* recalc vision if dirty */
  1139. X        limits = circle_ptr(range);
  1140. X        if ((max_y = (srow + range)) >= ROWNO) max_y = ROWNO-1;
  1141. X        if ((y = (srow - range)) < 0) y = 0;
  1142. X        for (; y <= max_y; y++) {
  1143. X        offset = limits[abs(y-srow)];
  1144. X        if((min_x = (scol - offset)) < 0) min_x = 0;
  1145. X        if((max_x = (scol + offset)) >= COLNO) max_x = COLNO-1;
  1146. X        for (x = min_x; x <= max_x; x++)
  1147. X            if (couldsee(x, y))
  1148. X            (*func)(x, y, arg);
  1149. X        }
  1150. X    }
  1151. X}
  1152. X
  1153. X/*vision.c*/
  1154. END_OF_FILE
  1155. if test 33352 -ne `wc -c <'src/vision.c2'`; then
  1156.     echo shar: \"'src/vision.c2'\" unpacked with wrong size!
  1157. fi
  1158. # end of 'src/vision.c2'
  1159. fi
  1160. if test -f 'sys/amiga/amiwind.c' -a "${1}" != "-c" ; then 
  1161.   echo shar: Will not clobber existing file \"'sys/amiga/amiwind.c'\"
  1162. else
  1163. echo shar: Extracting \"'sys/amiga/amiwind.c'\" \(21231 characters\)
  1164. sed "s/^X//" >'sys/amiga/amiwind.c' <<'END_OF_FILE'
  1165. X/*    SCCS Id: @(#)amiwind.c     3.1    93/01/08
  1166. X/*    Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992      */
  1167. X/*    Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993      */
  1168. X/* NetHack may be freely redistributed.  See license for details. */
  1169. X
  1170. X/*
  1171. X *  Here is some very Amiga specific stuff, dealing with
  1172. X *  screens, windows, menus, and input via IntuiMessages.
  1173. X */
  1174. X
  1175. X#include "hack.h"
  1176. X#include "winami.h"
  1177. X
  1178. X/* Have to undef CLOSE as display.h and intuition.h both use it */
  1179. X#undef CLOSE
  1180. X
  1181. X#include <exec/types.h>
  1182. X#include <exec/alerts.h>
  1183. X#include <exec/io.h>
  1184. X#include <exec/devices.h>
  1185. X#include <devices/console.h>
  1186. X#include <devices/conunit.h>
  1187. X#include <intuition/intuition.h>
  1188. X#include <intuition/intuitionbase.h>
  1189. X#include <libraries/dosextens.h>
  1190. X
  1191. X#ifdef __SASC
  1192. X# undef COUNT
  1193. X
  1194. X# include <dos.h>       /* for __emit */
  1195. X# include <string.h>
  1196. X# include <proto/dos.h>
  1197. X# include <proto/exec.h>
  1198. X
  1199. X/* kludge - see amirip for why */
  1200. X# undef red
  1201. X# undef green
  1202. X# undef blue
  1203. X# undef index
  1204. X# include <proto/graphics.h>
  1205. X
  1206. X# include <proto/intuition.h>
  1207. X# include <proto/diskfont.h>
  1208. X# include <proto/console.h>
  1209. X#endif
  1210. X
  1211. X#undef  NULL
  1212. X#define NULL    0L
  1213. X
  1214. X#include "Amiga:amimenu.c"
  1215. X
  1216. X/*  First, external declarations... */
  1217. X
  1218. Xstruct Library *ConsoleDevice;
  1219. X
  1220. X#ifdef AZTEC_50
  1221. X# include <functions.h>
  1222. X#endif
  1223. X
  1224. X#ifdef  INTUI_NEW_LOOK
  1225. X#define NewWindow ExtNewWindow
  1226. X#endif
  1227. X
  1228. X#include "Amiga:winami.p"
  1229. X#include "Amiga:amiwind.p"
  1230. X#include "Amiga:amidos.p"
  1231. X
  1232. Xstatic int BufferGetchar(void);
  1233. Xstatic void ProcessMessage( register struct IntuiMessage *message );
  1234. X
  1235. X#ifdef AMIFLUSH
  1236. Xstatic struct Message *FDECL(GetFMsg,(struct MsgPort *));
  1237. X#endif
  1238. X
  1239. X/*  Now our own variables */
  1240. X
  1241. Xstruct IntuitionBase *IntuitionBase;
  1242. Xstruct Screen *HackScreen;
  1243. Xstruct Window *pr_WindowPtr;
  1244. Xstruct MsgPort *HackPort;
  1245. Xstruct IOStdReq ConsoleIO;
  1246. Xchar Initialized = 0;
  1247. XWEVENT lastevent;
  1248. X
  1249. X#ifdef HACKFONT
  1250. Xstruct GfxBase *GfxBase;
  1251. Xstruct Library *DiskfontBase;
  1252. X#endif
  1253. X
  1254. Xextern struct Library *ConsoleDevice;
  1255. X
  1256. X#define CSI     '\x9b'
  1257. X#define NO_CHAR     -1
  1258. X#define RAWHELP     0x5F    /* Rawkey code of the HELP key */
  1259. X
  1260. X#define KBDBUFFER   10
  1261. Xstatic unsigned char KbdBuffer[KBDBUFFER];
  1262. Xunsigned char KbdBuffered;
  1263. X
  1264. X#define BufferQueueChar(ch) (KbdBuffer[KbdBuffered++] = (ch))
  1265. X
  1266. X/*
  1267. X * Define some stuff for our special glyph drawing routines
  1268. X */
  1269. Xstatic unsigned short glyph_node_index, glyph_buffer_index;
  1270. X#define NUMBER_GLYPH_NODES  80
  1271. X#define GLYPH_BUFFER_SIZE   512
  1272. Xstruct glyph_node {
  1273. X    short    x;
  1274. X    short    y;
  1275. X    short    len;
  1276. X    unsigned char   bg_color;
  1277. X    unsigned char   fg_color;
  1278. X    char    *buffer;
  1279. X};
  1280. Xstatic struct glyph_node g_nodes[NUMBER_GLYPH_NODES];
  1281. Xstatic char glyph_buffer[GLYPH_BUFFER_SIZE];
  1282. X
  1283. X#ifdef TEXTCOLOR
  1284. X/*
  1285. X * Map our amiga-specific colormap into the colormap specified in color.h.
  1286. X * See amiwind.c for the amiga specific colormap.
  1287. X */
  1288. X
  1289. Xint foreg[16] = { 0, 7, 4, 2, 6, 5, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
  1290. Xint backg[16] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 1, 6, 5, 3, 1 };
  1291. X#endif
  1292. X
  1293. X#ifdef HACKFONT
  1294. X
  1295. Xstruct TextFont *HackFont;
  1296. XUBYTE FontName[] = "NetHack:hack.font";
  1297. X    /* # chars in "NetHack:": */
  1298. X#define         SIZEOF_DISKNAME 8
  1299. X
  1300. X#endif
  1301. X
  1302. Xstruct TextAttr Hack80 = {
  1303. X#ifdef HACKFONT
  1304. X    &FontName[SIZEOF_DISKNAME],
  1305. X#else
  1306. X    (UBYTE *) "topaz.font",
  1307. X#endif
  1308. X    TOPAZ_EIGHTY, FS_NORMAL, FPF_DISKFONT | FPF_ROMFONT
  1309. X};
  1310. X
  1311. X/*
  1312. X * Open a window that shares the HackPort IDCMP. Use CloseShWindow()
  1313. X * to close.
  1314. X */
  1315. X
  1316. Xstruct Window *OpenShWindow(nw)
  1317. Xstruct NewWindow *nw;
  1318. X{
  1319. X    register struct Window *win;
  1320. X    register ULONG idcmpflags;
  1321. X
  1322. X    if (!HackPort)  /* Sanity check */
  1323. X    return (struct Window *) 0;
  1324. X
  1325. X    idcmpflags = nw->IDCMPFlags;
  1326. X    nw->IDCMPFlags = 0;
  1327. X    if (!(win = OpenWindow((void *)nw)))
  1328. X    return (struct Window *) 0;
  1329. X
  1330. X    win->UserPort = HackPort;
  1331. X    ModifyIDCMP(win, idcmpflags);
  1332. X    return win;
  1333. X}
  1334. X
  1335. X
  1336. X/*
  1337. X * Close a window that shared the HackPort IDCMP port.
  1338. X */
  1339. X
  1340. Xvoid FDECL(CloseShWindow, (struct Window *));
  1341. Xvoid CloseShWindow(win)
  1342. Xstruct Window *win;
  1343. X{
  1344. X    register struct IntuiMessage *msg, *nxt;
  1345. X
  1346. X    if( !HackPort )
  1347. X    panic("HackPort NULL in CloseShWindow" );
  1348. X    if (!win)
  1349. X    return;
  1350. X
  1351. X    Forbid();
  1352. X    /* Flush all messages for all windows to avoid typeahead and other
  1353. X     * similar problems...
  1354. X     */
  1355. X    while( msg = (struct IntuiMessage *)GetMsg( win->UserPort ) )
  1356. X    ReplyMsg( (struct Message *) msg );
  1357. X    KbdBuffered = 0;
  1358. X    win->UserPort = (struct MsgPort *) 0;
  1359. X    ModifyIDCMP(win, 0L);
  1360. X    Permit();
  1361. X    CloseWindow(win);
  1362. X}
  1363. X
  1364. Xstatic int BufferGetchar()
  1365. X{
  1366. X    register int c;
  1367. X
  1368. X    if (KbdBuffered > 0) {
  1369. X    c = KbdBuffer[0];
  1370. X    KbdBuffered--;
  1371. X    /* Move the remaining characters */
  1372. X    if( KbdBuffered < sizeof( KbdBuffer ) )
  1373. X        memcpy( KbdBuffer, KbdBuffer+1, KbdBuffered );
  1374. X    return c;
  1375. X    }
  1376. X
  1377. X    return NO_CHAR;
  1378. X}
  1379. X
  1380. X/*
  1381. X *  This should remind you remotely of DeadKeyConvert, but we are cheating
  1382. X *  a bit. We want complete control over the numeric keypad, and no dead
  1383. X *  keys... (they are assumed to be on Alted keys).
  1384. X *
  1385. X *  Also assumed is that the IntuiMessage is of type RAWKEY.  For some
  1386. X *  reason, IECODE_UP_PREFIX events seem to be lost when they  occur while
  1387. X *  our console window is inactive. This is particulary  troublesome with
  1388. X *  qualifier keys... Is this because I never RawKeyConvert those events???
  1389. X */
  1390. X
  1391. Xint ConvertKey(message)
  1392. Xregister struct IntuiMessage *message;
  1393. X{
  1394. X    static struct InputEvent theEvent;
  1395. X    static char       numpad[] = "bjnh.lyku";
  1396. X    static char  ctrl_numpad[] = "\x02\x0A\x0E\x08.\x0C\x19\x0B\x15";
  1397. X    static char shift_numpad[] = "BJNH.LYKU";
  1398. X
  1399. X    unsigned char buffer[1];
  1400. X    register int length;
  1401. X    register ULONG qualifier;
  1402. X    char numeric_pad, shift, control, alt;
  1403. X
  1404. X    qualifier = message->Qualifier;
  1405. X
  1406. X    control = (qualifier &  IEQUALIFIER_CONTROL) != 0;
  1407. X    shift   = (qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) != 0;
  1408. X    alt     = (qualifier & (IEQUALIFIER_LALT   | IEQUALIFIER_RALT  )) != 0;
  1409. X
  1410. X    /* Allow ALT to function as a META key ... */
  1411. X
  1412. X    qualifier &= ~(IEQUALIFIER_LALT | IEQUALIFIER_RALT);
  1413. X    numeric_pad = (qualifier & IEQUALIFIER_NUMERICPAD) != 0;
  1414. X
  1415. X    /*
  1416. X     *  Shortcut for HELP and arrow keys. I suppose this is allowed.
  1417. X     *  The defines are in intuition/intuition.h, and the keys don't
  1418. X     *  serve 'text' input, normally. Also, parsing their escape
  1419. X     *  sequences is such a mess...
  1420. X     */
  1421. X
  1422. X    switch (message->Code) {
  1423. X    case RAWHELP:
  1424. X        if( alt )
  1425. X        {
  1426. X        EditColor();
  1427. X        return( -1 );
  1428. X        }
  1429. X        return( '?' );
  1430. X        break;
  1431. X    case CURSORLEFT:
  1432. X        length = '4';
  1433. X        numeric_pad = 1;
  1434. X        goto arrow;
  1435. X    case CURSORDOWN:
  1436. X        length = '2';
  1437. X        numeric_pad = 1;
  1438. X        goto arrow;
  1439. X    case CURSORUP:
  1440. X        length = '8';
  1441. X        numeric_pad = 1;
  1442. X        goto arrow;
  1443. X    case CURSORRIGHT:
  1444. X        length = '6';
  1445. X        numeric_pad = 1;
  1446. X        goto arrow;
  1447. X    }
  1448. X
  1449. X    theEvent.ie_Class = IECLASS_RAWKEY;
  1450. X    theEvent.ie_Code = message->Code;
  1451. X    theEvent.ie_Qualifier = numeric_pad ? IEQUALIFIER_NUMERICPAD : qualifier;
  1452. X    theEvent.ie_EventAddress = (APTR) (message->IAddress);
  1453. X
  1454. X    length = RawKeyConvert(&theEvent, (char *)buffer, 
  1455. X      (long) sizeof(buffer), NULL);
  1456. X
  1457. X    if (length == 1) {   /* Plain ASCII character */
  1458. X    length = buffer[0];
  1459. X    /*
  1460. X     *  If flags.num_pad is set, movement is by 4286.
  1461. X     *  If not set, translate 4286 into hjkl.
  1462. X     *  This way, the numeric pad can /always/ be used
  1463. X     *  for moving, though best results are when it is off.
  1464. X     */
  1465. Xarrow:
  1466. X    if (!flags.num_pad && numeric_pad && length >= '1' && length <= '9') {
  1467. X        length -= '1';
  1468. X        if (control) {
  1469. X        length = ctrl_numpad[length];
  1470. X        } else if (shift) {
  1471. X        length = shift_numpad[length];
  1472. X        } else {
  1473. X        length = numpad[length];
  1474. X        }
  1475. X    }
  1476. X    if (alt)
  1477. X        length |= 0x80;
  1478. X    return(length);
  1479. X    } /* else shift, ctrl, alt, amiga, F-key, shift-tab, etc */
  1480. X    else
  1481. X    return( -1 );
  1482. X}
  1483. X
  1484. X/*
  1485. X *  Process an incoming IntuiMessage.
  1486. X *  It would certainly look nicer if this could be done using a
  1487. X *  PA_SOFTINT message port, but we cannot call RawKeyConvert()
  1488. X *  during a software interrupt.
  1489. X *  Anyway, kbhit() is called often enough, and usually gets
  1490. X *  ahead of input demands, when the user types ahead.
  1491. X */
  1492. X
  1493. Xstatic void ProcessMessage(message)
  1494. Xregister struct IntuiMessage *message;
  1495. X{
  1496. X    int c;
  1497. X    static int skip_mouse=0;    /* need to ignore next mouse event on
  1498. X                 * a window activation */
  1499. X    switch(message->Class) {
  1500. X    case ACTIVEWINDOW:
  1501. X    skip_mouse=1;break;
  1502. X    case MOUSEBUTTONS:
  1503. X    {
  1504. X        if(skip_mouse){
  1505. X        skip_mouse=0;
  1506. X        break;
  1507. X        }
  1508. X        if( message->Code == SELECTDOWN ){
  1509. X        lastevent.type = WEMOUSE;
  1510. X        lastevent.u.mouse.x = message->MouseX;
  1511. X        lastevent.u.mouse.y = message->MouseY;
  1512. X            /* With shift equals RUN */
  1513. X        lastevent.u.mouse.qual = (message->Qualifier &
  1514. X          (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) != 0;
  1515. X        }
  1516. X    }
  1517. X    break;
  1518. X
  1519. X    case MENUPICK:
  1520. X    {
  1521. X        USHORT thismenu;
  1522. X        struct MenuItem *item;
  1523. X
  1524. X        thismenu = message->Code;
  1525. X        while (thismenu != MENUNULL) {
  1526. X        item = ItemAddress(HackMenu, (ULONG) thismenu);
  1527. X        if (KbdBuffered < KBDBUFFER)
  1528. X            BufferQueueChar(item->Command); /* Unused: No COMMSEQ */
  1529. X        thismenu = item->NextSelect;
  1530. X        }
  1531. X    }
  1532. X    break;
  1533. X
  1534. X    case RAWKEY:
  1535. X    if (!(message->Code & IECODE_UP_PREFIX)){
  1536. X        /* May queue multiple characters
  1537. X         * but doesn't do that yet...
  1538. X         */
  1539. X        if( ( c = ConvertKey(message) ) > 0 )
  1540. X        BufferQueueChar( c );
  1541. X        }
  1542. X        break;
  1543. X    }
  1544. X    ReplyMsg((struct Message *) message);
  1545. X}
  1546. X
  1547. X/*
  1548. X *  Get all incoming messages and fill up the keyboard buffer,
  1549. X *  thus allowing Intuition to (maybe) free up the IntuiMessages.
  1550. X *  Return when no more messages left, or keyboard buffer half full.
  1551. X *  We need to do this since there is no one-to-one correspondence
  1552. X *  between characters and incoming messages.
  1553. X */
  1554. X
  1555. Xint kbhit()
  1556. X{
  1557. X    register struct IntuiMessage *message;
  1558. X    while( KbdBuffered < KBDBUFFER / 2 )
  1559. X    {
  1560. X#ifdef AMIFLUSH
  1561. X    message = (struct IntuiMessage *) GetFMsg(HackPort);
  1562. X#else
  1563. X    message = (struct IntuiMessage *) GetMsg(HackPort);
  1564. X#endif
  1565. X    if(message)
  1566. X    {
  1567. X        ProcessMessage(message);
  1568. X        if( lastevent.type != WEUNK && lastevent.type != WEKEY )
  1569. X        break;
  1570. X    }
  1571. X    else
  1572. X        break;
  1573. X    }
  1574. X    return ( lastevent.type == WEUNK ) ? KbdBuffered : -1;
  1575. X}
  1576. X
  1577. X/*
  1578. X *  Get a character from the keyboard buffer, waiting if not available.
  1579. X *  Ignore other kinds of events that happen in the mean time.
  1580. X */
  1581. X
  1582. Xint WindowGetchar( )
  1583. X{
  1584. X    while ((lastevent.type = WEUNK), kbhit() <= 0) {
  1585. X    WaitPort(HackPort);
  1586. X    }
  1587. X    return BufferGetchar();
  1588. X}
  1589. X
  1590. XWETYPE WindowGetevent()
  1591. X{
  1592. X    lastevent.type = WEUNK;
  1593. X    while (kbhit() == 0)
  1594. X    {
  1595. X    WaitPort(HackPort);
  1596. X    }
  1597. X
  1598. X    if( KbdBuffered )
  1599. X    {
  1600. X    lastevent.type = WEKEY;
  1601. X    lastevent.u.key = BufferGetchar();
  1602. X    }
  1603. X    return( lastevent.type );
  1604. X}
  1605. X
  1606. X/*
  1607. X *  Clean up everything. But before we do, ask the user to hit return
  1608. X *  when there is something that s/he should read.
  1609. X */
  1610. X
  1611. Xvoid CleanUp()
  1612. X{
  1613. X    register struct IntuiMessage *msg;
  1614. X
  1615. X    /* Finish closing things up */
  1616. X
  1617. X    amii_raw_print("");
  1618. X    amii_getret();
  1619. X
  1620. X    ((struct Process *) FindTask(NULL))->pr_WindowPtr = (APTR) pr_WindowPtr;
  1621. X    if (ConsoleIO.io_Device)
  1622. X    CloseDevice( (struct IORequest *)&ConsoleIO );
  1623. X
  1624. X    if (HackPort) {
  1625. X    Forbid();
  1626. X    while (msg = (struct IntuiMessage *) GetMsg(HackPort))
  1627. X        ReplyMsg((struct Message *) msg);
  1628. X    kill_nhwindows( 1 );
  1629. X    DeletePort( HackPort );
  1630. X    HackPort = NULL;
  1631. X    Permit();
  1632. X    }
  1633. X
  1634. X    if (HackScreen) {
  1635. X#ifdef  INTUI_NEW_LOOK
  1636. X    if( IntuitionBase->LibNode.lib_Version >= 37 )
  1637. X    {
  1638. X        while( CloseScreen(HackScreen) == FALSE )
  1639. X        {
  1640. X        struct EasyStruct easy =
  1641. X        {
  1642. X            sizeof( struct EasyStruct ),
  1643. X            0,
  1644. X            "Nethack Problem",
  1645. X            "Can't Close Screen, Close Remaining Windows",
  1646. X            "Okay",
  1647. X        };
  1648. X        EasyRequest( NULL, &easy, NULL, NULL );
  1649. X        }
  1650. X    }
  1651. X#else
  1652. X    CloseScreen(HackScreen);
  1653. X#endif
  1654. X    HackScreen = NULL;
  1655. X    }
  1656. X
  1657. X#ifdef HACKFONT
  1658. X
  1659. X    if (HackFont)
  1660. X    {
  1661. X    CloseFont(HackFont);
  1662. X    HackFont = NULL;
  1663. X    }
  1664. X
  1665. X    if( DiskfontBase )
  1666. X    {
  1667. X    CloseLibrary(DiskfontBase);
  1668. X    DiskfontBase = NULL;
  1669. X    }
  1670. X#endif
  1671. X
  1672. X    if (GfxBase) {
  1673. X    CloseLibrary((struct Library *)GfxBase);
  1674. X    GfxBase = NULL;
  1675. X    }
  1676. X
  1677. X    if (IntuitionBase) {
  1678. X    CloseLibrary((struct Library *)IntuitionBase);
  1679. X    IntuitionBase = NULL;
  1680. X    }
  1681. X
  1682. X    Initialized = 0;
  1683. X}
  1684. X
  1685. Xvoid Abort(rc)
  1686. Xlong rc;
  1687. X{
  1688. X#ifdef CHDIR
  1689. X    extern char orgdir[];
  1690. X    chdir(orgdir);
  1691. X#endif
  1692. X    if (Initialized && ConsoleDevice) {
  1693. X    printf("\n\nAbort with alert code %08lx...\n", rc);
  1694. X    amii_getret();
  1695. X    } else
  1696. X    Alert(rc);
  1697. X#ifdef __SASC
  1698. X    {
  1699. X/*  __emit(0x4afc);     /* illegal instruction */
  1700. X    __emit(0x40fc);     /* divide by */
  1701. X    __emit(0x0000);     /*  #0  */
  1702. X    /* NOTE: don't move CleanUp() above here - */
  1703. X    /* it is too likely to kill the system     */
  1704. X    /* before it can get the SnapShot out, if  */
  1705. X    /* there is something really wrong.    */
  1706. X    }
  1707. X#endif
  1708. X    CleanUp();
  1709. X#undef exit
  1710. X#ifdef AZTEC_C
  1711. X    _abort();
  1712. X#endif
  1713. X    exit((int) rc);
  1714. X}
  1715. X
  1716. X#ifdef AMIFLUSH
  1717. X/* This routine adapted from AmigaMail IV-37 by Michael Sinz */
  1718. Xstatic struct Message *
  1719. XGetFMsg(port)
  1720. X    struct MsgPort *port;
  1721. X    {
  1722. X    struct IntuiMessage *msg,*succ,*succ1;
  1723. X
  1724. X    if(msg=(struct IntuiMessage *)GetMsg(port)){
  1725. X    if(!flags.amiflush)return((struct Message *)msg);
  1726. X    if(msg->Class==RAWKEY){
  1727. X        Forbid();
  1728. X        succ=(struct IntuiMessage *)(port->mp_MsgList.lh_Head);
  1729. X        while(succ1=(struct IntuiMessage *)
  1730. X          (succ->ExecMessage.mn_Node.ln_Succ)){
  1731. X        if(succ->Class==RAWKEY){
  1732. X            Remove((struct Node *)succ);
  1733. X            ReplyMsg((struct Message *)succ);
  1734. X        }
  1735. X        succ=succ1;
  1736. X        }
  1737. X        Permit();
  1738. X    }
  1739. X    }
  1740. X    return((struct Message *)msg);
  1741. X}
  1742. X#endif
  1743. X
  1744. X/*
  1745. X * Begin Revamped Text display routines
  1746. X *
  1747. X * Up until version 3.1, the only method for displaying text on the playing
  1748. X * field was by using the console.device.  This was nice for a number of
  1749. X * reasons, the most signifigant of which was a lot of the nuts and bolts was
  1750. X * done for you via escape sequences interpreted by said device.  This did
  1751. X * not come without a price however.  And that price was speed. It has now
  1752. X * come to a point where the speed has now been deemed unacceptable.
  1753. X *
  1754. X * The following series of routines are designed to drop into the current
  1755. X * nethack display code, using hooks provided for such a measure. It works
  1756. X * on similar principals as the WindowPuts(), buffering I/O internally
  1757. X * until either an explicit flush or internal buffering is exceeded, thereby
  1758. X * forcing the flush.  The output (or glyphs) does not go to the
  1759. X * console.device, however.  It is driven directly to the rasterport of the
  1760. X * nethack window via the low-level Text() calls, increasing the speed by
  1761. X * a very signifigant factor.
  1762. X */
  1763. X/*
  1764. X * Routine to simply flush whatever is buffered
  1765. X */
  1766. Xvoid
  1767. Xflush_glyph_buffer( w )
  1768. X    struct Window *w;
  1769. X{
  1770. X    short i, x, y;
  1771. X
  1772. X    /* If nothing is buffered, return before we do anything */
  1773. X    if(glyph_node_index == 0)
  1774. X    return;
  1775. X
  1776. X    cursor_off( WIN_MAP );
  1777. X    start_glyphout( WIN_MAP );
  1778. X    /* Set up the drawing mode */
  1779. X    SetDrMd( w->RPort, JAM2);
  1780. X
  1781. X    /* Go ahead and start dumping the stuff */
  1782. X    for(i=0; i<glyph_node_index; ++i) {
  1783. X    /* These coordinate calculations must be synced with the
  1784. X     * code in curs() in winami.c.  curs_on_u() calls curs()
  1785. X     * to draw the cursor on top of the player
  1786. X     */
  1787. X    y = w->BorderTop + (g_nodes[i].y-1) * w->RPort->TxHeight +
  1788. X        w->RPort->TxBaseline + 1;
  1789. X    x = g_nodes[i].x * w->RPort->TxWidth + w->BorderLeft;
  1790. X
  1791. X    /* Move pens to correct location */
  1792. X    Move(w->RPort, (long)x, (long)y);
  1793. X
  1794. X    /* Setup the colors */
  1795. X    SetAPen(w->RPort, (long)g_nodes[i].fg_color);
  1796. X    SetBPen(w->RPort, (long)g_nodes[i].bg_color);
  1797. X
  1798. X    /* Do it */
  1799. X    Text(w->RPort, g_nodes[i].buffer, g_nodes[i].len);
  1800. X    }
  1801. X
  1802. X    end_glyphout( WIN_MAP );
  1803. X    /* Clean up */
  1804. X    glyph_node_index = glyph_buffer_index = 0;
  1805. X}
  1806. X
  1807. X/*
  1808. X * Glyph buffering routine.  Called instead of WindowPuts().
  1809. X */
  1810. Xvoid
  1811. Xamiga_print_glyph(window,color_index, glyph)
  1812. X    winid window;
  1813. X    int color_index, glyph;
  1814. X{
  1815. X    int fg_color, bg_color;
  1816. X    struct WinDesc *cw;
  1817. X    struct Window *w;
  1818. X    int curx;
  1819. X    int cury;
  1820. X
  1821. X    if( ( cw=wins[window] ) == (struct WinDesc *)NULL )
  1822. X    panic("bad winid in amiga_print_glyph: %d", window );
  1823. X
  1824. X    w = cw->win;
  1825. X    curx=cw->curx;
  1826. X    cury=cw->cury;
  1827. X
  1828. X#ifdef TEXTCOLOR
  1829. X    fg_color = foreg[color_index];
  1830. X    bg_color = backg[color_index];
  1831. X#else
  1832. X    fg_color = 1;
  1833. X    bg_color = 0;
  1834. X#endif /* TEXTCOLOR */
  1835. X
  1836. X    /* See if we have enough character buffer space... */
  1837. X    if(glyph_buffer_index  >= GLYPH_BUFFER_SIZE)
  1838. X    flush_glyph_buffer( w );
  1839. X
  1840. X    /*
  1841. X     * See if we can append it to the current active node of glyph buffer. It
  1842. X     * must satisfy the following conditions:
  1843. X     *
  1844. X     *    * background colors are the same, AND
  1845. X     *    * foreground colors are the same, AND
  1846. X     *    * they are precisely side by side
  1847. X     */
  1848. X    if((glyph_buffer_index != 0) &&
  1849. X       (fg_color == g_nodes[glyph_node_index-1].fg_color) &&
  1850. X       (bg_color == g_nodes[glyph_node_index-1].bg_color) &&
  1851. X       (g_nodes[glyph_node_index-1].x+
  1852. X    g_nodes[glyph_node_index-1].len == curx) &&
  1853. X       (g_nodes[glyph_node_index-1].y == cury)) {
  1854. X    /*
  1855. X     * Add it to the end of the buffer
  1856. X     */
  1857. X    glyph_buffer[glyph_buffer_index++] = glyph;
  1858. X    g_nodes[glyph_node_index-1].len ++;
  1859. X     } else {
  1860. X    /* See if we're out of glyph nodes */
  1861. X    if(glyph_node_index >= NUMBER_GLYPH_NODES)
  1862. X        flush_glyph_buffer( w );
  1863. X    g_nodes[glyph_node_index].len = 1;
  1864. X    g_nodes[glyph_node_index].x = curx;
  1865. X    g_nodes[glyph_node_index].y = cury;
  1866. X    g_nodes[glyph_node_index].fg_color = fg_color;
  1867. X    g_nodes[glyph_node_index].bg_color = bg_color;
  1868. X    g_nodes[glyph_node_index].buffer = &glyph_buffer[glyph_buffer_index];
  1869. X    glyph_buffer[glyph_buffer_index] = glyph;
  1870. X    ++glyph_buffer_index;
  1871. X    ++glyph_node_index;
  1872. X    }
  1873. X}
  1874. X
  1875. X/*
  1876. X * Define some variables which will be used to save context when toggling
  1877. X * back and forth between low level text and console I/O.
  1878. X */
  1879. Xstatic long xsave, ysave, modesave, apensave, bpensave;
  1880. Xstatic int usecolor;
  1881. X
  1882. X/*
  1883. X * The function is called before any glyphs are driven to the screen.  It
  1884. X * removes the cursor, saves internal state of the window, then returns.
  1885. X */
  1886. X
  1887. Xvoid
  1888. Xstart_glyphout(window)
  1889. X    winid window;
  1890. X{
  1891. X    struct WinDesc *cw;
  1892. X    struct Window *w;
  1893. X
  1894. X    if( ( cw=wins[window] ) == (struct WinDesc *)NULL )
  1895. X    panic( "bad winid %d in start_glyphout()", window );
  1896. X
  1897. X    if( cw->flags & FLMAP_INGLYPH )
  1898. X    return;
  1899. X
  1900. X    if( !(w = cw->win ) )
  1901. X    panic( "bad winid %d, no window ptr set", window );
  1902. X
  1903. X    /*
  1904. X     * Save the context of the window
  1905. X     */
  1906. X    xsave = w->RPort->cp_x;
  1907. X    ysave = w->RPort->cp_y;
  1908. X    modesave = w->RPort->DrawMode;
  1909. X    apensave = w->RPort->FgPen;
  1910. X    bpensave = w->RPort->BgPen;
  1911. X
  1912. X    /*
  1913. X     * Set the mode, and be done with it
  1914. X     */
  1915. X    usecolor = flags.use_color;
  1916. X    flags.use_color = FALSE;
  1917. X    cw->flags |= FLMAP_INGLYPH;
  1918. X}
  1919. X
  1920. X/*
  1921. X * General cleanup routine -- flushes and restores cursor
  1922. X */
  1923. Xvoid
  1924. Xend_glyphout(window)
  1925. X    winid window;
  1926. X{
  1927. X    struct WinDesc *cw;
  1928. X    struct Window *w;
  1929. X
  1930. X    if( ( cw = wins[ window ] ) == (struct WinDesc *)NULL )
  1931. X    panic("bad window id %d in end_glyphout()", window );
  1932. X
  1933. X    if( ( cw->flags & FLMAP_INGLYPH ) == 0 )
  1934. X    return;
  1935. X    cw->flags &= ~(FLMAP_INGLYPH);
  1936. X
  1937. X    if( !(w = cw->win ) )
  1938. X    panic( "bad winid %d, no window ptr set", window );
  1939. X
  1940. X    /*
  1941. X     * Clean up whatever is left in the buffer
  1942. X     */
  1943. X    flags.use_color = usecolor;
  1944. X
  1945. X    /*
  1946. X     * Reset internal data structs
  1947. X     */
  1948. X    SetAPen(w->RPort, apensave);
  1949. X    SetBPen(w->RPort, bpensave);
  1950. X    SetDrMd(w->RPort, modesave);
  1951. X
  1952. X    Move(w->RPort, xsave, ysave);
  1953. X}
  1954. X
  1955. Xstruct NewWindow *
  1956. XDupNewWindow( win )
  1957. X    struct NewWindow *win;
  1958. X{
  1959. X    struct NewWindow *nwin;
  1960. X    struct Gadget *ngd, *gd, *pgd = NULL;
  1961. X    struct PropInfo *pip;
  1962. X    struct StringInfo *sip;
  1963. X
  1964. X    /* Copy the (Ext)NewWindow structure */
  1965. X
  1966. X    nwin = (struct NewWindow *)alloc( sizeof( struct NewWindow ) );
  1967. X    *nwin = *win;
  1968. X
  1969. X    /* Now do the gadget list */
  1970. X
  1971. X    nwin->FirstGadget = NULL;
  1972. X    for( gd = win->FirstGadget; gd; gd = gd->NextGadget )
  1973. X    {
  1974. X    ngd = (struct Gadget *)alloc( sizeof( struct Gadget ) );
  1975. X    *ngd = *gd;
  1976. X    if( gd->GadgetType == STRGADGET )
  1977. X    {
  1978. X        sip = (struct StringInfo *)alloc( sizeof( struct StringInfo ) );
  1979. X        *sip = *((struct StringInfo *)gd->SpecialInfo);
  1980. X        sip->Buffer = (UBYTE *) alloc( sip->MaxChars );
  1981. X        *sip->Buffer = 0;
  1982. X        ngd->SpecialInfo = (APTR)sip;
  1983. X    }
  1984. X    else if( gd->GadgetType == PROPGADGET )
  1985. X    {
  1986. X        pip = (struct PropInfo *)alloc( sizeof( struct PropInfo ) );
  1987. X        *pip = *((struct PropInfo *)gd->SpecialInfo);
  1988. X        ngd->SpecialInfo = (APTR)pip;
  1989. X    }
  1990. X    if( pgd )
  1991. X        pgd->NextGadget = ngd;
  1992. X    else
  1993. X        nwin->FirstGadget = ngd;
  1994. X    pgd = ngd;
  1995. X    ngd->NextGadget = NULL;
  1996. X    }
  1997. X    return( nwin );
  1998. X}
  1999. X
  2000. Xvoid
  2001. XFreeNewWindow( win )
  2002. X    struct NewWindow *win;
  2003. X{
  2004. X    register struct Gadget *gd, *pgd;
  2005. X    register struct StringInfo *sip;
  2006. X
  2007. X    for( gd = win->FirstGadget; gd; gd = pgd )
  2008. X    {
  2009. X    pgd = gd->NextGadget;
  2010. X    if( gd->GadgetType == STRGADGET )
  2011. X    {
  2012. X        sip = (struct StringInfo *)gd->SpecialInfo;
  2013. X        free( sip->Buffer );
  2014. X        free( sip );
  2015. X    }
  2016. X    else if( gd->GadgetType == PROPGADGET )
  2017. X    {
  2018. X        free( (struct PropInfo *)gd->SpecialInfo );
  2019. X    }
  2020. X    free( gd );
  2021. X    }
  2022. X    free( win );
  2023. X}
  2024. X
  2025. Xvoid
  2026. Xbell()
  2027. X{
  2028. X    if (flags.silent) return;
  2029. X    DisplayBeep(NULL);
  2030. X}
  2031. X
  2032. Xvoid
  2033. Xamii_delay_output()
  2034. X{
  2035. X    /* delay 50 ms */
  2036. X    Delay(2L);
  2037. X}
  2038. X
  2039. Xvoid
  2040. Xamii_number_pad(state)
  2041. Xint state;
  2042. X{
  2043. X}
  2044. X
  2045. X/* fatal error */
  2046. X/*VARARGS1*/
  2047. Xvoid error VA_DECL(const char *, s)
  2048. X    VA_START(s);
  2049. X    VA_INIT(s, char *);
  2050. X
  2051. X    putchar('\n');
  2052. X    vprintf(s, VA_ARGS);
  2053. X    putchar('\n');
  2054. X
  2055. X    VA_END();
  2056. X    Abort(0L);
  2057. X}
  2058. END_OF_FILE
  2059. if test 21231 -ne `wc -c <'sys/amiga/amiwind.c'`; then
  2060.     echo shar: \"'sys/amiga/amiwind.c'\" unpacked with wrong size!
  2061. fi
  2062. # end of 'sys/amiga/amiwind.c'
  2063. fi
  2064. echo shar: End of archive 58 \(of 108\).
  2065. cp /dev/null ark58isdone
  2066. MISSING=""
  2067. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
  2068. 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
  2069. 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
  2070. 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
  2071. 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 \
  2072. 101 102 103 104 105 106 107 108 ; do
  2073.     if test ! -f ark${I}isdone ; then
  2074.     MISSING="${MISSING} ${I}"
  2075.     fi
  2076. done
  2077. if test "${MISSING}" = "" ; then
  2078.     echo You have unpacked all 108 archives.
  2079.     echo "Now execute 'rebuild.sh'"
  2080.     rm -f ark10[0-8]isdone ark[1-9]isdone ark[1-9][0-9]isdone
  2081. else
  2082.     echo You still need to unpack the following archives:
  2083.     echo "        " ${MISSING}
  2084. fi
  2085. ##  End of shell archive.
  2086. exit 0
  2087.