1 /*
2  *                               Alizarin Tetris
3  * Functions relating to the game board.
4  *
5  * Copyright 2000, Kiri Wagstaff & Westley Weimer
6  */
7 
8 #include <config.h>	/* go autoconf! */
9 
10 #include "atris.h"
11 #include "display.h"
12 #include "grid.h"
13 #include "options.h"
14 #include "piece.h"
15 
16 /***************************************************************************
17  *      cleanup_grid()
18  * Removes all of the REMOVE_ME's in a grid. Normally one uses draw_grid
19  * for this purpose, but you might have a personal testing grid or
20  * something that you're not displaying.
21  *********************************************************************PROTO*/
22 void
cleanup_grid(Grid * g)23 cleanup_grid(Grid *g)
24 {
25     int x,y;
26     for (y=g->h-1;y>=0;y--)
27 	for (x=g->w-1;x>=0;x--)
28 	    if (GRID_CONTENT(*g,x,y) == REMOVE_ME)
29 		GRID_SET(*g,x,y,0);
30 }
31 
32 /***************************************************************************
33  *      generate_board()
34  * Creates a new board at the given level.
35  *********************************************************************PROTO*/
36 Grid
generate_board(int w,int h,int level)37 generate_board(int w, int h, int level)
38 {
39     int i,j,r;
40 
41     Grid retval;
42 
43     retval.w = w;
44     retval.h = h;
45 
46     Calloc(retval.contents,unsigned char *,(w*h*sizeof(*retval.contents)));
47     Calloc(retval.fall,unsigned char *,(w*h*sizeof(*retval.fall)));
48     Calloc(retval.changed,unsigned char *,(w*h*sizeof(*retval.changed)));
49     Calloc(retval.temp,unsigned char *,(w*h*sizeof(*retval.temp)));
50 
51     if (level) {
52 	int start_garbage;
53 	level = GARBAGE_LEVEL(level);
54 	start_garbage = (h-level) - 2;
55 
56 	if (start_garbage < 2) start_garbage = 2;
57 	else if (start_garbage >= h) start_garbage = h - 1;
58 
59 	for (j=start_garbage;j<h;j++)
60 	    for (r=0;r<w/2;r++) {
61 		do {
62 		    i = ZEROTO(w);
63 		} while (GRID_CONTENT(retval,i,j) == 1);
64 		GRID_SET(retval,i,j,1);
65 	    }
66     }
67     return retval;
68 }
69 
70 /***************************************************************************
71  *      add_garbage()
72  * Adds garbage to the given board. Pushes all of the lines up, adds the
73  * garbage to the bottom.
74  *********************************************************************PROTO*/
75 void
add_garbage(Grid * g)76 add_garbage(Grid *g)
77 {
78     int i,j;
79     for (j=0;j<g->h-1;j++)
80 	for (i=0;i<g->w;i++) {
81 	    GRID_SET(*g,i,j, GRID_CONTENT(*g,i,j+1));
82 	    FALL_SET(*g,i,j, NOT_FALLING);
83 	    if (GRID_CONTENT(*g,i,j) == 0)
84 		GRID_SET(*g,i,j,REMOVE_ME);
85 	    GRID_CHANGED(*g,i,j) = 1;
86 	}
87 
88     j = g->h - 1;
89     for (i=0; i<g->w; i++) {
90 	    if (ZEROTO(100) < 50) {
91 		GRID_SET(*g,i,j,1);
92 		if (GRID_CONTENT(*g,i,j-1) &&
93 			GRID_CONTENT(*g,i,j-1) != REMOVE_ME)
94 		    GRID_SET(*g,i,j-1,1);
95 	    } else {
96 		GRID_SET(*g,i,j,REMOVE_ME);
97 	    }
98 	    FALL_SET(*g,i,j, NOT_FALLING);
99 	    GRID_CHANGED(*g,i,j) = 1;
100     }
101 
102     for (j=0;j<g->h;j++)
103 	for (i=0;i<g->w;i++) {
104 	    Assert(GRID_CHANGED(*g,i,j));
105 	    Assert(FALL_CONTENT(*g,i,j) == NOT_FALLING);
106 	}
107 
108     return;
109 }
110 
111 /***************************************************************************
112  *      draw_grid()
113  * Draws the main grid board. This involves drawing all of the pieces (and
114  * garbage) currently pasted on to it. This is the function that actually
115  * clears out grid pieces marked with "REMOVE_ME". The main bit of work
116  * here is calculating the shadows.
117  *
118  * Uses the color style to actually draw the right picture on the screen.
119  *********************************************************************PROTO*/
120 void
draw_grid(SDL_Surface * screen,color_style * cs,Grid * g,int draw)121 draw_grid(SDL_Surface *screen, color_style *cs, Grid *g, int draw)
122 {
123     SDL_Rect r,s;
124     int i,j;
125     int mini=20, minj=20, maxi=-1, maxj=-1;
126     for (j=g->h-1;j>=0;j--) {
127 	for (i=g->w-1;i>=0;i--) {
128 	    int c = GRID_CONTENT(*g,i,j);
129 	    if (draw && c && c != REMOVE_ME && GRID_CHANGED(*g,i,j)) {
130 		if (i < mini) mini = i; if (j < minj) minj = j;
131 		if (i > maxi) maxi = i; if (j > maxj) maxj = j;
132 
133 
134 		s.x = g->board.x + (i * cs->w);
135 		s.y = g->board.y + (j * cs->h);
136 		s.w = cs->w;
137 		s.h = cs->h;
138 
139 		SDL_BlitSafe(cs->color[c], NULL, screen, &s);
140 
141 		{
142 		    int fall = FALL_CONTENT(*g,i,j);
143 
144 		    int that_precolor = (j == 0) ? 0 :
145 			GRID_CONTENT(*g,i,j-1);
146 		    int that_fall = (j == 0) ? -1 :
147 			FALL_CONTENT(*g,i,j-1);
148 		    /* light up */
149 		    if (that_precolor != c || that_fall != fall) {
150 			r.x = g->board.x + i * cs->w;
151 			r.y = g->board.y + j * cs->h;
152 			r.h = edge[HORIZ_LIGHT]->h;
153 			r.w = edge[HORIZ_LIGHT]->w;
154 			SDL_BlitSafe(edge[HORIZ_LIGHT],NULL,
155 				    screen, &r);
156 		    }
157 
158 		    /* light left */
159 		    that_precolor = (i == 0) ? 0 :
160 			GRID_CONTENT(*g,i-1,j);
161 		    that_fall = (i == 0) ? -1 :
162 			FALL_CONTENT(*g,i-1,j);
163 		    if (that_precolor != c || that_fall != fall) {
164 			r.x = g->board.x + i * cs->w;
165 			r.y = g->board.y + j * cs->h;
166 			r.h = edge[VERT_LIGHT]->h;
167 			r.w = edge[VERT_LIGHT]->w;
168 			SDL_BlitSafe(edge[VERT_LIGHT],NULL,
169 				    screen,&r);
170 		    }
171 
172 		    /* shadow down */
173 		    that_precolor = (j == g->h-1) ? 0 :
174 			GRID_CONTENT(*g,i,j+1);
175 		    that_fall = (j == g->h-1) ? -1 :
176 			FALL_CONTENT(*g,i,j+1);
177 		    if (that_precolor != c || that_fall != fall) {
178 			r.x = g->board.x + i * cs->w;
179 			r.y = (g->board.y + (j+1) * cs->h)
180 			    - edge[HORIZ_DARK]->h;
181 			r.h = edge[HORIZ_DARK]->h;
182 			r.w = edge[HORIZ_DARK]->w;
183 			SDL_BlitSafe(edge[HORIZ_DARK],NULL,
184 				    screen,&r);
185 		    }
186 
187 		    /* shadow right */
188 		    that_precolor = (i == g->w-1) ? 0 :
189 			GRID_CONTENT(*g,i+1,j);
190 		    that_fall = (i == g->w-1) ? -1 :
191 			FALL_CONTENT(*g,i+1,j);
192 		    if (that_precolor != c || that_fall != fall) {
193 			r.x = (g->board.x + (i+1) * cs->w)
194 			    - edge[VERT_DARK]->w;
195 			r.y = (g->board.y + (j) * cs->h);
196 			r.h = edge[VERT_DARK]->h;
197 			r.w = edge[VERT_DARK]->w;
198 			SDL_BlitSafe(edge[VERT_DARK],NULL,
199 				    screen,&r);
200 		    }
201 		} /* endof: hikari to kage */
202 		/* SDL_UpdateSafe(screen, 1, &s); */
203 		GRID_CHANGED(*g,i,j) = 0;
204 	    } else if (c == REMOVE_ME) {
205 		if (i < mini) mini = i; if (j < minj) minj = j;
206 		if (i > maxi) maxi = i; if (j > maxj) maxj = j;
207 		if (draw) {
208 		    s.x = g->board.x + (i * cs->w);
209 		    s.y = g->board.y + (j * cs->h);
210 		    s.w = cs->w;
211 		    s.h = cs->h;
212 		    SDL_FillRect(screen, &s, int_solid_black);
213 		    GRID_SET(*g,i,j,0);
214 		    GRID_CHANGED(*g,i,j) = 0;
215 		} else {
216 		    GRID_SET(*g,i,j,0);
217 		}
218 	    }
219 	}
220     }
221     s.x = g->board.x + mini * cs->w;
222     s.y = g->board.y + minj * cs->h;
223     s.w = (maxi - mini + 1) * cs->w;
224     s.h = (maxj - minj + 1) * cs->h;
225     if (draw && maxi >  -1) SDL_UpdateSafe(screen,1,&s);
226     return;
227 }
228 
229 /***************************************************************************
230  *      draw_falling()
231  * Draws the falling pieces on the main grid. Offset should range from 1 to
232  * the size of the color tiles -- the falling pieces are drawn that far
233  * down out of their "real" places. This gives a smooth animation effect.
234  *********************************************************************PROTO*/
235 void
draw_falling(SDL_Surface * screen,int blockWidth,Grid * g,int offset)236 draw_falling(SDL_Surface *screen, int blockWidth, Grid *g, int offset)
237 {
238     SDL_Rect s;
239     SDL_Rect r;
240     int i,j;
241     int mini=100000, minj=100000, maxi=-1, maxj=-1;
242 
243     int cj;	/* cluster right, cluster bottom */
244 
245     memset(g->temp, 0, sizeof(*g->temp)*g->w*g->h);
246 
247     for (j=0;j<g->h;j++) {
248 	for (i=0;i<g->w;i++) {
249 	    int c = GRID_CONTENT(*g,i,j);
250 	    if (c && FALL_CONTENT(*g,i,j) == FALLING &&
251 		    TEMP_CONTENT(*g,i,j) == 0) {
252 
253 		for (cj = j; GRID_CONTENT(*g,i,cj) &&
254 			FALL_CONTENT(*g,i,cj) &&
255 			TEMP_CONTENT(*g,i,cj) == 0 &&
256 			cj < g->h; cj++)
257 		    TEMP_CONTENT(*g,i,cj) = 1;
258 
259 		/* source == up */
260 		s.x = g->board.x + (i * blockWidth);
261 		s.y = g->board.y + (j * blockWidth) + offset - 1;
262 		s.w = blockWidth;
263 		s.h = blockWidth * (cj - j + 1);
264 
265 		/* dest == down */
266 		r.x = g->board.x + (i * blockWidth);
267 		r.y = g->board.y + (j * blockWidth) + offset;
268 		r.w = blockWidth;
269 		r.h = blockWidth * (cj - j + 1);
270 
271 		/* just blit the screen down a notch */
272 		SDL_BlitSafe(screen, &s, screen, &r);
273 
274 		if (s.x < mini) mini = s.x;
275 		if (s.y < minj) minj = s.y;
276 		if (s.x+s.w > maxi) maxi = s.x+s.w;
277 		if (s.y+s.h > maxj) maxj = s.y+s.h;
278 
279 		/* clear! */
280 		if (j == 0 || FALL_CONTENT(*g,i,j-1) == NOT_FALLING ||
281 			GRID_CONTENT(*g,i,j-1) == 0) {
282 		    s.h = 1;
283 		    SDL_BlitSafe(widget_layer, &s, screen, &s);
284 		    /*  SDL_UpdateSafe(screen, 1, &s); */
285 		}
286 	    }
287 	}
288     }
289 
290     s.x = mini;
291     s.y = minj;
292     s.w = maxi - mini + 1;
293     s.h = maxj - minj + 1;
294     if (maxi >  -1) SDL_UpdateSafe(screen,1,&s);
295     return;
296 }
297 
298 /***************************************************************************
299  *      fall_down()
300  * Move all of the fallen pieces down a notch.
301  *********************************************************************PROTO*/
302 void
fall_down(Grid * g)303 fall_down(Grid *g)
304 {
305     int x,y;
306     for (y=g->h-1;y>=1;y--) {
307 	for (x=0;x<g->w;x++) {
308 	    if (FALL_CONTENT(*g,x,y-1) == FALLING &&
309 		     GRID_CONTENT(*g,x,y-1)) {
310 		Assert(GRID_CONTENT(*g,x,y) == 0 ||
311 		       GRID_CONTENT(*g,x,y) == REMOVE_ME);
312 		GRID_SET(*g,x,y, GRID_CONTENT(*g,x,y-1));
313 		GRID_SET(*g,x,y-1,REMOVE_ME);
314 		FALL_SET(*g,x,y, FALLING);
315 		/* FALL_SET(*g,x,y-1,UNKNOWN); */
316 	    }
317 	}
318     }
319     return;
320 }
321 
322 /***************************************************************************
323  *      determine_falling()
324  * Determines if anything can fall.
325  *********************************************************************PROTO*/
326 int
determine_falling(Grid * g)327 determine_falling(Grid *g)
328 {
329     int x,y;
330 #ifdef DEBUG
331     {
332 	int retval=0;
333     for (y=0;y<g->h;y++) {
334 	for (x=0;x<g->w;x++) {
335 	    if (GRID_CONTENT(*g,x,y) && FALL_CONTENT(*g,x,y) == FALLING) {
336 		printf("X");
337 		retval= 1;
338 	    } else printf(".");
339 	}
340 	printf("\n");
341     }
342     printf("--\n");
343     return retval;
344     }
345 #else
346     for (y=0;y<g->h;y++)
347 	for (x=0;x<g->w;x++)
348 	    if (GRID_CONTENT(*g,x,y) && FALL_CONTENT(*g,x,y) == FALLING)
349 		return 1;
350     return 0;
351 #endif
352 }
353 
354 /***************************************************************************
355  *      run_gravity()
356  * Applies gravity: pieces with no support change to "FALLING". After this,
357  * "determine_falling" can be used to determine if anything should be
358  * falling.
359  *
360  * Returns 1 if any pieces that were FALLING settled down.
361  *
362  * This is the Mark II iterative version. Heavy-sigh!
363  *********************************************************************PROTO*/
364 int
run_gravity(Grid * g)365 run_gravity(Grid *g)
366 {
367     int falling_pieces_settled;
368     int x,y,c,f, X,Y, YY;
369     int S;
370     int lowest_y = 0;
371     int garbage_on_row[21] ;	/* FIXME! */
372     /*   6.68      5.20     0.38    16769     0.02     0.02  run_gravity */
373 
374     char UP_QUEUE[2000], UP_POS=0;
375 
376 #define UP_X(P) UP_QUEUE[(P)*3]
377 #define UP_Y(P) UP_QUEUE[(P)*3 + 1]
378 #define UP_S(P) UP_QUEUE[(P)*3 + 2]
379 
380     falling_pieces_settled = 0;
381     for (y=0; y<g->h; y++) {
382 	garbage_on_row[y] = 0;
383 	for (x=0;x<g->w;x++) {
384 	    int c = GRID_CONTENT(*g,x,y);
385 	    if (!lowest_y && c)
386 		lowest_y = y;
387 	    if (c == 1)
388 		garbage_on_row[y] = 1;
389 	    if (FALL_CONTENT(*g,x,y) == NOT_FALLING)
390 		FALL_SET(*g,x,y,UNKNOWN);
391 	}
392     }
393     garbage_on_row[20] = 1;
394 
395     for (y=g->h-1;y>=lowest_y;y--)
396 	for (x=0;x<g->w;x++) {
397 	    c = GRID_CONTENT(*g,x,y);
398 	    if (!c) continue;
399 	    else if (c != 1 && y < g->h-1) continue;
400 	    else if (c == 1 && !garbage_on_row[y+1]) {
401 		/* if we do not set this, garbage from above us will appear
402 		 * to be supported and it will reach down and support us!
403 		 * scary! */
404 		garbage_on_row[y] = 0;
405 		continue;
406 	    }
407 	    f = FALL_CONTENT(*g,x,y);
408 	    if (f == NOT_FALLING) continue;
409 	    else if (f == FALLING) {
410 		falling_pieces_settled = 1;
411 	    }
412 
413 	    /* now, run up as far as we can ... */
414 	    if (y >= 1) {
415 		Y = y;
416 		while ((c = GRID_CONTENT(*g,x,Y)) &&
417 			FALL_CONTENT(*g,x,Y) != NOT_FALLING) {
418 		    /* mark stable */
419 		    f = FALL_CONTENT(*g,x,Y);
420 		    if (f == FALLING) {
421 			falling_pieces_settled = 1;
422 		    }
423 		    FALL_SET(*g,x,Y,NOT_FALLING);
424 		    /* promise to get to our same-color buddies later */
425 		    if (x >= 1 && GRID_CONTENT(*g,x-1,Y) == c &&
426 			    FALL_CONTENT(*g,x-1,Y) != NOT_FALLING) {
427 			UP_X(UP_POS) = x-1 ; UP_Y(UP_POS) = Y;
428 			UP_S(UP_POS) = (f == FALLING || c == 1); UP_POS++;
429 		    }
430 		    if (x < g->w-1 && GRID_CONTENT(*g,x+1,Y) == c &&
431 			    FALL_CONTENT(*g,x+1,Y) != NOT_FALLING) {
432 			UP_X(UP_POS) = x+1 ; UP_Y(UP_POS) = Y;
433 			UP_S(UP_POS) = (f == FALLING || c == 1); UP_POS++;
434 		    }
435 		    if (Y < g->h-1 && GRID_CONTENT(*g,x,Y+1) == c &&
436 			    FALL_CONTENT(*g,x,Y+1) != NOT_FALLING) {
437 			UP_X(UP_POS) = x ; UP_Y(UP_POS) = Y+1;
438 			UP_S(UP_POS) = (f == FALLING || c == 1); UP_POS++;
439 		    }
440 		    Y--;
441 		}
442 	    } else {
443 		/* Debug("2 (%2d,%2d)\n",x,y); */
444 		FALL_SET(*g,x,y,NOT_FALLING);
445 	    }
446 
447 	    /* now burn down the queue */
448 	    while (UP_POS > 0) {
449 		UP_POS--;
450 		X = UP_X(UP_POS);
451 		Y = UP_Y(UP_POS);
452 		S = UP_S(UP_POS);
453 		c = GRID_CONTENT(*g,X,Y);
454 		Assert(c);
455 		f = FALL_CONTENT(*g,X,Y);
456 		if (f == NOT_FALLING) continue;
457 		else if (f == FALLING && !S) continue;
458 
459 		if (Y >= 1) {
460 		    YY = Y;
461 		    while ((c = GRID_CONTENT(*g,X,YY)) &&
462 			    FALL_CONTENT(*g,X,YY) != NOT_FALLING) {
463 			/* mark stable */
464 			f = FALL_CONTENT(*g,X,YY);
465 			if (f == FALLING) falling_pieces_settled = 1;
466 			FALL_SET(*g,X,YY,NOT_FALLING);
467 			/* promise to get to our same-color buddies later */
468 			if (X >= 1 && GRID_CONTENT(*g,X-1,YY) == c &&
469 				FALL_CONTENT(*g,X-1,YY) != NOT_FALLING) {
470 			    UP_X(UP_POS) = X-1 ; UP_Y(UP_POS) = YY;
471 			    UP_S(UP_POS) = (f == FALLING || c == 1); UP_POS++;
472 			}
473 			if (X < g->w-1 && GRID_CONTENT(*g,X+1,YY) == c &&
474 				FALL_CONTENT(*g,X+1,YY) != NOT_FALLING) {
475 			    UP_X(UP_POS) = X+1 ; UP_Y(UP_POS) = YY;
476 			    UP_S(UP_POS) = (f == FALLING || c == 1); UP_POS++;
477 			}
478 			if (YY < g->h-1 && GRID_CONTENT(*g,X,YY+1) == c &&
479 				FALL_CONTENT(*g,X,YY+1) != NOT_FALLING) {
480 			    UP_X(UP_POS) = X ; UP_Y(UP_POS) = YY+1;
481 			    UP_S(UP_POS) = (f == FALLING || c == 1); UP_POS++;
482 			}
483 			YY--;
484 		    }
485 		} else {
486 		    FALL_SET(*g,X,Y,NOT_FALLING);
487 		}
488 	    }
489 	}
490 
491     for (y=g->h-1;y>=0;y--)
492 	for (x=0;x<g->w;x++)
493 	    if (FALL_CONTENT(*g,x,y) == UNKNOWN)
494 		FALL_CONTENT(*g,x,y) = FALLING;
495 
496     return falling_pieces_settled;
497 }
498 
499 
500 /***************************************************************************
501  *      check_tetris()
502  * Checks to see if any rows have been completely filled. Returns the
503  * number of such rows. Such rows are cleared.
504  *********************************************************************PROTO*/
505 int
check_tetris(Grid * g)506 check_tetris(Grid *g)
507 {
508     int tetris_count = 0;
509     int x,y;
510     for (y=g->h-1;y>=0;y--)  {
511 	int c = 0;
512 	for (x=0;x<g->w;x++)
513 	    if (GRID_CONTENT(*g,x,y))
514 		c++;
515 	if (c == g->w) {
516 	    tetris_count++;
517 	    for (x=0;x<g->w;x++)
518 		GRID_SET(*g,x,y,REMOVE_ME);
519 	}
520     }
521     return tetris_count;
522 }
523 
524 /*
525  * $Log: grid.c,v $
526  * Revision 1.24  2000/11/10 18:16:48  weimer
527  * changes for Atris 1.0.4 - three new special options
528  *
529  * Revision 1.23  2000/11/06 04:06:44  weimer
530  * option menu
531  *
532  * Revision 1.22  2000/11/03 04:25:58  weimer
533  * add some optimizations to run_gravity to make it just a bit faster (down
534  * to 0.01 ms/call from 0.02), sleep a bit more in event-loop: generally
535  * trying to make us more CPU friendly ...
536  *
537  * Revision 1.21  2000/11/03 03:41:35  weimer
538  * made the light and dark "edges" of pieces global, rather than part of a
539  * specific color style. also fixed a bug where we were updating too much
540  * when drawing falling pieces (bad min() code on my part)
541  *
542  * Revision 1.20  2000/10/29 21:23:28  weimer
543  * One last round of header-file changes to reflect my newest and greatest
544  * knowledge of autoconf/automake. Now if you fail to have some bizarro
545  * function, we try to go on anyway unless it is vastly needed.
546  *
547  * Revision 1.19  2000/10/29 17:23:13  weimer
548  * incorporate "xflame" flaming background for added spiffiness ...
549  *
550  * Revision 1.18  2000/10/26 22:23:07  weimer
551  * double the effective number of levels
552  *
553  * Revision 1.17  2000/10/21 01:14:42  weimer
554  * massic autoconf/automake restructure ...
555  *
556  * Revision 1.16  2000/10/18 23:57:49  weimer
557  * general fixup, color changes, display changes.
558  * Notable: "Safe" Blits and Updates now perform "clipping". No more X errors,
559  * we hope!
560  *
561  * Revision 1.15  2000/10/18 03:29:56  weimer
562  * fixed problem with "machine-gun" sounds caused by "run_gravity()" returning
563  * 1 too often
564  *
565  * Revision 1.14  2000/10/14 02:52:44  weimer
566  * fixed a memory corruption problem in display (a use after a free)
567  *
568  * Revision 1.13  2000/10/14 00:31:53  weimer
569  * non-recursive run-gravity ...
570  *
571  * Revision 1.12  2000/10/13 15:41:53  weimer
572  * revamped AI support, now you can pick your AI and have AI duels (such fun!)
573  * the mighty Aliz AI still crashes a bit, though ... :-)
574  *
575  * Revision 1.11  2000/10/12 22:21:25  weimer
576  * display changes, more multi-local-play threading (e.g., myScore ->
577  * Score[0]), that sort of thing ...
578  *
579  * Revision 1.10  2000/10/12 19:17:08  weimer
580  * Further support for AI players and multiple game types.
581  *
582  * Revision 1.9  2000/10/12 00:49:08  weimer
583  * added "AI" support and walking radio menus for initial game configuration
584  *
585  * Revision 1.8  2000/09/09 17:05:35  wkiri
586  * Hideous log changes (Wes: how dare you include a comment character!)
587  *
588  * Revision 1.7  2000/09/09 16:58:27  weimer
589  * Sweeping Change of Ultimate Mastery. Main loop restructuring to clean up
590  * main(), isolate the behavior of the three game types. Move graphic files
591  * into graphics/-, style files into styles/-, remove some unused files,
592  * add game flow support (breaks between games, remembering your level within
593  * this game), multiplayer support for the event loop, some global variable
594  * cleanup. All that and a bag of chips!
595  *
596  * Revision 1.6  2000/09/05 22:10:46  weimer
597  * fixed initial garbage generation strangeness
598  *
599  * Revision 1.5  2000/09/05 20:22:12  weimer
600  * native video mode selection, timing investigation
601  *
602  * Revision 1.4  2000/09/04 21:02:18  weimer
603  * Added some addition piece layout code, garbage now falls unless the row
604  * below it features some non-falling garbage
605  *
606  * Revision 1.3  2000/09/04 15:20:21  weimer
607  * faster blitting algorithms for drawing the grid and drawing falling pieces
608  * (when you eliminate a line)
609  *
610  * Revision 1.2  2000/09/03 18:26:10  weimer
611  * major header file and automatic prototype generation changes, restructuring
612  *
613  * Revision 1.1  2000/09/03 17:56:36  wkiri
614  * Reorganization of files (display.[ch], event.c are new).
615  *
616  * Revision 1.9  2000/08/26 02:28:55  weimer
617  * now you can see the other player!
618  *
619  * Revision 1.8  2000/08/26 01:36:25  weimer
620  * fixed a long-running update bug: the grid changed field was being reset to
621  * 0 when falling states or content were set to the same thing, even if they
622  * had actually previously changed ...
623  *
624  * Revision 1.7  2000/08/26 01:03:11  weimer
625  * remove keyboard repeat when you enter high scores
626  *
627  * Revision 1.6  2000/08/24 02:32:18  weimer
628  * gameplay changes (key repeats) and speed modifications (falling pieces,
629  * redraws, etc.)
630  *
631  * Revision 1.5  2000/08/22 15:13:53  weimer
632  * added a garbage-generation routine
633  *
634  * Revision 1.4  2000/08/21 00:04:56  weimer
635  * minor text placement changes, falling speed, etc.
636  *
637  * Revision 1.3  2000/08/15 00:59:41  weimer
638  * a few more sound things
639  *
640  * Revision 1.2  2000/08/13 19:27:20  weimer
641  * added file changelogs
642  *
643  */
644