source: branches/reyalp-flt/core/gui_tetris.c @ 1512

Revision 1512, 27.5 KB checked in by philmoz, 2 years ago (diff)

Add 'camera_info' struct for module platform independance (for review).

  • Property svn:eol-style set to native
Line 
1#include "stdlib.h"
2#include "keyboard.h"
3#include "platform.h"
4#include "core.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
12#include "module_load.h"
13
14void gui_module_menu_kbd_process();
15void gui_tetris_kbd_process();
16void gui_tetris_draw();
17
18gui_handler GUI_MODE_TETRIS =
19    /*GUI_MODE_TETRIS*/          { gui_tetris_draw,       gui_tetris_kbd_process,      gui_module_menu_kbd_process, GUI_MODE_FLAG_NODRAWRESTORE, GUI_MODE_MAGICNUM };
20
21
22#define BOARD_WIDTH     (10)
23#define BOARD_HEIGHT    (22)
24/* Initial time delay (in miliseconds) between falling moves */
25#define INI_DELAY_FALL  (540)
26/* Score points given by filled rows */
27#define SCORE_1_FILLED_ROW  (40)
28#define SCORE_2_FILLED_ROW  (100)
29#define SCORE_3_FILLED_ROW  (300)
30#define SCORE_4_FILLED_ROW  (1200)
31/* Number of filled rows required to increase the game level */
32#define FILLED_ROWS_FOR_LEVEL_UP    (10)
33/* The falling delay is multiplied by this factor with every level up */
34#define DELAY_FACTOR_FOR_LEVEL_UP   (0.9)
35
36#define GAME_ERROR_NONE         (0)     /* Everything is OK, oh wonders!      */
37#define GAME_ERROR_USER_QUITS   (1)     /* The user quits (bored?), our fail  */
38#define GAME_ERROR_NO_MEMORY    (-1)    /* Not enough memory                  */
39#define GAME_ERROR_NO_VIDEO     (-2)    /* Video system was not initialized   */
40#define GAME_ERROR_NO_IMAGES    (-3)    /* Problem loading the image files    */
41#define GAME_ERROR_ASSERT       (-100)  /* Something went very very wrong...  */
42
43#define EVENT_NONE          (0)
44#define EVENT_MOVE_DOWN     (1 << 1)
45#define EVENT_MOVE_LEFT     (1 << 2)
46#define EVENT_MOVE_RIGHT    (1 << 3)
47#define EVENT_ROTATE_CW     (1 << 4)    /* rotate clockwise         */
48#define EVENT_ROTATE_CCW    (1 << 5)    /* rotate counter-clockwise */
49#define EVENT_DROP          (1 << 6)
50#define EVENT_PAUSE         (1 << 7)
51#define EVENT_RESTART       (1 << 8)
52#define EVENT_SHOW_NEXT     (1 << 9)    /* toggle show next tetromino */
53// Tetromino definitions (used as indexes: must be between 0-6)
54#define TETROMINO_I     (0)
55#define TETROMINO_O     (1)
56#define TETROMINO_T     (2)
57#define TETROMINO_S     (3)
58#define TETROMINO_Z     (4)
59#define TETROMINO_J     (5)
60#define TETROMINO_L     (6)
61/* Tetromino colors */
62#define TETRIS_COLOR_CYAN      COLOR_SPLASH_PINK
63#define TETRIS_COLOR_RED       COLOR_RED
64#define TETRIS_COLOR_BLUE      COLOR_BLUE
65#define TETRIS_COLOR_ORANGE    COLOR_WHITE
66#define TETRIS_COLOR_GREEN     COLOR_GREEN
67#define TETRIS_COLOR_YELLOW    COLOR_YELLOW
68#define TETRIS_COLOR_PURPLE    COLOR_BLACK
69#define EMPTY_CELL  (-1)
70/* screen colors */
71#define TETRIS_COLOR_BG        MAKE_COLOR(COLOR_GREY,COLOR_GREY)
72#define TETRIS_COLOR_BOARD     MAKE_COLOR(COLOR_SPLASH_GREY,COLOR_SPLASH_GREY)
73
74typedef struct StcTetramino {
75    int cells[4][4];
76    int x;
77    int y;
78    int size;
79    int type;
80} StcTetramino;
81
82typedef struct StcPlatform StcPlatform;
83
84typedef struct StcGame {
85    int map[BOARD_WIDTH][BOARD_HEIGHT];
86
87    StcTetramino nextBlock;     /* next tetromino               */
88    StcTetramino fallingBlock;  /* current falling tetromino    */
89    StcPlatform *platform;      /* platform hidden data         */
90    int errorCode;              /* game error code              */
91    long systemTime;            /* system time in miliseconds   */
92    int delay;          /* delay time for falling tetrominoes   */
93    int isOver;         /* 1 if the game is over, 0 otherwise   */
94    int isPaused;       /* 1 if the game is paused, 0 otherwise */
95    int showPreview;    /* 1 if we must show preview tetramino  */
96    long lastFallTime;  /* last time the game moved the falling tetromino */
97
98    int events;
99
100    struct {
101        long score;         /* user score for current game      */
102        long high;          /* high score                       */
103        int lines;          /* total number of lines cleared    */
104        int totalPieces;    /* total number of tetraminoes used */
105        int pieces[7];      /* number of tetraminoes per type   */
106        int level;          /* current game level               */
107    } stats;
108} StcGame;
109StcGame *createGame();
110void deleteGame(StcGame *pGame);
111int gameInit(StcGame *gameInstance);
112void gameEnd(StcGame *gameInstance);
113void gameUpdate(StcGame *gameInstance);
114
115
116StcGame *game;
117
118
119// No need to import such simple
120long mkdir_if_not_exist(const char *dirname)
121{
122    // Check if directory exists and create it if it does not.
123    struct STD_stat st;
124    if (safe_stat(dirname,&st) != 0) return mkdir(dirname);
125    return 0;   // Success
126}
127
128
129int platformInit(StcGame *gameInstance){ return GAME_ERROR_NONE;}
130void platformEnd(StcGame *gameInstance){}
131
132/* Read input device and notify game */
133void platformReadInput(StcGame *gameInstance){}
134#define PREVIEW_X 150
135#define PREVIEW_Y 10
136#define BOARD_X 10
137#define BOARD_Y 10
138#define TILE_SIZE 10
139/* Render the state of the game */
140int tmp[BOARD_WIDTH][BOARD_HEIGHT];
141int tmp2[BOARD_WIDTH][BOARD_HEIGHT];
142
143int prevNextBlockType = -1;
144void platformRenderGame(StcGame *gameInstance){
145    int i, j;
146
147    for(i = 0; i < BOARD_WIDTH; ++i) {
148        for (j = 0; j < BOARD_HEIGHT; ++j){
149          tmp[i][j] = EMPTY_CELL;
150          tmp2[i][j] = EMPTY_CELL;
151        }
152    }
153
154    /* Draw preview block */
155    if(game->nextBlock.type != prevNextBlockType){
156        prevNextBlockType = game->nextBlock.type;
157        for (i = 0; i < 4; ++i) {
158            for (j = 0; j < 4; ++j) {
159                if (game->nextBlock.cells[i][j] != EMPTY_CELL) {
160                    draw_filled_rect(camera_info.ts_button_border+PREVIEW_X + (TILE_SIZE * i),
161                            PREVIEW_Y + (TILE_SIZE * j),
162                            camera_info.ts_button_border+PREVIEW_X + (TILE_SIZE * i)+TILE_SIZE-1,
163                            PREVIEW_Y + (TILE_SIZE * j)+TILE_SIZE-1,
164                             MAKE_COLOR(game->nextBlock.cells[i][j], game->nextBlock.cells[i][j]));
165                }else{
166                    draw_filled_rect(camera_info.ts_button_border+PREVIEW_X + (TILE_SIZE * i),
167                            PREVIEW_Y + (TILE_SIZE * j),
168                            camera_info.ts_button_border+PREVIEW_X + (TILE_SIZE * i)+TILE_SIZE-1,
169                            PREVIEW_Y + (TILE_SIZE * j)+TILE_SIZE-1,
170                            TETRIS_COLOR_BG);
171                }
172            }
173        }
174    }
175   
176    /* Draw the cells in the board */
177    for (i = 0; i < BOARD_WIDTH; ++i) {
178        for (j = 0; j < BOARD_HEIGHT; ++j){
179            if (game->map[i][j] != EMPTY_CELL) {
180                tmp2[i][j] = game->map[i][j];
181            }
182        }
183    }
184    /* Draw falling tetromino */
185    for (i = 0; i<4; ++i) {
186        for (j = 0; j < 4; ++j) {
187            if (game->fallingBlock.cells[i][j] != EMPTY_CELL) {
188              tmp[i+game->fallingBlock.x][j+game->fallingBlock.y] = game->fallingBlock.cells[i][j];
189            }
190        }
191    }
192
193    for (i = 0; i < BOARD_WIDTH; ++i) {
194        for (j = 0; j < BOARD_HEIGHT; ++j){
195                    if(tmp[i][j] != EMPTY_CELL){
196                    draw_filled_rect(camera_info.ts_button_border+BOARD_X + (TILE_SIZE * i),
197                            BOARD_Y + (TILE_SIZE * j),
198                            camera_info.ts_button_border+BOARD_X + (TILE_SIZE * i)+TILE_SIZE-1,
199                            BOARD_Y + (TILE_SIZE * j)+TILE_SIZE-1,
200                             MAKE_COLOR(tmp[i][j], tmp[i][j]));
201                    }else if(tmp2[i][j] != EMPTY_CELL){
202                    draw_filled_rect(camera_info.ts_button_border+BOARD_X + (TILE_SIZE * i),
203                            BOARD_Y + (TILE_SIZE * j),
204                            camera_info.ts_button_border+BOARD_X + (TILE_SIZE * i)+TILE_SIZE-1,
205                            BOARD_Y + (TILE_SIZE * j)+TILE_SIZE-1,
206                             MAKE_COLOR(tmp2[i][j], tmp2[i][j]));
207                    }else{
208                    draw_filled_rect(camera_info.ts_button_border+BOARD_X + (TILE_SIZE * i),
209                            BOARD_Y + (TILE_SIZE * j),
210                            camera_info.ts_button_border+BOARD_X + (TILE_SIZE * i)+TILE_SIZE-1,
211                            BOARD_Y + (TILE_SIZE * j)+TILE_SIZE-1,
212                             TETRIS_COLOR_BOARD);
213                    }
214        }
215    }
216    /* output game info */
217    char str_buf[100];
218    unsigned long t;
219    static struct tm *ttm;
220      sprintf(str_buf,"High:    %5d",game->stats.high);
221      draw_string(camera_info.ts_button_border+150,35,str_buf, MAKE_COLOR(TETRIS_COLOR_BG, COLOR_BLACK));
222      sprintf(str_buf,"Points:  %5d",game->stats.score);
223      draw_string(camera_info.ts_button_border+150,55,str_buf, MAKE_COLOR(TETRIS_COLOR_BG, COLOR_BLACK));
224      sprintf(str_buf,"Lines:   %5d",game->stats.lines);
225      draw_string(camera_info.ts_button_border+150,75,str_buf, MAKE_COLOR(TETRIS_COLOR_BG, COLOR_BLACK));
226      sprintf(str_buf,"Level:   %5d",game->stats.level);
227      draw_string(camera_info.ts_button_border+150,95,str_buf, MAKE_COLOR(TETRIS_COLOR_BG, COLOR_BLACK));
228     sprintf(str_buf,"UP  -> Pause");
229     draw_string(camera_info.ts_button_border+150,135,str_buf, MAKE_COLOR(TETRIS_COLOR_BG, COLOR_BLACK));
230     sprintf(str_buf,"SET -> Rotate");
231     draw_string(camera_info.ts_button_border+150,155,str_buf, MAKE_COLOR(TETRIS_COLOR_BG, COLOR_BLACK));
232     t = time(NULL);
233      ttm = localtime(&t);
234      sprintf(str_buf,"Time:    %2u:%02u", ttm->tm_hour, ttm->tm_min);
235     draw_string(camera_info.ts_button_border+150,195,str_buf, MAKE_COLOR(TETRIS_COLOR_BG, COLOR_BLACK));
236     sprintf(str_buf,"Batt:     %3d%%", get_batt_perc());
237     draw_string(camera_info.ts_button_border+150,215,str_buf, MAKE_COLOR(TETRIS_COLOR_BG, COLOR_BLACK));
238}
239
240/* Return the current system time in milliseconds */
241long platformGetSystemTime(){return get_tick_count();}
242
243/* Set matrix elements to indicated value */
244static void setMatrixCells(int *matrix, int width, int height, int value) {
245    int i, j;
246    for (i = 0; i < width; ++i) {
247        for (j = 0; j < height; ++j) {
248            *(matrix + i + (j * width)) = value;
249        }
250    }
251}
252
253/* Initialize tetromino cells for every tipe of tetromino */
254static void setTetramino(int indexTetramino, StcTetramino *tetramino) {
255
256    /* Initialize tetromino cells to empty cells */
257    setMatrixCells(&tetramino->cells[0][0], 4, 4, EMPTY_CELL);
258
259    /* Almost all the blocks have size 3 */
260    tetramino->size = 3;
261
262    /* Initial configuration from: http://www.tetrisconcept.com/wiki/index.php/SRS */
263    switch (indexTetramino) {
264    case TETROMINO_I:
265        tetramino->cells[0][1] = TETRIS_COLOR_CYAN;
266        tetramino->cells[1][1] = TETRIS_COLOR_CYAN;
267        tetramino->cells[2][1] = TETRIS_COLOR_CYAN;
268        tetramino->cells[3][1] = TETRIS_COLOR_CYAN;
269        tetramino->size = 4;
270        break;
271    case TETROMINO_O:
272        tetramino->cells[0][0] = TETRIS_COLOR_YELLOW;
273        tetramino->cells[0][1] = TETRIS_COLOR_YELLOW;
274        tetramino->cells[1][0] = TETRIS_COLOR_YELLOW;
275        tetramino->cells[1][1] = TETRIS_COLOR_YELLOW;
276        tetramino->size = 2;
277        break;
278    case TETROMINO_T:
279        tetramino->cells[0][1] = TETRIS_COLOR_PURPLE;
280        tetramino->cells[1][0] = TETRIS_COLOR_PURPLE;
281        tetramino->cells[1][1] = TETRIS_COLOR_PURPLE;
282        tetramino->cells[2][1] = TETRIS_COLOR_PURPLE;
283        break;
284    case TETROMINO_S:
285        tetramino->cells[0][1] = TETRIS_COLOR_GREEN;
286        tetramino->cells[1][0] = TETRIS_COLOR_GREEN;
287        tetramino->cells[1][1] = TETRIS_COLOR_GREEN;
288        tetramino->cells[2][0] = TETRIS_COLOR_GREEN;
289        break;
290    case TETROMINO_Z:
291        tetramino->cells[0][0] = TETRIS_COLOR_RED;
292        tetramino->cells[1][0] = TETRIS_COLOR_RED;
293        tetramino->cells[1][1] = TETRIS_COLOR_RED;
294        tetramino->cells[2][1] = TETRIS_COLOR_RED;
295        break;
296    case TETROMINO_J:
297        tetramino->cells[0][0] = TETRIS_COLOR_BLUE;
298        tetramino->cells[0][1] = TETRIS_COLOR_BLUE;
299        tetramino->cells[1][1] = TETRIS_COLOR_BLUE;
300        tetramino->cells[2][1] = TETRIS_COLOR_BLUE;
301        break;
302    case TETROMINO_L:
303        tetramino->cells[0][1] = TETRIS_COLOR_ORANGE;
304        tetramino->cells[1][1] = TETRIS_COLOR_ORANGE;
305        tetramino->cells[2][0] = TETRIS_COLOR_ORANGE;
306        tetramino->cells[2][1] = TETRIS_COLOR_ORANGE;
307        break;
308    }
309    tetramino->type = indexTetramino;
310}
311
312/*  Start a new game */
313static void startGame(StcGame *game) {
314    int i;
315
316    /* Initialize game data */
317    game->errorCode = GAME_ERROR_NONE;
318    game->systemTime = platformGetSystemTime();
319    game->lastFallTime = game->systemTime;
320    game->isOver = 0;
321    game->isPaused = 0;
322    game->showPreview = 1;
323    game->events = EVENT_NONE;
324    game->delay = INI_DELAY_FALL;
325    /* Initialize game statistics */
326    game->stats.score = 0;
327    game->stats.lines = 0;
328    game->stats.totalPieces = 0;
329    game->stats.level = 0;
330    for (i = 0; i < 7; ++i) {
331        game->stats.pieces[i] = 0;
332    }
333
334    /* Initialize rand generator */
335    srand(game->systemTime);
336
337    /* Initialize game tile map */
338    setMatrixCells(&game->map[0][0], BOARD_WIDTH, BOARD_HEIGHT, EMPTY_CELL);
339
340    /* Initialize falling tetromino */
341    setTetramino(rand() % 7, &game->fallingBlock);
342    game->fallingBlock.x = (BOARD_WIDTH - game->fallingBlock.size) / 2;
343    game->fallingBlock.y = 0;
344
345    /* Initialize preview tetromino */
346    setTetramino(rand() % 7, &game->nextBlock);
347}
348
349/* Create new game object */
350StcGame *createGame() {
351    /* Allocate space for our game object */
352    StcGame *game = (StcGame *) malloc(sizeof(StcGame));
353    return game;
354}
355
356/*
357 * Initializes the game, if there are no problems returns GAME_ERROR_NONE.
358 */
359int gameInit(StcGame *game) {
360    int errorCode;
361
362    errorCode = platformInit(game);
363    if (errorCode == GAME_ERROR_NONE) {
364        startGame(game);
365        return GAME_ERROR_NONE;
366    }
367    return errorCode;
368};
369
370void gameEnd(StcGame *game) {
371    /* Free platform resources */
372    platformEnd(game);
373}
374
375void deleteGame(StcGame *game) {
376    free(game);
377}
378
379/*
380 * Rotate falling tetromino. If there are no collisions when the
381 * tetromino is rotated this modifies the tetramino's cell buffer.
382 */
383void rotateTetramino(StcGame *game, int clockwise) {
384    int i, j;
385    int rotated[4][4];  /* temporary array to hold rotated cells */
386
387    /* If TETRAMINO_O is falling return immediately */
388    if (game->fallingBlock.type == TETROMINO_O) {
389        return; /* rotation doesn't require any changes */
390    }
391
392    /* Initialize rotated cells to blank */
393    setMatrixCells(&rotated[0][0], 4, 4, EMPTY_CELL);
394
395    /* Copy rotated cells to the temporary array */
396    for (i = 0; i < game->fallingBlock.size; ++i) {
397        for (j = 0; j < game->fallingBlock.size; ++j) {
398            if (clockwise) {
399                rotated[game->fallingBlock.size - j - 1][i] = game->fallingBlock.cells[i][j];
400            } else {
401                rotated[j][game->fallingBlock.size - i - 1] = game->fallingBlock.cells[i][j];
402            }
403        }
404    }
405    /* Check collision of the temporary array */
406    for (i = 0; i < game->fallingBlock.size; ++i) {
407        for (j = 0; j < game->fallingBlock.size; ++j) {
408            if (rotated[i][j] != EMPTY_CELL) {
409                /* Check collision with left, right or bottom borders of the map */
410                if ((game->fallingBlock.x + i < 0) || (game->fallingBlock.x + i >= BOARD_WIDTH)
411                        || (game->fallingBlock.y + j >= BOARD_HEIGHT)) {
412                    return; /* there was collision therefore return */
413                }
414                /* Check collision with existing cells in the map */
415                if (game->map[i + game->fallingBlock.x][j + game->fallingBlock.y] != EMPTY_CELL) {
416                    return; /* there was collision therefore return */
417                }
418            }
419        }
420    }
421    /* There are no collisions, replace tetramino cells with rotated cells */
422    for (i = 0; i < 4; ++i) {
423        for (j = 0; j < 4; ++j) {
424            game->fallingBlock.cells[i][j] = rotated[i][j];
425        }
426    }
427}
428
429/*
430 * Check if tetromino will collide with something if it is moved in the requested direction.
431 * If there are collisions returns 1 else returns 0.
432 */
433static int checkCollision(StcGame *game, int dx, int dy) {
434    int newx, newy, i, j;
435
436    newx = game->fallingBlock.x + dx;
437    newy = game->fallingBlock.y + dy;
438
439    for (i = 0; i < game->fallingBlock.size; ++i) {
440        for (j = 0; j < game->fallingBlock.size; ++j) {
441            if (game->fallingBlock.cells[i][j] != EMPTY_CELL) {
442                /* Check the tetramino would be inside the left, right and bottom borders */
443                if ((newx + i < 0) || (newx + i >= BOARD_WIDTH)
444                    || (newy + j >= BOARD_HEIGHT)) {
445                    return 1;
446                }
447                /* Check the tetromino won't collide with existing cells in the map */
448                if (game->map[newx + i][newy + j] != EMPTY_CELL) {
449                    return 1;
450                }
451            }
452        }
453    }
454    return 0;
455}
456
457/* Game scoring: http://www.tetrisconcept.com/wiki/index.php/Scoring */
458static void onFilledRows(StcGame *game, int filledRows) {
459    /* Update total number of filled rows */
460    game->stats.lines += filledRows;
461
462    /* Increase score accordingly to the number of filled rows */
463    switch (filledRows) {
464    case 1:
465        game->stats.score += (SCORE_1_FILLED_ROW * (game->stats.level));
466        break;
467    case 2:
468        game->stats.score += (SCORE_2_FILLED_ROW * (game->stats.level));
469        break;
470    case 3:
471        game->stats.score += (SCORE_3_FILLED_ROW * (game->stats.level));
472        break;
473    case 4:
474        game->stats.score += (SCORE_4_FILLED_ROW * (game->stats.level));
475        break;
476    default:
477        game->errorCode = GAME_ERROR_ASSERT;    /* This can't happen */
478    }
479    /* Check if we need to update level */
480    if (game->stats.lines >= FILLED_ROWS_FOR_LEVEL_UP * (game->stats.level)) {
481        game->stats.level++;
482
483        /* Increase speed for falling tetrominoes */
484        game->delay *= DELAY_FACTOR_FOR_LEVEL_UP;
485    }
486}
487
488/*
489 * Move tetramino in direction especified by (x, y) (in tile units)
490 * This function detects if there are filled rows or if the move
491 * lands a falling tetromino, also checks for game over condition.
492 */
493static void moveTetramino(StcGame *game, int x, int y) {
494    int i, j, hasFullRow, numFilledRows;
495   
496    /* Check if the move would create a collision */
497    if (checkCollision(game, x, y)) {
498        /* In case of collision check if move was downwards (y == 1) */
499        if (y == 1) {
500            /* Check if collision occur when the falling
501             * tetromino is in the 1st or 2nd row */
502            if (game->fallingBlock.y <= 1) {
503                game->isOver = 1;   /* if this happens the game is over */
504            }
505            else {
506                /* The falling tetromino has reached the bottom,
507                 * so we copy their cells to the board map */
508                for (i = 0; i < game->fallingBlock.size; ++i) {
509                    for (j = 0; j < game->fallingBlock.size; ++j) {
510                        if (game->fallingBlock.cells[i][j] != EMPTY_CELL) {
511                            game->map[game->fallingBlock.x + i][game->fallingBlock.y + j]
512                                    = game->fallingBlock.cells[i][j];
513                        }
514                    }
515                }
516
517                /* Check if the landing tetromino has created full rows */
518                numFilledRows = 0;
519                for (j = 1; j < BOARD_HEIGHT; ++j) {
520                    hasFullRow = 1;
521                    for (i = 0; i < BOARD_WIDTH; ++i) {
522                        if (game->map[i][j] == EMPTY_CELL) {
523                            hasFullRow = 0;
524                            break;
525                        }
526                    }
527                    /* If we found a full row we need to remove that row from the map
528                     * we do that by just moving all the above rows one row below */
529                    if (hasFullRow) {
530                        for (x = 0; x < BOARD_WIDTH; ++x) {
531                            for (y = j; y > 0; --y) {
532                                game->map[x][y] = game->map[x][y - 1];
533                            }
534                        }
535                        numFilledRows++;    /* increase filled row counter */
536                    }
537                }
538
539                /* Update game statistics */
540                if (numFilledRows) {
541                    onFilledRows(game, numFilledRows);
542                }
543                game->stats.totalPieces++;
544                game->stats.pieces[game->fallingBlock.type]++;
545               
546                /* Use preview tetromino as falling tetromino.
547                 * Copy preview tetramino for falling tetramino */
548                for (i = 0; i < 4; ++i) {
549                    for (j = 0; j < 4; ++j) {
550                        game->fallingBlock.cells[i][j] = game->nextBlock.cells[i][j];
551                    }
552                }
553                game->fallingBlock.size = game->nextBlock.size;
554                game->fallingBlock.type = game->nextBlock.type;
555
556                /* Reset position */
557                game->fallingBlock.y = 0;
558                game->fallingBlock.x = (BOARD_WIDTH - game->fallingBlock.size) / 2;
559
560                /* Create next preview tetromino */
561                setTetramino(rand() % 7, &game->nextBlock);
562            }
563        }
564    }
565    else {
566        /* There are no collisions, just move the tetramino */
567        game->fallingBlock.x += x;
568        game->fallingBlock.y += y;
569    }
570}
571
572/* Hard drop */
573static void dropTetramino(StcGame *game) {
574   int y;
575   y = 1;
576   /* Calculate number of cells to drop */
577   while (!checkCollision(game, 0, y)) {
578       y++;
579   }
580   moveTetramino(game, 0, y - 1);
581}
582
583/*
584 * Main function game called every frame
585 */
586void gameUpdate(StcGame *game) {
587    long sysTime;
588    /* Read user input */
589    platformReadInput(game);
590
591    /* Update game state */
592    if (game->isOver) {
593               
594                if (game->stats.score > game->stats.high) {
595                        game->stats.high = game->stats.score;
596                        FILE * f;
597                        long buf;
598                        buf = game->stats.score;
599
600                        mkdir_if_not_exist("A/CHDK/GAMES");
601                        f = fopen ( "A/CHDK/GAMES/TETRIS.SCO" , "wb" );
602                        fwrite (&buf , 1 , sizeof(buf) , f );
603                        fclose (f);
604                }
605                       
606               
607        //if (game->events & EVENT_RESTART) {
608                if (game->events & EVENT_PAUSE) {
609                   
610                        //TurnOnBackLight();
611                       
612            game->isOver = 0;
613                        startGame(game);
614                       
615        }
616    }
617    else {
618        sysTime = platformGetSystemTime();
619
620        /* Always handle pause event */
621        if (game->events & EVENT_PAUSE) {
622            game->isPaused = !game->isPaused;
623            game->events = EVENT_NONE;
624        }
625
626        /* Check if the game is paused */
627        if (game->isPaused) {
628            /* We achieve the effect of pausing the game
629             * adding the last frame duration to lastFallTime */
630            game->lastFallTime += (sysTime - game->systemTime);
631        }
632        else {
633            if (game->events != EVENT_NONE) {
634                if (game->events & EVENT_SHOW_NEXT) {
635                    game->showPreview = !game->showPreview;
636                }
637                if (game->events & EVENT_DROP) {
638                    dropTetramino(game);
639                }
640                if (game->events & EVENT_ROTATE_CW) {
641                    rotateTetramino(game, 1);
642                }
643                if (game->events & EVENT_MOVE_RIGHT) {
644                    moveTetramino(game, 1, 0);
645                }
646                else if (game->events & EVENT_MOVE_LEFT) {
647                    moveTetramino(game, -1, 0);
648                }
649                if (game->events & EVENT_MOVE_DOWN) {
650                    moveTetramino(game, 0, 1);
651                }
652                game->events = EVENT_NONE;
653            }
654            /* Check if it's time to move downwards the falling tetromino */
655            if (sysTime - game->lastFallTime >= game->delay) {
656                moveTetramino(game, 0, 1);
657                game->lastFallTime = sysTime;
658            }
659        }
660        game->systemTime = sysTime;
661    }
662    /* Draw game state */
663    platformRenderGame(game);
664}
665
666void gui_tetris_init(){
667    draw_filled_rect(camera_info.ts_button_border+0,0,screen_width-camera_info.ts_button_border,screen_height, TETRIS_COLOR_BG);
668    draw_rect(camera_info.ts_button_border+BOARD_X-1,BOARD_Y-1,camera_info.ts_button_border+BOARD_WIDTH*TILE_SIZE+10,BOARD_HEIGHT*TILE_SIZE+10, COLOR_BLACK);
669    game = createGame();
670    gameInit(game);
671 
672    long buf;
673    FILE *f;   
674
675    f=fopen("A/CHDK/GAMES/TETRIS.SCO","rb");
676    if(!f) {
677        game->stats.high = 0;
678    } else {
679   
680    fread( &buf, 1, sizeof( buf ), f );
681    game->stats.high = buf;
682   
683    }
684
685    fclose (f);
686    startGame(game);
687}
688
689void gui_tetris_draw(){
690  gameUpdate(game);
691}
692
693
694void gui_tetris_kbd_process() {
695        switch ( kbd_get_autoclicked_key() )
696        {
697            case KEY_UP:
698            if ((game->isPaused) || (game->isOver)) {
699                TurnOnBackLight();
700            } else { TurnOffBackLight(); }
701                game->events |= EVENT_PAUSE;
702                break;
703            case KEY_LEFT:
704                game->events |= EVENT_MOVE_LEFT;
705                break;
706            case KEY_RIGHT:
707                game->events |= EVENT_MOVE_RIGHT;
708                break;
709            case KEY_DOWN:
710                game->events |= EVENT_MOVE_DOWN;
711                break;
712            //case KEY_SET:
713            //game->events |= EVENT_RESTART;
714            //break;
715            case KEY_DISPLAY:
716            case KEY_ERASE:
717            case KEY_SET:
718                game->events |= EVENT_ROTATE_CW;
719                break;
720            default:
721                break;
722        }
723}
724
725extern int module_idx;
726
727void gui_module_menu_kbd_process() {
728        gui_default_kbd_process_menu_btn();
729        module_async_unload(module_idx);
730}
731
732// =========  MODULE INIT =================
733#include "module_load.h"
734int module_idx=-1;
735
736/***************** BEGIN OF AUXILARY PART *********************
737  ATTENTION: DO NOT REMOVE OR CHANGE SIGNATURES IN THIS SECTION
738 **************************************************************/
739
740void* MODULE_EXPORT_LIST[] = {
741        /* 0 */ (void*)EXPORTLIST_MAGIC_NUMBER,
742        /* 1 */ (void*)0
743                };
744
745
746//---------------------------------------------------------
747// PURPOSE:   Bind module symbols with chdk.
748//              Required function
749// PARAMETERS: pointer to chdk list of export
750// RETURN VALUE: 1 error, 0 ok
751//---------------------------------------------------------
752int _module_loader( void** chdk_export_list )
753{
754  if ( (unsigned int)chdk_export_list[0] != EXPORTLIST_MAGIC_NUMBER )
755     return 1;
756
757
758  return 0;
759}
760
761
762
763//---------------------------------------------------------
764// PURPOSE: Finalize module operations (close allocs, etc)
765// RETURN VALUE: 0-ok, 1-fail
766//---------------------------------------------------------
767int _module_unloader()
768{
769        GUI_MODE_TETRIS.magicnum = 0;   //sanity clean to prevent accidentaly assign/restore guimode to unloaded module
770 
771    deleteGame(game);
772
773    return 0;
774}
775
776
777//---------------------------------------------------------
778// PURPOSE: Default action for simple modules (direct run)
779// NOTE: Please comment this function if no default action and this library module
780//---------------------------------------------------------
781int _module_run(int moduleidx, int argn, int* arguments)
782{
783  module_idx=moduleidx;
784
785  gui_set_mode ((unsigned int)&GUI_MODE_TETRIS);
786  gui_tetris_init();
787
788  return 0;
789}
790
791
792/******************** Module Information structure ******************/
793
794struct ModuleInfo _module_info = {      MODULEINFO_V1_MAGICNUM,
795                                                                        sizeof(struct ModuleInfo),
796
797                                                                        ANY_CHDK_BRANCH, 0,                     // Requirements of CHDK version
798                                                                        ANY_PLATFORM_ALLOWED,           // Specify platform dependency
799                                                                        0,                                                      // flag
800                                                                        (int32_t)"Tetris",                      // Module name
801                                                                        1, 0,                                           // Module version
802                                                                        (int32_t)"Game"
803                                                                 };
804
805/*************** END OF AUXILARY PART *******************/
Note: See TracBrowser for help on using the repository browser.