1 /*
2  * Tetris game
3  * Copyright (C) 2010 Julien Odent <julien at odent dot net>
4  *
5  * This game is an unofficial clone of the original
6  * Tetris game and is not endorsed by the
7  * registered trademark owners The Tetris Company, Inc.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <time.h>
26 
27 #include <SDL.h>
28 #include <SDL_image.h>
29 #include <SDL_gfxPrimitives.h>
30 
31 #define BLOCK_SIZE 20
32 #define FALL_STEP 1
33 #define LETTER_A 0
34 #define LETTER_B 1
35 #define LETTER_C 2
36 #define LETTER_D 3
37 #define LETTER_E 4
38 #define LETTER_F 5
39 #define LETTER_G 6
40 #define LETTER_H 7
41 #define LETTER_I 8
42 #define LETTER_J 9
43 #define LETTER_K 10
44 #define LETTER_L 11
45 #define LETTER_M 12
46 #define LETTER_N 13
47 #define LETTER_O 14
48 #define LETTER_P 15
49 #define LETTER_Q 16
50 #define LETTER_R 17
51 #define LETTER_S 18
52 #define LETTER_T 19
53 #define LETTER_U 20
54 #define LETTER_V 21
55 #define LETTER_W 22
56 #define LETTER_X 23
57 #define LETTER_Y 24
58 #define LETTER_Z 25
59 #define WALL_WIDTH 400
60 #define WALL_HEIGHT 600
61 #define PTR_NULL ((void *) 0)
62 #define SCREEN_WIDTH 600
63 #define SCREEN_HEIGHT 600
64 #define SPEED 7
65 
66 typedef struct Game {
67   int delay;
68   int level;
69   int lines;
70   int over;
71   int paused;
72   int running;
73   SDL_Surface *digits[10];
74   SDL_Surface *letters[26];
75   SDL_Surface *screen;
76   struct Shape *falling, *next;
77   struct SDL_Surface *grid[SCREEN_WIDTH][SCREEN_HEIGHT];
78 } Game;
79 
80 typedef struct Shape {
81   // each shape consists in four squares, located by the upper left corner
82   SDL_Rect pos[4];
83   SDL_Surface *img;
84   /*
85    * type 0 : g.jpg
86    * type 1 : i.jpg
87    * type 2 : l.jpg
88    * type 3 : o.jpg
89    * type 4 : s.jpg
90    * type 5 : t.jpg
91    * type 6 : z.jpg
92    */
93   int type;
94   int angle;
95 } Shape;
96 
97 void check_lines(int y);
98 void check_lost();
99 int clean_up(int err);
100 void draw_blocks();
101 void draw_digit(int d, int x, int y);
102 void draw_number(int n, int x, int y);
103 void draw_right();
104 SDL_Surface *get_image(char *str);
105 void empty_line(int y);
106 void erase_screen();
107 void falling_next();
108 int flip_checking(SDL_Rect pos[]);
109 void game_new();
110 void game_over();
111 void game_pause();
112 int min(int y1, int y2, int y3, int y4);
113 void move_left();
114 void move_right();
115 void shape_draw();
116 void shape_fall();
117 void shape_flip(int clockwise);
118 void shape_new();
119 
120 Game *game;
121 
main(int argc,char ** argv)122 int main(int argc, char **argv) {
123   SDL_Event event;
124   Uint8 *keystate;
125   game = malloc(sizeof(struct Game));
126   game_new();
127   if (SDL_Init(SDL_INIT_VIDEO != 0)) {
128     fprintf(stderr, "Could not initialize SDL: %s\n", SDL_GetError());
129     return 1;
130   }
131   if ((game->screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 8, SDL_SWSURFACE)) == NULL) {
132     fprintf(stderr, "Could not set SDL video mode: %s\n", SDL_GetError());
133     return clean_up(1);
134   }
135   SDL_WM_SetCaption("Tetris", "Tetris");
136   SDL_ShowCursor(SDL_DISABLE);
137   while (1) {
138     erase_screen();
139     if (game->paused == 1)
140       game_pause();
141     else if (game->over == 1)
142       game_over();
143     else {
144       shape_fall();
145       shape_draw();
146       draw_blocks();
147     }
148     draw_right();
149     SDL_UpdateRect(game->screen, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
150     check_lost();
151     while (SDL_PollEvent(&event))
152       if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE))
153         game->running = 0;
154       else if (game->over == 0 && event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_p)
155         game->paused ^= 1;
156     if (game->running == 0)
157       break;
158     keystate = SDL_GetKeyState(NULL);
159     if (game->paused == 0 && game->over == 0) {
160       if (keystate[SDLK_RIGHT]) {
161         move_right();
162         keystate[SDLK_RIGHT] = 0;
163       }
164       else if (keystate[SDLK_LEFT]) {
165         move_left();
166         keystate[SDLK_LEFT] = 0;
167       }
168       else if (keystate[SDLK_UP]) {
169         shape_flip(1); // clockwise
170         keystate[SDLK_UP] = 0;
171       }
172       else if (keystate[SDLK_DOWN]) {
173         shape_flip(0); // counter clockwise
174         keystate[SDLK_DOWN] = 0;
175       }
176     }
177     if (game->delay - game->level > -1)
178       SDL_Delay(game->delay - game->level);
179   }
180   free(game->falling);
181   free(game->next);
182   free(game);
183   return clean_up(0);
184 }
185 
check_lines(int y)186 void check_lines(int y) {
187   int x, full;
188   if (y == WALL_HEIGHT)
189     return;
190   full = 1;
191   x = 0;
192   while (x < WALL_WIDTH) {
193     if (game->grid[x][y] == PTR_NULL) {
194       full = 0;
195       break;
196     }
197     x += BLOCK_SIZE;
198   }
199   if (full == 1)
200     empty_line(y);
201   check_lines(y + BLOCK_SIZE);
202 }
203 
check_lost()204 void check_lost() {
205   int x = 0;
206   while (x < WALL_WIDTH) {
207     if (game->grid[x][0] != PTR_NULL)
208       game->over = 1;
209     x += BLOCK_SIZE;
210   }
211 }
212 
clean_up(int err)213 int clean_up(int err) {
214   SDL_Quit();
215   return err;
216 }
217 
draw_blocks()218 void draw_blocks() {
219   int x, y;
220   SDL_Rect pos = { 0, 0, 0, 0 };
221   x = 0;
222   while (x < WALL_WIDTH) {
223     y = 0;
224     while (y < WALL_HEIGHT) {
225       if (game->grid[x][y] != PTR_NULL) {
226         pos.x = x;
227 	pos.y = y;
228         SDL_BlitSurface(game->grid[x][y], NULL, game->screen, &pos);
229       }
230       y += FALL_STEP;
231     }
232     x += BLOCK_SIZE;
233   }
234 }
235 
draw_digit(int d,int x,int y)236 void draw_digit(int d, int x, int y) {
237   SDL_Rect dest = { x, y, 0, 0 };
238   SDL_BlitSurface(game->digits[d], NULL, game->screen, &dest);
239 }
240 
draw_number(int n,int x,int y)241 void draw_number(int n, int x, int y) {
242   while (n != 0) {
243     draw_digit(n % 10, x, y);
244     x -= 20;
245     n /= 10;
246   }
247 }
248 
draw_right()249 void draw_right() {
250   SDL_Rect pos = { WALL_WIDTH + 50, 100, 0, 0 };
251   SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
252   if (game->next->type == 0) {
253     pos.x += BLOCK_SIZE;
254     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
255     pos.x -= BLOCK_SIZE;
256     pos.y += BLOCK_SIZE;
257     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
258     pos.y += BLOCK_SIZE;
259     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
260   }
261   else if (game->next->type == 1) {
262     pos.y += BLOCK_SIZE;
263     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
264     pos.y += BLOCK_SIZE;
265     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
266     pos.y += BLOCK_SIZE;
267     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
268   }
269   else if (game->next->type == 2) {
270     pos.y += BLOCK_SIZE;
271     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
272     pos.y += BLOCK_SIZE;
273     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
274     pos.x += BLOCK_SIZE;
275     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
276   }
277   else if (game->next->type == 3) {
278     pos.x += BLOCK_SIZE;
279     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
280     pos.y += BLOCK_SIZE;
281     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
282     pos.x -= BLOCK_SIZE;
283     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
284   }
285   else if (game->next->type == 4) {
286     pos.x += BLOCK_SIZE;
287     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
288     pos.x -= BLOCK_SIZE;
289     pos.y += BLOCK_SIZE;
290     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
291     pos.x -= BLOCK_SIZE;
292     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
293   }
294   else if (game->next->type == 5) {
295     pos.x += BLOCK_SIZE;
296     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
297     pos.x += BLOCK_SIZE;
298     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
299     pos.x -= BLOCK_SIZE;
300     pos.y += BLOCK_SIZE;
301     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
302   }
303   else {
304     pos.x += BLOCK_SIZE;
305     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
306     pos.y += BLOCK_SIZE;
307     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
308     pos.x += BLOCK_SIZE;
309     SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
310   }
311   lineRGBA(game->screen, WALL_WIDTH, 0, WALL_WIDTH, SCREEN_HEIGHT, 0, 178, 0, 255);
312   SDL_BlitSurface(game->next->img, NULL, game->screen, &pos);
313   pos.x = WALL_WIDTH + 20;
314   pos.y = 250;
315   SDL_BlitSurface(game->letters[LETTER_L], NULL, game->screen, &pos);
316   pos.x += 15;
317   SDL_BlitSurface(game->letters[LETTER_I], NULL, game->screen, &pos);
318   pos.x += 15;
319   SDL_BlitSurface(game->letters[LETTER_N], NULL, game->screen, &pos);
320   pos.x += 15;
321   SDL_BlitSurface(game->letters[LETTER_E], NULL, game->screen, &pos);
322   pos.x += 15;
323   SDL_BlitSurface(game->letters[LETTER_S], NULL, game->screen, &pos);
324   (game->lines == 0) ? draw_digit(0, 530, 250) : draw_number(game->lines, 530, 250);
325   pos.x = WALL_WIDTH + 20;
326   pos.y = 300;
327   SDL_BlitSurface(game->letters[LETTER_L], NULL, game->screen, &pos);
328   pos.x += 15;
329   SDL_BlitSurface(game->letters[LETTER_E], NULL, game->screen, &pos);
330   pos.x += 15;
331   SDL_BlitSurface(game->letters[LETTER_V], NULL, game->screen, &pos);
332   pos.x += 15;
333   SDL_BlitSurface(game->letters[LETTER_E], NULL, game->screen, &pos);
334   pos.x += 15;
335   SDL_BlitSurface(game->letters[LETTER_L], NULL, game->screen, &pos);
336   draw_number(game->level, 530, 300);
337 }
338 
get_image(char * str)339 SDL_Surface *get_image(char *str) {
340   int size = strlen("images/") + strlen(str) + 1;
341   char *path = malloc(size * sizeof(char));
342   snprintf(path, size, "images/%s", str);
343   SDL_Surface *image = IMG_Load(path);
344   if (!image) {
345     printf("IMG_Load: %s\n", IMG_GetError());
346     clean_up(1);
347   }
348   free(path);
349   return image;
350 }
351 
empty_line(int y)352 void empty_line(int y) {
353   if (++game->lines % 10 == 0)
354     ++game->level;
355   int x, yy, z;
356   x = 0;
357   while (x < WALL_WIDTH) {
358     game->grid[x][y] = NULL;
359     x += BLOCK_SIZE;
360   }
361   yy = y - BLOCK_SIZE;
362   while (yy > 0) {
363     x = 0;
364     while (x < WALL_WIDTH) {
365       if (game->grid[x][yy] != PTR_NULL) {
366         z = yy + BLOCK_SIZE;
367         while (game->grid[x][z] == PTR_NULL && z < WALL_HEIGHT) {
368 	  game->grid[x][z] = game->grid[x][z - BLOCK_SIZE];
369 	  game->grid[x][z - BLOCK_SIZE] = NULL;
370 	  z += BLOCK_SIZE;
371 	}
372       }
373       x += BLOCK_SIZE;
374     }
375     yy -= BLOCK_SIZE;
376   }
377 }
378 
erase_screen()379 void erase_screen() {
380   SDL_Rect rect = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
381   SDL_FillRect(game->screen, &rect, SDL_MapRGB(game->screen->format, 0x00, 0x00, 0x00));
382 }
falling_next()383 void falling_next() {
384   game->falling->pos[0] = game->next->pos[0];
385   game->falling->pos[1] = game->next->pos[1];
386   game->falling->pos[2] = game->next->pos[2];
387   game->falling->pos[3] = game->next->pos[3];
388   game->falling->img = game->next->img;
389   game->falling->angle = game->next->angle;
390   game->falling->type = game->next->type;
391   shape_new();
392 }
flip_checking(SDL_Rect pos[])393 int flip_checking(SDL_Rect pos[]) {
394   int max_width, max_height, y, ok;
395   max_width = WALL_WIDTH - BLOCK_SIZE;
396   max_height = WALL_HEIGHT - BLOCK_SIZE;
397   y = 0;
398   ok = 1;
399   while (y < BLOCK_SIZE) {
400     if (game->grid[pos[0].x][pos[0].y + y] != PTR_NULL ||
401       game->grid[pos[1].x][pos[1].y + y] != PTR_NULL ||
402       game->grid[pos[2].x][pos[2].y + y] != PTR_NULL ||
403       game->grid[pos[3].x][pos[3].y + y] != PTR_NULL)
404       ok = 0;
405     y += FALL_STEP;
406   }
407   if (pos[0].x >= 0 && pos[0].x <= max_width && pos[0].y >= 0 && pos[0].y <= max_height &&
408     pos[1].x >= 0 && pos[1].x <= max_width && pos[1].y >= 0 && pos[1].y <= max_height &&
409     pos[2].x >= 0 && pos[2].x <= max_width && pos[2].y >= 0 && pos[2].y <= max_height &&
410     pos[3].x >= 0 && pos[3].x <= max_width && pos[3].y >= 0 && pos[3].y <= max_height &&
411     ok == 1)
412     return 1;
413   return 0;
414 }
415 
game_new()416 void game_new() {
417   int x, y;
418   char *str = malloc(6 * sizeof(char));
419   // initializing the full grid as empty squares
420   x = 0;
421   while (x < WALL_WIDTH) {
422     y = 0;
423     while (y < WALL_HEIGHT) {
424       game->grid[x][y] = NULL;
425       y += FALL_STEP;
426     }
427     x += BLOCK_SIZE;
428   }
429   x = 0;
430   while (x < 10) {
431     snprintf(str, 6, "%d.jpg", x);
432     game->digits[x++] = get_image(str);
433   }
434   free(str);
435   game->letters[LETTER_A] = get_image("A.jpg");
436   game->letters[LETTER_B] = get_image("B.jpg");
437   game->letters[LETTER_C] = get_image("C.jpg");
438   game->letters[LETTER_D] = get_image("D.jpg");
439   game->letters[LETTER_E] = get_image("E.jpg");
440   game->letters[LETTER_F] = get_image("F.jpg");
441   game->letters[LETTER_G] = get_image("G.jpg");
442   game->letters[LETTER_H] = get_image("H.jpg");
443   game->letters[LETTER_I] = get_image("I.jpg");
444   game->letters[LETTER_J] = get_image("J.jpg");
445   game->letters[LETTER_K] = get_image("K.jpg");
446   game->letters[LETTER_L] = get_image("L.jpg");
447   game->letters[LETTER_M] = get_image("M.jpg");
448   game->letters[LETTER_N] = get_image("N.jpg");
449   game->letters[LETTER_O] = get_image("O.jpg");
450   game->letters[LETTER_P] = get_image("P.jpg");
451   game->letters[LETTER_Q] = get_image("Q.jpg");
452   game->letters[LETTER_R] = get_image("R.jpg");
453   game->letters[LETTER_S] = get_image("S.jpg");
454   game->letters[LETTER_T] = get_image("T.jpg");
455   game->letters[LETTER_U] = get_image("U.jpg");
456   game->letters[LETTER_V] = get_image("V.jpg");
457   game->letters[LETTER_W] = get_image("W.jpg");
458   game->letters[LETTER_X] = get_image("X.jpg");
459   game->letters[LETTER_Y] = get_image("Y.jpg");
460   game->letters[LETTER_Z] = get_image("Z.jpg");
461   game->level = 1;
462   game->lines = 0;
463   game->over = 0;
464   game->paused = 0;
465   game->running = 1;
466   game->delay = SPEED;
467   game->next = malloc(sizeof(struct Shape));
468   shape_new();
469   game->falling = malloc(sizeof(struct Shape));
470   falling_next();
471 }
472 
game_over()473 void game_over() {
474   SDL_Rect pos = { (int) WALL_WIDTH / 2 - 75, (int) WALL_HEIGHT / 2, 0, 0 };
475   SDL_BlitSurface(game->letters[LETTER_G], NULL, game->screen, &pos);
476   pos.x += 15;
477   SDL_BlitSurface(game->letters[LETTER_A], NULL, game->screen, &pos);
478   pos.x += 15;
479   SDL_BlitSurface(game->letters[LETTER_M], NULL, game->screen, &pos);
480   pos.x += 15;
481   SDL_BlitSurface(game->letters[LETTER_E], NULL, game->screen, &pos);
482   pos.x += 30;
483   SDL_BlitSurface(game->letters[LETTER_O], NULL, game->screen, &pos);
484   pos.x += 15;
485   SDL_BlitSurface(game->letters[LETTER_V], NULL, game->screen, &pos);
486   pos.x += 15;
487   SDL_BlitSurface(game->letters[LETTER_E], NULL, game->screen, &pos);
488   pos.x += 15;
489   SDL_BlitSurface(game->letters[LETTER_R], NULL, game->screen, &pos);
490 }
491 
game_pause()492 void game_pause() {
493   SDL_Rect pos = { (int) WALL_WIDTH / 2 - 45, (int) WALL_HEIGHT / 2, 0, 0 };
494   SDL_BlitSurface(game->letters[LETTER_P], NULL, game->screen, &pos);
495   pos.x += 15;
496   SDL_BlitSurface(game->letters[LETTER_A], NULL, game->screen, &pos);
497   pos.x += 15;
498   SDL_BlitSurface(game->letters[LETTER_U], NULL, game->screen, &pos);
499   pos.x += 15;
500   SDL_BlitSurface(game->letters[LETTER_S], NULL, game->screen, &pos);
501   pos.x += 15;
502   SDL_BlitSurface(game->letters[LETTER_E], NULL, game->screen, &pos);
503   pos.x += 15;
504   SDL_BlitSurface(game->letters[LETTER_D], NULL, game->screen, &pos);
505 }
506 
min(int y1,int y2,int y3,int y4)507 int min(int y1, int y2, int y3, int y4) {
508    int min1, min2;
509    min1 = (y1 < y2) ? y1 : y2;
510    min2 = (y3 < y4) ? y3 : y4;
511    return (min1 < min2) ? min1 : min2;
512 }
move_left()513 void move_left() {
514   int ok, y;
515   y = 0;
516   ok = 1;
517   while (y < BLOCK_SIZE) {
518     if (game->grid[game->falling->pos[0].x - BLOCK_SIZE][game->falling->pos[0].y + y] != PTR_NULL ||
519       game->grid[game->falling->pos[1].x - BLOCK_SIZE][game->falling->pos[1].y + y] != PTR_NULL ||
520       game->grid[game->falling->pos[2].x - BLOCK_SIZE][game->falling->pos[2].y + y] != PTR_NULL ||
521       game->grid[game->falling->pos[3].x - BLOCK_SIZE][game->falling->pos[3].y + y] != PTR_NULL)
522       ok = 0;
523     y += FALL_STEP;
524   }
525   if (game->falling->pos[0].x >= BLOCK_SIZE && game->falling->pos[1].x >= BLOCK_SIZE && game->falling->pos[2].x >= BLOCK_SIZE && game->falling->pos[3].x >= BLOCK_SIZE && ok == 1) {
526     game->falling->pos[0].x -= BLOCK_SIZE;
527     game->falling->pos[1].x -= BLOCK_SIZE;
528     game->falling->pos[2].x -= BLOCK_SIZE;
529     game->falling->pos[3].x -= BLOCK_SIZE;
530   }
531 }
532 
move_right()533 void move_right() {
534   int ok, y, max;
535   max = WALL_WIDTH - BLOCK_SIZE;
536   y = 0;
537   ok = 1;
538   while (y < BLOCK_SIZE) {
539     if (game->grid[game->falling->pos[0].x + BLOCK_SIZE][game->falling->pos[0].y + y] != PTR_NULL ||
540       game->grid[game->falling->pos[1].x + BLOCK_SIZE][game->falling->pos[1].y + y] != PTR_NULL ||
541       game->grid[game->falling->pos[2].x + BLOCK_SIZE][game->falling->pos[2].y + y] != PTR_NULL ||
542       game->grid[game->falling->pos[3].x + BLOCK_SIZE][game->falling->pos[3].y + y] != PTR_NULL)
543       ok = 0;
544     y += FALL_STEP;
545   }
546   if (game->falling->pos[0].x < max && game->falling->pos[1].x < max && game->falling->pos[2].x < max && game->falling->pos[3].x < max && ok == 1) {
547     game->falling->pos[0].x += BLOCK_SIZE;
548     game->falling->pos[1].x += BLOCK_SIZE;
549     game->falling->pos[2].x += BLOCK_SIZE;
550     game->falling->pos[3].x += BLOCK_SIZE;
551   }
552 }
553 
shape_draw()554 void shape_draw() {
555   SDL_BlitSurface(game->falling->img, NULL, game->screen, &game->falling->pos[0]);
556   SDL_BlitSurface(game->falling->img, NULL, game->screen, &game->falling->pos[1]);
557   SDL_BlitSurface(game->falling->img, NULL, game->screen, &game->falling->pos[2]);
558   SDL_BlitSurface(game->falling->img, NULL, game->screen, &game->falling->pos[3]);
559 }
560 
shape_fall()561 void shape_fall() {
562   int max = WALL_HEIGHT - BLOCK_SIZE;
563   if (game->falling->pos[0].y < max && game->falling->pos[1].y < max && game->falling->pos[2].y < max && game->falling->pos[3].y < max &&
564     game->grid[game->falling->pos[0].x][game->falling->pos[0].y + BLOCK_SIZE] == PTR_NULL &&
565     game->grid[game->falling->pos[1].x][game->falling->pos[1].y + BLOCK_SIZE] == PTR_NULL &&
566     game->grid[game->falling->pos[2].x][game->falling->pos[2].y + BLOCK_SIZE] == PTR_NULL &&
567     game->grid[game->falling->pos[3].x][game->falling->pos[3].y + BLOCK_SIZE] == PTR_NULL) {
568     game->falling->pos[0].y += FALL_STEP;
569     game->falling->pos[1].y += FALL_STEP;
570     game->falling->pos[2].y += FALL_STEP;
571     game->falling->pos[3].y += FALL_STEP;
572   }
573   else { // stuck, let's fall a new shape
574     game->grid[game->falling->pos[0].x][game->falling->pos[0].y] = game->falling->img;
575     game->grid[game->falling->pos[1].x][game->falling->pos[1].y] = game->falling->img;
576     game->grid[game->falling->pos[2].x][game->falling->pos[2].y] = game->falling->img;
577     game->grid[game->falling->pos[3].x][game->falling->pos[3].y] = game->falling->img;
578     check_lines(min(game->falling->pos[0].y, game->falling->pos[1].y, game->falling->pos[2].y, game->falling->pos[3].y));
579     falling_next();
580   }
581 }
shape_new()582 void shape_new() {
583   SDL_Rect pos = { (int) (WALL_WIDTH / 2), 0, 0, 0 };
584   game->next->angle = 0;
585   srand(time(NULL));
586   game->next->type = (int) (7.0 * rand() / (RAND_MAX + 1.0));
587   game->next->pos[0] = pos;
588   if (game->next->type == 0) { // g.jpg
589     game->next->img = get_image("g.jpg");
590     pos.x += BLOCK_SIZE;
591     game->next->pos[1] = pos;
592     pos.x -= BLOCK_SIZE;
593     pos.y += BLOCK_SIZE;
594     game->next->pos[2] = pos;
595     pos.y += BLOCK_SIZE;
596     game->next->pos[3] = pos;
597   }
598   else if (game->next->type == 1) { // i.jpg
599     game->next->img = get_image("i.jpg");
600     pos.y += BLOCK_SIZE;
601     game->next->pos[1] = pos;
602     pos.y += BLOCK_SIZE;
603     game->next->pos[2] = pos;
604     pos.y += BLOCK_SIZE;
605     game->next->pos[3] = pos;
606   }
607   else if (game->next->type == 2) { // l.jpg
608     game->next->img = get_image("l.jpg");
609     pos.y += BLOCK_SIZE;
610     game->next->pos[1] = pos;
611     pos.y += BLOCK_SIZE;
612     game->next->pos[2] = pos;
613     pos.x += BLOCK_SIZE;
614     game->next->pos[3] = pos;
615   }
616   else if (game->next->type == 3) { // o.jpg
617     game->next->img = get_image("o.jpg");
618     pos.x += BLOCK_SIZE;
619     game->next->pos[1] = pos;
620     pos.y += BLOCK_SIZE;
621     game->next->pos[2] = pos;
622     pos.x -= BLOCK_SIZE;
623     game->next->pos[3] = pos;
624   }
625   else if (game->next->type == 4) { // s.jpg
626     game->next->img = get_image("s.jpg");
627     pos.x += BLOCK_SIZE;
628     game->next->pos[1] = pos;
629     pos.x -= BLOCK_SIZE;
630     pos.y += BLOCK_SIZE;
631     game->next->pos[2] = pos;
632     pos.x -= BLOCK_SIZE;
633     game->next->pos[3] = pos;
634   }
635   else if (game->next->type == 5) { // t.jpg
636     game->next->img = get_image("t.jpg");
637     pos.x += BLOCK_SIZE;
638     game->next->pos[1] = pos;
639     pos.x += BLOCK_SIZE;
640     game->next->pos[2] = pos;
641     pos.x -= BLOCK_SIZE;
642     pos.y += BLOCK_SIZE;
643     game->next->pos[3] = pos;
644   }
645   else { // z.jpg
646     game->next->img = get_image("z.jpg");
647     pos.x += BLOCK_SIZE;
648     game->next->pos[1] = pos;
649     pos.y += BLOCK_SIZE;
650     game->next->pos[2] = pos;
651     pos.x += BLOCK_SIZE;
652     game->next->pos[3] = pos;
653   }
654 }
655 
shape_flip(int clockwise)656 void shape_flip(int clockwise) {
657   SDL_Rect pos[4];
658   pos[0] = game->falling->pos[0];
659   pos[1] = game->falling->pos[1];
660   pos[2] = game->falling->pos[2];
661   pos[3] = game->falling->pos[3];
662   if (game->falling->type == 0) { // g.jpg
663     if (game->falling->angle == 0)
664       if (clockwise == 0) {
665         pos[0].x += BLOCK_SIZE;
666 	pos[0].y += 2 * BLOCK_SIZE;
667 	pos[1].x += BLOCK_SIZE;
668 	pos[1].y += 2 * BLOCK_SIZE;
669       }
670       else {
671         pos[2].x += 2 * BLOCK_SIZE;
672 	pos[2].y -= BLOCK_SIZE;
673 	pos[3].x += 2 * BLOCK_SIZE;
674 	pos[3].y -= BLOCK_SIZE;
675       }
676     else if (game->falling->angle == 1)
677       if (clockwise == 0) {
678         pos[2].x -= 2 * BLOCK_SIZE;
679 	pos[2].y += BLOCK_SIZE;
680 	pos[3].x -= 2 * BLOCK_SIZE;
681 	pos[3].y += BLOCK_SIZE;
682       }
683       else {
684         pos[0].x += BLOCK_SIZE;
685 	pos[0].y += 2 * BLOCK_SIZE;
686 	pos[1].x += BLOCK_SIZE;
687 	pos[1].y += 2 * BLOCK_SIZE;
688       }
689     else if (game->falling->angle == 2)
690       if (clockwise == 0) {
691         pos[0].x -= BLOCK_SIZE;
692 	pos[0].y -= 2 * BLOCK_SIZE;
693 	pos[1].x -= BLOCK_SIZE;
694 	pos[1].y -= 2 * BLOCK_SIZE;
695       }
696       else {
697         pos[2].x -= 2 * BLOCK_SIZE;
698 	pos[2].y += BLOCK_SIZE;
699 	pos[3].x -= 2 * BLOCK_SIZE;
700 	pos[3].y += BLOCK_SIZE;
701       }
702     else
703       if (clockwise == 0) {
704         pos[2].x += 2 * BLOCK_SIZE;
705 	pos[2].y -= BLOCK_SIZE;
706 	pos[3].x += 2 * BLOCK_SIZE;
707 	pos[3].y -= BLOCK_SIZE;
708       }
709       else {
710         pos[0].x -= BLOCK_SIZE;
711 	pos[0].y -= 2 * BLOCK_SIZE;
712 	pos[1].x -= BLOCK_SIZE;
713 	pos[1].y -= 2 * BLOCK_SIZE;
714       }
715   }
716   else if (game->falling->type == 1) // i.jpg
717     if (game->falling->angle == 0) {
718       pos[0].x -= BLOCK_SIZE;
719       pos[0].y += BLOCK_SIZE;
720       pos[2].x += BLOCK_SIZE;
721       pos[2].y -= BLOCK_SIZE;
722       pos[3].x += 2 * BLOCK_SIZE;
723       pos[3].y -= 2 * BLOCK_SIZE;
724     }
725     else {
726       pos[0].x += BLOCK_SIZE;
727       pos[0].y -= BLOCK_SIZE;
728       pos[2].x -= BLOCK_SIZE;
729       pos[2].y += BLOCK_SIZE;
730       pos[3].x -= 2 * BLOCK_SIZE;
731       pos[3].y += 2 * BLOCK_SIZE;
732     }
733   else if (game->falling->type == 2) { // l.jpg
734     if (game->falling->angle == 0)
735       if (clockwise == 0) {
736         pos[0].x += 2 * BLOCK_SIZE;
737 	pos[0].y += BLOCK_SIZE;
738 	pos[1].x += 2 * BLOCK_SIZE;
739 	pos[1].y += BLOCK_SIZE;
740       }
741       else {
742         pos[2].x += BLOCK_SIZE;
743 	pos[2].y -= 2 * BLOCK_SIZE;
744 	pos[3].x += BLOCK_SIZE;
745 	pos[3].y -= 2 * BLOCK_SIZE;
746       }
747     else if (game->falling->angle == 1)
748       if (clockwise == 0) {
749         pos[2].x -= BLOCK_SIZE;
750 	pos[2].y += 2 * BLOCK_SIZE;
751 	pos[3].x -= BLOCK_SIZE;
752 	pos[3].y += 2 * BLOCK_SIZE;
753       }
754       else {
755         pos[0].x += 2 * BLOCK_SIZE;
756 	pos[0].y += BLOCK_SIZE;
757 	pos[1].x += 2 * BLOCK_SIZE;
758 	pos[1].y += BLOCK_SIZE;
759       }
760     else if (game->falling->angle == 2)
761       if (clockwise == 0) {
762         pos[0].x -= 2 * BLOCK_SIZE;
763 	pos[0].y -= BLOCK_SIZE;
764 	pos[1].x -= 2 * BLOCK_SIZE;
765 	pos[1].y -= BLOCK_SIZE;
766       }
767       else {
768         pos[2].x -= BLOCK_SIZE;
769 	pos[2].y += 2 * BLOCK_SIZE;
770         pos[3].x -= BLOCK_SIZE;
771 	pos[3].y += 2 * BLOCK_SIZE;
772       }
773     else
774       if (clockwise == 0) {
775         pos[2].x += BLOCK_SIZE;
776 	pos[2].y -= 2 * BLOCK_SIZE;
777 	pos[3].x += BLOCK_SIZE;
778 	pos[3].y -= 2 * BLOCK_SIZE;
779       }
780       else {
781         pos[0].x -= 2 * BLOCK_SIZE;
782 	pos[0].y -= BLOCK_SIZE;
783 	pos[1].x -= 2 * BLOCK_SIZE;
784 	pos[1].y -= BLOCK_SIZE;
785       }
786   }
787   else if (game->falling->type == 3) // o.jpg -- nothing to do
788     ;
789   else if (game->falling->type == 4) // s.jpg
790     if (game->falling->angle == 0) {
791       pos[2].y -= 2 * BLOCK_SIZE;
792       pos[3].x += 2 * BLOCK_SIZE;
793     }
794     else {
795       pos[2].y += 2 * BLOCK_SIZE;
796       pos[3].x -= 2 * BLOCK_SIZE;
797     }
798   else if (game->falling->type == 5) { // t.jpg
799     if (game->falling->angle == 0)
800       if (clockwise == 0) {
801         pos[0].x += BLOCK_SIZE;
802 	pos[0].y -= BLOCK_SIZE;
803       }
804       else {
805         pos[2].x -= BLOCK_SIZE;
806 	pos[2].y -= BLOCK_SIZE;
807       }
808     else if (game->falling->angle == 1)
809       if (clockwise == 0) {
810         pos[2].x += BLOCK_SIZE;
811 	pos[2].y += BLOCK_SIZE;
812       }
813       else {
814         pos[3].x += BLOCK_SIZE;
815 	pos[3].y -= BLOCK_SIZE;
816       }
817     else if (game->falling->angle == 2)
818       if (clockwise == 0) {
819         pos[3].x -= BLOCK_SIZE;
820 	pos[3].y += BLOCK_SIZE;
821       }
822       else {
823         pos[0].x += BLOCK_SIZE;
824 	pos[0].y -= BLOCK_SIZE;
825 	pos[2].x += BLOCK_SIZE;
826 	pos[2].y += BLOCK_SIZE;
827 	pos[3].x -= BLOCK_SIZE;
828 	pos[3].y += BLOCK_SIZE;
829       }
830     else
831       if (clockwise == 0) {
832         pos[0].x -= BLOCK_SIZE;
833 	pos[0].y += BLOCK_SIZE;
834 	pos[2].x -= BLOCK_SIZE;
835 	pos[2].y -= BLOCK_SIZE;
836 	pos[3].x += BLOCK_SIZE;
837 	pos[3].y -= BLOCK_SIZE;
838       }
839       else {
840         pos[0].x -= BLOCK_SIZE;
841 	pos[0].y += BLOCK_SIZE;
842       }
843   }
844   else // z.jpg
845     if (game->falling->angle == 0) {
846       pos[2].x -= BLOCK_SIZE;
847       pos[3].x -= BLOCK_SIZE;
848       pos[3].y -= 2 * BLOCK_SIZE;
849     }
850     else {
851       pos[2].x += BLOCK_SIZE;
852       pos[3].x += BLOCK_SIZE;
853       pos[3].y += 2 * BLOCK_SIZE;
854     }
855   if (flip_checking(pos) == 1) {
856     if (game->falling->type == 1 || game->falling->type == 4 || game->falling->type == 6)
857       game->falling->angle ^= 1;
858     else
859       game->falling->angle += (clockwise == 0) ? -1 : 1;
860     if (game->falling->angle == -1)
861       game->falling->angle = 3;
862     if (game->falling->angle == 4)
863       game->falling->angle = 0;
864     game->falling->pos[0] = pos[0];
865     game->falling->pos[1] = pos[1];
866     game->falling->pos[2] = pos[2];
867     game->falling->pos[3] = pos[3];
868   }
869 }
870