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