This source file includes following definitions.
- mkdir_if_not_exist
- platformInit
- platformEnd
- platformReadInput
- platformRenderGame
- platformGetSystemTime
- setMatrixCells
- setTetramino
- startGame
- createGame
- gameInit
- gameEnd
- deleteGame
- rotateTetramino
- checkCollision
- onFilledRows
- moveTetramino
- dropTetramino
- gameUpdate
- gui_tetris_init
- basic_module_init
- gui_tetris_draw
- gui_tetris_kbd_process
1 #include "camera_info.h"
2 #include "keyboard.h"
3 #include "clock.h"
4 #include "backlight.h"
5 #include "lang.h"
6 #include "gui.h"
7 #include "gui_draw.h"
8 #include "gui_lang.h"
9 #include "gui_batt.h"
10 #include "gui_mbox.h"
11 #include "modes.h"
12 #include "time.h"
13
14 #include "module_def.h"
15
16 void gui_game_menu_kbd_process();
17 int gui_tetris_kbd_process();
18 void gui_tetris_draw();
19
20 gui_handler GUI_MODE_TETRIS =
21 { GUI_MODE_MODULE, gui_tetris_draw, gui_tetris_kbd_process, gui_game_menu_kbd_process, 0, GUI_MODE_FLAG_NODRAWRESTORE };
22
23 #define BOARD_WIDTH (10)
24 #define BOARD_HEIGHT (22)
25
26 #define INI_DELAY_FALL (540)
27
28 #define SCORE_1_FILLED_ROW (40)
29 #define SCORE_2_FILLED_ROW (100)
30 #define SCORE_3_FILLED_ROW (300)
31 #define SCORE_4_FILLED_ROW (1200)
32
33 #define FILLED_ROWS_FOR_LEVEL_UP (10)
34
35 #define DELAY_FACTOR_FOR_LEVEL_UP (0.9)
36
37 #define GAME_ERROR_NONE (0)
38 #define GAME_ERROR_USER_QUITS (1)
39 #define GAME_ERROR_NO_MEMORY (-1)
40 #define GAME_ERROR_NO_VIDEO (-2)
41 #define GAME_ERROR_NO_IMAGES (-3)
42 #define GAME_ERROR_ASSERT (-100)
43
44 #define EVENT_NONE (0)
45 #define EVENT_MOVE_DOWN (1 << 1)
46 #define EVENT_MOVE_LEFT (1 << 2)
47 #define EVENT_MOVE_RIGHT (1 << 3)
48 #define EVENT_ROTATE_CW (1 << 4)
49 #define EVENT_ROTATE_CCW (1 << 5)
50 #define EVENT_DROP (1 << 6)
51 #define EVENT_PAUSE (1 << 7)
52 #define EVENT_RESTART (1 << 8)
53 #define EVENT_SHOW_NEXT (1 << 9)
54
55 #define TETROMINO_I (0)
56 #define TETROMINO_O (1)
57 #define TETROMINO_T (2)
58 #define TETROMINO_S (3)
59 #define TETROMINO_Z (4)
60 #define TETROMINO_J (5)
61 #define TETROMINO_L (6)
62
63 #define TETRIS_COLOR_CYAN COLOR_CYAN
64 #define TETRIS_COLOR_RED COLOR_RED
65 #define TETRIS_COLOR_BLUE COLOR_BLUE
66 #define TETRIS_COLOR_ORANGE COLOR_WHITE
67 #define TETRIS_COLOR_GREEN COLOR_GREEN
68 #define TETRIS_COLOR_YELLOW COLOR_YELLOW
69 #define TETRIS_COLOR_PURPLE COLOR_MAGENTA
70 #define EMPTY_CELL (-1)
71
72 #define TETRIS_COLOR_BG COLOR_GREY_DK
73 #define TETRIS_COLOR_BOARD COLOR_GREY
74 #define TETRIS_COLOR_TEXT COLOR_WHITE
75
76 typedef struct StcTetramino {
77 int cells[4][4];
78 int x;
79 int y;
80 int size;
81 int type;
82 } StcTetramino;
83
84 typedef struct StcPlatform StcPlatform;
85
86 typedef struct StcGame {
87 int map[BOARD_WIDTH][BOARD_HEIGHT];
88
89 StcTetramino nextBlock;
90 StcTetramino fallingBlock;
91 StcPlatform *platform;
92 int errorCode;
93 long systemTime;
94 int delay;
95 int isOver;
96 int isPaused;
97 int showPreview;
98 long lastFallTime;
99
100 int events;
101
102 struct {
103 long score;
104 long high;
105 int lines;
106 int totalPieces;
107 int pieces[7];
108 int level;
109 } stats;
110 } StcGame;
111
112 StcGame *createGame();
113 void deleteGame(StcGame *pGame);
114 int gameInit(StcGame *gameInstance);
115 void gameEnd();
116 void gameUpdate(StcGame *gameInstance);
117
118 StcGame *game = 0;
119
120
121 long mkdir_if_not_exist(const char *dirname)
122 {
123
124 if (stat(dirname,0) != 0) return mkdir(dirname);
125 return 0;
126 }
127
128 int platformInit() { return GAME_ERROR_NONE; }
129 void platformEnd() {}
130
131
132 void platformReadInput() {}
133
134 int tile_size;
135 #define PREVIEW_X (tile_size*15)
136 #define PREVIEW_Y (tile_size)
137 #define BOARD_X (tile_size)
138 #define BOARD_Y (tile_size)
139 #define TILE_SIZE (tile_size)
140
141 int tmp[BOARD_WIDTH][BOARD_HEIGHT];
142 int tmp2[BOARD_WIDTH][BOARD_HEIGHT];
143
144 int prevNextBlockType = -1;
145 void platformRenderGame()
146 {
147 int i, j;
148
149 for (i = 0; i < BOARD_WIDTH; ++i)
150 {
151 for (j = 0; j < BOARD_HEIGHT; ++j)
152 {
153 tmp[i][j] = EMPTY_CELL;
154 tmp2[i][j] = EMPTY_CELL;
155 }
156 }
157
158
159 if (game->nextBlock.type != prevNextBlockType)
160 {
161 prevNextBlockType = game->nextBlock.type;
162 for (i = 0; i < 4; ++i)
163 {
164 for (j = 0; j < 4; ++j)
165 {
166 if (game->nextBlock.cells[i][j] != EMPTY_CELL)
167 {
168 draw_rectangle(camera_screen.disp_left + PREVIEW_X + (TILE_SIZE * i),
169 PREVIEW_Y + (TILE_SIZE * j),
170 camera_screen.disp_left + PREVIEW_X + (TILE_SIZE * i) + TILE_SIZE - 1,
171 PREVIEW_Y + (TILE_SIZE * j) + TILE_SIZE - 1,
172 MAKE_COLOR(game->nextBlock.cells[i][j], game->nextBlock.cells[i][j]), RECT_BORDER0 | DRAW_FILLED);
173 }
174 else
175 {
176 draw_rectangle(camera_screen.disp_left + PREVIEW_X + (TILE_SIZE * i),
177 PREVIEW_Y + (TILE_SIZE * j),
178 camera_screen.disp_left + PREVIEW_X + (TILE_SIZE * i) + TILE_SIZE - 1,
179 PREVIEW_Y + (TILE_SIZE * j) + TILE_SIZE - 1,
180 MAKE_COLOR(TETRIS_COLOR_BG, TETRIS_COLOR_BG), RECT_BORDER0 | DRAW_FILLED);
181 }
182 }
183 }
184 }
185
186
187 for (i = 0; i < BOARD_WIDTH; ++i)
188 {
189 for (j = 0; j < BOARD_HEIGHT; ++j)
190 {
191 if (game->map[i][j] != EMPTY_CELL)
192 {
193 tmp2[i][j] = game->map[i][j];
194 }
195 }
196 }
197
198 for (i = 0; i < 4; ++i)
199 {
200 for (j = 0; j < 4; ++j)
201 {
202 if (game->fallingBlock.cells[i][j] != EMPTY_CELL)
203 {
204 tmp[i + game->fallingBlock.x][j + game->fallingBlock.y] = game->fallingBlock.cells[i][j];
205 }
206 }
207 }
208
209 for (i = 0; i < BOARD_WIDTH; ++i)
210 {
211 for (j = 0; j < BOARD_HEIGHT; ++j)
212 {
213 if (tmp[i][j] != EMPTY_CELL)
214 {
215 draw_rectangle(camera_screen.disp_left + BOARD_X + (TILE_SIZE * i),
216 BOARD_Y + (TILE_SIZE * j),
217 camera_screen.disp_left + BOARD_X + (TILE_SIZE * i) + TILE_SIZE - 1,
218 BOARD_Y + (TILE_SIZE * j) + TILE_SIZE - 1,
219 MAKE_COLOR(tmp[i][j], tmp[i][j]), RECT_BORDER0 | DRAW_FILLED);
220 }
221 else if (tmp2[i][j] != EMPTY_CELL)
222 {
223 draw_rectangle(camera_screen.disp_left + BOARD_X + (TILE_SIZE * i),
224 BOARD_Y + (TILE_SIZE * j),
225 camera_screen.disp_left + BOARD_X + (TILE_SIZE * i) + TILE_SIZE - 1,
226 BOARD_Y + (TILE_SIZE * j) + TILE_SIZE - 1,
227 MAKE_COLOR(tmp2[i][j], tmp2[i][j]), RECT_BORDER0 | DRAW_FILLED);
228 }
229 else
230 {
231 draw_rectangle(camera_screen.disp_left + BOARD_X + (TILE_SIZE * i),
232 BOARD_Y + (TILE_SIZE * j),
233 camera_screen.disp_left + BOARD_X + (TILE_SIZE * i) + TILE_SIZE - 1,
234 BOARD_Y + (TILE_SIZE * j) + TILE_SIZE - 1,
235 MAKE_COLOR(TETRIS_COLOR_BOARD, TETRIS_COLOR_BOARD), RECT_BORDER0 | DRAW_FILLED);
236 }
237 }
238 }
239
240
241 int tx = camera_screen.disp_right - 22 * FONT_WIDTH;
242 twoColors cl = MAKE_COLOR(TETRIS_COLOR_BG, TETRIS_COLOR_TEXT);
243 int yo = FONT_HEIGHT;
244 char str_buf[100];
245 static struct tm *ttm;
246 sprintf(str_buf, "High: %5d", game->stats.high);
247 draw_string(tx, camera_screen.height - yo * 11, str_buf, cl);
248 sprintf(str_buf, "Points: %5d", game->stats.score);
249 draw_string(tx, camera_screen.height - yo * 10, str_buf, cl);
250 sprintf(str_buf, "Lines: %5d", game->stats.lines);
251 draw_string(tx, camera_screen.height - yo * 9, str_buf, cl);
252 sprintf(str_buf, "Level: %5d", game->stats.level);
253 draw_string(tx, camera_screen.height - yo * 8, str_buf, cl);
254 sprintf(str_buf, "UP -> Pause");
255 draw_string(tx, camera_screen.height - yo * 6, str_buf, cl);
256 sprintf(str_buf, "SET -> Rotate");
257 draw_string(tx, camera_screen.height - yo * 5, str_buf, cl);
258
259 ttm = get_localtime();
260 sprintf(str_buf, "Time: %2u:%02u", ttm->tm_hour, ttm->tm_min);
261 draw_string(tx, camera_screen.height - yo * 3, str_buf, cl);
262 sprintf(str_buf, "Batt: %3d%%", get_batt_perc());
263 draw_string(tx, camera_screen.height - yo * 2, str_buf, cl);
264 }
265
266
267 long platformGetSystemTime() { return get_tick_count(); }
268
269
270 static void setMatrixCells(int *matrix, int width, int height, int value)
271 {
272 int i, j;
273 for (i = 0; i < width; ++i)
274 {
275 for (j = 0; j < height; ++j)
276 {
277 *(matrix + i + (j * width)) = value;
278 }
279 }
280 }
281
282
283 static void setTetramino(int indexTetramino, StcTetramino *tetramino)
284 {
285
286
287 setMatrixCells(&tetramino->cells[0][0], 4, 4, EMPTY_CELL);
288
289
290 tetramino->size = 3;
291
292
293 switch (indexTetramino)
294 {
295 case TETROMINO_I:
296 tetramino->cells[0][1] = TETRIS_COLOR_CYAN;
297 tetramino->cells[1][1] = TETRIS_COLOR_CYAN;
298 tetramino->cells[2][1] = TETRIS_COLOR_CYAN;
299 tetramino->cells[3][1] = TETRIS_COLOR_CYAN;
300 tetramino->size = 4;
301 break;
302 case TETROMINO_O:
303 tetramino->cells[0][0] = TETRIS_COLOR_YELLOW;
304 tetramino->cells[0][1] = TETRIS_COLOR_YELLOW;
305 tetramino->cells[1][0] = TETRIS_COLOR_YELLOW;
306 tetramino->cells[1][1] = TETRIS_COLOR_YELLOW;
307 tetramino->size = 2;
308 break;
309 case TETROMINO_T:
310 tetramino->cells[0][1] = TETRIS_COLOR_PURPLE;
311 tetramino->cells[1][0] = TETRIS_COLOR_PURPLE;
312 tetramino->cells[1][1] = TETRIS_COLOR_PURPLE;
313 tetramino->cells[2][1] = TETRIS_COLOR_PURPLE;
314 break;
315 case TETROMINO_S:
316 tetramino->cells[0][1] = TETRIS_COLOR_GREEN;
317 tetramino->cells[1][0] = TETRIS_COLOR_GREEN;
318 tetramino->cells[1][1] = TETRIS_COLOR_GREEN;
319 tetramino->cells[2][0] = TETRIS_COLOR_GREEN;
320 break;
321 case TETROMINO_Z:
322 tetramino->cells[0][0] = TETRIS_COLOR_RED;
323 tetramino->cells[1][0] = TETRIS_COLOR_RED;
324 tetramino->cells[1][1] = TETRIS_COLOR_RED;
325 tetramino->cells[2][1] = TETRIS_COLOR_RED;
326 break;
327 case TETROMINO_J:
328 tetramino->cells[0][0] = TETRIS_COLOR_BLUE;
329 tetramino->cells[0][1] = TETRIS_COLOR_BLUE;
330 tetramino->cells[1][1] = TETRIS_COLOR_BLUE;
331 tetramino->cells[2][1] = TETRIS_COLOR_BLUE;
332 break;
333 case TETROMINO_L:
334 tetramino->cells[0][1] = TETRIS_COLOR_ORANGE;
335 tetramino->cells[1][1] = TETRIS_COLOR_ORANGE;
336 tetramino->cells[2][0] = TETRIS_COLOR_ORANGE;
337 tetramino->cells[2][1] = TETRIS_COLOR_ORANGE;
338 break;
339 }
340 tetramino->type = indexTetramino;
341 }
342
343
344 static void startGame(StcGame *game)
345 {
346 int i;
347
348
349 game->errorCode = GAME_ERROR_NONE;
350 game->systemTime = platformGetSystemTime();
351 game->lastFallTime = game->systemTime;
352 game->isOver = 0;
353 game->isPaused = 0;
354 game->showPreview = 1;
355 game->events = EVENT_NONE;
356 game->delay = INI_DELAY_FALL;
357
358 game->stats.score = 0;
359 game->stats.lines = 0;
360 game->stats.totalPieces = 0;
361 game->stats.level = 0;
362 for (i = 0; i < 7; ++i)
363 {
364 game->stats.pieces[i] = 0;
365 }
366
367
368 srand(game->systemTime);
369
370
371 setMatrixCells(&game->map[0][0], BOARD_WIDTH, BOARD_HEIGHT, EMPTY_CELL);
372
373
374 setTetramino(rand() % 7, &game->fallingBlock);
375 game->fallingBlock.x = (BOARD_WIDTH - game->fallingBlock.size) / 2;
376 game->fallingBlock.y = 0;
377
378
379 setTetramino(rand() % 7, &game->nextBlock);
380 }
381
382
383 StcGame *createGame()
384 {
385
386 StcGame *game = (StcGame *) malloc(sizeof(StcGame));
387 return game;
388 }
389
390
391
392
393 int gameInit(StcGame *game)
394 {
395 int errorCode;
396
397 errorCode = platformInit();
398 if (errorCode == GAME_ERROR_NONE)
399 {
400 startGame(game);
401 return GAME_ERROR_NONE;
402 }
403 return errorCode;
404 };
405
406 void gameEnd()
407 {
408
409 platformEnd();
410 }
411
412 void deleteGame(StcGame *game)
413 {
414 free(game);
415 }
416
417
418
419
420
421 void rotateTetramino(StcGame *game, int clockwise)
422 {
423 int i, j;
424 int rotated[4][4];
425
426
427 if (game->fallingBlock.type == TETROMINO_O)
428 {
429 return;
430 }
431
432
433 setMatrixCells(&rotated[0][0], 4, 4, EMPTY_CELL);
434
435
436 for (i = 0; i < game->fallingBlock.size; ++i)
437 {
438 for (j = 0; j < game->fallingBlock.size; ++j)
439 {
440 if (clockwise)
441 {
442 rotated[game->fallingBlock.size - j - 1][i] = game->fallingBlock.cells[i][j];
443 }
444 else
445 {
446 rotated[j][game->fallingBlock.size - i - 1] = game->fallingBlock.cells[i][j];
447 }
448 }
449 }
450
451 for (i = 0; i < game->fallingBlock.size; ++i)
452 {
453 for (j = 0; j < game->fallingBlock.size; ++j)
454 {
455 if (rotated[i][j] != EMPTY_CELL)
456 {
457
458 if ((game->fallingBlock.x + i < 0) || (game->fallingBlock.x + i >= BOARD_WIDTH) || (game->fallingBlock.y + j >= BOARD_HEIGHT))
459 {
460 return;
461 }
462
463 if (game->map[i + game->fallingBlock.x][j + game->fallingBlock.y] != EMPTY_CELL)
464 {
465 return;
466 }
467 }
468 }
469 }
470
471 for (i = 0; i < 4; ++i)
472 {
473 for (j = 0; j < 4; ++j)
474 {
475 game->fallingBlock.cells[i][j] = rotated[i][j];
476 }
477 }
478 }
479
480
481
482
483
484 static int checkCollision(StcGame *game, int dx, int dy)
485 {
486 int newx, newy, i, j;
487
488 newx = game->fallingBlock.x + dx;
489 newy = game->fallingBlock.y + dy;
490
491 for (i = 0; i < game->fallingBlock.size; ++i)
492 {
493 for (j = 0; j < game->fallingBlock.size; ++j)
494 {
495 if (game->fallingBlock.cells[i][j] != EMPTY_CELL)
496 {
497
498 if ((newx + i < 0) || (newx + i >= BOARD_WIDTH) || (newy + j >= BOARD_HEIGHT))
499 {
500 return 1;
501 }
502
503 if (game->map[newx + i][newy + j] != EMPTY_CELL)
504 {
505 return 1;
506 }
507 }
508 }
509 }
510 return 0;
511 }
512
513
514 static void onFilledRows(StcGame *game, int filledRows)
515 {
516
517 game->stats.lines += filledRows;
518
519
520 switch (filledRows)
521 {
522 case 1:
523 game->stats.score += (SCORE_1_FILLED_ROW * (game->stats.level));
524 break;
525 case 2:
526 game->stats.score += (SCORE_2_FILLED_ROW * (game->stats.level));
527 break;
528 case 3:
529 game->stats.score += (SCORE_3_FILLED_ROW * (game->stats.level));
530 break;
531 case 4:
532 game->stats.score += (SCORE_4_FILLED_ROW * (game->stats.level));
533 break;
534 default:
535 game->errorCode = GAME_ERROR_ASSERT;
536 }
537
538 if (game->stats.lines >= FILLED_ROWS_FOR_LEVEL_UP * (game->stats.level))
539 {
540 game->stats.level++;
541
542
543 game->delay *= DELAY_FACTOR_FOR_LEVEL_UP;
544 }
545 }
546
547
548
549
550
551
552 static void moveTetramino(StcGame *game, int x, int y)
553 {
554 int i, j, hasFullRow, numFilledRows;
555
556
557 if (checkCollision(game, x, y))
558 {
559
560 if (y == 1)
561 {
562
563
564 if (game->fallingBlock.y <= 1)
565 {
566 game->isOver = 1;
567 }
568 else
569 {
570
571
572 for (i = 0; i < game->fallingBlock.size; ++i)
573 {
574 for (j = 0; j < game->fallingBlock.size; ++j)
575 {
576 if (game->fallingBlock.cells[i][j] != EMPTY_CELL)
577 {
578 game->map[game->fallingBlock.x + i][game->fallingBlock.y + j] = game->fallingBlock.cells[i][j];
579 }
580 }
581 }
582
583
584 numFilledRows = 0;
585 for (j = 1; j < BOARD_HEIGHT; ++j)
586 {
587 hasFullRow = 1;
588 for (i = 0; i < BOARD_WIDTH; ++i)
589 {
590 if (game->map[i][j] == EMPTY_CELL)
591 {
592 hasFullRow = 0;
593 break;
594 }
595 }
596
597
598 if (hasFullRow)
599 {
600 for (x = 0; x < BOARD_WIDTH; ++x)
601 {
602 for (y = j; y > 0; --y)
603 {
604 game->map[x][y] = game->map[x][y - 1];
605 }
606 }
607 numFilledRows++;
608 }
609 }
610
611
612 if (numFilledRows)
613 {
614 onFilledRows(game, numFilledRows);
615 }
616 game->stats.totalPieces++;
617 game->stats.pieces[game->fallingBlock.type]++;
618
619
620
621 for (i = 0; i < 4; ++i)
622 {
623 for (j = 0; j < 4; ++j)
624 {
625 game->fallingBlock.cells[i][j] = game->nextBlock.cells[i][j];
626 }
627 }
628 game->fallingBlock.size = game->nextBlock.size;
629 game->fallingBlock.type = game->nextBlock.type;
630
631
632 game->fallingBlock.y = 0;
633 game->fallingBlock.x = (BOARD_WIDTH - game->fallingBlock.size) / 2;
634
635
636 setTetramino(rand() % 7, &game->nextBlock);
637 }
638 }
639 }
640 else
641 {
642
643 game->fallingBlock.x += x;
644 game->fallingBlock.y += y;
645 }
646 }
647
648
649 static void dropTetramino(StcGame *game)
650 {
651 int y;
652 y = 1;
653
654 while (!checkCollision(game, 0, y))
655 {
656 y++;
657 }
658 moveTetramino(game, 0, y - 1);
659 }
660
661
662
663
664 void gameUpdate(StcGame *game)
665 {
666 long sysTime;
667
668 if (!game)
669 {
670 return;
671 }
672
673
674 platformReadInput();
675
676
677 if (game->isOver)
678 {
679
680 if (game->stats.score > game->stats.high)
681 {
682 game->stats.high = game->stats.score;
683 FILE * f;
684 long buf;
685 buf = game->stats.score;
686
687 mkdir_if_not_exist("A/CHDK/GAMES");
688 f = fopen("A/CHDK/GAMES/TETRIS.SCO", "wb");
689 fwrite(&buf, 1, sizeof(buf), f);
690 fclose(f);
691 }
692
693
694 if (game->events & EVENT_PAUSE)
695 {
696
697
698
699 game->isOver = 0;
700 startGame(game);
701
702 }
703 }
704 else
705 {
706 sysTime = platformGetSystemTime();
707
708
709 if (game->events & EVENT_PAUSE)
710 {
711 game->isPaused = !game->isPaused;
712 game->events = EVENT_NONE;
713 }
714
715
716 if (game->isPaused)
717 {
718
719
720 game->lastFallTime += (sysTime - game->systemTime);
721 }
722 else
723 {
724 if (game->events != EVENT_NONE)
725 {
726 if (game->events & EVENT_SHOW_NEXT)
727 {
728 game->showPreview = !game->showPreview;
729 }
730 if (game->events & EVENT_DROP)
731 {
732 dropTetramino(game);
733 }
734 if (game->events & EVENT_ROTATE_CW)
735 {
736 rotateTetramino(game, 1);
737 }
738 if (game->events & EVENT_MOVE_RIGHT)
739 {
740 moveTetramino(game, 1, 0);
741 }
742 else if (game->events & EVENT_MOVE_LEFT)
743 {
744 moveTetramino(game, -1, 0);
745 }
746 if (game->events & EVENT_MOVE_DOWN)
747 {
748 moveTetramino(game, 0, 1);
749 }
750 game->events = EVENT_NONE;
751 }
752
753 if (sysTime - game->lastFallTime >= game->delay)
754 {
755 moveTetramino(game, 0, 1);
756 game->lastFallTime = sysTime;
757 }
758 }
759 game->systemTime = sysTime;
760 }
761
762 platformRenderGame();
763 }
764
765 void gui_tetris_init()
766 {
767 tile_size = camera_screen.height / (BOARD_HEIGHT+2);
768
769 draw_rectangle(camera_screen.disp_left, 0, camera_screen.disp_right, camera_screen.height - 1, MAKE_COLOR(TETRIS_COLOR_BG, TETRIS_COLOR_BG), RECT_BORDER0 | DRAW_FILLED);
770 draw_rectangle(camera_screen.disp_left + BOARD_X - 1, BOARD_Y - 1, camera_screen.disp_left + BOARD_WIDTH * TILE_SIZE + TILE_SIZE, BOARD_HEIGHT * TILE_SIZE + TILE_SIZE, MAKE_COLOR(TETRIS_COLOR_TEXT, TETRIS_COLOR_TEXT), RECT_BORDER1);
771 game = createGame();
772 gameInit(game);
773
774 long buf;
775 FILE *f;
776
777 f = fopen("A/CHDK/GAMES/TETRIS.SCO", "rb");
778 if (!f)
779 {
780 game->stats.high = 0;
781 }
782 else
783 {
784 fread(&buf, 1, sizeof(buf), f);
785 game->stats.high = buf;
786 }
787
788 fclose(f);
789 startGame(game);
790 }
791
792 int basic_module_init()
793 {
794 gui_set_mode(&GUI_MODE_TETRIS);
795 gui_tetris_init();
796 return 1;
797 }
798
799 void gui_tetris_draw()
800 {
801 gameUpdate(game);
802 }
803
804 int gui_tetris_kbd_process()
805 {
806 if (!game)
807 {
808 return 0;
809 }
810 switch (kbd_get_autoclicked_key())
811 {
812 case KEY_UP:
813 if ((game->isPaused) || (game->isOver))
814 {
815 TurnOnBackLight();
816 }
817 else
818 {
819 TurnOffBackLight();
820 }
821 game->events |= EVENT_PAUSE;
822 break;
823 case KEY_LEFT:
824 game->events |= EVENT_MOVE_LEFT;
825 break;
826 case KEY_RIGHT:
827 game->events |= EVENT_MOVE_RIGHT;
828 break;
829 case KEY_DOWN:
830 game->events |= EVENT_MOVE_DOWN;
831 break;
832
833
834
835 case KEY_DISPLAY:
836 case KEY_ERASE:
837 case KEY_SET:
838 game->events |= EVENT_ROTATE_CW;
839 break;
840 default:
841 break;
842 }
843 return 0;
844 }
845
846 #include "simple_game.c"
847
848
849
850 ModuleInfo _module_info =
851 {
852 MODULEINFO_V1_MAGICNUM,
853 sizeof(ModuleInfo),
854 SIMPLE_MODULE_VERSION,
855
856 ANY_CHDK_BRANCH, 0, OPT_ARCHITECTURE,
857 ANY_PLATFORM_ALLOWED,
858
859 -LANG_MENU_GAMES_TETRIS,
860 MTYPE_GAME,
861
862 &_librun.base,
863
864 ANY_VERSION,
865 CAM_SCREEN_VERSION,
866 ANY_VERSION,
867 ANY_VERSION,
868
869 0,
870 };
871
872