1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <X11/Xlib.h>
4 #include <X11/Xutil.h>
5 #include <golddig.h>
6 
7 extern struct thing_s badguys[];  /* Array describing state of all */
8 extern int numbadguy;
9 
10 /* These are the graphics cursors used for drawing the player at */
11 /* various times. */
12 extern GC standgc,angelgc,angelugc,angellgc,flygc,hang1gc,hang2gc,up1gc,up2gc;
13 extern GC left1gc,left2gc,right1gc,right2gc;
14 
15 /* Redraw the player.  The graphics cursors all use the GXor function */
16 /* so they will not erase what is underneath. */
draw_player()17 void draw_player()
18 {
19   GC drawgc;
20   register int lpos,code;
21 
22   /* Get position of level array of player */
23   lpos = (player.xpos >> 1)*ysize + (player.ypos >> 1);
24   /* Get the control code describing block underneath player */
25   code = fast_lookup[level[lpos]].code;
26   /* If the block is inactive, use the code for empty space */
27   if((code & INACTIVE) && goldleft > 0)
28     code = fast_lookup[SPACE].code;
29 
30   /* Compute the graphics cursor appropriate to the player's current */
31   /* state */
32   drawgc = NULL;
33   if(angelleft) {
34     if(player.ypos & 1)
35       drawgc = angelugc;
36     else if(player.xpos & 1)
37       drawgc = angellgc;
38     else
39       drawgc = angelgc;
40   }
41   else {
42     /* Check if player is hanging from a rope */
43     if((player.ypos & 1) == 0) {
44       if((code & DLEAVE) && ! (code & (ULEAVE | DFALL))) {
45         if(player.xpos & 1)
46           drawgc = hang2gc;
47         else
48           drawgc = hang1gc;
49       }
50     }
51     else if((player.ypos & 1) && (code & DFALL))
52       drawgc = flygc;
53 
54     if(drawgc == NULL)
55       switch(player.dir) {
56       case UP:    case DOWN:
57         if(player.ypos & 1)
58           drawgc = up2gc;
59         else
60           drawgc = up1gc;
61         break;
62       case LEFT:
63         if(player.xpos & 1)
64           drawgc = left2gc;
65         else
66           drawgc = left1gc;
67         break;
68       case RIGHT:
69         if(player.xpos & 1)
70           drawgc = right2gc;
71         else
72           drawgc = right1gc;
73         break;
74       case STAND:
75         if(code & ULEAVE)
76           drawgc = up1gc;
77         else
78           drawgc = standgc;
79         break;
80       default:
81         drawgc = standgc;
82       }
83   }
84   /* Fill the rectangle surrounding the player with the chosen */
85   /* graphics cursor. */
86   if(drawgc != NULL)
87     XFillRectangle(disp,wind,drawgc,player.xpos << 3,player.ypos << 3,16,16);
88 }
89 
90 /* Erase the player by redrawing the block(s) underneath him */
drawmove_player()91 void drawmove_player()
92 {
93   register int x,y;
94 
95   /* Do not erase redraw player if it is not nessary */
96   if(! player.redraw)
97     return;
98   /* Draw block covering at least half of player */
99   x = player.xold;
100   y = player.yold;
101   draw_block(x >> 1,y >> 1);
102   /* If player is offset horizontally, redraw block to the right */
103   if(x & 1)
104     draw_block((x >> 1) + 1,y >> 1);
105   /* If player is offset vertically, redraw block below */
106   if(y & 1)
107     draw_block(x >> 1,(y >> 1) + 1);
108 
109   draw_player();
110 }
111 
112 /* Redraw everything.  This routine is called whenever something major */
113 /* changes or the window is exposed. */
redrawall()114 void redrawall()
115 {
116   draw_level();
117   draw_player();
118   draw_badguys();
119   XFlush(disp);
120 }
121 
122 /* Move player one movement */
move_player()123 void move_player()
124 {
125   register int i,code;
126   static int linepos = 0;   /* Output script line position */
127 
128   /* Read in input script character */
129   if(inscr != NULL) {
130     /* If input repetition factor is down to 0, read the next order */
131     /* from the script */
132     if(incount == 0) {
133       /* Loop through characters until a command is found */
134       do {
135         /* Read next script character */
136         i = getc(inscr);
137         /* Check for end of input script */
138         if(i == EOF) {
139           fclose(inscr);
140           inscr = NULL;
141           printf("Input script terminated.  Press any key to continue.\n");
142           newlevel = 1;
143           curtick --;   /* Reset clock back one tick */
144           score = 0;
145           draw_score();
146           return;
147         }
148         /* If character is a repitition count, add it to incount */
149         if(i >= 'a' && i <= 'z')
150           incount = 26 * incount + (i - 'a');
151       } while(i < '0' || i > '8');
152       /* Set next input order */
153       inorder = (enum directs) (i - '0');
154       /* Make sure input count is at least 1 if no multiplier was */
155       /* given */
156       if(incount == 0)
157         incount = 1;
158     }
159     curorder = inorder;     /* Set current order to input order */
160     incount --;             /* Decrement input order counter */
161   }
162   /* Write out output script character */
163   if(outscr != NULL) {
164     /* If current order has not changed, just increment output order */
165     /* count */
166     if(outorder == curorder)
167       outcount ++;
168     else {
169       /* Write output count multiplier */
170       if(outcount > 1) {
171         for(i=1;i <= outcount;i *= 26)
172           continue;
173         for(i /= 26;i > 0;i /= 26) {
174           if(putc(((char) (outcount / i)) + 'a',outscr) == EOF) {
175             perror("output script");
176             exit(3);
177           }
178           outcount -= (outcount / i) * i;
179         }
180       }
181       /* Write old output order */
182       if(outorder != UNMOVE)
183         if(putc(((char) outorder) + '0',outscr) == EOF) {
184           perror("output script");
185           exit(3);
186         }
187 
188       /* Reset output order to new order */
189       outorder = curorder;
190       outcount = 1;
191 
192       /* Periodically insert newlines to make the output pretty */
193       linepos ++;
194       if(linepos == 30) {
195         if(putc('\n',outscr) == EOF) {
196           perror("output script");
197           exit(3);
198         }
199         linepos = 0;
200       }
201     }
202   }
203 
204   /* Attempt to move player according to his standing orders */
205   if(angelleft)
206 	code = movedead(&player,curorder,-1);
207   else
208 	code = movething(&player,curorder,-1);
209   /* If digging completed, or if the player fell, and he was trying to */
210   /* move in the same direction, change the current order to STAND */
211   if(code == 4 || (code == 2 && curorder == player.dir))
212     curorder = STAND;
213   /* Redraw player if he dropped something (which will overwrite the */
214   /* block) */
215   if(code == 3)
216     player.redraw = 1;
217   /* If player is in the middle of a block, interesting things can */
218   /* happen. */
219   if((player.xpos & 1) == 0 && (player.ypos & 1) == 0)  {
220     /* If the player has picked up a gold piece, consume it and */
221     /* increment the score. */
222     if(fast_lookup[player.hold].code & TREASURE) {
223       player.hold = SPACE;
224       score++;
225       goldleft--;
226       /* If that was the last gold piece, escape ladder and other */
227       /* stuff may need to appear. */
228       if(goldleft == 0) {
229         regen_allow();      /* Regenerate the allowable movement array */
230         redrawall();        /* Refresh the entire screen */
231       }
232       /* Redraw the score line */
233       else
234         draw_score();
235     }
236     /* Get the control code for the block direction underneath the */
237     /* player */
238     i = (player.xpos >> 1)*ysize + (player.ypos >> 1);
239     code = fast_lookup[level[i]].code;
240 	/* If the player is an angel, and he is not inside a killer block, */
241 	/* decrement angelleft */
242 	if(angelleft > 0)
243 	  if(! --angelleft) {
244 		if((code & KILLIN) ||
245 		   overlap_badguy(player.xpos,player.ypos,-1))
246 		  ++angelleft;
247 		else
248 		  draw_score();
249 	  }
250     /* If the control code shows an active UPLEVEL block, or the */
251     /* player is at the top of the screen, and there is no more gold */
252     /* left, goto the next level. */
253     if((goldleft == 0 &&
254     (player.ypos == 0 || (code & UPLEVEL))) ||
255        ((code & UPLEVEL) && ! (code & INACTIVE)))  {
256       /* Increment the level number */
257       levelnum ++;
258       /* Load the next level in if the current one is done */
259       init_level();
260       /* Redraw the level */
261       redrawall();
262       /* Flush all the many X windows operations out to the server.  This */
263       /* is the only flush in all the operations in this procedure. */
264       XFlush(disp);
265       return;
266     }
267     /* If the block is a killer block, kill the player */
268     if((code & KILLIN) && ! angelleft) {
269       if (lives--) {
270         angelleft = ANGELTIME;
271         draw_score();
272       }
273       else
274         died("was crushed");
275     }
276   }
277   /* Do not let PUTDOWN order stay after movement has started */
278   else if(curorder == PUTDOWN)
279     curorder = STAND;
280 }
281 
282 /* Move everything one movement (or less).  This is the basic function */
283 /* which is called on every timer signal. */
moveall()284 void moveall()
285 {
286   /* Remember old position of player */
287   player.xold = player.xpos;
288   player.yold = player.ypos;
289   /* Assume that the player does not need to be redrawn initially */
290   player.redraw = 0;
291   /* Do player movement */
292   move_player();
293   /* Do secondary movement if player is sped up */
294   if(fast_lookup[player.hold].code & SPEED)
295     move_player();
296   /* Prevent time from advancing for bad guys if a TIMESTOP item is */
297   /* held by player */
298   if(! (fast_lookup[player.hold].code & TIMESTOP)) {
299     /* Regenerate bad guys movement tree periodically */
300     if(! (curtick & 0xf))
301       regen_tree();
302     /* Only move bad guys every other tick */
303     if(! (curtick & 0x1))
304       move_badguys();
305   }
306   /* Check if the player is overlapping one of the bad guys while not */
307   /* holding armor. */
308   if(! angelleft && ! (fast_lookup[player.hold].code & ARMOR) &&
309      overlap_badguy(player.xpos,player.ypos,-1)) {
310     if (lives--) {
311       angelleft = ANGELTIME;
312       draw_score();
313     }
314     else
315       died("was eaten");
316   }
317   /* Redraw player if he moved.  Redraw occasionally anyway. */
318   if(player.xpos != player.xold || player.ypos != player.yold ||
319      (! (curtick & 0xf)))
320     player.redraw = 1;
321   /* Erase and draw player if necessary */
322   drawmove_player();
323   /* Flush all the many X windows operations out to the server.  This */
324   /* is the only flush in all the operations in this procedure. */
325   XFlush(disp);
326 }
327