home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / x / volume19 / xtmines / part01 < prev    next >
Encoding:
Text File  |  1993-04-27  |  49.1 KB  |  1,712 lines

  1. Newsgroups: comp.sources.x
  2. From: ttsai@crhc.uiuc.edu (Timothy Tsai)
  3. Subject: v19i004:  xtmines - A game where you try to cross a minefield, Part01/02
  4. Message-ID: <csx-v19i004=xtmines.145640@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: ea564b61f2eb771d11a0d1e40f8e3a1b
  6. Date: Mon, 8 Mar 1993 20:58:06 GMT
  7. Approved: chris@sparky.imd.sterling.com
  8.  
  9. Submitted-by: ttsai@crhc.uiuc.edu (Timothy Tsai)
  10. Posting-number: Volume 19, Issue 4
  11. Archive-name: xtmines/part01
  12. Environment: X11
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 1 (of 2)."
  21. # Contents:  init.c play.c
  22. # Wrapped by ttsai@haydn.crhc.uiuc.edu on Fri Feb 26 12:01:35 1993
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'init.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'init.c'\"
  26. else
  27. echo shar: Extracting \"'init.c'\" \(16843 characters\)
  28. sed "s/^X//" >'init.c' <<'END_OF_FILE'
  29. X/* xtmines: game where you try to cross a minefield */
  30. X/* windows.c: routines to initialize windows, fonts, GCs, etc */
  31. X/* Written by Timothy Tsai  April 13, 1992 */
  32. X
  33. X#include "xtmines.h"
  34. X
  35. X/* open_display:  open the display;                */
  36. X/*                set up default values            */
  37. X/*                   (eg. root, white, black, etc) */
  38. X/*                set random seed                  */
  39. Xvoid open_display()
  40. X{
  41. X    if ((disp = XOpenDisplay(NULL)) == NULL) {
  42. X        fprintf(stderr, "Can't Open Display\n");
  43. X        exit(1);
  44. X    }
  45. X    root    = DefaultRootWindow(disp);
  46. X    screen    = DefaultScreen(disp);
  47. X    depth    = DefaultDepth(disp,screen);
  48. X    visual    = DefaultVisual(disp,screen);
  49. X    white    = WhitePixel(disp,screen);
  50. X    black    = BlackPixel(disp,screen);
  51. X
  52. X    srandom(time(0));
  53. X}
  54. X
  55. X/* load_fonts:  load 3 fonts:  fonts (status line and showfig) */
  56. X/*                             fontm (main -- for most text)   */
  57. X/*                             fontt (time and hiscores list)  */
  58. Xvoid load_fonts()
  59. X{
  60. X    fonts        = XLoadFont(disp,FONTS);
  61. X    fontsstruct    = XQueryFont(disp,fonts);
  62. X    /* fontsw, fontsh, fontsa are used by PrintStr() for status line */
  63. X    fontsw        = fontsstruct->max_bounds.rbearing -
  64. X                fontsstruct->min_bounds.lbearing;
  65. X    fontsh        = fontsstruct->ascent + fontsstruct->descent;
  66. X    fontsa        = fontsstruct->ascent;
  67. X    /* fonstshoww, fontshowh, fontshowa are used by draw() for showfig */
  68. X    fontshoww    = (fontsstruct->per_char + '0')->rbearing -
  69. X                (fontsstruct->per_char + '0')->lbearing;
  70. X    fontshowh    = (fontsstruct->per_char + '0')->ascent +
  71. X                (fontsstruct->per_char + '0')->descent;
  72. X    fontshowa    = (fontsstruct->per_char + '0')->ascent;
  73. X
  74. X    fontm        = XLoadFont(disp,FONTM);
  75. X    fontmstruct    = XQueryFont(disp,fontm);
  76. X    fontmw        = fontmstruct->max_bounds.rbearing -
  77. X                fontmstruct->min_bounds.lbearing;
  78. X    fontmh        = fontmstruct->ascent + fontmstruct->descent;
  79. X    fontma        = fontmstruct->ascent;
  80. X
  81. X    fontt        = XLoadFont(disp,FONTT);
  82. X    fonttstruct    = XQueryFont(disp,fontt);
  83. X    fonttw        = fonttstruct->max_bounds.rbearing -
  84. X                fonttstruct->min_bounds.lbearing;
  85. X    fontth        = fonttstruct->ascent + fonttstruct->descent;
  86. X    fontta        = fonttstruct->ascent;
  87. X}
  88. X
  89. X/* create_map_frame:  actually create each window and map to screen */
  90. X/*                    this is where each window's position and size */
  91. X/*                    are specified;  also, create all bitmaps and  */
  92. X/*                    initialize bitmaps dimension arrays           */
  93. Xvoid create_map_frame()
  94. X{
  95. X    int    ww,    /* window width of small button windows */
  96. X        wh1,    /* window height of status line right under field */
  97. X        wh2,    /*                  2nd row of buttons */
  98. X        wh3,    /*                  3rd row of buttons */
  99. X        wh4;    /*                  last row of buttons */
  100. X
  101. X    /*---First, create and map windows----------------------------*/
  102. X
  103. X    /* first wind button widths and heights */
  104. X    /* NUM1WINDS = num of buttons in one row */
  105. X    ww = (w-(NUM1WINDS+1)*bw)/(NUM1WINDS);
  106. X    wh1 = wh2 = wh3 = (h-fh-6*bw)/4;  wh4 = h-fh-6*bw-wh1-wh2-wh3;
  107. X
  108. X    /* create frame and field */
  109. X    frame    = XCreateSimpleWindow(disp,root,x,y,w,h,bw,black,white);
  110. X    field            = XCreateSimpleWindow(disp,frame,
  111. X                    0,0,w-2*bw,fh,bw,
  112. X                    black,white);
  113. X
  114. X    /* create status line */
  115. X    wind[status]        = XCreateSimpleWindow(disp,frame,
  116. X                    0,fh+bw,w-2*bw,wh1,bw,
  117. X                    black,white);
  118. X
  119. X    /* create 2nd button row */
  120. X    wind[bombs_left]    = XCreateSimpleWindow(disp,frame,
  121. X                    0,fh+wh1+2*bw,ww,
  122. X                    wh2,bw,black,white);
  123. X    wind[bonus_wind]    = XCreateSimpleWindow(disp,frame,
  124. X                    bonus_wind*(ww+bw),
  125. X                    fh+wh1+2*bw,ww,
  126. X                    wh2,bw,black,white);
  127. X    wind[time_left]        = XCreateSimpleWindow(disp,frame,
  128. X                    time_left*(ww+bw),
  129. X                    fh+wh1+2*bw,ww,
  130. X                    wh2,bw,black,white);
  131. X    wind[score]        = XCreateSimpleWindow(disp,frame,
  132. X                    score*(ww+bw),
  133. X                    fh+wh1+2*bw,ww,
  134. X                    wh2,bw,black,white);
  135. X    wind[grenades_left]    = XCreateSimpleWindow(disp,frame,
  136. X                    grenades_left*(ww+bw),
  137. X                    fh+wh1+2*bw,ww,
  138. X                    wh2,bw,black,white);
  139. X    wind[rank]        = XCreateSimpleWindow(disp,frame,
  140. X                    rank*(ww+bw),
  141. X                    fh+wh1+2*bw,w-2*bw-(rank)*(ww+bw),
  142. X                    wh2,bw,black,white);
  143. X
  144. X    /* create 3rd button row */
  145. X    wind[quit_wind]        = XCreateSimpleWindow(disp,frame,
  146. X                    rank*(ww+bw),
  147. X                    fh+3*bw+wh1+wh2,w-2*bw-(rank)*(ww+bw),
  148. X                    wh3,bw,black,white);
  149. X    wind[show_wind]        = XCreateSimpleWindow(disp,frame,
  150. X                    grenades_left*(ww+bw),
  151. X                    fh+3*bw+wh1+wh2,ww,
  152. X                    wh3,bw,black,white);
  153. X    wind[tgrenade_wind]    = XCreateSimpleWindow(disp,frame,
  154. X                    score*(ww+bw),
  155. X                    fh+3*bw+wh1+wh2,ww,
  156. X                    wh3,bw,black,white);
  157. X    wind[giveup_wind]    = XCreateSimpleWindow(disp,frame,
  158. X                    time_left*(ww+bw),
  159. X                    fh+3*bw+wh1+wh2,ww,
  160. X                    wh3,bw,black,white);
  161. X    wind[automark_wind]    = XCreateSimpleWindow(disp,frame,
  162. X                    bonus_wind*(ww+bw),
  163. X                    fh+3*bw+wh1+wh2,ww,
  164. X                    wh3,bw,black,white);
  165. X    wind[lives_left]    = XCreateSimpleWindow(disp,frame,
  166. X                    0,fh+3*bw+wh1+wh2,ww,
  167. X                    wh3,bw,black,white);
  168. X
  169. X    /* create last button row */
  170. X/* These are for future expansion
  171. X    wind[]            = XCreateSimpleWindow(disp,frame,
  172. X                    rank*(ww+bw),
  173. X                    fh+4*bw+wh1+wh2+wh3,
  174. X                    w-2*bw-(rank)*(ww+bw),
  175. X                    wh4,bw,black,white);
  176. X    wind[]            = XCreateSimpleWindow(disp,frame,
  177. X                    grenades_left*(ww+bw),
  178. X                    fh+4*bw+wh1+wh2+wh3,ww,
  179. X                    wh4,bw,black,white);
  180. X*/
  181. X    wind[pause_wind]    = XCreateSimpleWindow(disp,frame,
  182. X                    score*(ww+bw),
  183. X                    fh+4*bw+wh1+wh2+wh3,ww,
  184. X                    wh4,bw,black,white);
  185. X    wind[sanitycheck_wind]    = XCreateSimpleWindow(disp,frame,
  186. X                    time_left*(ww+bw),
  187. X                    fh+4*bw+wh1+wh2+wh3,ww,
  188. X                    wh4,bw,black,white);
  189. X    wind[eautomark_wind]    = XCreateSimpleWindow(disp,frame,
  190. X                    bonus_wind*(ww+bw),
  191. X                    fh+4*bw+wh1+wh2+wh3,ww,
  192. X                    wh4,bw,black,white);
  193. X    wind[refresh_wind]    = XCreateSimpleWindow(disp,frame,
  194. X                    0,fh+4*bw+wh1+wh2+wh3,ww,
  195. X                    wh4,bw,black,white);
  196. X
  197. X    /* set window and icon names */
  198. X    XStoreName(disp,frame,"xtmines");
  199. X    XSetIconName(disp,frame,"xtmines");
  200. X
  201. X    /* Map all windows to screen */
  202. X    XMapRaised(disp,frame);
  203. X    XMapRaised(disp,field);
  204. X    XMapRaised(disp,wind[bombs_left]);
  205. X    XMapRaised(disp,wind[bonus_wind]);
  206. X    XMapRaised(disp,wind[time_left]);
  207. X    XMapRaised(disp,wind[score]);
  208. X    XMapRaised(disp,wind[grenades_left]);
  209. X    XMapRaised(disp,wind[rank]);
  210. X    XMapRaised(disp,wind[quit_wind]);
  211. X    XMapRaised(disp,wind[show_wind]);
  212. X    XMapRaised(disp,wind[tgrenade_wind]);
  213. X    XMapRaised(disp,wind[giveup_wind]);
  214. X    XMapRaised(disp,wind[automark_wind]);
  215. X    XMapRaised(disp,wind[lives_left]); 
  216. X    XMapRaised(disp,wind[pause_wind]); 
  217. X    XMapRaised(disp,wind[sanitycheck_wind]); 
  218. X    XMapRaised(disp,wind[eautomark_wind]); 
  219. X    XMapRaised(disp,wind[refresh_wind]); 
  220. X    XMapRaised(disp,wind[status]);
  221. X
  222. X    /*---Now initialize all bitmaps and accompanying dimensions---*/
  223. X    
  224. X    /* load all bitmaps into memory */
  225. X    bitmap[bm_safe]        = XCreateBitmapFromData(disp,field, 
  226. X                    safe_bits,safe_width,safe_height);
  227. X    bitmap[bm_man]        = XCreateBitmapFromData(disp,field,
  228. X                    man_bits,man_width,man_height);
  229. X    bitmap[bm_bomb]        = XCreateBitmapFromData(disp,field,
  230. X                    bomb_bits,bomb_width,bomb_height);
  231. X    bitmap[bm_tombstone]    = XCreateBitmapFromData(disp,field,
  232. X                    tstone_bits,tstone_width,tstone_height);
  233. X    bitmap[bm_goal]        = XCreateBitmapFromData(disp,field,
  234. X                    goal_bits,goal_width,goal_height);
  235. X    bitmap[bm_trail]    = XCreateBitmapFromData(disp,field,
  236. X                    trail_bits,trail_width,trail_height);
  237. X    bitmap[bm_pow]        = XCreateBitmapFromData(disp,field,
  238. X                    pow_bits,pow_width,pow_height);
  239. X    bitmap[bm_bombmark]    = XCreateBitmapFromData(disp,field,
  240. X                    bombmark_bits,bombmark_width,
  241. X                    bombmark_height);
  242. X    bitmap[bm_safewrong]    = XCreateBitmapFromData(disp,field,
  243. X                    safewrong_bits,safewrong_width,
  244. X                    safewrong_height);
  245. X    bitmap[bm_bombmarkwrong]= XCreateBitmapFromData(disp,field,
  246. X                    bombmarkwrong_bits,bombmarkwrong_width,
  247. X                    bombmarkwrong_height);
  248. X
  249. X    /* put all bitmap dimensions into width and height arrays */
  250. X    bmwidth[bm_safe]    = safe_width;
  251. X    bmwidth[bm_man]        = man_width;
  252. X    bmwidth[bm_bomb]    = bomb_width;
  253. X    bmwidth[bm_tombstone]    = tstone_width;
  254. X    bmwidth[bm_goal]    = goal_width;
  255. X    bmwidth[bm_trail]    = trail_width;
  256. X    bmwidth[bm_pow]        = pow_width;
  257. X    bmwidth[bm_bombmark]    = bombmark_width;
  258. X    bmwidth[bm_safewrong]    = safewrong_width;
  259. X    bmwidth[bm_bombmarkwrong]    = bombmarkwrong_width;
  260. X
  261. X    bmheight[bm_safe]    = safe_height;
  262. X    bmheight[bm_man]    = man_height;
  263. X    bmheight[bm_bomb]    = bomb_height;
  264. X    bmheight[bm_tombstone]    = tstone_height;
  265. X    bmheight[bm_goal]    = goal_height;
  266. X    bmheight[bm_trail]    = trail_height;
  267. X    bmheight[bm_pow]    = pow_height;
  268. X    bmheight[bm_bombmark]    = bombmark_height;
  269. X    bmheight[bm_safewrong]    = safewrong_height;
  270. X    bmheight[bm_bombmarkwrong]    = bombmarkwrong_height;
  271. X}
  272. X
  273. X/* create_GC_colormap:  set up Graphics Contexts and colormaps             */
  274. X/*                      right now, there are only 2 colors (black & white) */
  275. Xvoid create_GC_colormap()
  276. X{
  277. X    XGCValues    gcv;    /* to determine attributes to set */
  278. X    XColor        exact;    /* used by XAllocNamedColor;     */
  279. X                /*    return value is never used */
  280. X    
  281. X    /* set up gcs -- GC for status line and showfig */
  282. X    gcv.font = fonts;
  283. X    gcv.line_width = 1;
  284. X    gcv.graphics_exposures = FALSE;
  285. X    gcs     = XCreateGC(disp,frame,
  286. X            GCFont | GCLineWidth | GCGraphicsExposures,
  287. X            &gcv);
  288. X
  289. X    /* set up gcm -- GC for main (most text) */
  290. X    gcv.font = fontm;
  291. X    gcv.line_width = 1;
  292. X    gcv.graphics_exposures = FALSE;
  293. X    gcm     = XCreateGC(disp,frame,
  294. X            GCFont | GCLineWidth | GCGraphicsExposures,
  295. X            &gcv);
  296. X
  297. X    /* set up gct -- GC for time and hiscores list */
  298. X    gcv.font = fontt;
  299. X    gcv.line_width = 1;
  300. X    gcv.graphics_exposures = FALSE;
  301. X    gct     = XCreateGC(disp,frame,
  302. X            GCFont | GCLineWidth | GCGraphicsExposures,
  303. X            &gcv);
  304. X
  305. X    /* Set up colormap */
  306. X    cmap     = XDefaultColormap(disp,screen);
  307. X    XAllocNamedColor(disp,cmap,FONTCOLOR,&color[font_color],&exact);
  308. X    XAllocNamedColor(disp,cmap,BACKGROUNDCOLOR,&color[background_color],
  309. X        &exact);
  310. X    XAllocNamedColor(disp,cmap,FIELDCOLOR,&color[field_color],
  311. X        &exact);
  312. X}
  313. X
  314. X/* set_event_masks:  all event masks are set here */
  315. Xvoid set_event_masks()
  316. X{
  317. X    int i;
  318. X    windtype windownum;
  319. X
  320. X    /* set exposure mask for all windows */
  321. X    XSelectInput(disp,frame,ExposureMask);
  322. X    for (windownum=0;windownum<NUMWINDS;windownum++)
  323. X        XSelectInput(disp,wind[windownum],ExposureMask);
  324. X
  325. X    /* check to see if quit */
  326. X    XSelectInput(disp,wind[quit_wind],ButtonPressMask|ExposureMask);
  327. X
  328. X    /* check to see if toggle show */
  329. X    XSelectInput(disp,wind[show_wind],ButtonPressMask|ExposureMask);
  330. X
  331. X    /* check to see if throw grenades */
  332. X    XSelectInput(disp,wind[tgrenade_wind],ButtonPressMask|ExposureMask);
  333. X
  334. X    /* check to see if give up */
  335. X    XSelectInput(disp,wind[giveup_wind],ButtonPressMask|ExposureMask);
  336. X
  337. X    /* check to see if toggle automark */
  338. X    XSelectInput(disp,wind[automark_wind],ButtonPressMask|ExposureMask);
  339. X
  340. X    /* check to see if toggle pause */
  341. X    XSelectInput(disp,wind[pause_wind],ButtonPressMask|ExposureMask);
  342. X
  343. X    /* check to see if toggle sanity check */
  344. X    XSelectInput(disp,wind[sanitycheck_wind],ButtonPressMask|ExposureMask);
  345. X
  346. X    /* check to see if toggle extended_automark */
  347. X    XSelectInput(disp,wind[eautomark_wind],ButtonPressMask|ExposureMask);
  348. X
  349. X    /* check to see if refresh */
  350. X    XSelectInput(disp,wind[refresh_wind],ButtonPressMask|ExposureMask);
  351. X
  352. X    /* allow mouse button and key presses in field */
  353. X    XSelectInput(disp,field,KeyPressMask|ButtonPressMask|ExposureMask);
  354. X}
  355. X
  356. X/* init_values:  called at the beginning of every level      */
  357. X/*               sets num_bombs_left, num_time_left_at_start */
  358. X/*                    num_time_left, used_showfig,           */
  359. X/*                    used_sanity, used_eautomark            */
  360. Xint    num_bombs_at_start[NUMRANKS];
  361. Xvoid init_values()
  362. X{
  363. X    num_bombs_at_start[grunt]    = 50;
  364. X    num_bombs_at_start[corporal]    = 100;
  365. X    num_bombs_at_start[lieutenant]    = 150;
  366. X    num_bombs_at_start[captain]    = 200;
  367. X    num_bombs_at_start[mmajor]    = 250;
  368. X    num_bombs_at_start[general]    = 300;
  369. X    num_bombs_at_start[president]    = 350;
  370. X    num_bombs_at_start[king]    = 400;
  371. X    num_bombs_at_start[emperor]    = 450;
  372. X    num_bombs_at_start[angel]    = 500;
  373. X
  374. X    num_tombstones        = 0;
  375. X    num_bombs_left        = num_bombs_at_start[level];
  376. X    num_time_left_at_start    = SECONDS_PER_LEVEL*(level+1);
  377. X    num_time_left        = num_time_left_at_start;
  378. X    pause_time        = 0;
  379. X    used_showfig        = (show==sh_fig) ? TRUE : FALSE;
  380. X    used_sanity        = (sanity) ? TRUE : FALSE;
  381. X    used_eautomark        = (extended_automark) ? TRUE : FALSE;
  382. X
  383. X    num_bonus        = current_bonus();
  384. X}
  385. X
  386. X/* illegal_bomb_position:  input a virtual field position             */
  387. X/*                         output a boolean=is bomb allowed here?     */
  388. X/*                         illegal is more than two bombs around goal */
  389. X/*                                    4 most top-left squares         */
  390. Xint illegal_bomb_position(vx,vy)
  391. Xint vx,vy;
  392. X{
  393. X    int    num_bombs_around_goal;
  394. X
  395. X    /* find how many of the 3 squares around the goal has bombs */
  396. X    num_bombs_around_goal =
  397. X        (FIELD[NUMCOLS-1][NUMROWS-2].c==fc_bomb) +
  398. X        (FIELD[NUMCOLS-2][NUMROWS-2].c==fc_bomb) +
  399. X        (FIELD[NUMCOLS-2][NUMROWS-1].c==fc_bomb);
  400. X
  401. X    /* check to see if 4 most top-left squares are free */ 
  402. X    if (((vx==0) && (vy==0)) || ((vx==0) && (vy==1)) ||
  403. X        ((vx==1) && (vy==0)) || ((vx==1) && (vy==1)) ||
  404. X        ((vx==NUMCOLS-1) && (vy==NUMROWS-1)) ||
  405. X        (FIELD[vx][vy].c==fc_bomb) ||
  406. X        ((((vx==NUMCOLS-1) && (vy=NUMROWS-2)) ||
  407. X          ((vx==NUMCOLS-2) && (vy=NUMROWS-2)) ||
  408. X          ((vx==NUMCOLS-2) && (vy=NUMROWS-1))) &&
  409. X         (num_bombs_around_goal==2)))
  410. X        return (TRUE);
  411. X    else
  412. X        return (FALSE);
  413. X}
  414. X
  415. X/* blocked:  returns a boolean indicating whether a continuous line of bombs */
  416. X/*              from square vx,vy (where vx,vy is on top or right edge) to   */
  417. X/*              the bottom or left edge of the field.  If so, then return    */
  418. X/*              TRUE, else return FALSE.  As each */
  419. Xint blocked(vx,vy)
  420. Xint vx,vy;
  421. X{
  422. X    /* marked as safe means that square has already been looked at */
  423. X    if (FIELD[vx][vy].m == fm_safe)
  424. X        return (FALSE);        /* square has already been looked at */
  425. X    else
  426. X        FIELD[vx][vy].m = fm_safe;    
  427. X                    /* else mark square as having */
  428. X                    /*    been looked at          */
  429. X
  430. X    if (FIELD[vx][vy].c != fc_bomb)
  431. X        return (FALSE);        /* square has no bomb; thus, */
  432. X                    /*    no path through here   */
  433. X    else {
  434. X        if ((vx==0) || (vy==NUMROWS-1))
  435. X           return (TRUE);    /* we have reached the bottom or */
  436. X                    /*    left edge and found a bomb */
  437. X        if ((vy>0) && (FIELD[vx][vy-1].m==fm_nomark) &&
  438. X            (blocked(vx,vy-1)))
  439. X                return (TRUE);
  440. X        if ((vy<NUMROWS-1) && (FIELD[vx][vy+1].m==fm_nomark) &&
  441. X            (blocked(vx,vy+1)))
  442. X                return (TRUE);
  443. X        if ((vx>0) && (FIELD[vx-1][vy].m==fm_nomark) &&
  444. X            (blocked(vx-1,vy)))
  445. X                return (TRUE);
  446. X        if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].m==fm_nomark) &&
  447. X            (blocked(vx+1,vy)))
  448. X                return (TRUE);
  449. X
  450. X        /* if we got this far, then there are no path of bombs */
  451. X        /*    through this square;  thus, return not blocked   */
  452. X        return (FALSE);
  453. X    } /* else FIELD[vx][vy] == fc_bomb */
  454. X}
  455. X
  456. X/* guaranteed_path:  returns a boolean indicating whether there is a path     */
  457. X/*                      through the from start to goal without using grenades */
  458. X/*                   all field contents must be set first                     */
  459. X/*                   all field marks must be cleared first                    */
  460. Xint guaranteed_path()
  461. X{
  462. X    int    c,r;    /* current column and row being considered */
  463. X
  464. X    for (c=1;c<NUMCOLS;c++)        /* c=1, skip starting square */
  465. X        if (blocked(c,0))
  466. X            return (FALSE);    /* no path from start to finish */
  467. X    for (r=0;r<NUMROWS-1;r++)    /* NUMROWS-1, skip goal square */
  468. X        if (blocked(NUMCOLS-1,r))
  469. X            return (FALSE);    /* no path from start to finish */
  470. X
  471. X    return (TRUE);            /* else there is a guaranteed path */
  472. X}
  473. X
  474. X/* manvx, manvy:  current virtual man position on field */
  475. Xint    manvx,manvy;
  476. X
  477. X/* set_field:  will put the appropriate number of bombs in field */
  478. X/*                according to level (makes sure that no illegal */
  479. X/*                squares have bombs                             */
  480. X/*             places man in top-left corner                     */
  481. X/*             places goal in bottom-right corner                */
  482. X/*             guarantees that there is a path from start to end */
  483. X/*                by repeating until that is true                */
  484. Xvoid set_field()
  485. X{
  486. X    int    c,r,    /* column and row for clearing field */
  487. X        i;    /* counter for number of bombs */
  488. X            /*    placed so far            */
  489. X    int    vx,vy;    /* current bomb position being considered */
  490. X
  491. X    do {
  492. X        /* first clear the entire field of all contents and marks */
  493. X        for (c=0;c<NUMCOLS;c++)
  494. X           for (r=0;r<NUMROWS;r++) {
  495. X            FIELD[c][r].c = fc_empty;    /* clear contents */
  496. X            FIELD[c][r].m = fm_nomark;    /* clear marks */
  497. X            clear(c,r);            /* erase bitmaps */
  498. X           }
  499. X
  500. X        /* put man in top-left corner */
  501. X        FIELD[0][0].c = fc_man;
  502. X        manvx = 0; manvy = 0;
  503. X
  504. X        /* place bombs in field */
  505. X        for (i=0;i<num_bombs_at_start[level];i++) {
  506. X           do {
  507. X            vx = random()%NUMCOLS;
  508. X            vy = random()%NUMROWS;
  509. X           } while (illegal_bomb_position(vx,vy));
  510. X           FIELD[vx][vy].c = fc_bomb;
  511. X        }
  512. X
  513. X        /* place goal in bottom-right corner */
  514. X        FIELD[NUMCOLS-1][NUMROWS-1].c = fc_goal;
  515. X
  516. X    } while (!guaranteed_path());
  517. X
  518. X    /* now clear all marks from field */
  519. X    for (c=0;c<NUMCOLS;c++)
  520. X       for (r=0;r<NUMROWS;r++)
  521. X        FIELD[c][r].m = fm_nomark;      /* clear marks */
  522. X}
  523. END_OF_FILE
  524. if test 16843 -ne `wc -c <'init.c'`; then
  525.     echo shar: \"'init.c'\" unpacked with wrong size!
  526. fi
  527. # end of 'init.c'
  528. fi
  529. if test -f 'play.c' -a "${1}" != "-c" ; then 
  530.   echo shar: Will not clobber existing file \"'play.c'\"
  531. else
  532. echo shar: Extracting \"'play.c'\" \(29521 characters\)
  533. sed "s/^X//" >'play.c' <<'END_OF_FILE'
  534. X/* xtmines: game where you try to cross a minefield */
  535. X/* play.c: */
  536. X/* Written by Timothy Tsai  April 13, 1992 */
  537. X
  538. X#include "xtmines.h"
  539. X
  540. X/* This is a kludge for systems without usleep() */
  541. X#ifdef NOUSLEEP
  542. X#define USLEEP_LOOPS    15000
  543. Xvoid usleep(usecs)
  544. Xunsigned usecs;
  545. X{
  546. X    int    i;
  547. X    for (i=0;i<USLEEP_LOOPS;i++);
  548. X}
  549. X#endif
  550. X
  551. Xvoid PrintStr(window,str)
  552. Xwindtype window;
  553. Xchar *str;
  554. X{
  555. X    unsigned int    ww,wh;    /* get width and height of window */
  556. X    unsigned int    wbw;    /*     border width               */
  557. X    Font        font;
  558. X    XFontStruct    *fs;
  559. X    Window        a;
  560. X    int        b,c;    /* dummy vars */
  561. X    unsigned int    e;    /* dummy vars */
  562. X    GC        gc;
  563. X
  564. X    gc = (window==status) ? gcs : (window==time_left) ? gct : gcm;
  565. X    XSetForeground(disp,gc,color[font_color].pixel);
  566. X    XSetBackground(disp,gc,color[background_color].pixel);
  567. X    XGetGeometry(disp,wind[window],&a,&b,&c,&ww,&wh,&wbw,&e);
  568. X    fs = (window==status) ? fontsstruct : 
  569. X         (window==time_left) ? fonttstruct : fontmstruct;
  570. X    XDrawImageString(disp,wind[window],gc,
  571. X        ((ww-2*wbw)-XTextWidth(fs,str,strlen(str)))/2,
  572. X        (wh - fs->ascent - fs->descent)/2 +
  573. X            fs->ascent,str,strlen(str));
  574. X    XFlush(disp);
  575. X}
  576. X
  577. Xvoid InvPrintStr(window,str)
  578. Xwindtype window;
  579. Xchar *str;
  580. X{
  581. X    unsigned int    ww,wh;    /* get width and height of window */
  582. X    unsigned int    wbw;    /*     border width               */
  583. X    Font        font;
  584. X    XFontStruct    *fs;
  585. X    Window        a;
  586. X    int        b,c;    /* dummy vars */
  587. X    unsigned int    e;    /* dummy vars */
  588. X    GC        gc;
  589. X
  590. X    gc = (window==status) ? gcs : (window==time_left) ? gct : gcm;
  591. X    XSetForeground(disp,gc,color[background_color].pixel);
  592. X    XSetBackground(disp,gc,color[font_color].pixel);
  593. X    XGetGeometry(disp,wind[window],&a,&b,&c,&ww,&wh,&wbw,&e);
  594. X    fs = (window==status) ? fontsstruct : 
  595. X         (window==time_left) ? fonttstruct : fontmstruct;
  596. X    XDrawImageString(disp,wind[window],gc,
  597. X        ((ww-2*wbw)-XTextWidth(fs,str,strlen(str)))/2,
  598. X        (wh - fs->ascent - fs->descent)/2 +
  599. X            fs->ascent,str,strlen(str));
  600. X    XFlush(disp);
  601. X}
  602. X
  603. Xvoid WindPrint(window,str)
  604. Xwindtype window;
  605. Xchar *str;
  606. X{
  607. X    XClearWindow(disp,wind[window]);
  608. X    PrintStr(window,str);
  609. X}
  610. X
  611. Xchar *num_rank_to_words(num_rank)
  612. Xranktype num_rank;
  613. X{
  614. X    switch (num_rank) {
  615. X        case grunt    : return ("grunt"); break;
  616. X        case corporal    : return ("corporal"); break;
  617. X        case lieutenant    : return ("lieutenant"); break;
  618. X        case captain    : return ("captain"); break;
  619. X        case mmajor    : return ("major"); break;
  620. X        case general    : return ("general"); break;
  621. X        case president    : return ("president"); break;
  622. X        case king    : return ("king"); break;
  623. X        case emperor    : return ("emperor"); break;
  624. X        case angel    : return ("angel"); break;
  625. X        case god    : return ("god"); break;
  626. X        default        : fprintf(stderr,"Error: Illegal rank\n");
  627. X                  exit(2);
  628. X    }
  629. X}
  630. X
  631. Xchar    last_status_str[MAXSTRLEN];
  632. Xvoid print_status(str)
  633. Xchar *str;
  634. X{
  635. X
  636. X    strcpy(last_status_str,str);
  637. X    WindPrint(status,str);
  638. X}
  639. X
  640. Xchar    *clock_time_str(time)
  641. Xint time;
  642. X{
  643. X    int        h,m,s;
  644. X    static char    str[MAXSTRLEN];
  645. X
  646. X    h = time/3600;
  647. X    m = (time-(h*3600))/60;
  648. X    s = (time-(h*3600)-(m*60));
  649. X    if (h != 0)
  650. X        sprintf(str,"%d:%02d:%02d",h,m,s);
  651. X    else if (m != 0)
  652. X        sprintf(str,"%d:%02d",m,s);
  653. X    else
  654. X        sprintf(str,"%d",s);
  655. X    return (str);
  656. X}
  657. X
  658. Xvoid print_display()
  659. X{
  660. X    char        str[MAXSTRLEN];
  661. X
  662. X    sprintf(str,"Bombs: %d",num_bombs_left);
  663. X    WindPrint(bombs_left,str);
  664. X
  665. X    sprintf(str,"Bonus: %d",num_bonus);
  666. X    WindPrint(bonus_wind,str);
  667. X
  668. X    sprintf(str,"Time: %s",clock_time_str(num_time_left));
  669. X    WindPrint(time_left,str);
  670. X
  671. X    sprintf(str,"Score: %d",num_score);
  672. X    WindPrint(score,str);
  673. X
  674. X    sprintf(str,"Grenades: %d",num_grenades_left);
  675. X    WindPrint(grenades_left,str);
  676. X
  677. X    sprintf(str,"Rank: %s",num_rank_to_words(level));
  678. X    WindPrint(rank,str);
  679. X
  680. X    WindPrint(quit_wind,"Quit");
  681. X
  682. X    if (used_showfig)
  683. X        sprintf(str,"Show = *%s", (show==sh_man) ? "man" : "fig");
  684. X    else
  685. X        sprintf(str,"Show = %s", (show==sh_man) ? "man" : "fig");
  686. X    WindPrint(show_wind,str);
  687. X
  688. X    WindPrint(tgrenade_wind,"Throw Grenade");
  689. X
  690. X    WindPrint(giveup_wind,"Surrender");
  691. X
  692. X    sprintf(str,"Automark = %s",automark ? "on" : "off");
  693. X    WindPrint(automark_wind,str);
  694. X
  695. X    sprintf(str,"Lives: %d",num_lives);
  696. X    WindPrint(lives_left,str);
  697. X
  698. X    WindPrint(pause_wind,"Pause");
  699. X
  700. X    if (used_sanity)
  701. X        sprintf(str,"Sanity = *%s",sanity ? "on" : "off");
  702. X    else
  703. X        sprintf(str,"Sanity = %s",sanity ? "on" : "off");
  704. X    WindPrint(sanitycheck_wind,str);
  705. X
  706. X    if (used_eautomark)
  707. X        sprintf(str,"ExtAmark = *%s",extended_automark ? "on" : "off");
  708. X    else
  709. X        sprintf(str,"ExtAmark = %s",extended_automark ? "on" : "off");
  710. X    WindPrint(eautomark_wind,str);
  711. X
  712. X    WindPrint(refresh_wind,"Refresh");
  713. X
  714. X    WindPrint(status,last_status_str);
  715. X
  716. X    XFlush(disp);
  717. X}
  718. X
  719. XPixmap bitmap[NUMBITMAPS];
  720. Xint bmwidth[NUMBITMAPS];
  721. Xint bmheight[NUMBITMAPS];
  722. X/* This function will draw the bitmap indicated by bm in the field at the */
  723. X/*   position (vx,vy).  If show==sh_fig, then a figure will be drawn      */
  724. X/*   instead of the man bitmap.  The figure is the number of surrounding  */
  725. X/*   bombs.  The font for figures is the same as the font for the status. */
  726. Xvoid draw(bm,vx,vy)
  727. Xbmtype bm;
  728. Xint vx,vy;
  729. X{
  730. X    int    x,y;
  731. X    int    numbombs;
  732. X    char    str[2];
  733. X
  734. X    setxy(vx,vy,&x,&y);
  735. X    if ((bm==bm_man) && (show==sh_fig)) {
  736. X       clear(vx,vy);
  737. X       numbombs = bomb_status(vx,vy);
  738. X       str[0] = '0' + numbombs; str[1]=NULL;
  739. X       XDrawString(disp,field,gcs,
  740. X        1+vx*(man_width+1)+(man_width-fontshoww)/2,
  741. X        1+vy*(man_height+1)+(man_height-fontshowa)/2+fontshowa,
  742. X        str,strlen(str));
  743. X    }
  744. X    else
  745. X       XCopyPlane(disp,bitmap[bm],field,gcm,0,0,bmwidth[bm],bmheight[bm],
  746. X        x+1,y+1,1);
  747. X    XFlush(disp);
  748. X}
  749. X
  750. Xvoid clear(vx,vy)
  751. Xint vx,vy;
  752. X{
  753. X    int    x,y;
  754. X
  755. X    setxy(vx,vy,&x,&y);
  756. X    XClearArea(disp,field,x+1,y+1,bmwidth[bm_man],bmwidth[bm_safe],FALSE);
  757. X}
  758. X
  759. Xfieldstruct FIELD[NUMCOLS][NUMROWS];
  760. Xvoid draw_field()
  761. X{
  762. X    int    r,c;
  763. X    double    rowsep,colsep;
  764. X
  765. X    /* draw vertical lines */
  766. X    colsep = ((double)(w-2*bw)/(double)NUMCOLS);
  767. X    for (c=0; c<NUMCOLS; c++) {
  768. X        XSetForeground(disp,gcm,color[field_color].pixel);
  769. X        XSetBackground(disp,gcm,color[background_color].pixel);
  770. X        XDrawLine(disp,field,gcm,(int)(c*colsep),0,(int)(c*colsep),fh);
  771. X    }
  772. X
  773. X    /* draw horizontal lines */
  774. X    rowsep = ((double)fh/(double)NUMROWS);
  775. X    for (r=0; r<NUMROWS; r++) {
  776. X        XSetForeground(disp,gcm,color[field_color].pixel);
  777. X        XSetBackground(disp,gcm,color[background_color].pixel);
  778. X        XDrawLine(disp,field,gcm,0,(int)(r*rowsep),w,(int)(r*rowsep));
  779. X    }
  780. X
  781. X    /* draw contents */
  782. X    for (c=0;c<NUMCOLS;c++)
  783. X        for (r=0;r<NUMROWS;r++)
  784. X            if (FIELD[c][r].m==fm_safe)
  785. X                draw(bm_safe,c,r);
  786. X            else if (FIELD[c][r].m==fm_bomb)
  787. X                draw(bm_bombmark,c,r);
  788. X            else switch (FIELD[c][r].c) {
  789. X                case fc_empty    : break;
  790. X                case fc_man    : draw(bm_man,c,r); break;
  791. X                case fc_bomb    : if (dead)
  792. X                            draw(bm_bomb,c,r);
  793. X                          break;
  794. X                case fc_tombstone
  795. X                        : draw(bm_tombstone,c,r); break;
  796. X                case fc_goal    : draw(bm_goal,c,r); break;
  797. X                case fc_trail    : draw(bm_trail,c,r); break;
  798. X                default        : fprintf(stderr,
  799. X                    "Error: Illegal FIELD content\n");
  800. X                    exit(1);
  801. X            }
  802. X    XFlush(disp);
  803. X}
  804. X
  805. X/* remove all Exposure events from the events queue; return the number
  806. X   of actual events removed */
  807. Xint remove_expose_events()
  808. X{
  809. X    int    r=0;        /* number of events removed so far */
  810. X    XEvent    event;        /* not used */
  811. X
  812. X    while (XCheckMaskEvent(disp,ExposureMask,&event))
  813. X        r++;
  814. X    return (r);
  815. X}
  816. X
  817. Xvoid refresh()
  818. X{
  819. X    XEvent        event;
  820. X    int        done=FALSE;    /* finished dequeuing all exposes? */
  821. X
  822. X    print_display();
  823. X    draw_field();
  824. X    draw(bm_man,manvx,manvy);
  825. X    XFlush(disp);
  826. X
  827. X    /* now dequeue all immediately succeeding exposure events */
  828. X    /*    to prevent multiple, useless refreshes              */
  829. X    remove_expose_events();
  830. X}
  831. X
  832. X/* set up windows for pausing;  the field should be blanked to prevent
  833. X   cheating;  the time should be adjusted so there is no penalty for pausing;
  834. X*/
  835. Xint do_pause()
  836. X{
  837. X    int        time_at_start_of_pause;
  838. X
  839. X    char        str[MAXSTRLEN];
  840. X    unsigned int    ww,wh;    /* get width and height of window */
  841. X    unsigned int    wbw;    /*     border width               */
  842. X    XFontStruct    *fs;
  843. X    Window        a;
  844. X    int        b,c;    /* dummy vars */
  845. X    unsigned int    e;    /* dummy vars */
  846. X
  847. X    int            wait=TRUE;
  848. X    XEvent            event;
  849. X    XButtonPressedEvent    *eventbp;
  850. X    XKeyPressedEvent    *eventkp;
  851. X    KeySym            ksym;
  852. X    char            s;
  853. X    int            done;
  854. X
  855. X    WindPrint(pause_wind,"Continue");
  856. X    time_at_start_of_pause = time(0);
  857. X
  858. X    /* blank out field and write "P-A-U-S-E" message on field */
  859. X    XClearWindow(disp,field);
  860. X    strcpy(str,"P-A-U-S-E");
  861. X    XSetForeground(disp,gcs,color[font_color].pixel);
  862. X    XSetBackground(disp,gcs,color[background_color].pixel);
  863. X    XGetGeometry(disp,field,&a,&b,&c,&ww,&wh,&wbw,&e);
  864. X    fs = fontsstruct;
  865. X    XDrawImageString(disp,field,gcs,
  866. X        ((ww-2*wbw)-XTextWidth(fs,str,strlen(str)))/2,
  867. X        (wh - fs->ascent - fs->descent)/2 +
  868. X            fs->ascent,str,strlen(str));
  869. X    XFlush(disp);
  870. X
  871. X    /* Wait for keypress or button click to signal done with pause */
  872. X    while (wait == TRUE) {
  873. X       while (!XPending(disp))
  874. X        usleep(XPENDING_UDELAY);
  875. X       XNextEvent(disp,&event);
  876. X       if (event.type==ButtonPress) {
  877. X        eventbp = (XButtonPressedEvent *) &event;
  878. X        if (eventbp->window == wind[pause_wind])
  879. X                    wait = FALSE;
  880. X       }
  881. X       else if (event.type == KeyPress) {
  882. X        eventkp = (XKeyPressedEvent *) &event;
  883. X        XLookupString(&event,&s,1,&ksym,NULL);
  884. X        if ((s == 'c') || (s == 'C'))
  885. X            wait = FALSE;
  886. X       }
  887. X       else if (event.type == Expose) {
  888. X       /* do refresh in pause mode; pause_wind and field are different */
  889. X        print_display();
  890. X        WindPrint(pause_wind,"Continue");
  891. X        sprintf(str,"Time: %s",clock_time_str(
  892. X            num_time_left_at_start-
  893. X            (time_at_start_of_pause-time_at_start_of_level
  894. X                           -pause_time)));
  895. X        WindPrint(time_left,str);
  896. X
  897. X        /* blank out field and write "P-A-U-S-E" message on field */
  898. X        WindPrint(pause_wind,"Continue");
  899. X        XClearWindow(disp,field);
  900. X        strcpy(str,"P-A-U-S-E");
  901. X        XSetForeground(disp,gcs,color[font_color].pixel);
  902. X        XSetBackground(disp,gcs,color[background_color].pixel);
  903. X        XGetGeometry(disp,field,&a,&b,&c,&ww,&wh,&wbw,&e);
  904. X        fs = fontsstruct;
  905. X        XDrawImageString(disp,field,gcs,
  906. X            ((ww-2*wbw)-XTextWidth(fs,str,strlen(str)))/2,
  907. X            (wh - fs->ascent - fs->descent)/2 +
  908. X                fs->ascent,str,strlen(str));
  909. X        XFlush(disp);
  910. X    
  911. X        /* now dequeue all immediately succeeding exposure events */
  912. X        /*    to prevent multiple, useless refreshes              */
  913. X        remove_expose_events();
  914. X       }
  915. X    }
  916. X
  917. X    pause_time += time(0) - time_at_start_of_pause;
  918. X
  919. X    /* Restore windows to continue game */
  920. X    XClearWindow(disp,field);
  921. X    refresh();
  922. X
  923. X    WindPrint(pause_wind,"Pause");
  924. X}
  925. X
  926. Xint setxy(vx,vy,x,y)
  927. Xint vx,vy,*x,*y;
  928. X{
  929. X/* convert virtual coordinates to actual field pixel coordinates */
  930. X    double    rowsep,colsep;
  931. X
  932. X    if (((vx>=0) && (vx<NUMCOLS)) &&
  933. X        ((vy>=0) && (vy<NUMROWS))) {
  934. X        colsep = ((double)(w-2*bw)/(double)NUMCOLS);
  935. X        rowsep = ((double)fh/(double)NUMROWS);
  936. X        *x = vx*colsep;
  937. X        *y = vy*rowsep;
  938. X        return (SUCCESS);
  939. X    }
  940. X    else
  941. X        return (OUT_OF_RANGE);
  942. X}
  943. X
  944. Xint setvxvy(x,y,vx,vy)
  945. Xint x,y,*vx,*vy;
  946. X{
  947. X/* convert actual field pixel coordinates to virtual coordinates */
  948. X    double    rowsep,colsep;
  949. X
  950. X    if (((x>=0) && (x<w-2*bw)) &&
  951. X        ((y>=0) && (y<fh))) {
  952. X        colsep = ((double)(w-2*bw)/(double)NUMCOLS);
  953. X        rowsep = ((double)fh/(double)NUMROWS);
  954. X        *vx = x/colsep;
  955. X        *vy = y/rowsep;
  956. X        return (SUCCESS);
  957. X    }
  958. X    else
  959. X        return (OUT_OF_RANGE);
  960. X}
  961. X
  962. Xint bomb_status(vx,vy)
  963. Xint vx,vy;
  964. X{
  965. X    int    numbombs=0;
  966. X
  967. X    if (vy>0) {
  968. X        if ((vx>0) && (FIELD[vx-1][vy-1].c==fc_bomb))
  969. X            numbombs++;
  970. X        if (FIELD[vx][vy-1].c==fc_bomb)
  971. X            numbombs++;
  972. X        if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy-1].c==fc_bomb))
  973. X            numbombs++;
  974. X    }
  975. X    if (vy<NUMROWS-1) {
  976. X        if ((vx>0) && (FIELD[vx-1][vy+1].c==fc_bomb))
  977. X            numbombs++;
  978. X        if (FIELD[vx][vy+1].c==fc_bomb)
  979. X            numbombs++;
  980. X        if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy+1].c==fc_bomb))
  981. X            numbombs++;
  982. X    }
  983. X    if ((vx>0) && (FIELD[vx-1][vy].c==fc_bomb))
  984. X        numbombs++;
  985. X    if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].c==fc_bomb))
  986. X        numbombs++;
  987. X
  988. X    return (numbombs);
  989. X}
  990. X
  991. Xvoid show_bomb_status(vx,vy)
  992. Xint vx,vy;
  993. X{
  994. X    int    numbombs;
  995. X    char    str[MAXSTRLEN];
  996. X
  997. X    numbombs = bomb_status(vx,vy);
  998. X
  999. X    sprintf(str,"%d surrounding bomb%c",numbombs,numbombs==1 ? ' ' : 's');
  1000. X    print_status(str);
  1001. X
  1002. X    if ((automark) && (numbombs==0))
  1003. X        mark_allaround_ok(manvx,manvy,0);
  1004. X} 
  1005. X
  1006. X/* show_all_bombs:  shows all bombs on field   */
  1007. X/*                  if any marks are incorrect */
  1008. X/*                     highlight those squares */
  1009. Xvoid show_all_bombs()
  1010. X{
  1011. X    int    c,r;    /* column and row under consideration */
  1012. X
  1013. X    for (c=0;c<NUMCOLS;c++)
  1014. X       for (r=0;r<NUMROWS;r++)
  1015. X        if (FIELD[c][r].c == fc_bomb)
  1016. X           if (FIELD[c][r].m == fm_safe)
  1017. X            draw(bm_safewrong,c,r);    /* bomb, marked safe */
  1018. X           else
  1019. X            draw(bm_bomb,c,r);    /* bomb, unmarked or correct */
  1020. X        else if (FIELD[c][r].m == fm_bomb)
  1021. X           draw(bm_bombmarkwrong,c,r);    /* no bomb, marked unsafe */
  1022. X}
  1023. X
  1024. Xvoid do_promotion()
  1025. X{
  1026. X        char                    str[MAXSTRLEN];
  1027. X    XEvent            event;
  1028. X        XButtonPressedEvent     *eventbp;
  1029. X        XKeyPressedEvent        *eventkp;
  1030. X        int                     wait = TRUE;
  1031. X
  1032. X    finished = TRUE;
  1033. X    num_score += current_bonus();
  1034. X    printf("Your bonus for reaching the goal at rank %s is\n",
  1035. X        num_rank_to_words(level));
  1036. X    printf("     %5d = %d*%d \t (level*Time left)\n",
  1037. X        current_bonus(),level+1,num_time_left);
  1038. X    if (num_bombs_left>0)
  1039. X        printf("           + %d    \t (Num bombs left)\n",
  1040. X        num_bombs_left);
  1041. X    if (num_grenades_left>0)
  1042. X        printf("           + %d*%d \t (Num grenades left*ppg)\n",
  1043. X        num_grenades_left,POINTS_PER_GRENADE);
  1044. X    if (num_tombstones>0)
  1045. X        printf("           - %d*%d \t (Num tombstones*ppts)\n",
  1046. X        num_tombstones,POINTS_PER_TOMBSTONE);
  1047. X/* This used to be used for ver 1.0
  1048. X    if (used_showfig)
  1049. X        printf("           - %d \t (Used showfig?)\n",
  1050. X        POINTS_FOR_USED_SHOWFIG);
  1051. X*/
  1052. X    if (used_sanity)
  1053. X        printf("           - %d \t (Used sanity check?)\n",
  1054. X        (PERCENT_FOR_USED_SANITY*bonus_without_penalties())/100);
  1055. X    if (used_eautomark)
  1056. X        printf("           - %d \t (Used extended_automark?)\n",
  1057. X        (PERCENT_FOR_USED_EAUTOMARK*bonus_without_penalties())/100);
  1058. X    printf("Your current score is %d = %d + %d\n",
  1059. X        num_score,num_score-current_bonus(),current_bonus());
  1060. X
  1061. X    show_all_bombs();
  1062. X
  1063. X    /* now update score on screen incrementally */
  1064. X    {
  1065. X        int i;
  1066. X        /* this will make sure that at most 100 steps are made */
  1067. X        int step = current_bonus()/100;
  1068. X
  1069. X        for (i=num_score-current_bonus();i<num_score;i+=step) {
  1070. X            sprintf(str,"Score: %d",i);
  1071. X            PrintStr(score,str);
  1072. X        }
  1073. X        sprintf(str,"Score: %d",num_score);
  1074. X        WindPrint(score,str);
  1075. X    }
  1076. X
  1077. X    if (level == HIGHEST_PLAYABLE_RANK) {
  1078. X       sprintf(str,
  1079. X       "Congratulations, you have reached completed the highest rank!");
  1080. X       level++;
  1081. X       show_and_add_scores();
  1082. X    }
  1083. X    else
  1084. X       sprintf(str,"Congratulations, you have been promoted to %s",
  1085. X        num_rank_to_words(level+1));
  1086. X    print_status(str);
  1087. X
  1088. X    /* reward additional lives and grenades */
  1089. X    if ((level>=LOWEST_LEVEL_FOR_REWARD) &&
  1090. X        (num_score>=LOWEST_SCORE_FOR_REWARD)) {
  1091. X        if (++num_grenades_left > NUM_GRENADES_AT_START)
  1092. X            num_grenades_left = NUM_GRENADES_AT_START;
  1093. X        sprintf(str,"Grenades: %d",num_grenades_left);
  1094. X        WindPrint(grenades_left,str);
  1095. X        if (++num_lives>MAXLIVES) num_lives=MAXLIVES;
  1096. X        sprintf(str,"Lives: %d",num_lives);
  1097. X        WindPrint(lives_left,str);
  1098. X    }
  1099. X
  1100. X    sleep(3);
  1101. X
  1102. X    print_status ("In the field, press key or click button to continue");
  1103. X    while (wait == TRUE) {
  1104. X       while (!XPending(disp))
  1105. X        usleep(XPENDING_UDELAY);
  1106. X       XNextEvent(disp,&event);
  1107. X       if (event.type==ButtonPress) {
  1108. X        eventbp = (XButtonPressedEvent *) &event;
  1109. X        if (eventbp->window == field)
  1110. X            wait = FALSE;
  1111. X        else if (eventbp->window == wind[quit_wind]) {
  1112. X            level++;
  1113. X            show_and_add_scores();
  1114. X        }
  1115. X       }
  1116. X       else if (event.type == KeyPress) {
  1117. X        eventkp = (XKeyPressedEvent *) &event;
  1118. X        if (eventkp->window == field)
  1119. X            wait = FALSE;
  1120. X       }
  1121. X       else if (event.type == Expose) {
  1122. X        refresh();
  1123. X        show_all_bombs();
  1124. X       }
  1125. X    }
  1126. X}
  1127. X
  1128. X/* next_to_trail:  returns TRUE is at least one of the up to eight adjacent */
  1129. X/*                 squares is already traversed and marked as fc_trail;     */
  1130. X/*                 vx and vy is the square in question                      */
  1131. Xint next_to_trail(vx,vy)
  1132. Xint vx,vy;
  1133. X{
  1134. X    int    numbombs=0;
  1135. X
  1136. X    if (vy>0) {
  1137. X        if ((vx>0) && (FIELD[vx-1][vy-1].c==fc_trail))
  1138. X            return (TRUE);
  1139. X        if (FIELD[vx][vy-1].c==fc_trail)
  1140. X            return (TRUE);
  1141. X        if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy-1].c==fc_trail))
  1142. X            return (TRUE);
  1143. X    }
  1144. X    if (vy<NUMROWS-1) {
  1145. X        if ((vx>0) && (FIELD[vx-1][vy+1].c==fc_trail))
  1146. X            return (TRUE);
  1147. X        if (FIELD[vx][vy+1].c==fc_trail)
  1148. X            return (TRUE);
  1149. X        if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy+1].c==fc_trail))
  1150. X            return (TRUE);
  1151. X    }
  1152. X    if ((vx>0) && (FIELD[vx-1][vy].c==fc_trail))
  1153. X        return (TRUE);
  1154. X    if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].c==fc_trail))
  1155. X        return (TRUE);
  1156. X
  1157. X    return (FALSE);
  1158. X}
  1159. X
  1160. Xint move_man(vx,vy)
  1161. Xint vx,vy;
  1162. X{
  1163. X    int    ax,ay;        /* adjusted x and y */
  1164. X    int    reached_goal=FALSE;
  1165. X
  1166. X    setxy(vx,vy,&ax,&ay);
  1167. X
  1168. X    if (FIELD[vx][vy].m == fm_bomb) {
  1169. X        XBell(disp,0);
  1170. X        print_status("Square is marked as unsafe!");
  1171. X        return (SQUARE_IS_UNSAFE);
  1172. X    }
  1173. X    if (((abs(manvx-vx)<=1) && (abs(manvy-vy)<=1)) ||
  1174. X        (FIELD[vx][vy].c==fc_trail) ||
  1175. X        (next_to_trail(vx,vy) && (FIELD[vx][vy].m==fm_safe))) {
  1176. X       switch (FIELD[vx][vy].c) {
  1177. X        case fc_goal    :
  1178. X        case fc_trail    :
  1179. X        case fc_empty    : /* only allow movement of one square */
  1180. X                  if ((FIELD[vx][vy].c==fc_goal) && (!dead))
  1181. X                    reached_goal = TRUE;
  1182. X                  draw(bm_trail,manvx,manvy);
  1183. X                  FIELD[manvx][manvy].c = fc_trail;
  1184. X                  manvx = vx; manvy = vy;
  1185. X                  draw(bm_man,vx,vy);
  1186. X                  FIELD[manvx][manvy].c = fc_man;
  1187. X                  FIELD[manvx][manvy].m = fm_nomark;
  1188. X                  if (reached_goal)
  1189. X                    do_promotion();
  1190. X                  break;
  1191. X        case fc_man    : show_bomb_status(manvx,manvy);
  1192. X                  draw(bm_man,manvx,manvy);
  1193. X                  break;
  1194. X        case fc_bomb    : draw(bm_trail,manvx,manvy);
  1195. X                  FIELD[manvx][manvy].c = fc_trail;
  1196. X                  die(vx,vy);
  1197. X                  break;
  1198. X        case fc_tombstone:
  1199. X                  break;
  1200. X        default        : fprintf(stderr,
  1201. X                    "Error: Illegal FIELD contents\n");
  1202. X                  exit(2);
  1203. X       }
  1204. X       show_bomb_status(manvx,manvy);
  1205. X    }
  1206. X    else {
  1207. X       print_status("Can't move that far!");
  1208. X       XBell(disp,0);          
  1209. X    }
  1210. X    return (SUCCESS);
  1211. X}
  1212. X
  1213. Xint remove_mark(vx,vy)
  1214. Xint vx,vy;
  1215. X{
  1216. X    if (FIELD[vx][vy].m == fm_nomark)
  1217. X        return (NO_MARK_TO_REMOVE);    
  1218. X    else {
  1219. X        FIELD[vx][vy].m = fm_nomark;
  1220. X        clear(vx,vy);
  1221. X        return (SUCCESS);
  1222. X    }
  1223. X}
  1224. X
  1225. Xint mark_ok(vx,vy)
  1226. Xint vx,vy;
  1227. X{
  1228. X    switch (FIELD[vx][vy].c) {
  1229. X        case fc_empty:
  1230. X        case fc_bomb:    FIELD[vx][vy].m = fm_safe;
  1231. X                draw(bm_safe,vx,vy);
  1232. X                return (SUCCESS);
  1233. X        case fc_trail:
  1234. X        case fc_man:
  1235. X        case fc_tombstone:
  1236. X        case fc_goal:    return (CANT_MARK);
  1237. X        default:    fprintf(stderr,
  1238. X                    "Error: Illegal FIELD contents\n");
  1239. X                exit(3);
  1240. X    }
  1241. X}
  1242. X
  1243. X/* if level<0, then only mark immediately surrounding squares;  don't do
  1244. X   extended automarking
  1245. X*/
  1246. Xint mark_allaround_ok(vx,vy,level)
  1247. Xint vx,vy,level;    /* level=level of recursion */
  1248. X{
  1249. X    int    c,r;    /* col and row to clear FIELD[][].done flags */
  1250. X
  1251. X    /* clear all done flags if on original call */
  1252. X    if (level==0)
  1253. X        for (c=0;c<NUMCOLS;c++)
  1254. X           for (r=0;r<NUMROWS;r++)
  1255. X            FIELD[c][r].done = FALSE;
  1256. X
  1257. X    if (vy>0) {
  1258. X        if ((vx>0) && (FIELD[vx-1][vy-1].m==fm_nomark))
  1259. X            mark_ok(vx-1,vy-1);
  1260. X        if (FIELD[vx][vy-1].m==fm_nomark)
  1261. X            mark_ok(vx,vy-1);
  1262. X        if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy-1].m==fm_nomark))
  1263. X            mark_ok(vx+1,vy-1);
  1264. X    }
  1265. X    if (vy<NUMROWS-1) {
  1266. X        if ((vx>0) && (FIELD[vx-1][vy+1].m==fm_nomark))
  1267. X            mark_ok(vx-1,vy+1);
  1268. X        if (FIELD[vx][vy+1].m==fm_nomark)
  1269. X            mark_ok(vx,vy+1);
  1270. X        if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy+1].m==fm_nomark))
  1271. X            mark_ok(vx+1,vy+1);
  1272. X    }
  1273. X    if ((vx>0) && (FIELD[vx-1][vy].m==fm_nomark))
  1274. X        mark_ok(vx-1,vy);
  1275. X    if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].m==fm_nomark))
  1276. X        mark_ok(vx+1,vy);
  1277. X
  1278. X    if ((level>=0) && (extended_automark) && (!FIELD[vx][vy].done)) {
  1279. X    /* mark square as being already marked-allaround to prevent repeat */
  1280. X        FIELD[vx][vy].done = TRUE;
  1281. X        if (bomb_status(vx,vy) == 0) {
  1282. X            draw(bm_trail,vx,vy);
  1283. X            FIELD[vx][vy].c = fc_trail;
  1284. X            FIELD[vx][vy].m = fm_nomark;
  1285. X        }
  1286. X        if (vy>0) {
  1287. X            if ((vx>0) && (FIELD[vx-1][vy-1].m==fm_safe) &&
  1288. X                (bomb_status(vx-1,vy-1)==0))
  1289. X                mark_allaround_ok(vx-1,vy-1,level+1);
  1290. X            if ((FIELD[vx][vy-1].m==fm_safe) &&
  1291. X                (bomb_status(vx,vy-1)==0))
  1292. X                mark_allaround_ok(vx,vy-1,level+1);
  1293. X            if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy-1].m==fm_safe) &&
  1294. X                (bomb_status(vx+1,vy-1)==0))
  1295. X                mark_allaround_ok(vx+1,vy-1,level+1);
  1296. X        }
  1297. X        if (vy<NUMROWS-1) {
  1298. X            if ((vx>0) && (FIELD[vx-1][vy+1].m==fm_safe) &&
  1299. X                (bomb_status(vx-1,vy+1)==0))
  1300. X                mark_allaround_ok(vx-1,vy+1,level+1);
  1301. X            if ((FIELD[vx][vy+1].m==fm_safe) &&
  1302. X                (bomb_status(vx,vy+1)==0))
  1303. X                mark_allaround_ok(vx,vy+1,level+1);
  1304. X            if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy+1].m==fm_safe) &&
  1305. X                (bomb_status(vx+1,vy+1)==0))
  1306. X                mark_allaround_ok(vx+1,vy+1,level+1);
  1307. X        }
  1308. X        if ((vx>0) && (FIELD[vx-1][vy].m==fm_safe) &&
  1309. X            (bomb_status(vx-1,vy)==0))
  1310. X            mark_allaround_ok(vx-1,vy,level+1);
  1311. X        if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].m==fm_safe) &&
  1312. X            (bomb_status(vx+1,vy)==0))
  1313. X            mark_allaround_ok(vx+1,vy,level+1);
  1314. X    }
  1315. X
  1316. X    /* put man marker back on field */
  1317. X    if (level<=0)
  1318. X        draw(bm_man,manvx,manvy);
  1319. X
  1320. X    return (SUCCESS);
  1321. X}
  1322. X
  1323. Xint mark_bomb(vx,vy)
  1324. Xint vx,vy;
  1325. X{
  1326. X    switch (FIELD[vx][vy].c) {
  1327. X        case fc_empty:
  1328. X        case fc_bomb:    FIELD[vx][vy].m = fm_bomb;
  1329. X                draw(bm_bombmark,vx,vy);
  1330. X                return (SUCCESS);
  1331. X        case fc_trail:
  1332. X        case fc_man:
  1333. X        case fc_tombstone:
  1334. X        case fc_goal:    return (CANT_MARK);
  1335. X        default:    fprintf(stderr,
  1336. X                    "Error: Illegal FIELD contents\n");
  1337. X                exit(3);
  1338. X    }
  1339. X}
  1340. X
  1341. Xvoid die(vx,vy)
  1342. Xint vx,vy;
  1343. X{
  1344. X    char            str[MAXSTRLEN];
  1345. X
  1346. X    explode(vx,vy);
  1347. X    draw(bm_tombstone,vx,vy);
  1348. X    FIELD[vx][vy].c = fc_tombstone;
  1349. X    num_tombstones++;
  1350. X    if (--num_lives<0)
  1351. X        num_lives = 0;
  1352. X    sprintf(str,"Lives: %d",num_lives);
  1353. X    WindPrint(lives_left,str);
  1354. X    if ((num_lives<=0) && (!dead)) {
  1355. X        show_bomb_status(manvx,manvy);
  1356. X        dead = TRUE;
  1357. X        show_all_bombs();
  1358. X        print_status("You have just died!  GAME OVER!");
  1359. X        XBell(disp,0);
  1360. X        XBell(disp,0);
  1361. X        XBell(disp,0);
  1362. X        XFlush(disp);
  1363. X        sleep(3);
  1364. X    }
  1365. X    draw(bm_man,0,0);
  1366. X    FIELD[0][0].c = fc_man;
  1367. X    FIELD[0][0].m = fm_nomark;
  1368. X    manvx = manvy = 0;
  1369. X    show_bomb_status(manvx,manvy);
  1370. X}
  1371. X
  1372. Xint explode(vx,vy)
  1373. Xint vx,vy;
  1374. X{
  1375. X    int    i;
  1376. X    char    str[MAXSTRLEN];
  1377. X
  1378. X    if (FIELD[vx][vy].c == fc_bomb) {
  1379. X        num_bombs_left--;
  1380. X        sprintf(str,"Bombs: %d",num_bombs_left);
  1381. X        WindPrint(bombs_left,str);
  1382. X    }
  1383. X
  1384. X    /* simulate explosion on screen */
  1385. X    for (i=0;i<10;i++) {
  1386. X        draw(bm_pow,vx,vy);
  1387. X        usleep(BOMB_EXPLODE_UDELAY);
  1388. X        draw(bm_bomb,vx,vy);
  1389. X        usleep(BOMB_EXPLODE_UDELAY);
  1390. X    }
  1391. X    clear(vx,vy);
  1392. X    FIELD[vx][vy].c = fc_empty;
  1393. X    FIELD[vx][vy].m = fm_nomark;
  1394. X
  1395. X
  1396. X    /* check to see if other bombs nearby--Manhattan dirs only */
  1397. X    if ((vx>0) && (FIELD[vx-1][vy].c==fc_bomb)) explode(vx-1,vy);
  1398. X    if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].c==fc_bomb)) explode(vx+1,vy);
  1399. X    if ((vy>0) && (FIELD[vx][vy-1].c==fc_bomb)) explode(vx,vy-1);
  1400. X    if ((vy<NUMROWS-1) && (FIELD[vx][vy+1].c==fc_bomb)) explode(vx,vy+1);
  1401. X
  1402. X    /* check to see if man nearby--Manhattan dirs only */
  1403. X    if ((vx>0) && (FIELD[vx-1][vy].c==fc_man)) die(vx-1,vy);
  1404. X    if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].c==fc_man)) die(vx+1,vy);
  1405. X    if ((vy>0) && (FIELD[vx][vy-1].c==fc_man)) die(vx,vy-1);
  1406. X    if ((vy<NUMROWS-1) && (FIELD[vx][vy+1].c==fc_man)) die(vx,vy+1);
  1407. X
  1408. X    return(SUCCESS);
  1409. X}
  1410. X
  1411. X/* bonus_without_penalties:  returns the current bonus remaining for */
  1412. X/*    this level, without used_* penalties                         */
  1413. Xint bonus_without_penalties()
  1414. X{
  1415. X    int    b;    /* temp value for current bonus */
  1416. X
  1417. X    b = (level+1)*num_time_left
  1418. X        + num_bombs_left
  1419. X        + num_grenades_left*POINTS_PER_GRENADE
  1420. X        - num_tombstones*POINTS_PER_TOMBSTONE;
  1421. X
  1422. X    if (b < 0)
  1423. X        b = 0;
  1424. X
  1425. X    return (b);
  1426. X}
  1427. X
  1428. X/* current_bonus:  returns the current amount of bonus */
  1429. X/*                    remaining for this level         */
  1430. Xint current_bonus()
  1431. X{
  1432. X    int    b;    /* temp value for current bonus */
  1433. X
  1434. X    b = bonus_without_penalties()
  1435. X/* This used to be used for ver 1.0
  1436. X        - used_showfig*POINTS_FOR_USED_SHOWFIG;
  1437. X*/
  1438. X        - used_sanity*
  1439. X           (PERCENT_FOR_USED_SANITY*bonus_without_penalties())/100
  1440. X        - used_eautomark*
  1441. X           (PERCENT_FOR_USED_EAUTOMARK*bonus_without_penalties())/100;
  1442. X
  1443. X    if (b < 0)
  1444. X        b = 0;
  1445. X
  1446. X    return (b);
  1447. X}
  1448. X        
  1449. X
  1450. X/* update_bonus:  recalculate the amount of bonus remaining for this level */
  1451. X/*                display the correct new bonus on screen                  */
  1452. Xint update_bonus()
  1453. X{
  1454. X    char        str[MAXSTRLEN];
  1455. X    static int    last_bonus;
  1456. X
  1457. X    if ((num_bonus = current_bonus()) != last_bonus) {
  1458. X        sprintf(str,"Bonus: %d",num_bonus);
  1459. X        WindPrint(bonus_wind,str);
  1460. X        last_bonus = num_bonus;
  1461. X    }
  1462. X}
  1463. X
  1464. Xint update_time()
  1465. X{
  1466. X    long    st,ct;    /* starting and current times */
  1467. X    char    str[MAXSTRLEN];
  1468. X    int    previous_num_time_left=num_time_left;
  1469. X
  1470. X    st = time_at_start_of_level;
  1471. X    ct = time(0);
  1472. X    num_time_left = num_time_left_at_start - (ct-st-pause_time);
  1473. X    update_bonus();
  1474. X    if (num_time_left<=0) {
  1475. X        print_status("Time is out!  GAME OVER!");
  1476. X        sprintf(str,"Time: %s",clock_time_str(num_time_left));
  1477. X        WindPrint(time_left,str);
  1478. X        XBell(disp,0);
  1479. X        XBell(disp,0);
  1480. X        XBell(disp,0);
  1481. X        return (TIME_IS_OVER);    /* TIME_IS_OVER = TRUE */
  1482. X    }
  1483. X    else if (num_time_left != previous_num_time_left) {
  1484. X        sprintf(str,"Time: %s",clock_time_str(num_time_left));
  1485. X        WindPrint(time_left,str);
  1486. X        return (SUCCESS);
  1487. X    }
  1488. X    return (SUCCESS);
  1489. X}
  1490. X
  1491. Xint throw_grenade()
  1492. X{
  1493. X    char            str[MAXSTRLEN];
  1494. X    XEvent            event;
  1495. X    XButtonPressedEvent    *eventbp;
  1496. X    int            vx,vy;
  1497. X
  1498. X    if (num_grenades_left==0) {
  1499. X        print_status("No grenades left!");
  1500. X        XBell(disp,0);
  1501. X        return (NO_GRENADES_LEFT);
  1502. X    }
  1503. X
  1504. X    XClearWindow(disp,wind[tgrenade_wind]);
  1505. X    InvPrintStr(tgrenade_wind,"Throw Grenade");
  1506. X    print_status("Ready to throw grenade");
  1507. X
  1508. X    /* Get position to throw grenade */
  1509. X    while (!XPending(disp))
  1510. X        usleep(XPENDING_UDELAY);
  1511. X    XNextEvent(disp,&event);
  1512. X    eventbp = (XButtonPressedEvent *) &event;
  1513. X    if ((event.type != ButtonPress) || (eventbp->window != field) ||
  1514. X        (setvxvy(eventbp->x,eventbp->y,&vx,&vy) == OUT_OF_RANGE)) {
  1515. X        print_status("Click on the position to throw grenade!");
  1516. X        XBell(disp,0);
  1517. X        WindPrint(tgrenade_wind,"Throw Grenade");
  1518. X        return (ILLEGAL_POSITION);
  1519. X    }
  1520. X
  1521. X    /* check to see if within range */
  1522. X    if (abs(manvx-vx) + abs(manvy-vy) > GRENADE_DISTANCE) {
  1523. X        sprintf(str,
  1524. X            "Can't toss grenade that far!  Max distance is %d.\n",
  1525. X            GRENADE_DISTANCE);
  1526. X        print_status(str);
  1527. X        XBell(disp,0);
  1528. X        WindPrint(tgrenade_wind,"Throw Grenade");
  1529. X        return (TOO_FAR_TO_TOSS_GRENADE);
  1530. X    }
  1531. X
  1532. X    /* passed checks -- toss grenade */
  1533. X    if (FIELD[vx][vy].c == fc_man) {
  1534. X        die(vx,vy);
  1535. X        sprintf(str,"Grenades: %d",--num_grenades_left);
  1536. X        WindPrint(grenades_left,str);
  1537. X        WindPrint(tgrenade_wind,"Throw Grenade");
  1538. X        return (DIED);
  1539. X    }
  1540. X    else if ((FIELD[vx][vy].c != fc_tombstone) && 
  1541. X        (FIELD[vx][vy].c != fc_goal)) {
  1542. X        explode(vx,vy);
  1543. X        show_bomb_status(manvx,manvy);
  1544. X        draw(bm_man,manvx,manvy);
  1545. X        sprintf(str,"Grenades: %d",--num_grenades_left);
  1546. X        WindPrint(grenades_left,str);
  1547. X        WindPrint(tgrenade_wind,"Throw Grenade");
  1548. X        return (SUCCESS);
  1549. X    }
  1550. X    else {
  1551. X        strcpy(str,"No bomb at that position.  ");
  1552. X        strcat(str,"Can't blow up tombstone or goal.");
  1553. X        print_status(str);
  1554. X        XBell(disp,0);
  1555. X        WindPrint(tgrenade_wind,"Throw Grenade");
  1556. X        return (CANT_EXPLODE);
  1557. X    }
  1558. X}
  1559. X
  1560. X/* num_adj_squares_marked_bomb: returns num adjacent squares user has marked
  1561. X    as being unsafe
  1562. X*/
  1563. Xint num_adj_squares_marked_bomb(vx,vy)
  1564. Xint vx,vy;
  1565. X{
  1566. X    int    nummarks=0;
  1567. X
  1568. X    if (vy>0) {
  1569. X        if ((vx>0) && (FIELD[vx-1][vy-1].m==fm_bomb))
  1570. X            nummarks++;
  1571. X        if (FIELD[vx][vy-1].m==fm_bomb)
  1572. X            nummarks++;
  1573. X        if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy-1].m==fm_bomb))
  1574. X            nummarks++;
  1575. X    }
  1576. X    if (vy<NUMROWS-1) {
  1577. X        if ((vx>0) && (FIELD[vx-1][vy+1].m==fm_bomb))
  1578. X            nummarks++;
  1579. X        if (FIELD[vx][vy+1].m==fm_bomb)
  1580. X            nummarks++;
  1581. X        if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy+1].m==fm_bomb))
  1582. X            nummarks++;
  1583. X    }
  1584. X    if ((vx>0) && (FIELD[vx-1][vy].m==fm_bomb))
  1585. X        nummarks++;
  1586. X    if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].m==fm_bomb))
  1587. X        nummarks++;
  1588. X
  1589. X    return (nummarks);
  1590. X}
  1591. X
  1592. X/* num_adj_squares_marked_safe: returns num adjacent squares user has marked
  1593. X    as being safe
  1594. X*/
  1595. Xint num_adj_squares_marked_safe(vx,vy)
  1596. Xint vx,vy;
  1597. X{
  1598. X    int    nummarks=0;
  1599. X
  1600. X    if (vy>0) {
  1601. X        if ((vx>0) && (FIELD[vx-1][vy-1].m==fm_safe))
  1602. X            nummarks++;
  1603. X        if (FIELD[vx][vy-1].m==fm_safe)
  1604. X            nummarks++;
  1605. X        if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy-1].m==fm_safe))
  1606. X            nummarks++;
  1607. X    }
  1608. X    if (vy<NUMROWS-1) {
  1609. X        if ((vx>0) && (FIELD[vx-1][vy+1].m==fm_safe))
  1610. X            nummarks++;
  1611. X        if (FIELD[vx][vy+1].m==fm_safe)
  1612. X            nummarks++;
  1613. X        if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy+1].m==fm_safe))
  1614. X            nummarks++;
  1615. X    }
  1616. X    if ((vx>0) && (FIELD[vx-1][vy].m==fm_safe))
  1617. X        nummarks++;
  1618. X    if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].m==fm_safe))
  1619. X        nummarks++;
  1620. X
  1621. X    return (nummarks);
  1622. X}
  1623. X
  1624. X/* num_unvisited_adj_squares: returns num adjacent squares user has
  1625. X    not yet visited (not marked with fc_trail)
  1626. X*/
  1627. Xint num_unvisited_adj_squares(vx,vy)
  1628. Xint vx,vy;
  1629. X{
  1630. X    int    num_unvisited=0;
  1631. X
  1632. X    if (vy>0) {
  1633. X        if ((vx>0) && (FIELD[vx-1][vy-1].c!=fc_trail))
  1634. X            num_unvisited++;
  1635. X        if (FIELD[vx][vy-1].c!=fc_trail)
  1636. X            num_unvisited++;
  1637. X        if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy-1].c!=fc_trail))
  1638. X            num_unvisited++;
  1639. X    }
  1640. X    if (vy<NUMROWS-1) {
  1641. X        if ((vx>0) && (FIELD[vx-1][vy+1].c!=fc_trail))
  1642. X            num_unvisited++;
  1643. X        if (FIELD[vx][vy+1].c!=fc_trail)
  1644. X            num_unvisited++;
  1645. X        if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy+1].c!=fc_trail))
  1646. X            num_unvisited++;
  1647. X    }
  1648. X    if ((vx>0) && (FIELD[vx-1][vy].c!=fc_trail))
  1649. X        num_unvisited++;
  1650. X    if ((vx<NUMCOLS-1) && (FIELD[vx+1][vy].c!=fc_trail))
  1651. X        num_unvisited++;
  1652. X
  1653. X    return (num_unvisited);
  1654. X}
  1655. X
  1656. X/* do_sanity_check: Make sure user is not losing his mind!
  1657. X    If more adjacent squares are marked unsafe than is indicated by the
  1658. X    current bomb status, warn the user.
  1659. X    If more adjacent squares are marked safe than the number of unvisited
  1660. X    squares - the current bomb status, warn the user.
  1661. X*/
  1662. Xint do_sanity_check(vx,vy)
  1663. Xint vx,vy;
  1664. X{
  1665. X    /* Check first for too many squares marked unsafe */
  1666. X    if (num_adj_squares_marked_bomb(vx,vy) > bomb_status(vx,vy)) {
  1667. X        print_status("WARNING: too many squares marked UNsafe!");
  1668. X        XBell(disp,0);
  1669. X        return (CHECK_FAILED);
  1670. X    }
  1671. X
  1672. X    /* Next check for too many squares marked safe */
  1673. X    if (num_adj_squares_marked_safe(vx,vy) > 
  1674. X       num_unvisited_adj_squares(vx,vy) - bomb_status(vx,vy)) {
  1675. X        print_status("WARNING: too many squares marked safe!");
  1676. X        XBell(disp,0);
  1677. X        return (CHECK_FAILED);
  1678. X    }
  1679. X
  1680. X    return (SUCCESS);
  1681. X}
  1682. END_OF_FILE
  1683. if test 29521 -ne `wc -c <'play.c'`; then
  1684.     echo shar: \"'play.c'\" unpacked with wrong size!
  1685. fi
  1686. # end of 'play.c'
  1687. fi
  1688. echo shar: End of archive 1 \(of 2\).
  1689. cp /dev/null ark1isdone
  1690. MISSING=""
  1691. for I in 1 2 ; do
  1692.     if test ! -f ark${I}isdone ; then
  1693.     MISSING="${MISSING} ${I}"
  1694.     fi
  1695. done
  1696. if test "${MISSING}" = "" ; then
  1697.     echo You have unpacked both archives.
  1698.     rm -f ark[1-9]isdone
  1699. else
  1700.     echo You still need to unpack the following archives:
  1701.     echo "        " ${MISSING}
  1702. fi
  1703. ##  End of shell archive.
  1704. exit 0
  1705.  
  1706. exit 0 # Just in case...
  1707. -- 
  1708.   // chris@IMD.Sterling.COM            | Send comp.sources.x submissions to:
  1709. \X/  Amiga - The only way to fly!      |
  1710.  "It's intuitively obvious to the most |    sources-x@imd.sterling.com
  1711.   casual observer..."                  |
  1712.