1 /*
2  *                               Alizarin Tetris
3  * The piece definition loading file.
4  *
5  * Copyright 2000, Kiri Wagstaff & Westley Weimer
6  */
7 
8 #include <config.h>	/* go autoconf! */
9 #include <ctype.h>
10 #include <string.h>
11 #include <unistd.h>
12 
13 /* configure magic for dirent */
14 #if HAVE_DIRENT_H
15 # include <dirent.h>
16 # define NAMLEN(dirent) strlen((dirent)->d_name)
17 #else
18 # define dirent direct
19 # define NAMLEN(dirent) (dirent)->d_namlen
20 # if HAVE_SYS_NDIR_H
21 #  include <sys/ndir.h>
22 # endif
23 # if HAVE_SYS_DIR_H
24 #  include <sys/dir.h>
25 # endif
26 # if HAVE_NDIR_H
27 #  include <ndir.h>
28 # endif
29 #endif
30 
31 #include "atris.h"
32 #include "display.h"
33 #include "piece.h"
34 #include "options.h"
35 
36 /***************************************************************************
37  *      load_piece_style()
38  * Load a piece style from the given file.
39  ***************************************************************************/
40 static piece_style *
load_piece_style(const char * filename)41 load_piece_style(const char *filename)
42 {
43     piece_style *retval;
44     char buf[2048];
45     FILE *fin = fopen(filename,"rt");
46     int i;
47 
48     if (!fin) {
49 	Debug("fopen(%s)\n",filename);
50 	return NULL;
51     }
52     Calloc(retval,piece_style *,sizeof(piece_style));
53 
54     fgets(buf,sizeof(buf),fin);
55     if (feof(fin)) {
56 	Debug("unexpected EOF after name in [%s]\n",filename);
57 	free(retval);
58 	return NULL;
59     }
60 
61     if (strchr(buf,'\n'))
62 	*(strchr(buf,'\n')) = 0;
63     retval->name = strdup(buf);
64 
65     if (fscanf(fin,"%d",&retval->num_piece) != 1) {
66 	Debug("malformed piece count in [%s]\n",filename);
67 	free(retval->name);
68 	free(retval);
69 	return NULL;
70     }
71 
72     Calloc(retval->shape,piece *,(retval->num_piece)*sizeof(piece));
73 
74     for (i=0;i<retval->num_piece;i++) {
75 	int x,y,rot,counter;
76 	do {
77 	    fgets(buf,sizeof(buf),fin);
78 	    if (feof(fin))
79 		PANIC("unexpected EOF in [%s], before piece %d",filename,i+1);
80 	} while (buf[0] == '\n');
81 	retval->shape[i].dim = strlen(buf) - 1;
82 	if (retval->shape[i].dim <= 0)
83 	    PANIC("piece %d malformed height/width in [%s]", i,filename);
84 #ifdef DEBUG
85 	Debug("... loading piece %d (%d by %d)\n",i,
86 		retval->shape[i].dim, retval->shape[i].dim);
87 #endif
88 	for (rot=0;rot<4;rot++) {
89 	    Malloc(retval->shape[i].bitmap[rot], unsigned char *,
90 		    retval->shape[i].dim * retval->shape[i].dim);
91 	}
92 	counter = 1;
93 	for (y=0;y<retval->shape[i].dim;y++) {
94 	    for (x=0;x<retval->shape[i].dim;x++) {
95 		BITMAP(retval->shape[i],0,x,y) =
96 		    (buf[x] != '.') ? counter++ : 0;
97 	    }
98 	    if (y != retval->shape[i].dim - 1) do {
99 		fgets(buf,sizeof(buf),fin);
100 		if (feof(fin))
101 		    PANIC("unexpected EOF in [%s]",filename);
102 	    } while (buf[0] == '\n');
103 	}
104 	retval->shape[i].num_color = counter-1;
105 
106 	for (rot=1;rot<4;rot++) {
107 	    for (y=0;y<retval->shape[i].dim;y++)
108 		for (x=0;x<retval->shape[i].dim;x++) {
109 		    BITMAP(retval->shape[i],rot,x,y) =
110 			BITMAP(retval->shape[i],rot-1,
111 				(retval->shape[i].dim - 1) - y,
112 				x);
113 		}
114 	} /* end: for rot = 0..4 */
115 
116 #ifdef DEBUG
117 	for (y=0;y<retval->shape[i].dim;y++) {
118 	    for (rot=0;rot<4;rot++) {
119 		for (x=0;x<retval->shape[i].dim;x++) {
120 		    printf("%d", BITMAP(retval->shape[i],rot,x,y));
121 		}
122 		printf("\t");
123 	    }
124 	    printf("\n");
125 	}
126 #endif
127     }
128 
129 
130     Debug("Piece Style [%s] loaded (%d pieces).\n",retval->name,
131 	    retval->num_piece);
132     return retval;
133 }
134 
135 /***************************************************************************
136  *	piece_Select()
137  * Returns 1 if the file pointed to ends with ".Piece"
138  * Used by scandir() to grab all the *.Piece files from a directory.
139  ***************************************************************************/
140 static int
piece_Select(const struct dirent * d)141 piece_Select(const struct dirent *d)
142 {
143     if (strstr(d->d_name,".Piece") &&
144 	    (signed)strlen(d->d_name) ==
145 	    (strstr(d->d_name,".Piece") - d->d_name + 6))
146 	return 1;
147     else
148 	return 0;
149 }
150 
151 /***************************************************************************
152  *      load_piece_styles()
153  * Load all ".Style" files in the directory.
154  *********************************************************************PROTO*/
155 piece_styles
load_piece_styles(void)156 load_piece_styles(void)
157 {
158     piece_styles retval;
159     int i = 0;
160     DIR *my_dir;
161     char filespec[2048];
162 
163     memset(&retval, 0, sizeof(retval));
164 
165     my_dir = opendir("styles");
166     if (my_dir) {
167 	while (1) {
168 	    struct dirent *this_file = readdir(my_dir);
169 	    if (!this_file) break;
170 	    if (piece_Select(this_file))
171 		i++;
172 	}
173 	closedir(my_dir);
174     } else {
175 	PANIC("Cannot read directory [styles/]");
176     }
177     my_dir = opendir("styles");
178     if (my_dir) {
179 	if (i > 0) {
180 	    int j;
181 	    Calloc(retval.style,piece_style **,sizeof(*(retval.style))*i);
182 	    retval.num_style = i;
183 	    j = 0;
184 	    while (j<i) {
185 		struct dirent *this_file = readdir(my_dir);
186 		if (!piece_Select(this_file)) continue;
187 		SPRINTF(filespec,"styles/%s",this_file->d_name);
188 		retval.style[j] = load_piece_style(filespec);
189 		if (strstr(retval.style[j]->name,"Default"))
190 		    retval.choice = j;
191 		j++;
192 	    }
193 	    closedir(my_dir);
194 	    return retval;
195 	} else {
196 	    PANIC("No piece styles [styles/*.Piece] found.\n");
197 	}
198     } else {
199 	PANIC("Cannot read directory [styles/]");
200     }
201     return retval;
202 }
203 
204 /***************************************************************************
205  *      load_color_style()
206  * Load a color style from the given file.
207  ***************************************************************************/
208 static color_style *
load_color_style(SDL_Surface * screen,const char * filename)209 load_color_style(SDL_Surface * screen, const char *filename)
210 {
211     color_style *retval;
212     char buf[2048];
213     FILE *fin = fopen(filename,"rt");
214     int i;
215 
216     if (!fin) {
217 	Debug("fopen(%s)\n",filename);
218 	return NULL;
219     }
220     Calloc(retval,color_style *,sizeof(*retval));
221 
222     fgets(buf,sizeof(buf),fin);
223     if (feof(fin)) {
224 	Debug("unexpected EOF after name in [%s]\n",filename);
225 	free(retval);
226 	return NULL;
227     }
228     if (strchr(buf,'\n'))
229 	*(strchr(buf,'\n')) = 0;
230     retval->name = strdup(buf);
231 
232     if (fscanf(fin,"%d\n",&retval->num_color) != 1) {
233 	Debug("malformed color count in [%s]\n",filename);
234 	free(retval->name);
235 	free(retval);
236 	return NULL;
237     }
238 
239     Malloc(retval->color, SDL_Surface **,
240 	    (retval->num_color+1)*sizeof(retval->color[0]));
241 
242     for (i=1;i<=retval->num_color;i++) {
243 	SDL_Surface *imagebmp;
244 
245 	do {
246 	    buf[0] = 0;
247 	    fgets(buf,sizeof(buf),fin);
248 	} while (!feof(fin) && (buf[0] == '\n' || buf[0] == '#'));
249 
250 	if (feof(fin)) PANIC("unexpected EOF in color style [%s]",retval->name);
251 	if (strchr(buf,'\n'))
252 	    *(strchr(buf,'\n')) = 0;
253 
254 	imagebmp = SDL_LoadBMP(buf);
255 	if (!imagebmp)
256 	    PANIC("cannot load [%s] in color style [%s]",buf,retval->name);
257 	/* set the video colormap */
258 	if ( imagebmp->format->palette != NULL ) {
259 	    SDL_SetColors(screen,
260 		    imagebmp->format->palette->colors, 0,
261 		    imagebmp->format->palette->ncolors);
262 	}
263 	/* Convert the image to the video format (maps colors) */
264 	retval->color[i] = SDL_DisplayFormat(imagebmp);
265 	SDL_FreeSurface(imagebmp);
266 	if ( !retval->color[i] )
267 	    PANIC("could not convert [%s] in color style [%s]",
268 		buf, retval->name);
269 	if (i == 1) {
270 	    retval->h = retval->color[i]->h;
271 	    retval->w = retval->color[i]->w;
272 	} else {
273 	    if (retval->h != retval->color[i]->h ||
274 		    retval->w != retval->color[i]->w)
275 		PANIC("[%s] has the wrong size in color style [%s]",
276 			buf, retval->name);
277 	}
278 
279     }
280     retval->color[0] = retval->color[1];
281 
282     Debug("Color Style [%s] loaded (%d colors).\n",retval->name,
283 	    retval->num_color);
284 
285     return retval;
286 }
287 
288 /***************************************************************************
289  *	color_Select()
290  * Returns 1 if the file pointed to ends with ".Color"
291  * Used by scandir() to grab all the *.Color files from a directory.
292  ***************************************************************************/
293 static int
color_Select(const struct dirent * d)294 color_Select(const struct dirent *d)
295 {
296     if (strstr(d->d_name,".Color") &&
297 	    (signed)strlen(d->d_name) ==
298 	    (strstr(d->d_name,".Color") - d->d_name + 6))
299 	return 1;
300     else
301 	return 0;
302 }
303 
304 /***************************************************************************
305  *	load_specials()
306  * Loads the pictures for the special pieces.
307  ***************************************************************************/
308 static void
load_special(void)309 load_special(void)
310 {
311     int i;
312 #define NUM_SPECIAL 6
313     char *filename[NUM_SPECIAL] = {
314 	"graphics/Special-Bomb.bmp",		/* special_bomb */
315 	"graphics/Special-Drip.bmp",		/* special_repaint */
316 	"graphics/Special-DownArrow.bmp",	/* special_pushdown */
317 	"graphics/Special-Skull.bmp",		/* special_colorkill */
318 	"graphics/Special-X.bmp",
319 	"graphics/Special-YinYang.bmp" };
320 
321     special_style.name = "Special Pieces";
322     special_style.num_color = NUM_SPECIAL;
323     Malloc(special_style.color, SDL_Surface **, NUM_SPECIAL * sizeof(SDL_Surface *));
324     special_style.w = 20;
325     special_style.h = 20;
326 
327     for (i=0; i<NUM_SPECIAL; i++) {
328 	SDL_Surface *imagebmp;
329 	/* grab the lighting */
330 	imagebmp = SDL_LoadBMP(filename[i]);
331 	if (!imagebmp)
332 	    PANIC("cannot load [%s], a required special piece",filename[i]);
333 	if ( imagebmp->format->palette != NULL ) {
334 	    SDL_SetColors(screen,
335 		    imagebmp->format->palette->colors, 0,
336 		    imagebmp->format->palette->ncolors);
337 	}
338 	/* Convert the image to the video format (maps colors) */
339 	special_style.color[i] = SDL_DisplayFormat(imagebmp);
340 	SDL_FreeSurface(imagebmp);
341 	if ( !special_style.color[i] )
342 	    PANIC("could not convert [%s], a required special piece",filename[i]);
343     }
344     return;
345 }
346 
347 /***************************************************************************
348  *	load_edges()
349  * Loads the pictures for the edges.
350  ***************************************************************************/
351 static void
load_edges(void)352 load_edges(void)
353 {
354     int i;
355     char *filename[4] = {
356 	"graphics/Horiz-Light.bmp",
357 	"graphics/Vert-Light.bmp",
358 	"graphics/Horiz-Dark.bmp",
359 	"graphics/Vert-Dark.bmp" };
360 
361     for (i=0;i<4;i++) {
362 	SDL_Surface *imagebmp;
363 	/* grab the lighting */
364 	imagebmp = SDL_LoadBMP(filename[i]);
365 	if (!imagebmp)
366 	    PANIC("cannot load [%s], a required edge",filename[i]);
367 	/* set the video colormap */
368 	if ( imagebmp->format->palette != NULL ) {
369 	    SDL_SetColors(screen,
370 		    imagebmp->format->palette->colors, 0,
371 		    imagebmp->format->palette->ncolors);
372 	}
373 	/* Convert the image to the video format (maps colors) */
374 	edge[i] = SDL_DisplayFormat(imagebmp);
375 	SDL_FreeSurface(imagebmp);
376 	if ( !edge[i] )
377 	    PANIC("could not convert [%s], a required edge",filename[i]);
378 
379 	SDL_SetAlpha(edge[i],SDL_SRCALPHA|SDL_RLEACCEL, 48 /*128+64*/);
380     }
381     return;
382 }
383 
384 
385 /***************************************************************************
386  *      load_color_styles()
387  * Loads all available color styles.
388  *********************************************************************PROTO*/
389 color_styles
load_color_styles(SDL_Surface * screen)390 load_color_styles(SDL_Surface * screen)
391 {
392     color_styles retval;
393     int i = 0;
394     DIR *my_dir;
395     char filespec[2048];
396 
397     load_edges();
398     load_special();
399 
400     memset(&retval, 0, sizeof(retval));
401 
402     my_dir = opendir("styles");
403     if (my_dir) {
404 	while (1) {
405 	    struct dirent *this_file = readdir(my_dir);
406 	    if (!this_file) break;
407 	    if (color_Select(this_file))
408 		i++;
409 	}
410 	closedir(my_dir);
411     } else {
412 	PANIC("Cannot read directory [styles/]");
413     }
414     my_dir = opendir("styles");
415     if (my_dir) {
416 	if (i > 0) {
417 	    int j;
418 	    Calloc(retval.style,color_style **,sizeof(*(retval.style))*i);
419 	    retval.num_style = i;
420 	    j = 0;
421 	    while (j<i) {
422 		struct dirent *this_file = readdir(my_dir);
423 		if (!color_Select(this_file)) continue;
424 		SPRINTF(filespec,"styles/%s",this_file->d_name);
425 		retval.style[j] = load_color_style(screen, filespec);
426 		if (strstr(retval.style[j]->name,"Default"))
427 		    retval.choice = j;
428 		j++;
429 	    }
430 	    closedir(my_dir);
431 	    return retval;
432 	} else {
433 	    PANIC("No piece styles [styles/*.Color] found.\n");
434 	}
435     } else {
436 	PANIC("Cannot read directory [styles/]");
437     }
438     return retval;
439 }
440 
441 /***************************************************************************
442  *      generate_piece()
443  * Chooses the next piece in sequence. This involves assigning colors to
444  * all of the tiles that make up the shape of the piece.
445  *
446  * Uses the color style because it needs to know the number of colors.
447  *********************************************************************PROTO*/
448 play_piece
generate_piece(piece_style * ps,color_style * cs,unsigned int seq)449 generate_piece(piece_style *ps, color_style *cs, unsigned int seq)
450 {
451     unsigned int p,q,r,c;
452     play_piece retval;
453 
454     SeedRandom(seq);
455 
456     p = ZEROTO(ps->num_piece);
457     q = 2 + ZEROTO(cs->num_color - 1);
458     r = 2 + ZEROTO(cs->num_color - 1);
459     retval.base = &(ps->shape[p]);
460 
461     retval.special = No_Special;
462     if (Options.special_wanted && ZEROTO(10000) < 2000) {
463 	switch (ZEROTO(4)) {
464 	    case 0: retval.special = Special_Bomb; /* bomb */
465 		    break;
466 	    case 1: retval.special = Special_Repaint; /* repaint */
467 		    break;
468 	    case 2: retval.special = Special_Pushdown; /* repaint */
469 		    break;
470 	    case 3: retval.special = Special_Colorkill; /* trace and kill color */
471 		    break;
472 	}
473     }
474     if (retval.special != No_Special) {
475 	for (c=1;c<=(unsigned)ps->shape[p].num_color;c++) {
476 	    retval.colormap[c] = (unsigned char) retval.special;
477 	}
478     } else for (c=1;c<=(unsigned)ps->shape[p].num_color;c++) {
479 	if (ZEROTO(100) < 25)
480 	    retval.colormap[c] = q;
481 	else
482 	    retval.colormap[c] = r;
483 	Assert(retval.colormap[c] > 1);
484     }
485     return retval;
486 }
487 
488 #define PRECOLOR_AT(pp,rot,i,j) BITMAP(*pp->base,rot,i,j)
489 
490 /***************************************************************************
491  *      draw_play_piece()
492  * Draws a play piece on the screen.
493  *
494  * Needs the color style because it actually has to paste the color
495  * bitmaps.
496  *********************************************************************PROTO*/
497 void
draw_play_piece(SDL_Surface * screen,color_style * cs,play_piece * o_pp,int o_x,int o_y,int o_rot,play_piece * pp,int x,int y,int rot)498 draw_play_piece(SDL_Surface *screen, color_style *cs,
499 	play_piece *o_pp, int o_x, int o_y, int o_rot,	/* old */
500 	play_piece *pp,int x, int y, int rot)		/* new */
501 {
502     SDL_Rect dstrect;
503     int i,j;
504     int w,h;
505 
506     if (pp->special != No_Special)
507 	cs = &special_style;
508 
509     w = cs->w;
510     h = cs->h;
511 
512     for (j=0;j<o_pp->base->dim;j++)
513 	for (i=0;i<o_pp->base->dim;i++) {
514 	    int what;
515 	    /* clear old */
516 	    if ((what = PRECOLOR_AT(o_pp,o_rot,i,j))) {
517 		dstrect.x = o_x + i * w;
518 		dstrect.y = o_y + j * h;
519 		dstrect.w = w;
520 		dstrect.h = h;
521 		SDL_BlitSafe(widget_layer,&dstrect,screen,&dstrect);
522 	    }
523 	}
524     for (j=0;j<pp->base->dim;j++)
525 	for (i=0;i<pp->base->dim;i++) {
526 	    int this_precolor;
527 	    /* draw new */
528 	    if ((this_precolor = PRECOLOR_AT(pp,rot,i,j))) {
529 		int this_color = pp->colormap[this_precolor];
530 		dstrect.x = x + i * w;
531 		dstrect.y = y + j * h;
532 		dstrect.w = w;
533 		dstrect.h = h;
534 		SDL_BlitSafe(cs->color[this_color], NULL,screen,&dstrect) ;
535 		if (pp->special == No_Special)
536 		{
537 		    int that_precolor = (j == 0) ? 0 :
538 			PRECOLOR_AT(pp,rot,i,j-1);
539 
540 		    /* light up */
541 		    if (that_precolor == 0 ||
542 			    pp->colormap[that_precolor] != this_color) {
543 			dstrect.x = x + i * w;
544 			dstrect.y = y + j * h;
545 			dstrect.h = edge[HORIZ_LIGHT]->h;
546 			dstrect.w = edge[HORIZ_LIGHT]->w;
547 			SDL_BlitSafe(edge[HORIZ_LIGHT],NULL,
548 				    screen,&dstrect) ;
549 		    }
550 
551 		    /* light left */
552 		    that_precolor = (i == 0) ? 0 :
553 			PRECOLOR_AT(pp,rot,i-1,j);
554 		    if (that_precolor == 0 ||
555 			    pp->colormap[that_precolor] != this_color) {
556 			dstrect.x = x + i * w;
557 			dstrect.y = y + j * h;
558 			dstrect.h = edge[VERT_LIGHT]->h;
559 			dstrect.w = edge[VERT_LIGHT]->w;
560 			SDL_BlitSafe(edge[VERT_LIGHT],NULL,
561 				    screen,&dstrect) ;
562 		    }
563 
564 		    /* shadow down */
565 		    that_precolor = (j == pp->base->dim-1) ? 0 :
566 			PRECOLOR_AT(pp,rot,i,j+1);
567 		    if (that_precolor == 0 ||
568 			    pp->colormap[that_precolor] != this_color) {
569 			dstrect.x = x + i * w;
570 			dstrect.y = (y + (j+1) * h) - edge[HORIZ_DARK]->h;
571 			dstrect.h = edge[HORIZ_DARK]->h;
572 			dstrect.w = edge[HORIZ_DARK]->w;
573 			SDL_BlitSafe(edge[HORIZ_DARK],NULL,
574 				    screen,&dstrect);
575 		    }
576 
577 		    /* shadow right */
578 		    that_precolor = (i == pp->base->dim-1) ? 0 :
579 			PRECOLOR_AT(pp,rot,i+1,j);
580 		    if (that_precolor == 0 ||
581 			    pp->colormap[that_precolor] != this_color) {
582 			dstrect.x = (x + (i+1) * w) - edge[VERT_DARK]->w;
583 			dstrect.y = (y + (j) * h);
584 			dstrect.h = edge[VERT_DARK]->h;
585 			dstrect.w = edge[VERT_DARK]->w;
586 			SDL_BlitSafe(edge[VERT_DARK],NULL, screen,&dstrect);
587 		    }
588 		}
589 	    }
590 	}
591     /* now update the entire relevant area */
592     dstrect.x = min(o_x, x);
593     dstrect.x = max( dstrect.x, 0 );
594 
595     dstrect.w = max(o_x + (o_pp->base->dim * cs->w),
596 	    x + (pp->base->dim * cs->w)) - dstrect.x;
597     dstrect.w = min( dstrect.w , screen->w - dstrect.x );
598 
599     dstrect.y = min(o_y, y);
600     dstrect.y = max( dstrect.y, 0 );
601     dstrect.h = max(o_y + (o_pp->base->dim * cs->h),
602 	    y + (pp->base->dim * cs->h)) - dstrect.y;
603     dstrect.h = min( dstrect.h , screen->h - dstrect.y );
604 
605     SDL_UpdateSafe(screen,1,&dstrect);
606 
607     return;
608 }
609 
610 
611 /*
612  * $Log: piece.c,v $
613  * Revision 1.29  2000/11/06 04:16:10  weimer
614  * "power pieces" plus images
615  *
616  * Revision 1.28  2000/11/06 04:06:44  weimer
617  * option menu
618  *
619  * Revision 1.27  2000/11/06 01:25:54  weimer
620  * add in the other special piece
621  *
622  * Revision 1.26  2000/11/06 00:24:01  weimer
623  * add WalkRadioGroup modifications (inactive field for Kiri) and some support
624  * for special pieces
625  *
626  * Revision 1.25  2000/11/03 04:25:58  weimer
627  * add some optimizations to run_gravity to make it just a bit faster (down
628  * to 0.01 ms/call from 0.02), sleep a bit more in event-loop: generally
629  * trying to make us more CPU friendly ...
630  *
631  * Revision 1.24  2000/11/03 03:41:35  weimer
632  * made the light and dark "edges" of pieces global, rather than part of a
633  * specific color style. also fixed a bug where we were updating too much
634  * when drawing falling pieces (bad min() code on my part)
635  *
636  * Revision 1.23  2000/10/29 21:23:28  weimer
637  * One last round of header-file changes to reflect my newest and greatest
638  * knowledge of autoconf/automake. Now if you fail to have some bizarro
639  * function, we try to go on anyway unless it is vastly needed.
640  *
641  * Revision 1.22  2000/10/29 17:23:13  weimer
642  * incorporate "xflame" flaming background for added spiffiness ...
643  *
644  * Revision 1.21  2000/10/29 00:17:39  weimer
645  * added support for a system independent random number generator
646  *
647  * Revision 1.20  2000/10/29 00:06:27  weimer
648  * networking fixes, change "styles/" to "styles" so that it works on Windows
649  *
650  * Revision 1.19  2000/10/21 01:14:43  weimer
651  * massic autoconf/automake restructure ...
652  *
653  * Revision 1.18  2000/10/19 22:06:51  weimer
654  * minor changes ...
655  *
656  * Revision 1.17  2000/10/18 23:57:49  weimer
657  * general fixup, color changes, display changes.
658  * Notable: "Safe" Blits and Updates now perform "clipping". No more X errors,
659  * we hope!
660  *
661  * Revision 1.16  2000/10/13 18:23:28  weimer
662  * fixed a race condition in tetris_event()
663  *
664  * Revision 1.15  2000/10/13 17:55:36  weimer
665  * Added another color "Style" ...
666  *
667  * Revision 1.14  2000/10/13 15:41:53  weimer
668  * revamped AI support, now you can pick your AI and have AI duels (such fun!)
669  * the mighty Aliz AI still crashes a bit, though ... :-)
670  *
671  * Revision 1.13  2000/10/12 19:17:08  weimer
672  * Further support for AI players and multiple game types.
673  *
674  * Revision 1.12  2000/10/12 00:49:08  weimer
675  * added "AI" support and walking radio menus for initial game configuration
676  *
677  * Revision 1.11  2000/09/09 17:05:35  wkiri
678  * Hideous log changes (Wes: how dare you include a comment character!)
679  *
680  * Revision 1.10  2000/09/09 16:58:27  weimer
681  * Sweeping Change of Ultimate Mastery. Main loop restructuring to clean up
682  * main(), isolate the behavior of the three game types. Move graphic files
683  * into graphics/-, style files into styles/-, remove some unused files,
684  * add game flow support (breaks between games, remembering your level within
685  * this game), multiplayer support for the event loop, some global variable
686  * cleanup. All that and a bag of chips!
687  *
688  * Revision 1.9  2000/09/04 21:02:18  weimer
689  * Added some addition piece layout code, garbage now falls unless the row
690  * below it features some non-falling garbage
691  *
692  * Revision 1.8  2000/09/04 19:48:02  weimer
693  * interim menu for choosing among game styles, button changes (two states)
694  *
695  * Revision 1.7  2000/09/04 14:08:30  weimer
696  * Added another color scheme and color/piece scheme scanning code.
697  *
698  * Revision 1.6  2000/09/03 21:06:31  wkiri
699  * Now handles three different game types (and does different things).
700  * Major changes in display.c to handle this.
701  *
702  * Revision 1.5  2000/09/03 18:26:11  weimer
703  * major header file and automatic prototype generation changes, restructuring
704  *
705  * Revision 1.4  2000/08/20 16:14:10  weimer
706  * changed the piece generation so that pieces and colors cluster together
707  *
708  * Revision 1.3  2000/08/15 00:48:28  weimer
709  * Massive sound rewrite, fixed a few memory problems. We now have
710  * sound_styles that work like piece_styles and color_styles.
711  *
712  * Revision 1.2  2000/08/13 19:27:20  weimer
713  * added file changelogs
714  *
715  */
716