1 /*
2  *                               Alizarin Tetris
3  *
4  * Copyright 2000, Kiri Wagstaff & Westley Weimer
5  */
6 
7 #include <config.h>	/* go autoconf! */
8 #include <unistd.h>
9 
10 #include "atris.h"
11 #include "display.h"
12 #include "grid.h"
13 #include "piece.h"
14 
15 #include "xflame.pro"
16 
17 struct layout_struct {
18     /* the whole board layout */
19     SDL_Rect grid_border[2];
20     SDL_Rect grid[2];
21 
22     SDL_Rect score[2];
23 
24     SDL_Rect name[2];
25 
26     struct adjust_struct {
27 	SDL_Rect symbol[3];
28     } adjust[2];
29 
30     SDL_Rect time;
31     SDL_Rect time_border;
32 
33     SDL_Rect next_piece_border[2];
34     SDL_Rect next_piece[2];
35 
36     SDL_Rect 	  pause;
37 } layout;
38 
39 /* The background image, global so we can do updates */
40 SDL_Surface *adjust_symbol[3] = { NULL, NULL, NULL };
41 /* Rectangles that specify where my/their pieces can legally be */
42 
43 int Score[2];
44 
45 /***************************************************************************
46  *      poll_and_flame()
47  * Poll for events and run the flaming background.
48  *********************************************************************PROTO*/
49 void
poll_and_flame(SDL_Event * ev)50 poll_and_flame(SDL_Event *ev)
51 {
52     while (!(SDL_PollEvent(ev))) {
53 	atris_run_flame();
54     }
55     return;
56 }
57 
58 /***************************************************************************
59  *      clear_screen_to_flame()
60  * Clears the screen so that only the flame layer is visible.
61  *********************************************************************PROTO*/
62 void
clear_screen_to_flame(void)63 clear_screen_to_flame(void)
64 {
65     SDL_Rect all;
66 
67     all.x = all.y = 0;
68     all.w = screen->w;
69     all.h = screen->h;
70 
71     SDL_FillRect(widget_layer, &all, int_black);
72     SDL_FillRect(screen, &all, int_black);
73     SDL_BlitSafe(flame_layer, NULL, screen, NULL);
74     SDL_UpdateSafe(screen, 1, &all);
75 }
76 
77 /***************************************************************************
78  *      setup_colors()
79  * Sets up our favorite colors.
80  *********************************************************************PROTO*/
81 void
setup_colors(SDL_Surface * screen)82 setup_colors(SDL_Surface *screen)
83 {
84     int i = 0;
85 
86     color_white.r = color_white.g = color_white.b = 0xFF;
87     color_white.unused = 0;
88 
89     color_black.r = color_black.g = color_black.b = color_black.unused = 0;
90 
91     color_red.r = 0xFF; color_red.g = color_red.b = color_red.unused = 0;
92 
93     color_blue.b = 0xFF; color_blue.r = color_blue.g = color_blue.unused = 0;
94 
95     color_purple.b = 128; color_purple.r = 128; color_purple.g = 64;
96 	color_purple.unused = 0;
97 
98     int_black = SDL_MapRGB(screen->format, 0, 0, 0);
99 
100     /* find the darkest black that is different from "all black" */
101     do {
102 	i++;
103 	int_solid_black = SDL_MapRGB(screen->format, i, i, i);
104     } while (int_black == int_solid_black && i < 255);
105     /* couldn't find one?! */
106     if (i == 255) {
107 	Debug("*** Warning: transparency is compromised by RGB format.\n");
108 	int_solid_black = SDL_MapRGB(screen->format, 1, 1, 1);
109     } else if (i != 1)
110 	Debug("*** Note: First non-black color found at magnitude %d.\n",i);
111 
112     int_white = SDL_MapRGB(screen->format, 255, 255, 255);
113     int_grey  = SDL_MapRGB(screen->format, 128, 128, 128);
114     int_blue  = SDL_MapRGB(screen->format, 0, 0, 255);
115     int_med_blue = SDL_MapRGB(screen->format, 0, 0, 0);
116     int_dark_blue  = SDL_MapRGB(screen->format, 0, 0, 128);
117     int_purple  = SDL_MapRGB(screen->format, 128, 64, 128);
118     int_dark_purple  = SDL_MapRGB(screen->format, 64, 32, 64);
119 }
120 
121 /***************************************************************************
122  *      draw_string()
123  * Draws the given string at the given location using the default font.
124  *********************************************************************PROTO*/
125 #define	DRAW_CENTER	(1<<0)
126 #define	DRAW_ABOVE	(1<<1)
127 #define DRAW_LEFT	(1<<2)
128 #define DRAW_UPDATE	(1<<3)
129 #define DRAW_CLEAR	(1<<4)
130 #define DRAW_HUGE	(1<<5)
131 #define DRAW_LARGE	(1<<6)
132 #define DRAW_GRID_0	(1<<7)
133 int
draw_string(char * text,SDL_Color sc,int x,int y,int flags)134 draw_string(char *text, SDL_Color sc, int x, int y, int flags)
135 {
136     SDL_Surface * text_surface;
137     SDL_Rect r;
138 
139     if (flags & DRAW_GRID_0) {
140 	r.x = layout.grid[0].x + layout.grid[0].w / 2;
141 	r.y = layout.grid[0].y + layout.grid[0].h / 2;
142     } else {
143 	r.x = x;
144 	r.y = y;
145     }
146 
147     if (flags & DRAW_HUGE) {
148 	text_surface = TTF_RenderText_Blended(hfont, text, sc); Assert(text_surface);
149     } else if (flags & DRAW_LARGE) {
150 	text_surface = TTF_RenderText_Blended(lfont, text, sc); Assert(text_surface);
151     } else {
152 	text_surface = TTF_RenderText_Blended(font, text, sc); Assert(text_surface);
153     }
154 
155     r.w = text_surface->w;
156     r.h = text_surface->h;
157 
158     if (flags & DRAW_CENTER)
159 	r.x -= (r.w / 2);
160     if (flags & DRAW_LEFT)
161 	r.x -= text_surface->w;
162     if (flags & DRAW_ABOVE)
163 	r.y -= (r.h);
164     if (flags & DRAW_CLEAR) {
165 	SDL_FillRect(widget_layer, &r, int_black);
166 	SDL_FillRect(screen, &r, int_black);
167     }
168 
169     SDL_BlitSafe(text_surface, NULL, widget_layer, &r);
170     SDL_BlitSafe(flame_layer, &r, screen, &r);
171     SDL_BlitSafe(widget_layer, &r, screen, &r);
172     if (flags & DRAW_UPDATE)
173 	SDL_UpdateSafe(screen, 1, &r);
174 
175     SDL_FreeSurface(text_surface);
176     return r.h;
177 }
178 
179 /***************************************************************************
180  *      give_notice()
181  * Draws a little "press any key to continue"-type notice between levels.
182  * "s" is any message you would like to display.
183  * Returns 1 if the user presses 'q', 0 if the users presses 'c'.
184  *********************************************************************PROTO*/
185 int
give_notice(char * s,int quit_possible)186 give_notice(char *s, int quit_possible)
187 {
188     SDL_Event event;
189 
190     while (SDL_PollEvent(&event)) {
191 	/* pull out all leading 'Q's */
192     }
193 
194     if (s && s[0]) 	/* throw that 'ol user text up there */
195 	draw_string(s, color_blue,
196 		layout.grid[0].x + (layout.grid[0].w / 2), layout.grid[0].y
197 		+ 64, DRAW_CENTER | DRAW_UPDATE);
198 
199     if (quit_possible)
200 	draw_string("Press 'Q' to Quit", color_red,
201 		layout.grid[0].x + (layout.grid[0].w / 2), layout.grid[0].y + 128,
202 		DRAW_CENTER | DRAW_UPDATE);
203 
204     draw_string("Press 'G' to Go On", color_red,
205 	    layout.grid[0].x + (layout.grid[0].w / 2), layout.grid[0].y +
206 	    128 + 30, DRAW_CENTER | DRAW_UPDATE);
207     while (1) {
208 	poll_and_flame(&event);
209 	if (event.type == SDL_KEYDOWN &&
210 		event.key.keysym.sym == 'q')
211 	    return 1;
212 	if (event.type == SDL_KEYDOWN &&
213 		event.key.keysym.sym == 'g')
214 	    return 0;
215     }
216 }
217 
218 /***************************************************************************
219  *      load_adjust_symbol()
220  * Loads the level adjustment images.
221  ***************************************************************************/
222 static void
load_adjust_symbols()223 load_adjust_symbols()
224 {
225     SDL_Surface *bitmap = SDL_LoadBMP("graphics/Level-Up.bmp");
226     if (!bitmap) PANIC("Could not load [graphics/Level-Up.bmp]");
227     if (bitmap->format->palette != NULL ) {
228 	SDL_SetColors(screen, bitmap->format->palette->colors, 0,
229 		bitmap->format->palette->ncolors);
230     }
231     adjust_symbol[0] = SDL_DisplayFormat(bitmap);
232     if (!adjust_symbol[0])
233 	PANIC("Can not convert [graphics/Level-Up.bmp] to hardware format");
234     SDL_SetColorKey(adjust_symbol[0], SDL_SRCCOLORKEY,
235 	    SDL_MapRGB(screen->format, 0, 0, 0));
236     SDL_FreeSurface(bitmap);
237 
238     bitmap = SDL_LoadBMP("graphics/Level-Medium.bmp");
239     if (!bitmap) PANIC("Could not load [graphics/Level-Medium.bmp]");
240     if (bitmap->format->palette != NULL ) {
241 	SDL_SetColors(screen, bitmap->format->palette->colors, 0,
242 		bitmap->format->palette->ncolors);
243     }
244     adjust_symbol[1] = SDL_DisplayFormat(bitmap);
245     if (!adjust_symbol[1])
246 	PANIC("Can not convert [graphics/Level-Medium.bmp] to hardware format");
247     SDL_SetColorKey(adjust_symbol[1], SDL_SRCCOLORKEY,
248 	    SDL_MapRGB(screen->format, 0, 0, 0));
249     SDL_FreeSurface(bitmap);
250 
251     bitmap = SDL_LoadBMP("graphics/Level-Down.bmp");
252     if (!bitmap) PANIC("Could not load [graphics/Level-Down.bmp]");
253     if (bitmap->format->palette != NULL ) {
254 	SDL_SetColors(screen, bitmap->format->palette->colors, 0,
255 		bitmap->format->palette->ncolors);
256     }
257     adjust_symbol[2] = SDL_DisplayFormat(bitmap);
258     if (!adjust_symbol[2])
259 	PANIC("Can not convert [graphics/Level-Down.bmp] to hardware format");
260     SDL_SetColorKey(adjust_symbol[2], SDL_SRCCOLORKEY,
261 	    SDL_MapRGB(screen->format, 0, 0, 0));
262     SDL_FreeSurface(bitmap);
263 
264     Assert(adjust_symbol[0]->h == adjust_symbol[1]->h);
265     Assert(adjust_symbol[1]->h == adjust_symbol[2]->h);
266 }
267 
268 /***************************************************************************
269  *      draw_bordered_rect()
270  * Draws a bordered rectangle. Sets "border" based on "orig".
271  *********************************************************************PROTO*/
272 void
draw_bordered_rect(SDL_Rect * orig,SDL_Rect * border,int thick)273 draw_bordered_rect(SDL_Rect *orig, SDL_Rect *border, int thick)
274 {
275     Assert(thick > 0 && thick < 8);
276 
277     border->x = orig->x - thick;
278     border->y = orig->y - thick;
279     border->w = orig->w + thick * 2;
280     border->h = orig->h + thick * 2;
281 
282     SDL_FillRect(widget_layer, border, int_border_color);
283     SDL_FillRect(widget_layer, orig, int_solid_black);
284 
285     /* unchanged: SDL_BlitSafe(flame_layer, NULL, screen, &r); */
286     SDL_BlitSafe(widget_layer, border, screen, border);
287     SDL_UpdateSafe(screen, 1, border);
288 
289     return;
290 }
291 
292 /***************************************************************************
293  *      draw_pre_bordered_rect()
294  * Draws a bordered rectangle.
295  *********************************************************************PROTO*/
296 void
draw_pre_bordered_rect(SDL_Rect * border,int thick)297 draw_pre_bordered_rect(SDL_Rect *border, int thick)
298 {
299     SDL_Rect orig;
300     Assert(thick > 0 && thick < 8);
301 
302     orig.x = border->x + thick;
303     orig.y = border->y + thick;
304     orig.w = border->w - thick * 2;
305     orig.h = border->h - thick * 2;
306 
307     SDL_FillRect(widget_layer, border, int_border_color);
308     SDL_FillRect(widget_layer, &orig, int_solid_black);
309 
310     /* unchanged: SDL_BlitSafe(flame_layer, NULL, screen, &r); */
311     SDL_BlitSafe(widget_layer, border, screen, border);
312     SDL_UpdateSafe(screen, 1, border);
313     return;
314 }
315 
316 /***************************************************************************
317  *      setup_layers()
318  * Set up the widget and flame layers.
319  *********************************************************************PROTO*/
320 void
setup_layers(SDL_Surface * screen)321 setup_layers(SDL_Surface * screen)
322 {
323     SDL_Rect all;
324     flame_layer = SDL_CreateRGBSurface
325 	(SDL_HWSURFACE|SDL_SRCCOLORKEY,
326 	 screen->w, screen->h, 8, 0, 0, 0, 0);
327     widget_layer = SDL_CreateRGBSurface
328 	(SDL_HWSURFACE|SDL_SRCCOLORKEY,
329 	 screen->w, screen->h, screen->format->BitsPerPixel,
330 	 screen->format->Rmask, screen->format->Gmask,
331 	 screen->format->Bmask, screen->format->Amask);
332     if (SDL_SetColorKey(widget_layer, SDL_SRCCOLORKEY,
333 		SDL_MapRGB(widget_layer->format, 0, 0, 0)))
334 	PANIC("SDL_SetColorKey failed on the widget layer.");
335 
336     if (int_black != SDL_MapRGB(widget_layer->format, 0, 0, 0)) {
337 	Debug("*** Warning: screen and widget layer have different RGB format.\n");
338     }
339     if (int_black != SDL_MapRGB(flame_layer->format, 0, 0, 0)) {
340 	Debug("*** Warning: screen and flame layer have different RGB format.\n");
341     }
342 
343     all.x = all.y = 0;
344     all.w = screen->w;
345     all.h = screen->h;
346 
347     SDL_FillRect(widget_layer, &all, int_black);
348     SDL_FillRect(flame_layer, &all, int_solid_black);
349 }
350 
351 /***************************************************************************
352  *      draw_background()
353  * Draws the Alizarin Tetris background. Not yet complete, but it's getting
354  * better. :-)
355  *********************************************************************PROTO*/
356 void
draw_background(SDL_Surface * screen,int blockWidth,Grid g[],int level[],int my_adj[],int their_adj[],char * name[])357 draw_background(SDL_Surface *screen, int blockWidth, Grid g[],
358 	int level[], int my_adj[], int their_adj[], char *name[])
359 {
360     char buf[1024];
361     int i;
362 #define IS_DOUBLE(x) ((x==NETWORK)||(x==SINGLE_VS_AI)||(x==TWO_PLAYERS)||(x==AI_VS_AI))
363 
364     if (IS_DOUBLE(gametype)) {
365 	Assert(g[0].w == g[1].w);
366 	Assert(g[0].h == g[1].h);
367     }
368 
369     /*
370      * clear away the old stuff
371      */
372     memset(&layout, 0, sizeof(layout));
373 
374     if (!adjust_symbol[0]) { /* only load these guys the first time */
375 	load_adjust_symbols();
376     }
377     /*
378      * 	THE BOARD
379      */
380     if (IS_DOUBLE(gametype)) {
381 	layout.grid[0].x = ((screen->w / 2) - ((g[0].w*blockWidth))) - 5 * blockWidth - 2;
382 	layout.grid[0].y = ((screen->h - (g[0].h*blockWidth)) / 2);
383 	layout.grid[0].w = (g[0].w*blockWidth);
384 	layout.grid[0].h = (g[0].h*blockWidth);
385 
386 	layout.grid[1].y = ((screen->h - (g[0].h*blockWidth)) / 2);
387 	layout.grid[1].w = (g[0].w*blockWidth);
388 	layout.grid[1].h = (g[0].h*blockWidth);
389 	layout.grid[1].x = ((screen->w / 2) - 4) + 5 * blockWidth + 6;
390 
391 	/* Draw the opponent's board */
392 	draw_bordered_rect(&layout.grid[1], &layout.grid_border[1], 2);
393 	g[1].board = layout.grid[1];
394     }  else {
395 	layout.grid[0].x = (screen->w - (g[0].w*blockWidth))/2 ;
396 	layout.grid[0].y = (screen->h - (g[0].h*blockWidth))/2 ;
397 	layout.grid[0].w = (g[0].w*blockWidth) ;
398 	layout.grid[0].h = (g[0].h*blockWidth) ;
399 	/* Don't need a Board[1] */
400     }
401     /* draw the leftmost board */
402     draw_bordered_rect(&layout.grid[0], &layout.grid_border[0], 2);
403     g[0].board = layout.grid[0];
404 
405     /*
406      * 	SCORING, Names
407      */
408     for (i=0; i< 1+IS_DOUBLE(gametype); i++) {
409 	layout.name[i].x = layout.grid[i].x;
410 	layout.name[i].y = layout.grid[i].y + layout.grid[i].h + 2;
411 	layout.name[i].w = layout.grid[i].w;
412 	layout.name[i].h = screen->h - layout.name[i].y;
413 
414 	if (gametype == DEMO) {
415 	    char buf[1024];
416 	    SDL_FillRect(widget_layer, &layout.name[i], int_black);
417 	    SDL_FillRect(screen, &layout.name[i], int_black);
418 	    SPRINTF(buf,"Demo (%s)",name[i]);
419 	    draw_string(buf, color_blue, layout.grid_border[i].x +
420 		    layout.grid_border[i].w/2, layout.grid_border[i].y +
421 		    layout.grid_border[i].h, DRAW_CENTER | DRAW_CLEAR | DRAW_UPDATE);
422 	} else {
423 	    draw_string(name[i], color_blue,
424 		    layout.grid_border[i].x + layout.grid_border[i].w/2,
425 		    layout.grid_border[i].y + layout.grid_border[i].h,
426 		    DRAW_CENTER);
427 	}
428 	/* Set up the coordinates for future score writing */
429 	layout.score[i].x = layout.grid_border[i].x;
430 	layout.score[i].w = layout.grid_border[i].w;
431 	layout.score[i].y = 0;
432 	layout.score[i].h = layout.grid_border[i].y;
433 	SDL_FillRect(widget_layer, &layout.score[i], int_black);
434 	SDL_FillRect(screen, &layout.score[i], int_black);
435 
436 	SPRINTF(buf,"Level %d, Score:",level[i]);
437 	draw_string(buf, color_blue, layout.grid_border[i].x,
438 		layout.grid_border[i].y, DRAW_ABOVE | DRAW_CLEAR);
439 
440 	layout.score[i].x = layout.grid_border[i].x + layout.grid_border[i].w;
441 	layout.score[i].y = layout.grid_border[i].y;
442     }
443 
444     /*
445      * 	TIME LEFT
446      */
447 
448 #define TIME_WIDTH 	(16*5)
449 #define TIME_HEIGHT 	28
450 
451     if (gametype == DEMO) {
452 	/* do nothing */
453     } else if (IS_DOUBLE(gametype)) {
454 	draw_string("Time Left", color_blue,
455 		screen->w/2, layout.score[0].y, DRAW_CENTER | DRAW_ABOVE);
456 	layout.time.x = (screen->w - TIME_WIDTH)/2;
457 	layout.time.y = layout.score[0].y;
458 	layout.time.w = TIME_WIDTH;
459 	layout.time.h = TIME_HEIGHT;
460 	draw_bordered_rect(&layout.time, &layout.time_border, 2);
461     } else { /* single */
462 	int text_h = draw_string("Time Left", color_blue,
463 		screen->w/10, screen->h/5, 0);
464 	layout.time.x = screen->w / 10;
465 	layout.time.y = screen->h / 5 + text_h;
466 	layout.time.w = TIME_WIDTH;
467 	layout.time.h = TIME_HEIGHT;
468 
469 	draw_bordered_rect(&layout.time, &layout.time_border, 2);
470     }
471 
472     /*
473      *	LEVEL ADJUSTMENT
474      */
475     if (gametype == DEMO) {
476 
477     } else if (gametype == AI_VS_AI) {
478 	for (i=0;i<3;i++) {
479 	    char buf[80];
480 
481 	    layout.adjust[0].symbol[i].x = (screen->w - adjust_symbol[i]->w)/2;
482 	    layout.adjust[0].symbol[i].w = adjust_symbol[i]->w;
483 	    layout.adjust[0].symbol[i].h = adjust_symbol[i]->h;
484 	    layout.adjust[0].symbol[i].y =
485 		layout.time_border.y+layout.time_border.h + i * adjust_symbol[i]->h;
486 
487 	    SDL_BlitSafe(adjust_symbol[i], NULL, widget_layer,
488 		    &layout.adjust[0].symbol[i]);
489 
490 	    /* draw the textual tallies */
491 	    SPRINTF(buf,"%d",my_adj[i]);
492 	    draw_string(buf, color_red,
493 		    layout.adjust[0].symbol[i].x - 10,
494 		    layout.adjust[0].symbol[i].y, DRAW_LEFT | DRAW_CLEAR);
495 	    SPRINTF(buf,"%d",their_adj[i]);
496 	    draw_string(buf, color_red,
497 		    layout.adjust[0].symbol[i].x + layout.adjust[0].symbol[i].w + 10,
498 		    layout.adjust[0].symbol[i].y, DRAW_CLEAR);
499 	}
500     } else if (IS_DOUBLE(gametype)) {
501 	for (i=0;i<3;i++) {
502 	    layout.adjust[0].symbol[i].w = adjust_symbol[i]->w;
503 	    layout.adjust[0].symbol[i].h = adjust_symbol[i]->h;
504 	    layout.adjust[0].symbol[i].x = (screen->w - 3*adjust_symbol[i]->w)/2;
505 	    layout.adjust[0].symbol[i].y =
506 		layout.time_border.y+layout.time_border.h + i * adjust_symbol[i]->h;
507 	    SDL_FillRect(widget_layer, &layout.adjust[0].symbol[i], int_black);
508 	    SDL_FillRect(screen, &layout.adjust[0].symbol[i], int_black);
509 	    if (my_adj[i] != -1)
510 		SDL_BlitSafe(adjust_symbol[my_adj[i]], NULL, widget_layer,
511 			&layout.adjust[0].symbol[i]);
512 	    layout.adjust[1].symbol[i].w = adjust_symbol[i]->w;
513 	    layout.adjust[1].symbol[i].h = adjust_symbol[i]->h;
514 	    layout.adjust[1].symbol[i].x = (screen->w)/2 + adjust_symbol[i]->w/2;
515 	    layout.adjust[1].symbol[i].y =
516 		layout.time_border.y+layout.time_border.h + i * adjust_symbol[i]->h;
517 	    SDL_FillRect(widget_layer, &layout.adjust[1].symbol[i], int_black);
518 	    SDL_FillRect(screen, &layout.adjust[1].symbol[i], int_black);
519 	    if (their_adj[i] != -1)
520 		SDL_BlitSafe(adjust_symbol[their_adj[i]], NULL, widget_layer,
521 			&layout.adjust[1].symbol[i]);
522 	}
523     } else { /* single player */
524 	for (i=0;i<3;i++) {
525 	    layout.adjust[0].symbol[i].w = adjust_symbol[i]->w;
526 	    layout.adjust[0].symbol[i].h = adjust_symbol[i]->h;
527 	    layout.adjust[0].symbol[i].x =
528 		layout.grid_border[0].x + layout.grid_border[0].w +
529 		2 * adjust_symbol[i]->w;
530 	    layout.adjust[0].symbol[i].y =
531 		layout.time_border.y +layout.time_border.h+ i * adjust_symbol[i]->h;
532 	    SDL_FillRect(widget_layer, &layout.adjust[0].symbol[i], int_black);
533 	    SDL_FillRect(screen, &layout.adjust[0].symbol[i], int_black);
534 	    if (my_adj[i] != -1)
535 		SDL_BlitSafe(adjust_symbol[my_adj[i]], NULL, widget_layer,
536 			&layout.adjust[0].symbol[i]);
537 	}
538     }
539 
540     /*
541      * NEXT PIECE
542      */
543     if (gametype == DEMO) {
544 	/* do nothing */
545     } else if (IS_DOUBLE(gametype)) {
546 	int text_h = draw_string("Next Piece", color_blue,
547 		screen->w / 2,
548 		layout.adjust[0].symbol[2].y +
549 		layout.adjust[0].symbol[2].h, DRAW_CENTER);
550 
551 	layout.next_piece[0].w = 5 * blockWidth;
552 	layout.next_piece[0].h = 5 * blockWidth;
553 	layout.next_piece[0].x = (screen->w / 2) - (5 * blockWidth);
554 	layout.next_piece[0].y = layout.adjust[0].symbol[2].y +
555 	    layout.adjust[0].symbol[2].h + text_h;
556 	draw_bordered_rect(&layout.next_piece[0], &layout.next_piece_border[0], 2);
557 
558 	layout.next_piece[1].w = layout.next_piece[0].w;
559 	layout.next_piece[1].h = layout.next_piece[0].h;
560 	layout.next_piece[1].y = layout.next_piece[0].y;
561 	layout.next_piece[1].x = (screen->w / 2);
562 	draw_bordered_rect(&layout.next_piece[1], &layout.next_piece_border[1], 2);
563     } else {
564 	int text_h = draw_string("Next Piece", color_blue,
565 		screen->w/10, 2*screen->h/5, 0);
566 
567 	layout.next_piece[0].w = 5 * blockWidth;
568 	layout.next_piece[0].h = 5 * blockWidth;
569 	layout.next_piece[0].x = screen->w/10;
570 	layout.next_piece[0].y = (2*screen->h/5) + text_h;
571 
572 	/* Draw the box for the next piece to fit in */
573 	draw_bordered_rect(&layout.next_piece[0], &layout.next_piece_border[0], 2);
574     }
575 
576     /*
577      *	PAUSE BOX
578      */
579     if (gametype == DEMO) {
580 
581     } else if (IS_DOUBLE(gametype)) {
582 	layout.pause.x = layout.next_piece_border[0].x;
583 	layout.pause.y = layout.next_piece_border[0].h + layout.next_piece_border[0].y + 2 +
584 	    layout.next_piece_border[0].h / 3;
585 	layout.pause.w = layout.next_piece_border[0].w + layout.next_piece[1].w;
586 	layout.pause.h = layout.next_piece_border[0].h / 3;
587     } else {
588 	layout.pause.x = layout.next_piece_border[0].x;
589 	layout.pause.y = layout.next_piece_border[0].h + layout.next_piece_border[0].y + 2 +
590 	    layout.next_piece_border[0].h / 3;
591 	layout.pause.w = layout.next_piece_border[0].w;
592 	layout.pause.h = layout.next_piece_border[0].h / 3;
593     }
594 
595     /* Blit onto the screen surface */
596     {
597 	SDL_Rect dest;
598 	dest.x = 0; dest.y = 0; dest.w = screen->w; dest.h = screen->h;
599 
600 	SDL_BlitSafe(flame_layer, NULL, screen, NULL);
601 	SDL_BlitSafe(widget_layer, NULL, screen, NULL);
602 	SDL_UpdateSafe(screen, 1, &dest);
603     }
604     return;
605 }
606 
607 /***************************************************************************
608  *      draw_pause()
609  * Draw or clear the pause indicator.
610  *********************************************************************PROTO*/
611 void
draw_pause(int on)612 draw_pause(int on)
613 {
614     int i;
615     if (on) {
616 	draw_pre_bordered_rect(&layout.pause, 2);
617 	draw_string("* Paused *", color_blue,
618 		layout.pause.x + layout.pause.w / 2, layout.pause.y,
619 		DRAW_CENTER | DRAW_UPDATE);
620 	for (i=0; i<2; i++) {
621 	    /* save this stuff so that the flame doesn't go over it .. */
622 	    if (layout.grid[i].w) {
623 		SDL_BlitSafe(screen, &layout.grid[i], widget_layer,
624 			&layout.grid[i]);
625 		SDL_BlitSafe(screen, &layout.next_piece[i], widget_layer,
626 			&layout.next_piece[i]);
627 	    }
628 	}
629     } else {
630 	SDL_FillRect(widget_layer, &layout.pause, int_black);
631 	SDL_FillRect(screen, &layout.pause, int_black);
632 	SDL_BlitSafe(flame_layer, &layout.pause, screen, &layout.pause);
633 	/* no need to paste over it with the widget layer: we know it to
634 	 * be all transparent */
635 	SDL_UpdateSafe(screen, 1, &layout.pause);
636 
637 	for (i=0; i<2; i++)
638 	    if (layout.grid[i].w) {
639 		SDL_BlitSafe(widget_layer, &layout.grid[i], screen,
640 			&layout.grid[i]);
641 		SDL_FillRect(widget_layer, &layout.grid[i], int_solid_black);
642 
643 		SDL_BlitSafe(widget_layer, &layout.next_piece[i], screen,
644 			&layout.next_piece[i]);
645 		SDL_FillRect(widget_layer, &layout.next_piece[i], int_solid_black);
646 	    }
647     }
648 }
649 
650 /***************************************************************************
651  *      draw_clock()
652  * Draws a five-digit (-x:yy) clock in the center of the screen.
653  *********************************************************************PROTO*/
654 void
draw_clock(int seconds)655 draw_clock(int seconds)
656 {
657     static int old_seconds = -111;	/* last time we drew */
658     static SDL_Surface * digit[12];
659     char buf[16];
660     static int w = -1, h= -1; /* max digit width/height */
661     int i, c;
662 
663     if (seconds == old_seconds || gametype == DEMO) return;
664 
665     if (old_seconds == -111) {
666 	/* setup code */
667 
668 	for (i=0;i<10;i++) {
669 	    SPRINTF(buf,"%d",i);
670 	    digit[i] = TTF_RenderText_Blended(font,buf,color_blue);
671 	}
672 	SPRINTF(buf,":"); digit[10] = TTF_RenderText_Blended(font,buf,color_red);
673 	SPRINTF(buf,"-"); digit[11] = TTF_RenderText_Blended(font,buf,color_red);
674 
675 	for (i=0;i<12;i++) {
676 	    Assert(digit[i]);
677 	    /* the colorkey and display format are already done */
678 	    /* find the largest dimensions */
679 	    if (digit[i]->w > w) w = digit[i]->w;
680 	    if (digit[i]->h > h) h = digit[i]->h;
681 	}
682     }
683 
684     old_seconds = seconds;
685 
686     SPRINTF(buf,"%d:%02d",seconds / 60, seconds % 60);
687 
688     c = layout.time.x;
689     layout.time.w = w * 5;
690     layout.time.h = h;
691 
692     SDL_FillRect(widget_layer, &layout.time, int_solid_black);
693 
694     if (strlen(buf) > 5)
695 	SPRINTF(buf,"----");
696 
697     if (strlen(buf) < 5)
698 	layout.time.x += ((5 - strlen(buf)) * w) / 2;
699 
700 
701     for (i=0;buf[i];i++) {
702 	SDL_Surface * to_blit;
703 
704 	if (buf[i] >= '0' && buf[i] <= '9')
705 	    to_blit = digit[buf[i] - '0'];
706 	else if (buf[i] == ':')
707 	    to_blit = digit[10];
708 	else if (buf[i] == '-')
709 	    to_blit = digit[11];
710 	else PANIC("unknown character in clock string [%s]",buf);
711 
712 	/* center the letter horizontally */
713 	if (w > to_blit->w) layout.time.x += (w - to_blit->w) / 2;
714 	layout.time.w = to_blit->w;
715 	layout.time.h = to_blit->h;
716 	/*
717 	Debug("[%d+%d, %d+%d]\n",
718 		clockPos.x,clockPos.w,clockPos.y,clockPos.h);
719 		*/
720 	SDL_BlitSafe(to_blit, NULL, widget_layer, &layout.time);
721 	if (w > to_blit->w) layout.time.x -= (w - to_blit->w) / 2;
722 	layout.time.x += w;
723     }
724 
725     layout.time.x = c;
726     /*    clockPos.x = (screen->w - (w * 5)) / 2;*/
727     layout.time.w = w * 5;
728     layout.time.h = h;
729     SDL_BlitSafe(flame_layer, &layout.time, screen, &layout.time);
730     SDL_BlitSafe(widget_layer, &layout.time, screen, &layout.time);
731     SDL_UpdateSafe(screen, 1, &layout.time);
732 
733     return;
734 }
735 
736 /***************************************************************************
737  *      draw_score()
738  *********************************************************************PROTO*/
739 void
draw_score(SDL_Surface * screen,int i)740 draw_score(SDL_Surface *screen, int i)
741 {
742     char buf[256];
743 
744     SPRINTF(buf, "%d", Score[i]);
745     draw_string(buf, color_red,
746 	    layout.score[i].x, layout.score[i].y, DRAW_LEFT | DRAW_CLEAR |
747 	    DRAW_ABOVE | DRAW_UPDATE);
748 }
749 
750 /***************************************************************************
751  *      draw_next_piece()
752  * Draws the next piece on the screen.
753  *
754  * Needs the color style because draw_play_piece() needs it to paste the
755  * bitmaps.
756  *********************************************************************PROTO*/
757 void
draw_next_piece(SDL_Surface * screen,piece_style * ps,color_style * cs,play_piece * cp,play_piece * np,int P)758 draw_next_piece(SDL_Surface *screen, piece_style *ps, color_style *cs,
759 	play_piece *cp, play_piece *np, int P)
760 {
761     if (gametype != DEMO) {
762 	/* fake-o centering */
763 	int cp_right = 5 - cp->base->dim;
764 	int cp_down = 5 - cp->base->dim;
765 	int np_right = 5 - np->base->dim;
766 	int np_down = 5 - np->base->dim;
767 
768 	draw_play_piece(screen, cs,
769 		cp,
770 		layout.next_piece[P].x + cp_right * cs->w / 2,
771 		layout.next_piece[P].y + cp_down * cs->w / 2, 0,
772 		np,
773 		layout.next_piece[P].x + np_right * cs->w / 2,
774 		layout.next_piece[P].y + np_down * cs->w / 2, 0);
775     }
776     return;
777 }
778 
779 /*
780  * $Log: display.c,v $
781  * Revision 1.25  2000/11/01 04:39:41  weimer
782  * clear the little scoring spot correctly, updates for making a no-sound
783  * distribution
784  *
785  * Revision 1.24  2000/11/01 03:53:06  weimer
786  * modifications for version 1.0.1: you can pick your starting level, you can
787  * pick the AI difficulty factor, the game is better about placing new pieces
788  * when there is garbage, when things fall out of your control they now fall
789  * at a uniform rate ...
790  *
791  * Revision 1.23  2000/10/30 16:25:25  weimer
792  * display the network player score during network games. Also give the
793  * non-server a little message when waiting for the server to go on.
794  *
795  * Revision 1.22  2000/10/29 22:55:01  weimer
796  * networking consistency checks (you must have the same number of doodads):
797  * special hotkey 'f' in main menu toggles full screen mode
798  * added depth specification on the command line
799  * automatically search for the darkest non-black color ...
800  *
801  * Revision 1.21  2000/10/29 21:28:58  weimer
802  * fixed a few failures to clear the screen if we didn't have a flaming
803  * backdrop
804  *
805  * Revision 1.20  2000/10/29 21:23:28  weimer
806  * One last round of header-file changes to reflect my newest and greatest
807  * knowledge of autoconf/automake. Now if you fail to have some bizarro
808  * function, we try to go on anyway unless it is vastly needed.
809  *
810  * Revision 1.19  2000/10/29 19:04:32  weimer
811  * minor highscore handling changes: new filename, use the draw_string() and
812  * draw_bordered_rect() and input_string() interfaces, handle the widget layer
813  * and the flame layer, etc. Also fix a minor bug where you would be prevented
814  * from settling if you pressed a key even if it didn't really move you. :-)
815  *
816  * Revision 1.18  2000/10/29 17:23:13  weimer
817  * incorporate "xflame" flaming background for added spiffiness ...
818  *
819  * Revision 1.17  2000/10/28 13:39:14  weimer
820  * added a pausing feature ...
821  *
822  * Revision 1.16  2000/10/21 01:14:42  weimer
823  * massic autoconf/automake restructure ...
824  *
825  * Revision 1.15  2000/10/18 23:57:49  weimer
826  * general fixup, color changes, display changes.
827  * Notable: "Safe" Blits and Updates now perform "clipping". No more X errors,
828  * we hope!
829  *
830  * Revision 1.14  2000/10/18 02:04:02  weimer
831  * playability changes ...
832  *
833  * Revision 1.13  2000/10/14 02:52:44  weimer
834  * fixed a memory corruption problem in display (a use after a free)
835  *
836  * Revision 1.12  2000/10/13 16:37:39  weimer
837  * Changed the AI so that it now passes state around via void pointers, rather
838  * than using global variables. This allows the same AI to play itself. Also
839  * changed the "AI vs. AI" display so that you can keep track of total wins
840  * and losses.
841  *
842  * Revision 1.11  2000/10/13 15:41:53  weimer
843  * revamped AI support, now you can pick your AI and have AI duels (such fun!)
844  * the mighty Aliz AI still crashes a bit, though ... :-)
845  *
846  * Revision 1.10  2000/10/12 22:21:25  weimer
847  * display changes, more multi-local-play threading (e.g., myScore ->
848  * Score[0]), that sort of thing ...
849  *
850  * Revision 1.9  2000/10/12 19:17:08  weimer
851  * Further support for AI players and multiple game types.
852  *
853  * Revision 1.8  2000/10/12 00:49:08  weimer
854  * added "AI" support and walking radio menus for initial game configuration
855  *
856  * Revision 1.7  2000/09/09 17:05:35  wkiri
857  * Hideous log changes (Wes: how dare you include a comment character!)
858  *
859  * Revision 1.6  2000/09/09 16:58:27  weimer
860  * Sweeping Change of Ultimate Mastery. Main loop restructuring to clean up
861  * main(), isolate the behavior of the three game types. Move graphic files
862  * into graphics/-, style files into styles/-, remove some unused files,
863  * add game flow support (breaks between games, remembering your level within
864  * this game), multiplayer support for the event loop, some global variable
865  * cleanup. All that and a bag of chips!
866  *
867  * Revision 1.5  2000/09/05 20:22:12  weimer
868  * native video mode selection, timing investigation
869  *
870  * Revision 1.4  2000/09/03 21:06:31  wkiri
871  * Now handles three different game types (and does different things).
872  * Major changes in display.c to handle this.
873  *
874  * Revision 1.3  2000/09/03 18:40:23  wkiri
875  * Cleaned up atris.c some more (high_score_check()).
876  * Added variable for game type (defaults to MARATHON).
877  *
878  */
879 
880