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