1 /*
2  *                               Alizarin Tetris
3  * The main file. Library initialization and utility functions.
4  *
5  * Copyright 2000, Westley Weimer & Kiri Wagstaff
6  */
7 
8 #include <config.h>	/* go autoconf! */
9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <stdarg.h>
12 #include <sys/stat.h>
13 
14 #include "SDL.h"
15 #include "SDL_main.h"
16 #include "SDL_ttf.h"
17 
18 #if HAVE_SYS_SOCKET_H
19 #	include <sys/socket.h>
20 #else
21 #	if HAVE_WINSOCK_H
22 #		include <winsock.h>
23 #	endif
24 #endif
25 
26 /* header files */
27 #include "atris.h"
28 #include "ai.h"
29 #include "display.h"
30 #include "grid.h"
31 #include "piece.h"
32 #include "sound.h"
33 #include "identity.h"
34 #include "options.h"
35 
36 /* function prototypes */
37 #include "ai.pro"
38 #include "display.pro"
39 #include "event.pro"
40 #include "gamemenu.pro"
41 #include "highscore.pro"
42 #include "identity.pro"
43 #include "network.pro"
44 #include "xflame.pro"
45 
46 static color_style *event_cs[2];	/* pass these to event_loop */
47 static sound_style *event_ss[2];
48 static AI_Player *event_ai[2];
49 static char *event_name[2];
50 extern int Score[2];
51 
52 /***************************************************************************
53  *      Panic()
54  * It's over. Don't even try to clean up.
55  *********************************************************************PROTO*/
56 void
Panic(const char * func,const char * file,char * fmt,...)57 Panic(const char *func, const char *file, char *fmt, ...)
58 {
59   va_list ap;
60   va_start(ap, fmt);
61 
62   printf("\nPANIC in %s() of %s:\n\t",func,file);
63 #if HAVE_VPRINTF
64   vprintf((const char *)fmt, ap);
65 #else
66 #warning "Since you lack vprintf(), you will not get informative PANIC messages."
67 #endif
68   printf("\n\nlibc error %3d| %s\n",errno,strerror(errno));
69   printf(    "SDL error     | %s\n",SDL_GetError());
70   SDL_CloseAudio();
71   exit(1);
72 }
73 
74 /***************************************************************************
75  *      usage()
76  * Display summary usage information.
77  ***************************************************************************/
78 static void
usage(void)79 usage(void)
80 {
81     printf("\n\t\t\t\tatris -- Alizarin Tetris\n"
82 	   "Usage: atris [options] \n"
83 	   "\t-h --help\t\tThis message.\n"
84 	   "\t-b --bg     \t\tFlaming background (default).\n"
85 	   "\t-n --noflame\t\tNo flaming background.\n"
86 	   "\t-s --sound\t\tEnable sound effects (default).\n"
87 	   "\t-q --quiet\t\tNo sound effects.\n"
88 	   "\t-w --window\t\tWindowed display (default).\n"
89 	   "\t-f --fullscreen\t\tFull-screen display.\n"
90 	   "\t-d=X --depth=X\t\tSet color detph (bpp) to X.\n"
91 	   "\t-r=X --repeat=X\t\tSet the keyboard repeat delay to X.\n"
92 	   "\t\t\t\t(1 = Slow Repeat, 16 = Fast Repeat)\n"
93 	   );
94     exit(1);
95 }
96 
97 /***************************************************************************
98  *      save_options()
99  * Save current settings to a file.
100  ***************************************************************************/
101 void
save_options(char * filespec)102 save_options(char *filespec)
103 {
104     FILE *fout = fopen(filespec, "wt");
105     if (!fout) return;
106     fprintf(fout,
107 	    "# bpp = 15, 16, 24, 32 or 0 for auto-detect bits per pixel\n"
108 	    "bpp = %d\n"
109 	    "# sound_wanted = 0 or 1\n"
110 	    "sound_wanted = %d\n"
111 	    "# full_screen = 0 or 1\n"
112 	    "full_screen = %d\n"
113 	    "# flame = 0 or 1 (CPU-sucking background flame)\n"
114 	    "flame = %d\n"
115 	    "# key_repeat = 1 to 32 (1 = slow repeat, 16 = default)\n"
116 	    "key_repeat = %d\n"
117 	    "# power_pieces = 0 or 1\n"
118 	    "power_pieces = %d\n"
119 	    "# double_difficulty = 0 or 1\n"
120 	    "double_difficulty = %d\n"
121 	    "# long_settle = 0 or 1\n"
122 	    "long_settle = %d\n"
123 	    "# upward_rotation = 0 or 1\n"
124 	    "upward_rotation = %d\n"
125 	    "#\n"
126 	    "color_style = %d\n"
127 	    "sound_style = %d\n"
128 	    "piece_style = %d\n"
129 	    "game_style = %d\n"
130 	    ,
131 	    Options.bpp_wanted, Options.sound_wanted,
132 	    Options.full_screen, Options.flame_wanted,
133 	    Options.key_repeat_delay, Options.special_wanted,
134 	    Options.faster_levels, Options.long_settle_delay,
135 	    Options.upward_rotation,
136 	    Options.named_color, Options.named_sound, Options.named_piece,
137 	    Options.named_game);
138     fclose(fout);
139     Debug("Preference file [%s] saved.\n",filespec);
140     return;
141 }
142 
143 /***************************************************************************
144  *      load_options()
145  * Load options from a user settings file.
146  ***************************************************************************/
147 void
load_options(char * filespec)148 load_options(char * filespec)
149 {
150     FILE *fin = fopen(filespec, "rt");
151 
152     Options.full_screen = TRUE;
153     Options.sound_wanted = TRUE;
154     Options.flame_wanted = TRUE;
155     Options.bpp_wanted = 0;
156     Options.key_repeat_delay = 8;
157     Options.special_wanted = FALSE;
158     Options.faster_levels = FALSE;
159     Options.upward_rotation = TRUE;
160     Options.long_settle_delay = TRUE;
161     Options.named_color = -1;
162     Options.named_sound = -1;
163     Options.named_piece = -1;
164     Options.named_game = -1;
165 
166     if (!fin) return;
167 
168     while (!feof(fin)) {
169 	char buf[1024];
170 	char cmd[1024];
171 	fgets(buf,sizeof(buf),fin);
172 	if (feof(fin)) break;
173 	if (buf[0] == '#' || buf[0] == '\n')
174 	    continue;
175 
176 	sscanf(buf,"%s",cmd);
177 	if (!strcasecmp(cmd,"full_screen")) {
178 	    sscanf(buf,"%s = %d",cmd,&Options.full_screen);
179 	} else if (!strcasecmp(cmd,"sound_wanted")) {
180 	    sscanf(buf,"%s = %d",cmd,&Options.sound_wanted);
181 	} else if (!strcasecmp(cmd,"flame")) {
182 	    sscanf(buf,"%s = %d",cmd,&Options.flame_wanted);
183 	} else if (!strcasecmp(cmd,"bpp")) {
184 	    sscanf(buf,"%s = %d",cmd,&Options.bpp_wanted);
185 	} else if (!strcasecmp(cmd,"key_repeat")) {
186 	    sscanf(buf,"%s = %d",cmd,&Options.key_repeat_delay);
187 	    if (Options.key_repeat_delay < 1) Options.key_repeat_delay = 1;
188 	    if (Options.key_repeat_delay > 32) Options.key_repeat_delay = 32;
189 	} else if (!strcasecmp(cmd,"power_pieces")) {
190 	    sscanf(buf,"%s = %d",cmd,&Options.special_wanted);
191 	} else if (!strcasecmp(cmd,"double_difficulty")) {
192 	    sscanf(buf,"%s = %d",cmd,&Options.faster_levels);
193 	} else if (!strcasecmp(cmd,"long_settle")) {
194 	    sscanf(buf,"%s = %d",cmd,&Options.long_settle_delay);
195 	} else if (!strcasecmp(cmd,"upward_rotation")) {
196 	    sscanf(buf,"%s = %d",cmd,&Options.upward_rotation);
197 	} else if (!strcasecmp(cmd,"color_style")) {
198 	    sscanf(buf,"%s = %d",cmd,&Options.named_color);
199 	} else if (!strcasecmp(cmd,"sound_style")) {
200 	    sscanf(buf,"%s = %d",cmd,&Options.named_sound);
201 	} else if (!strcasecmp(cmd,"piece_style")) {
202 	    sscanf(buf,"%s = %d",cmd,&Options.named_piece);
203 	} else if (!strcasecmp(cmd,"game_style")) {
204 	    sscanf(buf,"%s = %d",cmd,&Options.named_game);
205 	} else {
206 	    Debug("Unable to parse configuration line\n%s",buf);
207 	}
208     }
209     fclose(fin);
210     Debug("Preference file [%s] loaded.\n",filespec);
211     return;
212 }
213 
214 /***************************************************************************
215  *      parse_options()
216  * Check the command-line arguments.
217  ***************************************************************************/
218 static void
parse_options(int argc,char * argv[])219 parse_options(int argc, char *argv[])
220 {
221     int i;
222 
223     for (i=1; i<argc; i++) {
224 	if (!strcmp(argv[i],"-h") || !strcmp(argv[i],"--help"))
225 	    usage();
226 	else if (!strcmp(argv[i],"-?") || !strcmp(argv[i],"-help"))
227 	    usage();
228 	else if (!strcmp(argv[i],"-b") || !strcmp(argv[i],"--bg"))
229 	    Options.flame_wanted = TRUE;
230 	else if (!strcmp(argv[i],"-n") || !strcmp(argv[i],"--noflame"))
231 	    Options.flame_wanted = FALSE;
232 	else if (!strcmp(argv[i],"-s") || !strcmp(argv[i],"--sound"))
233 	    Options.sound_wanted = TRUE;
234 	else if (!strcmp(argv[i],"-q") || !strcmp(argv[i],"--quiet"))
235 	    Options.sound_wanted = FALSE;
236 	else if (!strcmp(argv[i],"-w") || !strcmp(argv[i],"--window"))
237 	    Options.full_screen = FALSE;
238 	else if (!strcmp(argv[i],"-f") || !strcmp(argv[i],"--fullscreen"))
239 	    Options.full_screen = TRUE;
240 	else if (!strncmp(argv[i],"-d=", 3) || !strncmp(argv[i],"--depth=", 8)) {
241 	    sscanf(strchr(argv[i],'=')+1,"%d",&Options.bpp_wanted);
242 	} else if (!strncmp(argv[i],"-r=", 3) || !strncmp(argv[i],"--repeat=", 8)) {
243 	    sscanf(strchr(argv[i],'=')+1,"%d",&Options.key_repeat_delay);
244 	    if (Options.key_repeat_delay < 1) Options.key_repeat_delay = 1;
245 	    if (Options.key_repeat_delay > 32) Options.key_repeat_delay = 32;
246 	} else {
247 	    Debug("option not understood: [%s]\n",argv[i]);
248 	    usage();
249 	}
250     }
251     Debug("Command line arguments parsed.\n");
252     return;
253 }
254 
255 /***************************************************************************
256  *      level_adjust()
257  * What happens with all of those thumbs-up, thumbs-down adjustments?
258  *
259  * Returns the new value of "match".
260  ***************************************************************************/
261 static int
level_adjust(int a[3],int b[3],int level[2],int match)262 level_adjust(int a[3], int b[3], int level[2], int match)
263 {
264     int i;
265     int up[2] = {0, 0}, down[2] = {0, 0};
266 
267     for (i=0;i<=match;i++) {
268 	if (a[i] == ADJUST_UP) up[0]++;
269 	if (a[i] == ADJUST_DOWN) down[0]++;
270 	if (b[i] == ADJUST_UP) up[1]++;
271 	if (b[i] == ADJUST_DOWN) down[1]++;
272     }
273 
274     while (up[0] > 0 && up[1] > 0) {
275 	up[0]--;
276 	up[1]--;
277     }
278     while (up[0] > 0 && down[0] > 0) {
279 	up[0]--;
280 	down[0]--;
281     }
282     while (up[1] > 0 && down[1] > 0) {
283 	up[1]--;
284 	down[1]--;
285     }
286     while (down[0] > 0 && down[1] > 0) {
287 	down[0]--;
288 	down[1]--;
289     }
290     if (up[0] == 3 || down[0] == 3 || up[1] == 3 || down[1] == 3) {
291 	if (up[0] == 3) 	level[0]++;
292 	if (down[0] == 3) 	level[0]--;
293 	if (up[1] == 3) 	level[1]++;
294 	if (down[1] == 3) 	level[1]--;
295 	a[0] = a[1] = a[2] = b[0] = b[1] = b[2] = -1;
296 	return 0;
297     }
298     a[0] = a[1] = a[2] = b[0] = b[1] = b[2] = -1;
299     match = max( max(up[0],up[1]), max(down[0], down[1]) );
300     /* fill out the a[], b[] arrays */
301     for (i=0;i<up[0];i++)
302 	a[i] = ADJUST_UP;
303     for (i=up[0]; i<up[0] + down[0]; i++)
304 	a[i] = ADJUST_DOWN;
305     for (i=up[0] + down[0]; i<match;i++)
306 	a[i] = ADJUST_SAME;
307 
308     for (i=0;i<up[1];i++)
309 	b[i] = ADJUST_UP;
310     for (i=up[1]; i<up[1] + down[1]; i++)
311 	b[i] = ADJUST_DOWN;
312     for (i=up[1] + down[1]; i<match;i++)
313 	b[i] = ADJUST_SAME;
314 
315     return match;
316 }
317 
318 /***************************************************************************
319  *      play_TWO_PLAYERS()
320  * Play the TWO_PLAYERS-style game. You and someone else both have two
321  * minutes per level, but the limit isn't deadly. Complex adjustment rules.
322  ***************************************************************************/
323 static void
play_TWO_PLAYERS(color_styles cs,piece_styles ps,sound_styles ss,Grid g[2],person * p1,person * p2)324 play_TWO_PLAYERS(color_styles cs, piece_styles ps, sound_styles ss,
325     Grid g[2], person *p1, person *p2)
326 {
327     int curtimeleft;
328     int match;
329     int adjustment[2] = {-1, -1};	/* result of playing a match */
330     int my_adj[3];			/* my three winnings so far */
331     int their_adj[3];			/* their three winnings so far */
332     int done = 0;
333     int level[2];
334     time_t our_time;
335 
336     my_adj[0] = my_adj[1] = my_adj[2] = -1;
337     their_adj[0] = their_adj[1] = their_adj[2] = -1;
338     match = 0;
339 
340     level[0] = p1->level;
341     level[1] = p2->level;
342 
343     /* start the games */
344     while (!done) {
345 	time(&our_time);
346 	/* make the boards */
347 
348 	SeedRandom(our_time);
349 	g[0] = generate_board(10,20,level[0]);
350 	SeedRandom(our_time);
351 	g[1] = generate_board(10,20,level[1]);
352 	SeedRandom(our_time);
353 
354 	event_name[0] = p1->name;
355 	event_name[1] = p2->name;
356 
357 	/* draw the background */
358 	draw_background(screen, cs.style[0]->w, g, level, my_adj, their_adj,
359 		event_name);
360 
361 	/* start the fun! */
362 	curtimeleft = 120;
363 
364 	event_cs[0] = event_cs[1] = cs.style[cs.choice];
365 	event_ss[0] = event_ss[1] = ss.style[ss.choice];
366 
367 	if (event_loop(screen, ps.style[ps.choice],
368 		event_cs, event_ss, g,
369 		level, 0, &curtimeleft, 0, adjustment, NULL,
370 		our_time, HUMAN_PLAYER, HUMAN_PLAYER, NULL) >= 0) {
371 	    draw_background(screen, cs.style[0]->w,g,level,my_adj,their_adj,
372 		    event_name);
373 	    SDL_Delay(1000);
374 	}
375 	my_adj[match] = adjustment[0];
376 	their_adj[match] = adjustment[1];
377 	match = level_adjust(my_adj, their_adj, level, match);
378 
379 
380 	/* update results */
381 	p1->level = level[0];
382 	p2->level = level[1];
383 
384 	/* show them what's what! */
385 	draw_background(screen, cs.style[0]->w,g,level,my_adj,their_adj,
386 		event_name);
387 	draw_score(screen,0);
388 	draw_score(screen,1);
389 	done = give_notice(NULL,1);
390     } /* end: while !done */
391     return;
392 }
393 
394 /***************************************************************************
395  *      play_AI_VS_AI()
396  * Play the AI_VS_AI-style game. Two AI's duke it out! Winnings and scores
397  * are collected.
398  ***************************************************************************/
399 static void
play_AI_VS_AI(color_styles cs,piece_styles ps,sound_styles ss,Grid g[2],AI_Player * p1,AI_Player * p2)400 play_AI_VS_AI(color_styles cs, piece_styles ps, sound_styles ss,
401     Grid g[2], AI_Player *p1, AI_Player *p2)
402 {
403     int curtimeleft;
404     int match;
405     int level[2];			/* level array: me + dummy slot */
406     int adjustment[2] = {-1, -1};	/* result of playing a match */
407     int my_adj[3];			/* my three winnings so far */
408     int their_adj[3];			/* their three winnings so far */
409     int done = 0;
410     time_t our_time;
411     int p1_results[3] = {0, 0, 0};
412     int p2_results[3] = {0, 0, 0};
413 
414     my_adj[0] = -1; my_adj[1] = -1; my_adj[2] = -1;
415     their_adj[0] = -1; their_adj[1] = -1; their_adj[2] = -1;
416     match = 0;
417 
418     /* start the games */
419     while (!done) {
420 
421 	time(&our_time);
422 	/* make the boards */
423 	level[0] = level[1] = Options.faster_levels ? 1+ZEROTO(8) :
424 	    2+ZEROTO(16);
425 
426 
427 	SeedRandom(our_time);
428 	g[0] = generate_board(10,20,level[0]);
429 	SeedRandom(our_time);
430 	g[1] = generate_board(10,20,level[0]);
431 	SeedRandom(our_time);
432 
433 	event_name[0] = p1->name;
434 	event_name[1] = p2->name;
435 
436 	/* draw the background */
437 	draw_background(screen, cs.style[0]->w, g, level,
438 		p1_results, p2_results, event_name);
439 	/* start the fun! */
440 	curtimeleft = 120;
441 
442 	event_cs[0] = cs.style[cs.choice];
443 	event_cs[1] = cs.style[ZEROTO(cs.num_style)];
444 	event_ss[0] = event_ss[1] = ss.style[ss.choice];
445 	event_ai[0] = p1; event_ai[1] = p2;
446 
447 	if (event_loop(screen, ps.style[ps.choice],
448 		event_cs, event_ss, g,
449 		level, 0, &curtimeleft, 0, adjustment, NULL,
450 		our_time, AI_PLAYER, AI_PLAYER, event_ai) < 0) {
451 	    return;
452 	}
453 
454 	if (adjustment[0] != -1)
455 	    p1_results[ adjustment[0] ] ++;
456 	if (adjustment[1] != -1)
457 	    p2_results[ adjustment[1] ] ++;
458 
459 	/* show them what's what! */
460 	draw_background(screen, cs.style[0]->w, g, level,
461 		p1_results, p2_results, event_name);
462 	draw_score(screen,0);
463 	draw_score(screen,1);
464     } /* end: while !done */
465     return;
466 }
467 
468 /***************************************************************************
469  *      play_SINGLE_VS_AI()
470  * Play the SINGLE_VS_AI-style game. You and someone else both have two
471  * minutes per level, but the limit isn't deadly. Complex adjustment rules.
472  ***************************************************************************/
473 static int
play_SINGLE_VS_AI(color_styles cs,piece_styles ps,sound_styles ss,Grid g[2],person * p,AI_Player * aip)474 play_SINGLE_VS_AI(color_styles cs, piece_styles ps, sound_styles ss,
475     Grid g[2], person *p, AI_Player *aip)
476 {
477     int curtimeleft;
478     int match;
479     int level[2];			/* level array: me + dummy slot */
480     int adjustment[2] = {-1, -1};	/* result of playing a match */
481     int my_adj[3];			/* my three winnings so far */
482     int their_adj[3];			/* their three winnings so far */
483     int done = 0;
484     time_t our_time;
485 
486     my_adj[0] = my_adj[1] = my_adj[2] = -1;
487     their_adj[0] = their_adj[1] = their_adj[2] = -1;
488     match = 0;
489 
490     /* start the games */
491     level[0] = level[1] = p->level; /* AI matches skill */
492     while (!done) {
493 	time(&our_time);
494 	/* make the boards */
495 	level[1] = level[0];
496 
497 	SeedRandom(our_time);
498 	g[0] = generate_board(10,20,level[0]);
499 	SeedRandom(our_time);
500 	g[1] = generate_board(10,20,level[0]);
501 	SeedRandom(our_time);
502 
503 	event_name[0] = p->name;
504 	event_name[1] = aip->name;
505 
506 	/* draw the background */
507 	draw_background(screen, cs.style[0]->w, g, level, my_adj, their_adj,
508 		event_name);
509 
510 	/* start the fun! */
511 	curtimeleft = 120;
512 
513 	event_cs[0] = cs.style[cs.choice];
514 	event_cs[1] = cs.style[ZEROTO(cs.num_style)];
515 	event_ss[0] = event_ss[1] = ss.style[ss.choice];
516 	event_ai[0] = NULL; event_ai[1] = aip;
517 
518 	if (event_loop(screen, ps.style[ps.choice],
519 		event_cs, event_ss, g,
520 		level, 0, &curtimeleft, 0, adjustment, NULL,
521 		our_time, HUMAN_PLAYER, AI_PLAYER, event_ai) >= 0) {
522 	    draw_background(screen, cs.style[0]->w,g,level,my_adj,their_adj,
523 		    event_name);
524 	    draw_score(screen,0);
525 	    draw_score(screen,1);
526 	    SDL_Delay(1000);
527 	}
528 	my_adj[match] = adjustment[0];
529 	their_adj[match] = adjustment[1];
530 	match = level_adjust(my_adj, their_adj, level, match);
531 
532 	/* show them what's what! */
533 	draw_background(screen, cs.style[0]->w,g,level,my_adj,their_adj,
534 		event_name);
535 	draw_score(screen,0);
536 	draw_score(screen,1);
537 	done = give_notice(NULL, 1);
538     } /* end: while !done */
539     return level[0];
540 }
541 
542 
543 /***************************************************************************
544  *      play_NETWORK()
545  * Play the NETWORK-style game. You and someone else both have two minutes
546  * per level, but the limit isn't deadly. Complex adjustment rules. :-)
547  ***************************************************************************/
548 static int
play_NETWORK(color_styles cs,piece_styles ps,sound_styles ss,Grid g[2],person * p,char * hostname)549 play_NETWORK(color_styles cs, piece_styles ps, sound_styles ss,
550     Grid g[2], person *p, char *hostname)
551 {
552     int curtimeleft;
553     extern char *error_msg;
554     int server;
555     int match;
556     int level[2];			/* level array: me + dummy slot */
557     int adjustment[2] = {-1, -1};	/* result of playing a match */
558     int my_adj[3];			/* my three winnings so far */
559     int their_adj[3];			/* their three winnings so far */
560     char message[1024];
561     char *their_name;
562     int done = 0;
563     int sock;
564     int their_cs_choice;
565     int their_data;
566     time_t our_time;
567 
568     server = (hostname == NULL);
569 
570 #define SEND(msg,len) {if (send(sock,(const char *)msg,len,0) < (signed)len) goto error;}
571 #define RECV(msg,len) {if (recv(sock,(char *)msg,len,0) < (signed)len) goto error;}
572 
573 #define SERVER_SYNC	0x12345678
574 #define CLIENT_SYNC	0x98765432
575 
576     level[0] = p->level;
577     /* establish connection */
578     if (server) {
579 	SDL_Event event;
580 	/* try this a lot until they press Q to give up */
581 	clear_screen_to_flame();
582 
583 	draw_string("Waiting for the client ...",
584 		color_blue, screen->w/2, screen->h/2, DRAW_CENTER|DRAW_ABOVE
585 		|DRAW_UPDATE);
586 	draw_string("Press 'Q' to give up.",
587 		color_blue, screen->w/2, screen->h/2, DRAW_CENTER|DRAW_UPDATE);
588 
589 	do {
590 	    sock = Server_AwaitConnection(7741);
591 	    if (sock == -1 && SDL_PollEvent(&event) && event.type == SDL_KEYDOWN)
592 		if (event.key.keysym.sym == SDLK_q)
593 		    goto done;
594 	} while (sock == -1);
595     } else { /* client */
596 	int i;
597 	SDL_Event event;
598 	sock = -1;
599 	for (i=0; i<5 && sock == -1; i++) {
600 	    sock = Client_Connect(hostname,7741);
601 	    if (sock == -1 && SDL_PollEvent(&event) && event.type == SDL_KEYDOWN &&
602 		 event.key.keysym.sym == SDLK_q)
603 		goto done;
604 	    if (sock == -1) SDL_Delay(1000);
605 	}
606 	if (sock == -1)
607 	    goto error;
608     }
609     clear_screen_to_flame();
610 
611     /* consistency checks: same number of colors */
612     SEND(&cs.style[cs.choice]->num_color, sizeof(int));
613     RECV(&their_data, sizeof(int));
614     if (their_data != cs.style[cs.choice]->num_color) {
615 	SPRINTF(message,"The # of colors in your styles are not equal. (%d/%d)",
616 		cs.style[cs.choice]->num_color, their_data);
617 	goto known_error;
618     }
619 
620     SEND(&ps.style[ps.choice]->num_piece, sizeof(int));
621     RECV(&their_data, sizeof(int));
622     if (their_data != ps.style[ps.choice]->num_piece) {
623 	SPRINTF(message,"The # of shapes in your styles are not equal. (%d/%d)",
624 		ps.style[ps.choice]->num_piece, their_data);
625 	goto known_error;
626     }
627 
628     SEND(&Options.special_wanted, sizeof(int));
629     RECV(&their_data, sizeof(int));
630     if (their_data != Options.special_wanted) {
631 	SPRINTF(message,"You must both agree on whether to use Power Pieces");
632 	goto known_error;
633     }
634 
635     SEND(&Options.faster_levels, sizeof(int));
636     RECV(&their_data, sizeof(int));
637     if (their_data != Options.special_wanted) {
638 	SPRINTF(message,"You must both agree on Double Difficulty");
639 	goto known_error;
640     }
641 
642     /* initial levels */
643     SEND(&level[0],sizeof(level[0]));
644     SEND(&cs.choice,sizeof(cs.choice));
645     match = strlen(p->name);
646     SEND(&match, sizeof(match));
647     SEND(p->name,strlen(p->name));
648 
649     RECV(&level[1],sizeof(level[1]));
650     Assert(sizeof(their_cs_choice) == sizeof(cs.choice));
651     RECV(&their_cs_choice,sizeof(cs.choice));
652     if (their_cs_choice < 0 || their_cs_choice >= cs.num_style) {
653 	their_cs_choice = cs.choice;
654     }
655     RECV(&match,sizeof(match));
656     Calloc(their_name, char *, match);
657     RECV(their_name, match);
658 
659     my_adj[0] = my_adj[1] = my_adj[2] = -1;
660     their_adj[0] = their_adj[1] = their_adj[2] = -1;
661     match = 0;
662 
663     /* start the games */
664     while (!done) {
665 	/* pass the seed */
666 	if (server) {
667 	    time(&our_time);
668 	    SEND(&our_time,sizeof(our_time));
669 	} else {
670 	    RECV(&our_time,sizeof(our_time));
671 	}
672 	/* make the boards */
673 	SeedRandom(our_time);
674 	g[0] = generate_board(10,20,level[0]);
675 	SeedRandom(our_time);
676 	g[1] = generate_board(10,20,level[1]);
677 	SeedRandom(our_time);
678 
679 	event_name[0] = p->name;
680 	event_name[1] = their_name;
681 
682 	/* draw the background */
683 	draw_background(screen, cs.style[0]->w, g, level, my_adj, their_adj,
684 		event_name);
685 
686 	/* start the fun! */
687 	curtimeleft = 120;
688 
689 	event_cs[0] = cs.style[cs.choice];
690 	event_cs[1] = cs.style[their_cs_choice];
691 	event_ss[0] = event_ss[1] = ss.style[ss.choice];
692 
693 	event_loop(screen, ps.style[ps.choice],
694 		event_cs, event_ss, g,
695 		level, sock, &curtimeleft, 0, adjustment, NULL,
696 		our_time, HUMAN_PLAYER, NETWORK_PLAYER, NULL);
697 	SEND(&Score[0],sizeof(Score[0]));
698 	RECV(&Score[1],sizeof(Score[1]));
699 	draw_background(screen, cs.style[0]->w,g,level,my_adj,their_adj,
700 		event_name);
701 	draw_score(screen,0);
702 	draw_score(screen,1);
703 	SDL_Delay(1000);
704 	my_adj[match] = adjustment[0];
705 	their_adj[match] = adjustment[1];
706 	match = level_adjust(my_adj, their_adj, level, match);
707 
708 	/* verify that our hearts are in the right place */
709 	if (server) {
710 	    unsigned int msg = SERVER_SYNC;
711 	    SEND(&msg,sizeof(msg));
712 	    RECV(&msg,sizeof(msg));
713 	    if (msg != CLIENT_SYNC) {
714 		give_notice("Network Error: Syncronization Failed", 0);
715 		goto done;
716 	    }
717 	} else {
718 	    unsigned int msg;
719 	    RECV(&msg,sizeof(msg));
720 	    if (msg != SERVER_SYNC) {
721 		give_notice("Network Error: Syncronization Failed", 1);
722 		goto done;
723 	    }
724 	    msg = CLIENT_SYNC;
725 	    SEND(&msg,sizeof(msg));
726 	}
727 	/* OK, we believe we are both dancing on the beat ... */
728 	/* don't even talk to me about three-way handshakes ... */
729 
730 	/* show them what's what! */
731 	draw_background(screen, cs.style[0]->w,g,level,my_adj,their_adj,
732 		event_name);
733 	draw_score(screen,0);
734 	draw_score(screen,1);
735 	if (server) {
736 	    done = give_notice(NULL, 1);
737 	    SEND(&done,sizeof(done));
738 	} else {
739 	    SDL_Event event;
740 	    draw_string("Waiting for the", color_blue, 0, 0,
741 		    DRAW_CENTER|DRAW_ABOVE |DRAW_UPDATE|DRAW_GRID_0);
742 	    draw_string("Server to go on.", color_blue, 0, 0, DRAW_CENTER
743 		    |DRAW_UPDATE|DRAW_GRID_0);
744 	    RECV(&done,sizeof(done));
745 	    while (SDL_PollEvent(&event))
746 		/* do nothing */ ;
747 	}
748 	clear_screen_to_flame();
749     } /* end: while !done */
750     close(sock);
751     return level[0];
752 
753     /* error conditions! */
754 error:
755     if (error_msg)
756 	SPRINTF(message,"Network Error: %s",error_msg);
757     else
758 	SPRINTF(message,"Network Error: %s",strerror(errno));
759 known_error:
760     clear_screen_to_flame();
761     give_notice(message, 0);
762 done:
763     close(sock);
764     return level[0];
765 }
766 
767 /***************************************************************************
768  *      play_MARATHON()
769  * Play the MARATHON-style game. You have five minutes per level: try to
770  * get many points. Returns the final level.
771  ***************************************************************************/
772 static int
play_MARATHON(color_styles cs,piece_styles ps,sound_styles ss,Grid g[2],person * p)773 play_MARATHON(color_styles cs, piece_styles ps, sound_styles ss,
774     Grid g[2], person *p)
775 {
776     int curtimeleft;
777     int level[2];			/* level array: me + dummy slot */
778     int adjustment[2] = {-1, -1};	/* result of playing a match */
779     int my_adj[3];			/* my three winnings so far */
780     char message[1024];
781     int result;
782 
783     level[0] = p->level;		/* starting level */
784     SeedRandom(0);
785     Score[0] = 0;		/* global variable! */
786 
787     my_adj[0] = -1; my_adj[1] = -1; my_adj[2] = -1;
788     while (1) {
789 	/* until they give up by pressing 'q'! */
790 	/* 5 mintues per match */
791 	curtimeleft = 300;
792 	/* generate the board */
793 	g[0] = generate_board(10,20,level[0]);
794 	/* draw the background */
795 
796 	event_name[0] = p->name;
797 
798 	draw_background(screen, cs.style[0]->w, g, level, my_adj, NULL,
799 		event_name);
800 	/* get the result, but don't update level yet */
801 
802 	event_cs[0] = event_cs[1] = cs.style[cs.choice];
803 	event_ss[0] = event_ss[1] = ss.style[ss.choice];
804 
805 	result = event_loop(screen, ps.style[ps.choice],
806 		event_cs, event_ss, g,
807 		level, 0, &curtimeleft, 1, adjustment, NULL,
808 		time(NULL), HUMAN_PLAYER, NO_PLAYER, NULL);
809 	if (result < 0) { 	/* explicit quit */
810 	    return level[0];
811 	}
812 	/* reset board */
813 	my_adj[0] = adjustment[0];
814 	/* display those mighty accomplishments winnings */
815 	draw_background(screen, cs.style[0]->w ,g, level,my_adj,NULL,
816 		event_name);
817 	draw_score(screen,0);
818 	if (adjustment[0] != ADJUST_UP) {
819 	    give_notice("Game Over!", 0);
820 	    return level[0];
821 	}
822 	my_adj[0] = -1;
823 	level[0]++;
824 	SPRINTF(message,"Up to Level %d!",level[0]);
825 	if (give_notice(message, 1)) {
826 	    return level[0];
827 	}
828     }
829 }
830 
831 /***************************************************************************
832  *      play_SINGLE()
833  * Play the SINGLE-style game. You have five total minutes to win three
834  * matches. Returns the final level.
835  ***************************************************************************/
836 static int
play_SINGLE(color_styles cs,piece_styles ps,sound_styles ss,Grid g[],person * p)837 play_SINGLE(color_styles cs, piece_styles ps, sound_styles ss,
838     Grid g[], person *p)
839 {
840     int curtimeleft;
841     int match;
842     int level[2];			/* level array: me + dummy slot */
843     int adjustment[2] = {-1, -1};	/* result of playing a match */
844     int my_adj[3];			/* my three winnings so far */
845     char message[1024];
846     int result;
847 
848     level[0] = p->level;	/* starting level */
849     SeedRandom(0);
850     Score[0] = 0;		/* global variable! */
851 
852     while (1) {
853 	/* until they give up by pressing 'q'! */
854 	/* 5 total minutes for three matches */
855 	curtimeleft = 300;
856 	my_adj[0] = -1; my_adj[1] = -1; my_adj[2] = -1;
857 
858 	for (match=0; match<3 && curtimeleft > 0; match++) {
859 	    /* generate the board */
860 	    g[0] = generate_board(10,20,level[0]);
861 
862 	    event_name[0] = p->name;
863 
864 	    /* draw the background */
865 	    draw_background(screen, cs.style[0]->w, g, level, my_adj, NULL,
866 		    event_name);
867 	    /* get the result, but don't update level yet */
868 
869 	    event_cs[0] = event_cs[1] = cs.style[cs.choice];
870 	    event_ss[0] = event_ss[1] = ss.style[ss.choice];
871 
872 	    result = event_loop(screen, ps.style[ps.choice],
873 		    event_cs, event_ss, g,
874 		    level, 0, &curtimeleft, 1, adjustment, NULL,
875 		    time(NULL), HUMAN_PLAYER, NO_PLAYER, NULL);
876 	    if (result < 0) { 	/* explicit quit */
877 		return level[0];
878 	    }
879 	    /* reset board */
880 	    my_adj[match] = adjustment[0];
881 	    /* display those mighty accomplishments winnings */
882 	    draw_background(screen, cs.style[0]->w,g, level,my_adj,NULL,
883 		    event_name);
884 	    draw_score(screen,0);
885 	    message[0] = 0;
886 	    if (match == 2) {
887 		if (my_adj[0] == ADJUST_UP && my_adj[1] == ADJUST_UP &&
888 			my_adj[2] == ADJUST_UP)  /* go up! */ {
889 		    level[0]++;
890 		    SPRINTF(message,"Up to level %d!",level[0]);
891 		}
892 		else if (my_adj[0] == ADJUST_DOWN && my_adj[1] == ADJUST_DOWN &&
893 			my_adj[2] == ADJUST_DOWN) { /* devolve! */
894 		    level[0]--;
895 		    SPRINTF(message,"Down to level %d!",level[0]);
896 		}
897 	    }
898 	    if (give_notice(message, 1) == 1) { /* explicit quit */
899 		return level[0];
900 	    }
901 	}
902     }
903 }
904 
905 /***************************************************************************
906  *      main()
907  * Start the program, check the arguments, etc.
908  ***************************************************************************/
909 int
main(int argc,char * argv[])910 main(int argc, char *argv[])
911 {
912     color_styles cs;
913     piece_styles ps;
914     sound_styles ss;
915     identity *id;
916     AI_Players *ai;
917     Grid g[2];
918     int renderstyle = TTF_STYLE_NORMAL;
919     unsigned int flags;
920     Uint32 time_now;
921     SDL_Event event;
922 
923     umask(000);
924     Debug("\tWelcome to Alizarin Tetris (version %s - %s)\n", VERSION, "Delay" );
925     Debug("\t~~~~~~~~~~~~~~~~~~~~~~~~~~ (%s)\n", __DATE__);
926 
927 #ifdef HAVE_WINSOCK_H
928     load_options("atris.rc");
929 #else
930     {
931 	char filespec[2048];
932 	SPRINTF(filespec,"%s/.atrisrc", getenv("HOME"));
933 	load_options(filespec);
934     }
935 #endif
936     parse_options(argc, argv);
937 
938     if (SDL_Init(SDL_INIT_VIDEO))
939 	PANIC("SDL_Init failed!");
940 
941     /* Clean up on exit */
942     atexit(SDL_Quit);
943     /* Initialize the TTF library */
944     if ( TTF_Init() < 0 ) PANIC("TTF_Init failed!"); atexit(TTF_Quit);
945     Debug("SDL initialized.\n");
946 
947     /* Initialize the display in a 640x480 native-depth mode */
948     flags = // SDL_HWSURFACE |
949             SDL_SWSURFACE |
950 	    SDL_FULLSCREEN |
951             // SDL_SRCCOLORKEY |
952             // SDL_ANYFORMAT |
953             0;
954     if (Options.full_screen) flags |= SDL_FULLSCREEN;
955     screen = SDL_SetVideoMode(640, 480, Options.bpp_wanted, flags);
956     if ( screen == NULL ) PANIC("Could not set 640x480 video mode");
957     Debug("Video Mode: %d x %d @ %d bpp\n",
958 	    screen->w, screen->h, screen->format->BitsPerPixel);
959 
960     if (screen->format->BitsPerPixel <= 8) {
961 	PANIC("You need >256 colors to play atris");
962     }
963 
964     /* Set the window title */
965     SDL_WM_SetCaption("Alizarin Tetris", (char*)NULL);
966 
967     Network_Init();
968 
969     setup_colors(screen);
970     setup_layers(screen);
971 
972     if (chdir(ATRIS_LIBDIR)) {
973 	Debug("WARNING: cannot change directory to [%s]\n", ATRIS_LIBDIR);
974 	Debug("WARNING: playing in current directory instead\n");
975     } else
976 	Debug("Changing directory to [%s]\n",ATRIS_LIBDIR);
977 
978     /* Set up the font */
979     sfont = TTF_OpenFont("graphics/NewMediumNormal.ttf",18);
980      font = TTF_OpenFont("graphics/NewMediumNormal.ttf",24);
981     lfont = TTF_OpenFont("graphics/NewMediumNormal.ttf",36);
982     hfont = TTF_OpenFont("graphics/NewMediumNormal.ttf",96);
983     if ( font == NULL ) PANIC("Couldn't open [graphics/NewMediumNormal.ttf].", ATRIS_LIBDIR);
984     TTF_SetFontStyle(font, renderstyle);
985     TTF_SetFontStyle(sfont, renderstyle);
986     /* Initialize scores */
987     Score[0] = Score[1] = 0;
988     /* enable unicode so we can easily see which key they pressed */
989     SDL_EnableUNICODE(1);
990 
991     ps = load_piece_styles();
992     cs = load_color_styles(screen);
993     ss = load_sound_styles(Options.sound_wanted);
994 
995     if (Options.named_color >= 0 && Options.named_color <
996 	    cs.num_style) cs.choice = Options.named_color;
997     if (Options.named_piece >= 0 && Options.named_piece <
998 	    ps.num_style) ps.choice = Options.named_piece;
999     if (Options.named_sound >= 0 && Options.named_sound <
1000 	    ss.num_style) ss.choice = Options.named_sound;
1001     if (Options.named_game >= 0 && Options.named_game <= 5)
1002 	gametype = (GT) Options.named_game;
1003     else gametype = SINGLE;
1004 
1005     ai = AI_Players_Setup();
1006     id = load_identity_file();
1007 
1008     atris_xflame_setup();
1009 
1010     /* our happy splash screen */
1011     {
1012 	while (SDL_PollEvent(&event))
1013 	    ;
1014 	draw_string(PACKAGE " - " VERSION, color_white, screen->w, 0,
1015 		DRAW_LEFT | DRAW_UPDATE);
1016 	draw_string("Welcome To", color_purple, screen->w/2,
1017 		screen->h/2, DRAW_CENTER | DRAW_UPDATE | DRAW_ABOVE | DRAW_LARGE);
1018 	draw_string("Alizarin Tetris", color_blue, screen->w/2,
1019 		screen->h/2, DRAW_CENTER | DRAW_UPDATE | DRAW_HUGE);
1020     }
1021 
1022     time_now = SDL_GetTicks();
1023     do {
1024 	poll_and_flame(&event);
1025     } while (SDL_GetTicks() < time_now + 600);
1026 
1027     clear_screen_to_flame();	/* lose the "welcome to" words */
1028 
1029     while (1) {
1030 	int p1, p2;
1031 	int retval;
1032 
1033 	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY*10,
1034 		SDL_DEFAULT_REPEAT_INTERVAL);
1035 	choose_gametype(&ps,&cs,&ss,ai);
1036 	if (gametype == QUIT) break;
1037 	else Options.named_game = (int)gametype;
1038 	/* play our game! */
1039 
1040 	Score[0] = Score[1] = 0;
1041 	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY*10,
1042 		SDL_DEFAULT_REPEAT_INTERVAL);
1043 
1044 	/* what sort of game would you like? */
1045 	switch (gametype) {
1046 	    case SINGLE:
1047 		p1 = who_are_you(screen, &id, -1, 1);
1048 		clear_screen_to_flame();
1049 		if (p1 < 0) break;
1050 		id->p[p1].level = play_SINGLE(cs,ps,ss,g,&id->p[p1]);
1051 		clear_screen_to_flame();
1052 		break;
1053 	    case MARATHON:
1054 		p1 = who_are_you(screen, &id, -1, 1);
1055 		clear_screen_to_flame();
1056 		if (p1 < 0) break;
1057 		retval = play_MARATHON(cs,ps,ss,g,&id->p[p1]);
1058 		clear_screen_to_flame();
1059 		/* it's high score time */
1060 		SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY*10,
1061 			SDL_DEFAULT_REPEAT_INTERVAL);
1062 		high_score_check(retval, Score[0]);
1063 		clear_screen_to_flame();
1064 		break;
1065 	    case SINGLE_VS_AI:
1066 		p1 = who_are_you(screen, &id, -1, 1);
1067 		clear_screen_to_flame();
1068 		if (p1 < 0) break;
1069 		p2 = pick_an_ai(screen, "As Your Opponent", ai);
1070 		if (p2 < 0) break;
1071 		ai->player[p2].delay_factor = pick_ai_factor(screen);
1072 		clear_screen_to_flame();
1073 		id->p[p1].level = play_SINGLE_VS_AI(cs,ps,ss,g,
1074 			&id->p[p1], &ai->player[p2]);
1075 		clear_screen_to_flame();
1076 		break;
1077 	    case AI_VS_AI:
1078 		p1 = pick_an_ai(screen, "As Player 1", ai);
1079 		clear_screen_to_flame();
1080 		if (p1 < 0) break;
1081 		p2 = pick_an_ai(screen, "As Player 2", ai);
1082 		clear_screen_to_flame();
1083 		if (p2 < 0) break;
1084 		play_AI_VS_AI(cs,ps,ss,g,
1085 			&ai->player[p1], &ai->player[p2]);
1086 		clear_screen_to_flame();
1087 		break;
1088 	    case TWO_PLAYERS:
1089 		p1 = who_are_you(screen, &id, -1, 1);
1090 		clear_screen_to_flame();
1091 		if (p1 < 0) break;
1092 		p2 = who_are_you(screen, &id, p1, 2);
1093 		clear_screen_to_flame();
1094 		if (p2 < 0) break;
1095 		play_TWO_PLAYERS(cs,ps,ss,g, &id->p[p1], &id->p[p2]);
1096 		clear_screen_to_flame();
1097 		break;
1098 	    case NETWORK:
1099 		p1 = who_are_you(screen, &id, -1, 1);
1100 		clear_screen_to_flame();
1101 		if (p1 < 0) break;
1102 
1103 		id->p[p1].level =
1104 		    play_NETWORK(cs,ps,ss,g,&id->p[p1],network_choice(screen));
1105 		clear_screen_to_flame();
1106 		break;
1107 	    default:
1108 		break;
1109 	}
1110 
1111 	/*
1112 	 * save those updates!
1113 	 */
1114 	save_identity_file(id, NULL, 0);
1115     } /* end: while(choose_gametype() != -1) */
1116     SDL_CloseAudio();
1117     TTF_CloseFont(sfont);
1118     TTF_CloseFont( font);
1119     TTF_CloseFont(lfont);
1120     TTF_CloseFont(hfont);
1121     Network_Quit();
1122 
1123     Options.named_color = cs.choice;
1124     Options.named_piece = ps.choice;
1125     Options.named_sound = ss.choice;
1126 
1127 #ifdef HAVE_WINSOCK_H
1128     save_options("atris.rc");
1129 #else
1130     {
1131 	char filespec[2048];
1132 	SPRINTF(filespec,"%s/.atrisrc", getenv("HOME"));
1133 	save_options(filespec);
1134     }
1135 #endif
1136     return 0;
1137 }
1138 
1139 /*
1140  * $Log: atris.c,v $
1141  * Revision 1.100  2001/01/06 00:30:55  weimer
1142  * yada
1143  *
1144  * Revision 1.99  2001/01/06 00:25:23  weimer
1145  * changes so that we remember things ...
1146  *
1147  * Revision 1.98  2001/01/05 21:38:01  weimer
1148  * more key changes
1149  *
1150  * Revision 1.97  2001/01/05 21:36:28  weimer
1151  * little change ...
1152  *
1153  * Revision 1.96  2001/01/05 21:12:31  weimer
1154  * advance to atris 1.0.5, add support for ".atrisrc" and changing the
1155  * keyboard repeat rate
1156  *
1157  * Revision 1.95  2000/11/10 18:16:48  weimer
1158  * changes for Atris 1.0.4 - three new special options
1159  *
1160  * Revision 1.94  2000/11/06 04:41:47  weimer
1161  * fixed up Nirgal to Olympus
1162  *
1163  * Revision 1.93  2000/11/06 04:39:56  weimer
1164  * networking consistency check for power pieces
1165  *
1166  * Revision 1.92  2000/11/06 04:06:44  weimer
1167  * option menu
1168  *
1169  * Revision 1.91  2000/11/06 01:22:40  wkiri
1170  * Updated menu system.
1171  *
1172  * Revision 1.90  2000/11/03 03:41:35  weimer
1173  * made the light and dark "edges" of pieces global, rather than part of a
1174  * specific color style. also fixed a bug where we were updating too much
1175  * when drawing falling pieces (bad min() code on my part)
1176  *
1177  * Revision 1.89  2000/11/02 03:06:20  weimer
1178  * better interface for walk-radio menus: we are now ready for Kiri to change
1179  * them to add run-time options ...
1180  *
1181  * Revision 1.88  2000/11/01 03:53:06  weimer
1182  * modifications for version 1.0.1: you can pick your starting level, you can
1183  * pick the AI difficulty factor, the game is better about placing new pieces
1184  * when there is garbage, when things fall out of your control they now fall
1185  * at a uniform rate ...
1186  *
1187  * Revision 1.87  2000/10/30 16:25:25  weimer
1188  * display the network player score during network games. Also give the
1189  * non-server a little message when waiting for the server to go on.
1190  *
1191  * Revision 1.86  2000/10/30 03:49:09  weimer
1192  * minor changes ...
1193  *
1194  * Revision 1.85  2000/10/29 22:55:01  weimer
1195  * networking consistency checks (you must have the same number of doodads):
1196  * special hotkey 'f' in main menu toggles full screen mode
1197  * added depth specification on the command line
1198  * automatically search for the darkest non-black color ...
1199  *
1200  * Revision 1.84  2000/10/29 21:28:58  weimer
1201  * fixed a few failures to clear the screen if we didn't have a flaming
1202  * backdrop
1203  *
1204  * Revision 1.83  2000/10/29 21:23:28  weimer
1205  * One last round of header-file changes to reflect my newest and greatest
1206  * knowledge of autoconf/automake. Now if you fail to have some bizarro
1207  * function, we try to go on anyway unless it is vastly needed.
1208  *
1209  * Revision 1.82  2000/10/29 19:04:32  weimer
1210  * minor highscore handling changes: new filename, use the draw_string() and
1211  * draw_bordered_rect() and input_string() interfaces, handle the widget layer
1212  * and the flame layer, etc. Also fix a minor bug where you would be prevented
1213  * from settling if you pressed a key even if it didn't really move you. :-)
1214  *
1215  * Revision 1.81  2000/10/29 17:23:13  weimer
1216  * incorporate "xflame" flaming background for added spiffiness ...
1217  *
1218  * Revision 1.80  2000/10/29 00:17:39  weimer
1219  * added support for a system independent random number generator
1220  *
1221  * Revision 1.79  2000/10/29 00:06:27  weimer
1222  * networking fixes, change "styles/" to "styles" so that it works on Windows
1223  *
1224  * Revision 1.78  2000/10/28 23:39:24  weimer
1225  * added initialization support for Winsock 1.1 networking, ala SDL_net
1226  *
1227  * Revision 1.77  2000/10/28 16:40:17  weimer
1228  * Further changes: we can now build .tar.gz files and RPMs!
1229  *
1230  * Revision 1.76  2000/10/28 13:39:14  weimer
1231  * added a pausing feature ...
1232  *
1233  * Revision 1.75  2000/10/27 19:39:49  weimer
1234  * doubled the level for random AI deathmatches ...
1235  *
1236  * Revision 1.74  2000/10/21 01:14:42  weimer
1237  * massive autoconf/automake restructure ...
1238  *
1239  * Revision 1.73  2000/10/20 21:17:37  weimer
1240  * re-added the lemmings sound style ...
1241  *
1242  * Revision 1.72  2000/10/20 01:32:09  weimer
1243  * Minor play issue problems -- time is now truly a hard limit!
1244  *
1245  * Revision 1.71  2000/10/19 01:04:46  weimer
1246  * consistency error
1247  *
1248  * Revision 1.70  2000/10/19 00:20:27  weimer
1249  * sound directory changes, added a ticking clock ...
1250  *
1251  * Revision 1.69  2000/10/18 23:57:49  weimer
1252  * general fixup, color changes, display changes.
1253  * Notable: "Safe" Blits and Updates now perform "clipping". No more X errors,
1254  * we hope!
1255  *
1256  * Revision 1.68  2000/10/18 02:12:37  weimer
1257  * network fix
1258  *
1259  * Revision 1.67  2000/10/18 02:07:16  weimer
1260  * network play improvements
1261  *
1262  * Revision 1.66  2000/10/18 02:04:02  weimer
1263  * playability changes ...
1264  *
1265  * Revision 1.65  2000/10/14 16:17:41  weimer
1266  * level adjustment changes, added some new AIs, etc.
1267  *
1268  * Revision 1.64  2000/10/14 02:52:44  weimer
1269  * fixed a memory corruption problem in display (a use after a free)
1270  *
1271  * Revision 1.63  2000/10/14 01:42:53  weimer
1272  * better scoring of thumbs-up, thumbs-down
1273  *
1274  * Revision 1.62  2000/10/14 01:24:34  weimer
1275  * fixed error with not advancing levels when fighting AI
1276  *
1277  * Revision 1.61  2000/10/13 22:34:26  weimer
1278  * minor wessy AI changes
1279  *
1280  * Revision 1.60  2000/10/13 18:23:28  weimer
1281  * fixed a race condition in tetris_event()
1282  *
1283  * Revision 1.59  2000/10/13 16:37:39  weimer
1284  * Changed the AI so that it now passes state around via void pointers, rather
1285  * than using global variables. This allows the same AI to play itself. Also
1286  * changed the "AI vs. AI" display so that you can keep track of total wins
1287  * and losses.
1288  *
1289  * Revision 1.58  2000/10/13 15:41:53  weimer
1290  * revamped AI support, now you can pick your AI and have AI duels (such fun!)
1291  * the mighty Aliz AI still crashes a bit, though ... :-)
1292  *
1293  * Revision 1.57  2000/10/13 02:26:54  weimer
1294  * rudimentary identity functions, including adding new players
1295  *
1296  * Revision 1.56  2000/10/12 22:21:25  weimer
1297  * display changes, more multi-local-play threading (e.g., myScore ->
1298  * Score[0]), that sort of thing ...
1299  *
1300  * Revision 1.55  2000/10/12 19:17:08  weimer
1301  * Further support for AI players and multiple game types.
1302  *
1303  * Revision 1.54  2000/10/12 01:38:07  weimer
1304  * added initial support for persistent player identities
1305  *
1306  * Revision 1.53  2000/10/12 00:49:08  weimer
1307  * added "AI" support and walking radio menus for initial game configuration
1308  *
1309  * Revision 1.52  2000/09/09 19:14:34  weimer
1310  * forgot to draw the background in MULTI games ..
1311  *
1312  * Revision 1.51  2000/09/09 17:05:35  wkiri
1313  * Hideous log changes (Wes: how dare you include a comment character!)
1314  *
1315  * Revision 1.50  2000/09/09 16:58:27  weimer
1316  * Sweeping Change of Ultimate Mastery. Main loop restructuring to clean up
1317  * main(), isolate the behavior of the three game types. Move graphic files
1318  * into graphics/-, style files into styles/-, remove some unused files,
1319  * add game flow support (breaks between games, remembering your level within
1320  * this game), multiplayer support for the event loop, some global variable
1321  * cleanup. All that and a bag of chips!
1322  *
1323  * Revision 1.49  2000/09/05 20:22:12  weimer
1324  * native video mode selection, timing investigation
1325  *
1326  * Revision 1.48  2000/09/04 19:48:02  weimer
1327  * interim menu for choosing among game styles, button changes (two states)
1328  *
1329  * Revision 1.47  2000/09/03 21:17:38  wkiri
1330  * non-MULTI player games don't need to check for passing random seed around.
1331  *
1332  * Revision 1.46  2000/09/03 21:06:31  wkiri
1333  * Now handles three different game types (and does different things).
1334  * Major changes in display.c to handle this.
1335  */
1336