home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume5 / golddig2 / part03 < prev    next >
Encoding:
Internet Message Format  |  1989-12-13  |  49.3 KB

  1. Path: uunet!ssbell!kent@ssbell.uu.net
  2. From: kent@ssbell.uu.net (Kent Landfield)
  3. Newsgroups: comp.sources.x
  4. Subject: v05i047: golddig2 -- A game for X11, Part03/04
  5. Message-ID: <596@ssbell.uu.net>
  6. Date: 14 Dec 89 03:18:07 GMT
  7. Sender: kent@ssbell.uu.net
  8. Lines: 1458
  9. Approved: kent@ssbell.uu.net (Kent Landfield)
  10.  
  11. Submitted-by: Alexander Siegel <siegel@cs.cornell.edu>
  12. Posting-number: Volume 5, Issue 47
  13. Archive-name: golddig2/part03
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 3 (of 4)."
  22. # Contents:  golddig2/badguy.c golddig2/movement.c golddig2/shared.c
  23. # Wrapped by kent@ssbell on Wed Dec 13 20:36:59 1989
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'golddig2/badguy.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'golddig2/badguy.c'\"
  27. else
  28. echo shar: Extracting \"'golddig2/badguy.c'\" \(16560 characters\)
  29. sed "s/^X//" >'golddig2/badguy.c' <<'END_OF_FILE'
  30. X/* This program was written by Alexander Siegel in September of 1989   */
  31. X/* at Cornell University.  It may may copied freely for private use or */
  32. X/* public dispersion provided that this comment is not removed.  This  */
  33. X/* program, any portion of this program, or any derivative of this     */
  34. X/* program may not be sold or traded for financial gain.               */
  35. X
  36. X#include <stdio.h>
  37. X#include <X11/Xlib.h>
  38. X#include <X11/keysym.h>
  39. X#include "golddig.h"
  40. X
  41. Xextern char badguy_bits[];
  42. X#include "bitmap/badguy2.bits"
  43. X#include "bitmap/badguy3.bits"
  44. X
  45. Xlong random();
  46. X
  47. X#define MAXBADGUY 30     /* Maximum number of bad guys */
  48. X#define MAXBADSCORE 20   /* Maximum amount of score given for */
  49. X                         /* killing bad guys */
  50. Xint numbadguy = 0;       /* Total number of bad guys. */
  51. Xstruct thing_s badguys[MAXBADGUY];  /* Array describing state of all */
  52. X                                    /* bad guys */
  53. Xchar movetree[MAXLEVEL]; /* Direction that badguy should go at each location */
  54. Xint badscore;            /* Score given during current level due to */
  55. X                         /* killing bad guys */
  56. X
  57. X/* Graphics cursors for drawing the possible states of the badguys */
  58. XGC badguy1gc,badguy2gc,badguy3gc;
  59. X
  60. X/* Initialize graphics cursors for bad guys */
  61. Xvoid init_badguy()
  62. X{
  63. X  int gcfunc;
  64. X
  65. X  /* Decide whether to use GXand or GXor depending on screen type */
  66. X  if((BlackPixel(disp,0) & WhitePixel(disp,0)) == BlackPixel(disp,0))
  67. X    gcfunc = GXand;
  68. X  else
  69. X    gcfunc = GXor;
  70. X  /* Generate graphics cursors for drawing bad guy */
  71. X  badguy1gc = makegc(gcfunc,badguy_bits);
  72. X  badguy2gc = makegc(gcfunc,badguy2_bits);
  73. X  badguy3gc = makegc(gcfunc,badguy3_bits);
  74. X}
  75. X
  76. X/* Initialize data structure for bad guys from level data */
  77. Xvoid start_badguy()
  78. X{
  79. X  register int x,y,pos;
  80. X
  81. X  /* Reset the limit on bad guy score given */
  82. X  badscore = 0;
  83. X  /* Initialize number of bad guys to 0 */
  84. X  numbadguy = 0;
  85. X  pos = 0;
  86. X  /* Iterate through each position in level array */
  87. X  for(x=0;x<xsize;++x)
  88. X    for(y=0;y<ysize;++y) {
  89. X      /* Check if level holds a bad guys block at that position */
  90. X      if(level[pos] == BADGUY) {
  91. X        /* Replace bad guys block with space */
  92. X        level[pos] = SPACE;
  93. X        if(numbadguy < MAXBADGUY) {
  94. X          /* Add bad guy to global array.  Note the multiplication by */
  95. X          /* 2 when producing position. */
  96. X          badguys[numbadguy].xstart = badguys[numbadguy].xpos = x << 1;
  97. X          badguys[numbadguy].ystart = badguys[numbadguy].ypos = y << 1;
  98. X          badguys[numbadguy].dir = STAND;
  99. X          /* Bad guys start holding nothing */
  100. X          badguys[numbadguy].hold = SPACE;
  101. X          numbadguy ++;
  102. X        }
  103. X      }
  104. X      pos ++;
  105. X    }
  106. X}
  107. X
  108. X/* Draw all the bad guys out to the game window */
  109. Xvoid draw_badguys()
  110. X{
  111. X  register int i;
  112. X  GC drawgc;
  113. X
  114. X  /* Iterate through each bad guy */
  115. X  for(i=0;i<numbadguy;++i) {
  116. X    /* If bad guy is horizontally offset, use the second graphics */
  117. X    /* cursor */
  118. X    if(badguys[i].xpos & 1)
  119. X      drawgc = badguy2gc;
  120. X    /* If bad guy is vertically offset, use the third graphics cursor */
  121. X    else if(badguys[i].ypos & 1)
  122. X      drawgc = badguy3gc;
  123. X    /* Otherwise use the normal graphics cursor */
  124. X    else
  125. X      drawgc = badguy1gc;
  126. X    /* Fill rectangle surrounding bad guy */
  127. X    XFillRectangle(disp,wind,drawgc,badguys[i].xpos << 3,
  128. X                   badguys[i].ypos << 3,16,16);
  129. X  }
  130. X}
  131. X
  132. X/* Return 1 if the specified position overlaps a bad guy, 0 otherwise. */
  133. X/* Another parameter is provided so that this routine can ignore one */
  134. X/* bad guy. */
  135. Xint overlap_badguy(x,y,num)
  136. Xregister int x,y;   /* Position which will be checked for overlap. */
  137. Xregister int num;   /* Number of bad guy to ignore.  Use a -1 for no */
  138. X                    /* ignoring. */
  139. X{
  140. X  register int i,d;
  141. X
  142. X  /* Iterate through each bad guy */
  143. X  for(i=0;i<numbadguy;++i) {
  144. X    /* If this bad guy is the one that I am supposed to ignore, */
  145. X    /* continue to the next */
  146. X    if(i == num)
  147. X      continue;
  148. X    /* Compute horizontal distance between position and bad guy and */
  149. X    /* check it.  Things are two positions wide in each direction */
  150. X    d = x - badguys[i].xpos;
  151. X    if(d < -1 || d > 1)
  152. X      continue;
  153. X    /* Check vertical distance */
  154. X    d = y - badguys[i].ypos;
  155. X    if(d < -1 || d > 1)
  156. X      continue;
  157. X    /* Found overlap, return a 1 */
  158. X    return(1);
  159. X  }
  160. X  /* Could not find overlap */
  161. X  return(0);
  162. X}
  163. X
  164. X/* Erase and redraw all badguys who have moved in the previous */
  165. X/* movement.  Movement is detected when (xpos,ypos) is different from */
  166. X/* (xold,yold). */
  167. Xvoid drawmove_badguys()
  168. X{
  169. X  register int x,y,i;
  170. X  GC drawgc;
  171. X
  172. X  /* iterate through each bad guy */
  173. X  for(i=0;i<numbadguy;++i) {
  174. X    /* do not erase bad guys who did not move */
  175. X    if(! badguys[i].redraw)
  176. X      continue;
  177. X    /* get position of bad guy in normal coordinates */
  178. X    x = badguys[i].xold >> 1;
  179. X    y = badguys[i].yold >> 1;
  180. X    /* draw block underneath bad guy */
  181. X    draw_block(x,y);
  182. X    /* if horizontally offset, draw block to the right */
  183. X    if(badguys[i].xold & 1)
  184. X      draw_block(x + 1,y);
  185. X    /* if vertically offset, draw block below */
  186. X    if(badguys[i].yold & 1)
  187. X      draw_block(x,y + 1);
  188. X  }
  189. X
  190. X  /* iterate through each bad guy */
  191. X  for(i=0;i<numbadguy;++i) {
  192. X    /* do not draw bad guys who did not move */
  193. X    if(! badguys[i].redraw)
  194. X      continue;
  195. X    /* Put badguy coordinates in registers */
  196. X    x = badguys[i].xpos;
  197. X    y = badguys[i].ypos;
  198. X    /* if bad guy is horizontally offset, use the second graphics */
  199. X    /* cursor */
  200. X    if(x & 1)
  201. X      drawgc = badguy2gc;
  202. X    /* If bad guy is vertically offset, use the third graphics cursor */
  203. X    else if(y & 1)
  204. X      drawgc = badguy3gc;
  205. X    /* Otherwise use the normal graphics cursor */
  206. X    else
  207. X      drawgc = badguy1gc;
  208. X    /* Fill rectangle surrounding bad guy */
  209. X    XFillRectangle(disp,wind,drawgc,x << 3,y << 3,16,16);
  210. X  }
  211. X}
  212. X
  213. X/* Maximum size for FIFO queue used by breadth first search algorithm */
  214. X#define QSIZE 1000
  215. X
  216. X/* Regenerate the movement tree used by bad guys when determining */
  217. X/* movement.  The basic algorithm is a breadth first search of the */
  218. X/* graph produced by interpreting the moveallow array as a directed */
  219. X/* graph.  The root of the tree is the player position.  The result of */
  220. X/* this algorithm is that the shortest path from each position to the */
  221. X/* player is described by the directions in the movement tree. */
  222. Xvoid regen_tree()
  223. X{
  224. X  register int head,tail,lpos,dist;
  225. X  /* This array is used for the queue of graph nodes.  The head and */
  226. X  /* tail variables describe the head and tail of the queue in the */
  227. X  /* array. */
  228. X  struct goals_s {
  229. X    short x,y,dir;
  230. X  } goals[QSIZE];
  231. X
  232. X  /* Do a fast pre-initialization of the movement tree */
  233. X  dist = xsize * ysize;
  234. X  for(lpos=0;lpos<dist;++lpos) {
  235. X    /* Zero out each position.  A 0 in a position signifies that the */
  236. X    /* direction of movement for that position is unknown. */
  237. X    movetree[lpos] = 0;
  238. X    /* If can only move in one direction, set movetree value */
  239. X    /* immediately.  Do not set it if is a force into a STOPBAD space */
  240. X    /* to allow bad guys to try to run over holes.  This loop screws up the */
  241. X    /* search algorithm and the result is that bad guys will not jump */
  242. X    /* off of things.  It makes the search run much faster, and the */
  243. X    /* bad guys were too smart otherwise. */
  244. X    if((moveallow[lpos] & FORCEDOWN) &&
  245. X       ! (fast_lookup[level[lpos + 1]].code & STOPBAD))
  246. X      movetree[lpos] = MOVEDOWN;
  247. X    if((moveallow[lpos] & FORCEUP) &&
  248. X       ! (fast_lookup[level[lpos - 1]].code & STOPBAD))
  249. X      movetree[lpos] = MOVEUP;
  250. X    if((moveallow[lpos] & FORCERIGHT) &&
  251. X       ! (fast_lookup[level[lpos + ysize]].code & STOPBAD))
  252. X      movetree[lpos] = MOVERIGHT;
  253. X    if((moveallow[lpos] & FORCELEFT) &&
  254. X       ! (fast_lookup[level[lpos - ysize]].code & STOPBAD))
  255. X      movetree[lpos] = MOVELEFT;
  256. X    /* If no movement is possible, set a -1 in the movement tree. */
  257. X    if(moveallow[lpos] == 0)
  258. X      movetree[lpos] = -1;
  259. X  }
  260. X  /* Initialize the head and tail of the FIFO queue. */
  261. X  head = 0;
  262. X  tail = 1;
  263. X  /* Set the first goal node to be the player */
  264. X  goals[0].x = player.xpos >> 1;
  265. X  goals[0].y = player.ypos >> 1;
  266. X  goals[0].dir = -1;    /* Make sure every direction is possible */
  267. X  /* While there are still goal nodes, continue */
  268. X  while(head != tail) {
  269. X    /* Compute position of position of goal */
  270. X    lpos = goals[head].x * ysize + goals[head].y;
  271. X    /* If the suggested movement direction is valid and the movement */
  272. X    /* has for that position has not been set, set it. */
  273. X    if(movetree[lpos] == 0 && (moveallow[lpos] & goals[head].dir) != 0) {
  274. X      movetree[lpos] = goals[head].dir;
  275. X      /* Suggest that the block to the left has to rightward pointer */
  276. X      if(goals[head].x > 0 && movetree[lpos - ysize] == 0)
  277. X
  278. X/* Add a suggested movement direction to the FIFO queue */
  279. X#define ADDGOAL(dx,dy,ndir)  { goals[tail].x = goals[head].x + dx; \
  280. X                             goals[tail].y = goals[head].y + dy; \
  281. X                             goals[tail++].dir = ndir; \
  282. X                             if(tail == QSIZE) tail = 0; }
  283. X
  284. X        ADDGOAL(-1,0,MOVERIGHT)
  285. X      /* Suggest that the block to the right has a leftware pointer */
  286. X      if(goals[head].x < xsize - 1 && movetree[lpos + ysize] == 0)
  287. X        ADDGOAL(1,0,MOVELEFT)
  288. X      /* Suggest that the block above has a downward pointer */
  289. X      if(goals[head].y > 0 && movetree[lpos - 1] == 0)
  290. X        ADDGOAL(0,-1,MOVEDOWN)
  291. X      /* Suggest that the block below has an upward pointer */
  292. X      if(goals[head].y < ysize - 1 && movetree[lpos + 1] == 0)
  293. X        ADDGOAL(0,1,MOVEUP)
  294. X    }
  295. X    /* Remove current goal node from head of queue */
  296. X    head ++;
  297. X    if(head == QSIZE)
  298. X      head = 0;
  299. X  }
  300. X}
  301. X
  302. X/* Move all the bad guys one position */
  303. Xvoid move_badguys()
  304. X{
  305. X  int i,x,y,allow;
  306. X  register int lpos;
  307. X  enum directs dir;
  308. X  register char curchar,below;
  309. X
  310. X  /* Iterate through all the bad guys */
  311. X  for(i=0;i<numbadguy;++i) {
  312. X    /* Get old position for bad guys */
  313. X    x = badguys[i].xold = badguys[i].xpos;
  314. X    y = badguys[i].yold = badguys[i].ypos;
  315. X    /* Initially assume that the badguy does not need to be redrawn */
  316. X    badguys[i].redraw = 0;
  317. X    /* Get the character underneath the bad guy */
  318. X    lpos = (x >> 1)*ysize + (y >> 1);
  319. X    curchar = level[lpos];
  320. X    /* Get the character below the bad guy.  If it is off the level, */
  321. X    /* assume it is a stone */
  322. X    if(y < (ysize - 1) << 1)
  323. X      below = level[lpos + 1];
  324. X    else
  325. X      below = STONE;
  326. X
  327. X    /* If the current character is a killer block, move the bad guy to */
  328. X    /* its starting position */
  329. X    if(fast_lookup[curchar].code & KILLIN) {
  330. X      /* Prevent getting too many points from kill bad guys on a */
  331. X      /* single level */
  332. X      if(badscore < MAXBADSCORE) {
  333. X        /* Increment the score */
  334. X        score += 2;
  335. X        badscore += 2;
  336. X      }
  337. X      /* Redraw the score line */
  338. X      draw_score();
  339. X      /* Move the bad guy back to its start */
  340. X      badguys[i].xpos = badguys[i].xstart;
  341. X      badguys[i].ypos = badguys[i].ystart;
  342. X      lpos = (badguys[i].xpos >> 1)*ysize + (badguys[i].ypos >> 1);
  343. X      /* Prevent a bad guy from forming on top of another */
  344. X      while(overlap_badguy(badguys[i].xpos,badguys[i].ypos,i) ||
  345. X            level[lpos] != SPACE) {
  346. X        badguys[i].xpos = random() % xsize;
  347. X        badguys[i].ypos = random() % ysize;
  348. X        lpos = (badguys[i].xpos >> 1)*ysize + (badguys[i].ypos >> 1);
  349. X      }
  350. X      /* Redraw bad guy */
  351. X      badguys[i].redraw = 1;
  352. X      /* Destroy whatever the bad guy was holding */
  353. X      if(badguys[i].hold != SPACE) {
  354. X        if(fast_lookup[badguys[i].hold].code & TREASURE) {
  355. X          goldleft --;
  356. X          /* If that was the last gold piece, escape ladder and other */
  357. X          /* stuff may need to appear. */
  358. X          if(goldleft == 0) {
  359. X            regen_allow();      /* Regenerate the allowable movement array */
  360. X            redrawall();        /* Refresh the entire screen */
  361. X          }
  362. X        }
  363. X        badguys[i].hold = SPACE;
  364. X      }
  365. X      /* Continue to the next bad guy */
  366. X      continue;
  367. X    }
  368. X
  369. X    /* If the bad guy is stuck in a STOPBAD block, do not move him */
  370. X    if((x & 1) == 0 && (y & 1) == 0 &&
  371. X       (fast_lookup[curchar].code & STOPBAD)) {
  372. X      /* Redraw bad guy since underlying block gets redrawn occasionally */
  373. X      badguys[i].redraw = 1;      
  374. X      continue;
  375. X    }
  376. X
  377. X    /* Check if the bad guy is above a hole. */
  378. X    if((x & 1) == 0 && (y & 1) == 0 && fast_lookup[below].code & STOPBAD) {
  379. X      /* If the hole is premature, fill it */
  380. X      if(below >= HOLE1 && below <= HOLE1+2)
  381. X        fill_hole(x >> 1,(y >> 1) + 1);
  382. X    }
  383. X
  384. X    /* Complete previous movement */
  385. X    if((x & 1) != 0 || (y & 1) != 0)
  386. X      dir = badguys[i].dir;
  387. X
  388. X    /* Can only drop things when at a non-offset position and when */
  389. X    /* there is space underneath */
  390. X    else if(curchar == SPACE && badguys[i].hold != SPACE && 
  391. X       /* Drop stuff with a 1 in 20 chance */
  392. X       random() % 20 == 0)
  393. X      dir = PUTDOWN;
  394. X
  395. X    /* Compute next hopeful direction of movement, since badguy is at */
  396. X    /* an even spot */
  397. X    else {
  398. X      /* Get allowable movement direction */
  399. X      allow = moveallow[lpos];
  400. X      /* Prevent bad guy from spontaneously switching direction */
  401. X      if(badguys[i].dir == UP)
  402. X        allow &= ~MOVEDOWN;
  403. X      else if(badguys[i].dir == DOWN)
  404. X        allow &= ~MOVEUP;
  405. X      else if(badguys[i].dir == LEFT)
  406. X        allow &= ~MOVERIGHT;
  407. X      else if(badguys[i].dir == RIGHT)
  408. X        allow &= ~MOVELEFT;
  409. X
  410. X      /* Prevent bad guy from trying to run into somebody else */
  411. X      if((allow & MOVEUP) &&
  412. X         overlap_badguy(badguys[i].xpos,badguys[i].ypos - 2,i))
  413. X        allow &= ~MOVEUP;
  414. X      /* Prevent bad guy from trying to run into somebody else */
  415. X      if((allow & MOVEDOWN) &&
  416. X         overlap_badguy(badguys[i].xpos,badguys[i].ypos + 2,i))
  417. X        allow &= ~MOVEDOWN;
  418. X      /* Prevent bad guy from trying to run into somebody else */
  419. X      if((allow & MOVELEFT) &&
  420. X         overlap_badguy(badguys[i].xpos - 2,badguys[i].ypos,i))
  421. X        allow &= ~MOVELEFT;
  422. X      /* Prevent bad guy from trying to run into somebody else */
  423. X      if((allow & MOVERIGHT) &&
  424. X         overlap_badguy(badguys[i].xpos + 2,badguys[i].ypos,i))
  425. X        allow &= ~MOVERIGHT;
  426. X      
  427. X      /* Try to move according to movement tree */
  428. X      if((allow & MOVEUP) && movetree[lpos] == MOVEUP)
  429. X        dir = UP;
  430. X      else if((allow & MOVEDOWN) && movetree[lpos] == MOVEDOWN)
  431. X        dir = DOWN;
  432. X      else if((allow & MOVELEFT) && movetree[lpos] == MOVELEFT)
  433. X        dir = LEFT;
  434. X      else if((allow & MOVERIGHT) && movetree[lpos] == MOVERIGHT)
  435. X        dir = RIGHT;
  436. X      
  437. X      /* Try circling clockwise around player */
  438. X      else if((allow & MOVEUP) && badguys[i].xpos < player.xpos)
  439. X        dir = UP;
  440. X      else if((allow & MOVEDOWN) && badguys[i].xpos > player.xpos)
  441. X        dir = DOWN;
  442. X      else if((allow & MOVELEFT) && badguys[i].ypos > player.ypos)
  443. X        dir = LEFT;
  444. X      else if((allow & MOVERIGHT) && badguys[i].ypos < player.ypos)
  445. X        dir = RIGHT;
  446. X
  447. X      /* Try approaching player */
  448. X      else if((allow & MOVEUP) && badguys[i].ypos > player.ypos)
  449. X        dir = UP;
  450. X      else if((allow & MOVEDOWN) && badguys[i].ypos < player.ypos)
  451. X        dir = DOWN;
  452. X      else if((allow & MOVELEFT) && badguys[i].xpos > player.xpos)
  453. X        dir = LEFT;
  454. X      else if((allow & MOVERIGHT) && badguys[i].xpos < player.xpos)
  455. X        dir = RIGHT;
  456. X      
  457. X      /* Try moving in any possible direction */
  458. X      else if(allow & MOVEUP)
  459. X        dir = UP;
  460. X      else if(allow & MOVEDOWN)
  461. X        dir = DOWN;
  462. X      else if(allow & MOVELEFT)
  463. X        dir = LEFT;
  464. X      else if(allow & MOVERIGHT)
  465. X        dir = RIGHT;
  466. X
  467. X      /* If totally stuck, just stand in place */
  468. X      else
  469. X        dir = STAND;
  470. X    }
  471. X
  472. X    /* Reverse bad guys direction is REVERSE item is held by player */
  473. X    if((fast_lookup[player.hold].code & REVERSE) &&
  474. X       (x & 1) == 0 && (y & 1) == 0)
  475. X      switch(dir) {
  476. X      case LEFT:  dir = RIGHT; break;
  477. X      case RIGHT: dir = LEFT;  break;
  478. X      case UP:    dir = DOWN;  break;
  479. X      case DOWN:  dir = UP;    break;
  480. X      }
  481. X    
  482. X    /* Execute computed movement. */
  483. X    if(movething(&(badguys[i]),dir,i) == 3) {
  484. X      /* If the bad guy dropped something, the block will have been */
  485. X      /* overwritten and now the bad guy needs to be redrawn */
  486. X      badguys[i].redraw = 1;
  487. X      break;
  488. X    }
  489. X
  490. X    /* Redraw bad guy if it has moved */
  491. X    if(x != badguys[i].xpos || y != badguys[i].ypos)
  492. X      badguys[i].redraw = 1;
  493. X  }
  494. X  /* Redraw bad guys in new positions */
  495. X  drawmove_badguys();
  496. X}
  497. END_OF_FILE
  498. if test 16560 -ne `wc -c <'golddig2/badguy.c'`; then
  499.     echo shar: \"'golddig2/badguy.c'\" unpacked with wrong size!
  500. fi
  501. # end of 'golddig2/badguy.c'
  502. fi
  503. if test -f 'golddig2/movement.c' -a "${1}" != "-c" ; then 
  504.   echo shar: Will not clobber existing file \"'golddig2/movement.c'\"
  505. else
  506. echo shar: Extracting \"'golddig2/movement.c'\" \(15801 characters\)
  507. sed "s/^X//" >'golddig2/movement.c' <<'END_OF_FILE'
  508. X/* This program was written by Alexander Siegel in September of 1989   */
  509. X/* at Cornell University.  It may may copied freely for private use or */
  510. X/* public dispersion provided that this comment is not removed.  This  */
  511. X/* program, any portion of this program, or any derivative of this     */
  512. X/* program may not be sold or traded for financial gain.               */
  513. X
  514. X#include <stdio.h>
  515. X#include <X11/Xlib.h>
  516. X#include <X11/keysym.h>
  517. X#include "golddig.h"
  518. X
  519. Xlong random();
  520. X
  521. X#define MAXHOLE 100     /* Maximum number of holes at once */
  522. X
  523. Xint holedecay[] = {2,4,6,62,66,70,74};  /* Number of ticks after which */
  524. X                                        /* hole will change form. */
  525. Xint numholes;           /* Total number of holes */
  526. X/* Structure to describe a hole */
  527. Xstruct {
  528. X  int x,y;      /* Position of hole */
  529. X  int ticmade;  /* Value of curtick when hole was created.  Used to */
  530. X                /* time hole transitions. */
  531. X} holes[MAXHOLE];   /* Array for holes. */
  532. X
  533. X/* Compute the allowable directions of movement out of a block.  The */
  534. X/* value in the moveallow array is updated at that position. */
  535. Xvoid allow_posit(x,y)
  536. Xregister int x,y;       /* Position of block which is to be checked */
  537. X{
  538. X  register int pos,code,code2,allow;
  539. X
  540. X  /* Get position of block in level array */
  541. X  pos = x*ysize + y;
  542. X  /* Initially assume that all directions of movement are acceptable */
  543. X  allow = MOVEUP | MOVEDOWN | MOVELEFT | MOVERIGHT;
  544. X  /* Prevent movement off of the level into nowhere land */
  545. X  if(x == 0)
  546. X    allow &= ~MOVELEFT;
  547. X  if(y == 0)
  548. X    allow &= ~MOVEUP;
  549. X  if(x == xsize - 1)
  550. X    allow &= ~MOVERIGHT;
  551. X  if(y == ysize - 1)
  552. X    allow &= ~MOVEDOWN;
  553. X  
  554. X  /* Get the control code for the block at the position */
  555. X  code = fast_lookup[level[pos]].code;
  556. X  /* Use the control code for space if the block is inactive */
  557. X  if((code & INACTIVE) && goldleft > 0)
  558. X    code = fast_lookup[SPACE].code;
  559. X  /* Use the control bits for the block to reduce the allowable */
  560. X  /* movement directions */
  561. X  if(! (code & ULEAVE))
  562. X    allow &= ~MOVEUP;
  563. X  if(! (code & DLEAVE))
  564. X    allow &= ~MOVEDOWN;
  565. X  if(! (code & LLEAVE))
  566. X    allow &= ~MOVELEFT;
  567. X  if(! (code & RLEAVE))
  568. X    allow &= ~MOVERIGHT;
  569. X
  570. X  /* Check block to the left to make sure that it is possible to enter */
  571. X  /* that block from the current position. */
  572. X  if(x > 0) {
  573. X    /* Put control code for block to the left into register */
  574. X    code2 = fast_lookup[level[pos - ysize]].code;
  575. X    if((code2 & INACTIVE) && goldleft > 0)
  576. X      code2 = fast_lookup[SPACE].code;
  577. X    /* Determine if it possible to enter */
  578. X    if(! (code2 & HENTER))
  579. X      allow &= ~MOVELEFT;
  580. X    /* Prevent falling back into it if something can walk back from it */
  581. X    if((code2 & RLEAVE) && ! (code2 & CANFALL))
  582. X      code &= ~LFALL;
  583. X  }
  584. X  /* Check block to the right */
  585. X  if(x < xsize - 1) {
  586. X    code2 = fast_lookup[level[pos + ysize]].code;
  587. X    if((code2 & INACTIVE) && goldleft > 0)
  588. X      code2 = fast_lookup[SPACE].code;
  589. X    /* Determine if it possible to enter */
  590. X    if(! (code2 & HENTER))
  591. X      allow &= ~MOVERIGHT;
  592. X    /* Prevent falling back into it if something can walk back from it */
  593. X    if((code2 & LLEAVE) && ! (code2 & CANFALL))
  594. X      code &= ~RFALL;
  595. X  }
  596. X  /* Check block above */
  597. X  if(y > 0) {
  598. X    code2 = fast_lookup[level[pos - 1]].code;
  599. X    if((code2 & INACTIVE) && goldleft > 0)
  600. X      code2 = fast_lookup[SPACE].code;
  601. X    /* Determine if it possible to enter */
  602. X    if(! (code2 & VENTER))
  603. X      allow &= ~MOVEUP;
  604. X    /* Prevent falling back into it if something can walk back from it */
  605. X    if((code2 & DLEAVE) && ! (code2 & CANFALL))
  606. X      code &= ~UFALL;
  607. X  }
  608. X  /* Check block below */
  609. X  if(y < ysize - 1) {
  610. X    code2 = fast_lookup[level[pos + 1]].code;
  611. X    if((code2 & INACTIVE) && goldleft > 0)
  612. X      code2 = fast_lookup[SPACE].code;
  613. X    /* Determine if it possible to enter */
  614. X    if(! (code2 & VENTER))
  615. X      allow &= ~MOVEDOWN;
  616. X    /* Prevent falling back into it if something can walk back from it */
  617. X    /* Note that things will stick up if there is upward gravity */
  618. X    /* pointing into downward gravity. */
  619. X    if(code2 & ULEAVE)
  620. X      code &= ~DFALL;
  621. X  }
  622. X
  623. X  /* Add gravity force */
  624. X  if((code & DFALL) && (allow & MOVEDOWN))
  625. X    allow |= FORCEDOWN;
  626. X  if((code & UFALL) && (allow & MOVEUP))
  627. X    allow |= FORCEUP;
  628. X  if((code & LFALL) && (allow & MOVELEFT))
  629. X    allow |= FORCELEFT;
  630. X  if((code & RFALL) && (allow & MOVERIGHT))
  631. X    allow |= FORCERIGHT;
  632. X
  633. X  /* Store value back into moveallow array */
  634. X  moveallow[pos] = allow;
  635. X}
  636. X
  637. X/* Call allow_posit on a position and all surrounding positions */
  638. Xvoid allow_area(x,y)
  639. Xint x,y;        /* Position to call allow_posit at */
  640. X{
  641. X  allow_posit(x,y);
  642. X  if(x < xsize - 1)
  643. X    allow_posit(x+1,y);
  644. X  if(x > 0)
  645. X    allow_posit(x-1,y);
  646. X  if(y < ysize - 1)
  647. X    allow_posit(x,y+1);
  648. X  if(y > 0)
  649. X    allow_posit(x,y-1);
  650. X}
  651. X
  652. X/* Regenerate entire moveallow array */
  653. Xvoid regen_allow()
  654. X{
  655. X  int x,y;
  656. X
  657. X  /* Iterate through every possible position and call allow_posit on */
  658. X  /* it. */
  659. X  for(x=0;x<xsize;++x)
  660. X    for(y=0;y<ysize;++y)
  661. X      allow_posit(x,y);
  662. X}
  663. X
  664. X/* Form a hole. */
  665. Xvoid make_hole(x,y,code)
  666. Xint x,y;        /* Position where hole is to be formed */
  667. Xlong code;      /* Code of item held while digging */
  668. X{
  669. X  register int pos;
  670. X
  671. X  /* Compute position in level array where hole is to be created */
  672. X  pos = x*ysize + y;
  673. X  /* Make sure that the position is inside the level array */
  674. X  if(x < 0 || x >= xsize || y < 1 || y >= ysize)
  675. X    return;
  676. X  /* Check for reverse shovel */
  677. X  if(code & RSHOVEL) {
  678. X    /* Make sure that there is space is the specified position */
  679. X    if(level[pos] != SPACE)
  680. X      return;
  681. X    /* Replace space with brick */
  682. X    setchar(x,y,BRICK);
  683. X  }
  684. X  else {
  685. X    /* Make sure that the block can be dug */
  686. X    if(! (fast_lookup[level[pos]].code & CANDIG) ||
  687. X       /* Make sure that the block above it allows for digging */
  688. X       /* underneath. */
  689. X       ! (fast_lookup[level[pos - 1]].code & DIGUND))
  690. X      return;
  691. X    
  692. X    /* Check for power shovel */
  693. X    if(code & PSHOVEL)
  694. X      setchar(x,y,SPACE);
  695. X    else {
  696. X      /* Prevent the creation of too many holes */
  697. X      if(numholes >= MAXHOLE)
  698. X        return;
  699. X      /* Replace the character at the position with the first hole block */
  700. X      setchar(x,y,HOLE1);
  701. X      /* Add that hole to the hole array */
  702. X      holes[numholes].x = x;
  703. X      holes[numholes].y = y;
  704. X      holes[numholes].ticmade = curtick;
  705. X      numholes ++;
  706. X    }
  707. X  }
  708. X  /* Recompute the allowable movement direction for that position and */
  709. X  /* all surrounding positions */
  710. X  allow_area(x,y);
  711. X}
  712. X
  713. X/* Fill up a hole with brick */
  714. Xvoid fill_hole(x,y)
  715. Xint x,y;        /* Position specifying hole */
  716. X{
  717. X  register int i;
  718. X
  719. X  /* Look through all the holes until the right one is found */
  720. X  for(i=0;i<numholes;++i)
  721. X    if(holes[i].x == x && holes[i].y == y) {
  722. X      /* Change the block to a brick */
  723. X      setchar(holes[i].x,holes[i].y,BRICK);
  724. X      /* Recompute the allowable movement for the specified position */
  725. X      /* and all surrounding positions. */
  726. X      allow_area(holes[i].x,holes[i].y);
  727. X      /* Remove the hole from the holes array */
  728. X      holes[i] = holes[numholes - 1];
  729. X      numholes --;
  730. X      return;
  731. X    }
  732. X}
  733. X
  734. X/* Age all holes by one clock tick */
  735. Xvoid change_holes()
  736. X{
  737. X  register int i,j;
  738. X
  739. X  /* Look for decaying holes.  Iterate through each hole. */
  740. X  for(i=0;i<numholes;++i) {
  741. X    /* Check if the hole is exactly at any transition point */
  742. X    for(j=0;j<7;++j)
  743. X      if(holes[i].ticmade + holedecay[j] == curtick) {
  744. X        /* If it is a normal transition point, just change the block */
  745. X        /* type */
  746. X        if(j < 6)
  747. X          setchar(holes[i].x,holes[i].y,(char) (HOLE1 + j + 1));
  748. X        /* If it is the last transition point, fill the hole in */
  749. X        else {
  750. X          fill_hole(holes[i].x,holes[i].y);
  751. X          /* Back up one hole since the hole that was at this position */
  752. X          /* has now been replaced by another. */
  753. X          i --;
  754. X        }
  755. X        break;
  756. X      }
  757. X  }
  758. X}
  759. X
  760. X/* Try to move a thing (player or bad guy) in a given direction.  The */
  761. X/* structure describing the things is updated in place with the new */
  762. X/* position and apparent active command.  A code value is returned */
  763. X/* describing what type of movement actually occurred. */
  764. Xint movething(thing,newdir,num)
  765. Xregister struct thing_s *thing;     /* Pointer to struct describing */
  766. X                                    /* current state of thing */
  767. Xenum directs newdir;                /* New command being attempted */
  768. Xint num;                            /* Number of bad guy or -1 for */
  769. X                                    /* player */
  770. X{
  771. X  register int lpos,code;
  772. X  int nx,ny;
  773. X
  774. X  /* Compute useful local values */
  775. X  lpos = (thing->xpos >> 1)*ysize + (thing->ypos >> 1);
  776. X  code = fast_lookup[level[lpos]].code;
  777. X  if((code & INACTIVE) && goldleft > 0)
  778. X    code = fast_lookup[SPACE].code;
  779. X
  780. X  /* Complete previous initiated movement */
  781. X  if((thing->xpos & 1) || (thing->ypos & 1)) {
  782. X    /* Allow partial horizontal movement to complete */
  783. X    if(thing->xpos & 1) {
  784. X      /* Continue in old direction */
  785. X      switch(thing->dir) {
  786. X      case LEFT:
  787. X        thing->xpos -= 1;
  788. X        thing->dir = LEFT;
  789. X        break;
  790. X      default:
  791. X        thing->xpos += 1;
  792. X        thing->dir = RIGHT;
  793. X        break;
  794. X      }
  795. X    }
  796. X    
  797. X    /* Allow partial vertical movement to complete */
  798. X    if(thing->ypos & 1) {
  799. X      /* Continue in old direction */
  800. X      switch(thing->dir) {
  801. X      case UP:
  802. X        thing->ypos -= 1;
  803. X        thing->dir = UP;
  804. X        break;
  805. X      default:
  806. X        thing->ypos += 1;
  807. X        thing->dir = DOWN;
  808. X        break;
  809. X      }
  810. X    }
  811. X
  812. X    /* Pickup things which are laying around */
  813. X    lpos = (thing->xpos >> 1)*ysize + (thing->ypos >> 1);
  814. X    code = fast_lookup[level[lpos]].code;
  815. X    if(newdir != PUTDOWN && (code & PICKUP) && thing->hold == SPACE) {
  816. X      thing->hold = level[lpos];
  817. X      setchar(thing->xpos >> 1,thing->ypos >> 1,SPACE);
  818. X      allow_area(thing->xpos >> 1,thing->ypos >> 1);
  819. X    }
  820. X
  821. X    /* Activate teleporter if standing on one and not holding an */
  822. X    /* anchor */
  823. X    if((code & TELEPORT) &&
  824. X       ! (fast_lookup[thing->hold].code & ANCHOR)) {
  825. X      do {
  826. X        lpos ++;
  827. X        thing->ypos += 2;
  828. X        if(thing->ypos >> 1 == ysize) {
  829. X          thing->ypos = 0;
  830. X          thing->xpos += 2;
  831. X          if(thing->xpos >> 1 == xsize) {
  832. X            lpos = 0;
  833. X            thing->xpos = 0;
  834. X          }
  835. X        }
  836. X      } while(! (fast_lookup[level[lpos]].code & TELEPORT));
  837. X    }
  838. X
  839. X    /* Activate jump pad if standing on one and not holding an anchor */
  840. X    if((code & UPTWO) &&
  841. X       ! (fast_lookup[thing->hold].code & ANCHOR)) {
  842. X      thing->ypos -= 4;
  843. X      if(thing->ypos < 0)
  844. X        thing->ypos = 0;
  845. X    }
  846. X
  847. X    /* Activate super jump pad */
  848. X    if(code & UPALL) {
  849. X      thing->ypos -= 4;
  850. X      /* Jump to the top of screen if not holding an anchor */
  851. X      if(thing->ypos < 0 ||
  852. X         ! (fast_lookup[thing->hold].code & ANCHOR))
  853. X        thing->ypos = 0;
  854. X    }
  855. X
  856. X    return(1);
  857. X  }
  858. X
  859. X  /* Allow creature to fall */
  860. X  if((moveallow[lpos] & FORCEALL) &&
  861. X     ! (fast_lookup[thing->hold].code & STOPFALL)) {
  862. X    /* Compute position offset in direction of fall */
  863. X    nx = ny = 0;
  864. X    if(moveallow[lpos] & FORCEDOWN) {
  865. X      ny = 1;
  866. X      thing->dir = DOWN;
  867. X    }
  868. X    if(moveallow[lpos] & FORCEUP) {
  869. X      ny = -1;
  870. X      thing->dir = UP;
  871. X    }
  872. X    if(moveallow[lpos] & FORCERIGHT) {
  873. X      nx = 1;
  874. X      thing->dir = RIGHT;
  875. X    }
  876. X    if(moveallow[lpos] & FORCELEFT) {
  877. X      nx = -1;
  878. X      thing->dir = LEFT;
  879. X    }
  880. X
  881. X    /* Prevent falling into another thing */
  882. X    if(! overlap_badguy(thing->xpos + nx + nx,thing->ypos + ny + ny,num)) {
  883. X      /* Drop item behind if falling into a hole */
  884. X      if(level[lpos] == SPACE && thing->hold != SPACE) {
  885. X        /* Compute level position of space that thing is falling into */
  886. X        lpos = ((thing->xpos >> 1)+nx)*ysize + 
  887. X          ((thing->ypos >> 1)+ny);
  888. X        /* Check to see if next position is a hole */
  889. X        if(fast_lookup[level[lpos]].code & STOPBAD) {
  890. X          setchar(thing->xpos >> 1,thing->ypos >> 1,thing->hold);
  891. X          thing->hold = SPACE;
  892. X          allow_area(thing->xpos >> 1,thing->ypos >> 1);
  893. X        }
  894. X      }
  895. X
  896. X      /* Increment position */
  897. X      thing->xpos += nx;
  898. X      thing->ypos += ny;
  899. X      return(2);
  900. X    }
  901. X  }
  902. X
  903. X  /* Slow movement down if holding an anchor */
  904. X  if((fast_lookup[thing->hold].code & ANCHOR) && (random() % 4 != 0))
  905. X    newdir = STAND;
  906. X
  907. X  /* Continue previous movement if it was at right angles to intended */
  908. X  /* movement, and intended movement is impossible */
  909. X  switch(newdir) {
  910. X  /* Check for possible upward movement. */
  911. X  case UP:
  912. X    if(! (moveallow[lpos] & MOVEUP)) {
  913. X      if(thing->dir == LEFT || thing->dir == RIGHT)
  914. X        newdir = thing->dir;
  915. X    }
  916. X    break;
  917. X  /* Check for possible downward movement. */
  918. X  case DOWN:
  919. X    if(! (moveallow[lpos] & MOVEDOWN)) {
  920. X      if(thing->dir == LEFT || thing->dir == RIGHT)
  921. X        newdir = thing->dir;
  922. X    }
  923. X    break;
  924. X  /* Check for possible left movement. */
  925. X  case LEFT:
  926. X    if(! (moveallow[lpos] & MOVELEFT)) {
  927. X      if(thing->dir == UP || thing->dir == DOWN)
  928. X        newdir = thing->dir;
  929. X    }
  930. X    break;
  931. X  /* Check for possible right movement. */
  932. X  case RIGHT:
  933. X    if(! (moveallow[lpos] & MOVERIGHT)) {
  934. X      if(thing->dir == UP || thing->dir == DOWN)
  935. X        newdir = thing->dir;
  936. X    }
  937. X    break;
  938. X  }
  939. X
  940. X  /* By default, the thing is standing in place */
  941. X  thing->dir = STAND;
  942. X  /* Try to execute the intended movement */
  943. X  switch(newdir) {
  944. X  /* Put something down if that is the order */
  945. X  case PUTDOWN:
  946. X    if(level[lpos] == SPACE && thing->hold != SPACE) {
  947. X      setchar(thing->xpos >> 1,thing->ypos >> 1,thing->hold);
  948. X      thing->hold = SPACE;
  949. X      allow_area(thing->xpos >> 1,thing->ypos >> 1);
  950. X    }
  951. X    return(3);
  952. X  /* Dig holes left or right if that is the command.  The make_hole */
  953. X  /* command will fail if it is impossible to dig a hole at the */
  954. X  /* specified location. */
  955. X  case DIGLEFT:
  956. X    make_hole((thing->xpos >> 1) - 1,(thing->ypos >> 1) + 1,
  957. X              fast_lookup[thing->hold].code);
  958. X    if(fast_lookup[thing->hold].code & NSHOVEL) {
  959. X      make_hole((thing->xpos >> 1) - 2,(thing->ypos >> 1) + 1,
  960. X                fast_lookup[thing->hold].code);
  961. X      make_hole((thing->xpos >> 1) - 1,(thing->ypos >> 1) + 2,
  962. X                fast_lookup[thing->hold].code);
  963. X      make_hole((thing->xpos >> 1) - 2,(thing->ypos >> 1) + 2,
  964. X                fast_lookup[thing->hold].code);
  965. X    }
  966. X    return(4);
  967. X  case DIGRIGHT:
  968. X    make_hole((thing->xpos >> 1) + 1,(thing->ypos >> 1) + 1,
  969. X              fast_lookup[thing->hold].code);
  970. X    if(fast_lookup[thing->hold].code & NSHOVEL) {
  971. X      make_hole((thing->xpos >> 1) + 2,(thing->ypos >> 1) + 1,
  972. X                fast_lookup[thing->hold].code);
  973. X      make_hole((thing->xpos >> 1) + 1,(thing->ypos >> 1) + 2,
  974. X                fast_lookup[thing->hold].code);
  975. X      make_hole((thing->xpos >> 1) + 2,(thing->ypos >> 1) + 2,
  976. X                fast_lookup[thing->hold].code);
  977. X    }
  978. X    return(4);
  979. X  /* Since the thing is not falling or completing a previous movement, */
  980. X  /* it can start off in a new direction.  The moveallow array is used */
  981. X  /* to determine which directions are possible. */
  982. X  /* Check for possible upward movement. */
  983. X  case UP:
  984. X    if(moveallow[lpos] & MOVEUP) {
  985. X      thing->ypos -= 1;
  986. X      thing->dir = UP;
  987. X    }
  988. X    break;
  989. X  /* Check for possible downward movement. */
  990. X  case DOWN:
  991. X    if(moveallow[lpos] & MOVEDOWN) {
  992. X      thing->ypos += 1;
  993. X      thing->dir = DOWN;
  994. X    }
  995. X    break;
  996. X  /* Check for possible left movement. */
  997. X  case LEFT:
  998. X    if(moveallow[lpos] & MOVELEFT) {
  999. X      thing->xpos -= 1;
  1000. X      thing->dir = LEFT;
  1001. X    }
  1002. X    break;
  1003. X  /* Check for possible right movement. */
  1004. X  case RIGHT:
  1005. X    if(moveallow[lpos] & MOVERIGHT) {
  1006. X      thing->xpos += 1;
  1007. X      thing->dir = RIGHT;
  1008. X    }
  1009. X    break;
  1010. X  }
  1011. X  return(0);
  1012. X}
  1013. END_OF_FILE
  1014. if test 15801 -ne `wc -c <'golddig2/movement.c'`; then
  1015.     echo shar: \"'golddig2/movement.c'\" unpacked with wrong size!
  1016. fi
  1017. # end of 'golddig2/movement.c'
  1018. fi
  1019. if test -f 'golddig2/shared.c' -a "${1}" != "-c" ; then 
  1020.   echo shar: Will not clobber existing file \"'golddig2/shared.c'\"
  1021. else
  1022. echo shar: Extracting \"'golddig2/shared.c'\" \(14143 characters\)
  1023. sed "s/^X//" >'golddig2/shared.c' <<'END_OF_FILE'
  1024. X/* This program was written by Alexander Siegel in September of 1989   */
  1025. X/* at Cornell University.  It may may copied freely for private use or */
  1026. X/* public dispersion provided that this comment is not removed.  This  */
  1027. X/* program, any portion of this program, or any derivative of this     */
  1028. X/* program may not be sold or traded for financial gain.               */
  1029. X
  1030. X#include <stdio.h>
  1031. X#include <X11/Xlib.h>
  1032. X#include <X11/keysym.h>
  1033. X#include <X11/Xutil.h>
  1034. X#include <errno.h>
  1035. X#include <string.h>
  1036. X#include "golddig.h"
  1037. X
  1038. X/* Include all the bitmaps for the terrain blocks */
  1039. X#include "bitmap/player.bits"
  1040. X#include "bitmap/badguy.bits"
  1041. X#include "bitmap/ladder.bits"
  1042. X#include "bitmap/space.bits"
  1043. X#include "bitmap/wall.bits"
  1044. X#include "bitmap/hole1.bits"
  1045. X#include "bitmap/hole2.bits"
  1046. X#include "bitmap/hole3.bits"
  1047. X#include "bitmap/hole4.bits"
  1048. X#include "bitmap/hole5.bits"
  1049. X#include "bitmap/hole6.bits"
  1050. X#include "bitmap/hole7.bits"
  1051. X#include "bitmap/stone.bits"
  1052. X#include "bitmap/ghost.bits"
  1053. X#include "bitmap/gold.bits"
  1054. X#include "bitmap/escape.bits"
  1055. X#include "bitmap/rope.bits"
  1056. X#include "bitmap/uplevel.bits"
  1057. X#include "bitmap/invis.bits"
  1058. X#include "bitmap/steplad.bits"
  1059. X#include "bitmap/tube.bits"
  1060. X#include "bitmap/chute.bits"
  1061. X#include "bitmap/vrope.bits"
  1062. X#include "bitmap/teleport.bits"
  1063. X#include "bitmap/armor.bits"
  1064. X#include "bitmap/parac.bits"
  1065. X#include "bitmap/nshovel.bits"
  1066. X#include "bitmap/hourgl.bits"
  1067. X#include "bitmap/reverse.bits"
  1068. X#include "bitmap/portable.bits"
  1069. X#include "bitmap/larrow.bits"
  1070. X#include "bitmap/rarrow.bits"
  1071. X#include "bitmap/darrow.bits"
  1072. X#include "bitmap/uarrow.bits"
  1073. X#include "bitmap/kill.bits"
  1074. X#include "bitmap/jump.bits"
  1075. X#include "bitmap/anchor.bits"
  1076. X#include "bitmap/sjump.bits"
  1077. X#include "bitmap/speed.bits"
  1078. X#include "bitmap/pshovel.bits"
  1079. X#include "bitmap/rshovel.bits"
  1080. X#include "bitmap/fog.bits"
  1081. X#include "bitmap/window.bits"
  1082. X#include "bitmap/anti.bits"
  1083. X
  1084. Xchar *sprintf();    /* UNIX brain damage */
  1085. X
  1086. X/* All in and out movements except up */
  1087. X#define NOUPBITS   DLEAVE | LLEAVE | RLEAVE | HENTER | VENTER
  1088. X/* All in and out movements */
  1089. X#define MOVEBITS   NOUPBITS | ULEAVE
  1090. X/* Standard bit pattern for empty space */
  1091. X#define SPACEBITS  NOUPBITS | DIGUND | DFALL
  1092. X/* Generic item which can be picked up */
  1093. X#define ITEMBITS   SPACEBITS | PICKUP
  1094. X/* Bit pattern used for dug holes */
  1095. X#define HOLEBITS   SPACEBITS | STOPBAD | NODRAW
  1096. X
  1097. X/* Structure describing all the characteristics of all blocks.  Refer */
  1098. X/* to the defines and structure definition in golddig.h. */
  1099. Xstruct symbs_s symbs[] = 
  1100. X  {{SPACE,SPACE,"space",space_bits,SPACEBITS,XK_space,0},
  1101. X   {'!','|',"escape",escape_bits,MOVEBITS | DIGUND | INACTIVE,XK_exclam,XK_1},
  1102. X   {BRICK,BRICK,"wall",wall_bits,CANDIG | KILLIN,XK_3,XK_numbersign},
  1103. X   {'$','$',"gold",gold_bits,ITEMBITS | TREASURE,XK_4,XK_dollar},
  1104. X   {'-','-',"rope",rope_bits,NOUPBITS | DIGUND,XK_minus,0},
  1105. X   {HOLE1,HOLE1,"hole1",hole1_bits,HOLEBITS,0,0},
  1106. X   {HOLE1+1,HOLE1+1,"hole2",hole2_bits,HOLEBITS,0,0},
  1107. X   {HOLE1+2,HOLE1+2,"hole3",hole3_bits,HOLEBITS,0,0},
  1108. X   {HOLE1+3,HOLE1+3,"hole4",hole4_bits,HOLEBITS,0,0},
  1109. X   {HOLE1+4,HOLE1+4,"hole5",hole5_bits,HOLEBITS,0,0},
  1110. X   {HOLE1+5,HOLE1+5,"hole6",hole6_bits,HOLEBITS,0,0},
  1111. X   {HOLE1+6,HOLE1+6,"hole7",hole7_bits,HOLEBITS,0,0},
  1112. X   {'<','<',"left arrow",larrow_bits,LLEAVE | HENTER | VENTER | LFALL | DIGUND,
  1113. X      XK_comma,XK_less},
  1114. X   {'=','=',"tube",tube_bits,RLEAVE | LLEAVE | HENTER,XK_equal,0},
  1115. X   {'>','>',"right arrow",rarrow_bits,RLEAVE | HENTER | VENTER | RFALL | 
  1116. X      DIGUND,XK_period,XK_greater},
  1117. X   {STONE,STONE,"stone",stone_bits,KILLIN,XK_2,XK_at},
  1118. X   {'^','^',"anti-space",anti_bits,ULEAVE | LLEAVE | RLEAVE | HENTER |
  1119. X      VENTER | DIGUND | UFALL,XK_6,XK_asciicircum},
  1120. X   {'a','a',"armor",armor_bits,ITEMBITS | ARMOR,XK_A,XK_a},
  1121. X   {BADGUY,BADGUY,"bad guy",badguy_bits,SPACEBITS,XK_B,XK_b},
  1122. X   {'c','c',"chute",chute_bits,DLEAVE | DFALL | VENTER,XK_C,XK_c},
  1123. X   {'d','d',"down arrow",darrow_bits,DLEAVE | HENTER | VENTER | DIGUND |
  1124. X      DFALL,XK_D,XK_d},
  1125. X   {'e','e',"reverse monster",reverse_bits,ITEMBITS | REVERSE, XK_E,XK_e},
  1126. X   {'f','f',"up arrow",uarrow_bits,ULEAVE | HENTER | VENTER | UFALL |
  1127. X      DIGUND,XK_F,XK_f},
  1128. X   {'g',BRICK,"ghost brick",ghost_bits,(SPACEBITS) & ~HENTER,XK_G,XK_g},
  1129. X   {'i',SPACE,"invisible block",invis_bits,KILLIN,XK_I,XK_i},
  1130. X   {'j','j',"jump pad",jump_bits,NOUPBITS | UPTWO,XK_J,XK_j},
  1131. X   {'k','k',"kill zone",kill_bits,HENTER | VENTER | DIGUND |
  1132. X      KILLIN,XK_K,XK_k},
  1133. X   {'l','l',"power shovel",pshovel_bits,ITEMBITS | PSHOVEL,XK_L,XK_l},
  1134. X   {'m','m',"super jump pad",sjump_bits,NOUPBITS | UPALL,XK_M,XK_m},
  1135. X   {'n','n',"nuclear shovel",nshovel_bits,ITEMBITS | NSHOVEL,XK_N,XK_n},
  1136. X   {'o','o',"anchor",anchor_bits,ITEMBITS | ANCHOR,XK_O,XK_o},
  1137. X   {PLAYER,PLAYER,"player",player_bits,SPACEBITS,XK_P,XK_p},
  1138. X   {'q','q',"speed boot",speed_bits,ITEMBITS | SPEED,XK_Q,XK_q},
  1139. X   {'r','r',"parachute",parac_bits,ITEMBITS | STOPFALL,XK_R,XK_r},
  1140. X   {'s','s',"step ladder",steplad_bits,MOVEBITS | PICKUP,XK_S,XK_s},
  1141. X   {'t','t',"teleporter",teleport_bits,SPACEBITS | TELEPORT,XK_T,XK_t},
  1142. X   {'u','u',"leave level",uplevel_bits,SPACEBITS | UPLEVEL |
  1143. X      INACTIVE,XK_U,XK_u},
  1144. X   {'v','v',"vertical rope",vrope_bits,ULEAVE | DLEAVE |
  1145. X      HENTER | VENTER,XK_V,XK_v},
  1146. X   {'w','w',"window",window_bits,SPACEBITS | UPLEVEL,XK_W,XK_w},
  1147. X   {'x','x',"extra brick",rshovel_bits,ITEMBITS | RSHOVEL,XK_X,XK_x},
  1148. X   {'y','y',"heavy fog",fog_bits,SPACEBITS,XK_Y,XK_y},
  1149. X   {'z','z',"time stop",hourgl_bits,ITEMBITS | TIMESTOP,XK_Z,XK_z},
  1150. X   {'|','|',"ladder",ladder_bits,MOVEBITS,XK_backslash,XK_bar},
  1151. X   {'~','-',"portable rope",portable_bits,NOUPBITS | DIGUND |
  1152. X      PICKUP,XK_asciitilde,XK_quoteleft},
  1153. X
  1154. X   /* List terminator */
  1155. X   {'\0','\0',(char *) 0,(char *) 0,0,0,0}};
  1156. X
  1157. XFont scorefont;     /* Font used to display score */
  1158. XGC scoregc;         /* GC used to draw score */
  1159. XGC blackgc;         /* Simple black foreground GC */
  1160. X
  1161. X/* Manufaction a 16x16 graphics cursor used in a XFill... operation. */
  1162. XGC makegc(func,bits)
  1163. Xint func;       /* Drawing function such as GXcopy or GXor. */
  1164. Xchar bits[];    /* Bits describing fill pattern.  Produced in an X11 */
  1165. X                /* bitmap file usually. */
  1166. X{
  1167. X  static XGCValues gcv;
  1168. X  Pixmap pmap;
  1169. X
  1170. X  /* Build X11 bitmap from data in bits */
  1171. X  pmap = XCreatePixmapFromBitmapData(disp,wind,bits,16,16,BlackPixel(disp,0),
  1172. X                                     WhitePixel(disp,0),DisplayPlanes(disp,0));
  1173. X  /* Assign the graphics cursor parameters */
  1174. X  gcv.function = func;
  1175. X  gcv.foreground = BlackPixel(disp,0);
  1176. X  gcv.background = WhitePixel(disp,0);
  1177. X  gcv.tile = pmap;
  1178. X  gcv.fill_style = FillTiled;
  1179. X  /* Return the created graphics cursor */
  1180. X  return(XCreateGC(disp,wind,GCFunction | GCForeground | GCBackground | 
  1181. X                   GCTile | GCFillStyle,&gcv));
  1182. X}
  1183. X
  1184. X/* Start X11 and do some basic initialization */
  1185. Xvoid xstart(evmask)
  1186. Xlong evmask;    /* Event mask which will be used in XSelectInput */
  1187. X{
  1188. X  register int i;
  1189. X  XGCValues xgcv;
  1190. X  XWMHints wmhints;
  1191. X
  1192. X  /* Open up the display */
  1193. X  disp = XOpenDisplay(NULL);
  1194. X  /* Check to see if the open display succeeded */
  1195. X  if(disp == NULL) {
  1196. X    fprintf(stderr,"Display open failed.  Check DISPLAY environment variable.\n");
  1197. X    exit(-1);
  1198. X  }
  1199. X
  1200. X  /* Create the game window */
  1201. X  wind = XCreateSimpleWindow(disp,DefaultRootWindow(disp),20,20,
  1202. X                             50 << 4,(30 << 4) + SCORESIZE,
  1203. X                             2,WhitePixel(disp,0),BlackPixel(disp,0));
  1204. X  /* Check to see if the open window succeeded */
  1205. X  if(wind == 0) {
  1206. X    fprintf(stderr,"Window open failed.\n");
  1207. X    XCloseDisplay(disp);
  1208. X    exit(-1);
  1209. X  }
  1210. X
  1211. X  /* Clear fast block type lookup table */
  1212. X  for(i=0;i<256;++i) {
  1213. X    fast_lookup[i].gc = NULL;
  1214. X    /* Everything starts out looking like a space */
  1215. X    fast_lookup[i].code = SPACEBITS;
  1216. X  }
  1217. X  /* Generate block type lookup table from symbs array defined above. */
  1218. X  /* After this the symbs array will be used very rarely. */
  1219. X  for(i=0;symbs[i].symb != '\0';++i) {
  1220. X    fast_lookup[symbs[i].symb].gc  =
  1221. X      makegc(GXcopy,symbs[i].bits);
  1222. X    fast_lookup[symbs[i].symb].code = symbs[i].code;
  1223. X  }
  1224. X  /* Load in the font used to display the score */
  1225. X  scorefont = XLoadFont(disp,SCOREFONT);
  1226. X  /* Create GC which will be used from drawing score */
  1227. X  xgcv.function = GXcopy;
  1228. X  xgcv.font = scorefont;
  1229. X  xgcv.foreground = WhitePixel(disp,0);
  1230. X  xgcv.background = BlackPixel(disp,0);
  1231. X  scoregc = XCreateGC(disp,wind,
  1232. X                      GCFunction | GCFont | GCForeground | GCBackground,
  1233. X                      &xgcv);
  1234. X  /* Create GC which will be used for clearing score line */
  1235. X  xgcv.function = GXcopy;
  1236. X  xgcv.foreground = BlackPixel(disp,0);
  1237. X  xgcv.background = WhitePixel(disp,0);
  1238. X  blackgc = XCreateGC(disp,wind,
  1239. X                      GCFunction | GCForeground | GCBackground,
  1240. X                      &xgcv);
  1241. X
  1242. X  /* Tell the WM that we want input... */
  1243. X  wmhints.input = True;
  1244. X  wmhints.flags = InputHint;
  1245. X  XSetWMHints(disp, wind, &wmhints);
  1246. X
  1247. X  /* Select the interesting window events */
  1248. X  XSelectInput(disp,wind,evmask);
  1249. X
  1250. X  /* Name and raise the window */
  1251. X  XMapRaised(disp,wind);
  1252. X
  1253. X  /* Flush and synchronize the server */
  1254. X  XFlush(disp);
  1255. X  XSync(disp,False);
  1256. X}
  1257. X
  1258. X/* Gracefully shut X windows down.  It is not strictly necessary to */
  1259. X/* call this function. */
  1260. Xvoid xend()
  1261. X{
  1262. X  XUnloadFont(disp,scorefont);
  1263. X  XUnmapWindow(disp,wind);
  1264. X  XDestroyWindow(disp,wind);
  1265. X  XCloseDisplay(disp);
  1266. X}
  1267. X
  1268. X/* Draw a block from the level array in the output window. */
  1269. Xvoid draw_block(x,y)
  1270. Xint x,y;    /* Position of block in array */
  1271. X{
  1272. X  register char curchar;
  1273. X  GC drawgc;
  1274. X
  1275. X  /* Get the block character out of the level array */
  1276. X  curchar = level[x*ysize + y];
  1277. X  /* If there is gold left and this block is inactive, replace it with */
  1278. X  /* a space. */
  1279. X  if(goldleft > 0 && (fast_lookup[curchar].code & INACTIVE))
  1280. X    curchar = SPACE;
  1281. X  /* Get the graphics cursor */
  1282. X  drawgc = fast_lookup[curchar].gc;
  1283. X  /* Replace questionable characters with spaces */
  1284. X  if(drawgc == NULL)
  1285. X    drawgc = fast_lookup[SPACE].gc;
  1286. X  /* Fill the block */
  1287. X  XFillRectangle(disp,wind,drawgc,x << 4,y << 4,16,16);
  1288. X}
  1289. X
  1290. X/* Change a block character in the level array.  The block is redrawn. */
  1291. Xvoid setchar(x,y,ch)
  1292. Xint x,y;    /* Position of block character to change. */
  1293. Xchar ch;    /* Character to change it to */
  1294. X{
  1295. X  if(level[x*ysize + y] != ch) {
  1296. X    level[x*ysize + y] = ch;
  1297. X    draw_block(x,y);
  1298. X  }
  1299. X}
  1300. X
  1301. X/* Draw the score and level number */
  1302. Xvoid draw_score()
  1303. X{
  1304. X  char buf[50];
  1305. X
  1306. X  /* Build the output string */
  1307. X  sprintf(buf,"score: %d  level: %d  speed: %d",score,levelnum,speed);
  1308. X  /* Clear the current score line */
  1309. X  XFillRectangle(disp,wind,blackgc,0,ysize << 4,xsize << 4,SCORESIZE);
  1310. X  /* Actually draw the text */
  1311. X  XDrawString(disp,wind,scoregc,0,(ysize << 4) + SCORESIZE - 1,buf,
  1312. X              strlen(buf));
  1313. X}
  1314. X
  1315. X/* Redraw the entire level */
  1316. Xvoid draw_level()
  1317. X{
  1318. X  int x,y;
  1319. X
  1320. X  /* Change the window size */
  1321. X  XResizeWindow(disp,wind,xsize << 4,(ysize << 4) + SCORESIZE);
  1322. X  /* Draw the score and level number */
  1323. X  draw_score();
  1324. X  /* Iterate through each block position and draw it */
  1325. X  for(x=0;x < xsize;++x)
  1326. X    for(y=0;y < ysize;++y)
  1327. X      draw_block(x,y);
  1328. X}
  1329. X
  1330. X/* Load a level out of a file.  The global variables worldname and */
  1331. X/* levelnum are used to produce the file name which is stored in */
  1332. X/* filename. */
  1333. Xvoid load_level()
  1334. X{
  1335. X  FILE *levelfile;
  1336. X  register int i,j;
  1337. X  int x,y;
  1338. X  char buf[300];
  1339. X
  1340. X  /* Manufaction the file name by starting with the world name and */
  1341. X  /* appending the level number to it. */
  1342. X  strcpy(filename,LIB);
  1343. X  strcat(filename,"/");
  1344. X  strcat(filename,worldname);
  1345. X  sprintf(filename + strlen(filename),"%03d",levelnum);
  1346. X  /* Open level file for reading */
  1347. X  levelfile = fopen(filename,"r");
  1348. X  /* If level file does not exist, use the default level file. */
  1349. X  if(levelfile == NULL) {
  1350. X    /* Build the default level name */
  1351. X    strcpy(buf,LIB);
  1352. X    strcat(buf,"/default");
  1353. X    /* Open default level file for reading */
  1354. X    levelfile = fopen(buf,"r");
  1355. X    if(levelfile == NULL) {
  1356. X      perror(worldname);
  1357. X      exit(1);
  1358. X    }
  1359. X  }
  1360. X
  1361. X  /* Load the first line of the level file */
  1362. X  if(fgets(buf,300,levelfile) == NULL) {
  1363. X    x = 50;
  1364. X    y = 30;
  1365. X  }
  1366. X  else {
  1367. X    /* Extract the level size */
  1368. X    sscanf(buf,"%d %d",&x,&y);
  1369. X  }
  1370. X  /* Change level size only if it is necessary */
  1371. X  if(xsize == -1)
  1372. X    xsize = x;
  1373. X  if(ysize == -1)
  1374. X    ysize = y;
  1375. X  /* Carefully check the sanity of the size parameters */
  1376. X  if(xsize < 5)
  1377. X    xsize = 5;
  1378. X  if(xsize > 250)
  1379. X    xsize = 250;
  1380. X  if(ysize < 5)
  1381. X    ysize = 5;
  1382. X  if(ysize > 250)
  1383. X    ysize = 250;
  1384. X  if(xsize * ysize > MAXLEVEL) {
  1385. X    if(xsize > ysize)
  1386. X      xsize = MAXLEVEL / ysize;
  1387. X    else
  1388. X      ysize = MAXLEVEL / xsize;
  1389. X  }
  1390. X  /* Iterate through each horizontal line */
  1391. X  for(i=0;i<ysize;++i) {
  1392. X    /* Load the next line from the file */
  1393. X    if(fgets(buf,300,levelfile) != NULL) {
  1394. X      /* Go through each horizontal position and copy the data into */
  1395. X      /* the level array. */
  1396. X      for(j=0;j<xsize;++j) {
  1397. X        /* Break out if line ends prematurely */
  1398. X        if(buf[j] == '\n' || buf[j] == '\0')
  1399. X          break;
  1400. X        level[j*ysize + i] = buf[j];
  1401. X      }
  1402. X    }
  1403. X    else
  1404. X      j = 0;
  1405. X    /* Fill in rest of premature lines with spaces */
  1406. X    for(;j<xsize;++j)
  1407. X      level[j*ysize + i] = SPACE;
  1408. X  }
  1409. X  /* Close the level file */
  1410. X  fclose(levelfile);
  1411. X}
  1412. X
  1413. X/* Save the current level back into a file.  The global variable */
  1414. X/* filename is used to determine the file name. */
  1415. Xvoid save_level()
  1416. X{
  1417. X  FILE *levelfile;
  1418. X  char buf[300];
  1419. X  register int i,j;
  1420. X
  1421. X  /* Open the data file */
  1422. X  levelfile = fopen(filename,"w");
  1423. X  if(levelfile == NULL) {
  1424. X    perror(worldname);
  1425. X    exit(1);
  1426. X  }
  1427. X  /* Write out the size of the level.  Normal text is used so that */
  1428. X  /* levels can be easily copied across architectures. */
  1429. X  fprintf(levelfile,"%d %d\n",xsize,ysize);
  1430. X  /* Terminate the lines for writing out the horizontal level lines */
  1431. X  buf[xsize] = '\n';
  1432. X  buf[xsize+1] = '\0';
  1433. X  /* Iterate through each vertical position */
  1434. X  for(i=0;i<ysize;++i) {
  1435. X    /* Copy each horizontal line into the output buffer */
  1436. X    for(j=0;j<xsize;++j)
  1437. X      buf[j] = level[j*ysize + i];
  1438. X    /* Write the line out to the file */
  1439. X    fputs(buf,levelfile);
  1440. X  }
  1441. X  /* Close the data file */
  1442. X  fclose(levelfile);
  1443. X}
  1444. X
  1445. X
  1446. END_OF_FILE
  1447. if test 14143 -ne `wc -c <'golddig2/shared.c'`; then
  1448.     echo shar: \"'golddig2/shared.c'\" unpacked with wrong size!
  1449. fi
  1450. # end of 'golddig2/shared.c'
  1451. fi
  1452. echo shar: End of archive 3 \(of 4\).
  1453. cp /dev/null ark3isdone
  1454. MISSING=""
  1455. for I in 1 2 3 4 ; do
  1456.     if test ! -f ark${I}isdone ; then
  1457.     MISSING="${MISSING} ${I}"
  1458.     fi
  1459. done
  1460. if test "${MISSING}" = "" ; then
  1461.     echo You have unpacked all 4 archives.
  1462.     rm -f ark[1-9]isdone
  1463. else
  1464.     echo You still need to unpack the following archives:
  1465.     echo "        " ${MISSING}
  1466. fi
  1467. ##  End of shell archive.
  1468. exit 0
  1469.