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