3 Tetris for Sherman's aquarium by Jonas Aaberg <cja@gmx.net>
9 On their spare time, some reads a book, some goes shopping,
10 some do sports, some spends time with friends, and one
11 sits programming yet another tetris version and listens to
14 Strange world, isn't it?
26 #include <gdk/gdkkeysyms.h>
38 static int pieces[PIECES][4][2] = {
39 { {0, 1}, {1, 1}, {2, 1}, {3, 1} },
40 { {0, 1}, {1, 1}, {2, 1}, {2, 2} },
41 { {0, 2}, {1, 2}, {2, 2}, {2, 1} },
42 { {0, 2}, {1, 1}, {1, 2}, {2, 2} },
43 { {0, 2}, {1, 2}, {1, 1}, {2, 1} },
44 { {0, 1}, {1, 1}, {1, 2}, {2, 2} },
45 { {1, 1}, {2, 1}, {1, 2}, {2, 2} }
51 static Tetris_highscore_table highscores[11];
52 static Tetris_settings tetris_settings;
56 static int curr_piece_num;
57 static int next_piece_num;
59 static int location[2];
60 static int curr_piece[4][2];
61 static int gameover, firsttime;
62 static int show_highscore_upper;
64 static SA_Image tetris_pieces, tetris_figures, tetris_figures2;
65 static SA_Image tetris_status, tetris_gameover;
69 static int has_highscore, use_font2;
73 static unsigned char* tetris_background;
75 static int score, level, lines;
76 static int horizontal;
78 Tetris_highscore_table *tetris_get_highscore_table_ptr(void)
83 Tetris_settings *tetris_get_settings_ptr(void)
85 return &tetris_settings;
88 void prepare_tetris_background()
93 ad= aquarium_get_settings_ptr();
95 //printf("prepare tetris background\n");
97 tetris_background = g_malloc0(ad->ymax * ad->xmax * 4);
100 for(y = 0; y < ad->ymax; y++){
101 ypos = y * ad->xmax * 4;
102 for(x = 0; x < ad->xmax; x++){
103 if((y == 0 || y == ((board_y) * tetris_pieces.height + 1))
104 && x <= (board_x * (tetris_pieces.width))){
108 } else if (x == (board_x * (tetris_pieces.width)) &&
109 y >= 0 && y < (board_y) * tetris_pieces.height + 1){
118 tetris_background[ypos + x * 4 + 0] = R;
119 tetris_background[ypos + x * 4 + 1] = G;
120 tetris_background[ypos + x * 4 + 2] = B;
121 tetris_background[ypos + x * 4 + 3] = 0xff;
127 for(y = 0; y < ad->ymax; y++){
128 ypos = y * ad->xmax * 4;
129 for(x = 0; x < ad->xmax; x++){
130 if((x == 2 || x == ((board_x + 1) * tetris_pieces.width - 1))
131 && y <= (board_y * (tetris_pieces.height))){
135 } else if (y == (board_y * (tetris_pieces.height)) &&
136 x >= 2 && x < (board_x + 1) * tetris_pieces.width){
147 tetris_background[ypos + x * 4 + 0] = R;
148 tetris_background[ypos + x * 4 + 1] = G;
149 tetris_background[ypos + x * 4 + 2] = B;
150 tetris_background[ypos + x * 4 + 3] = 0xff;
158 void tetris_exit(void)
160 //printf("tetris exit\n");
163 if(tetris_background != NULL)
164 g_free(tetris_background);
167 tetris_background = NULL;
170 void tetris_restart(void)
178 // printf("tetris restart\n");
180 ad = aquarium_get_settings_ptr();
182 //printf("xmax %d ymax %d\n", ad->xmax, ad->ymax);
184 board_x = (ad->xmax - 24) / tetris_pieces.width;
185 board_y = (ad->ymax - 2) / tetris_pieces.height;
187 if(tetris_settings.size_limit){
188 if(board_x > tetris_settings.width)
189 board_x = tetris_settings.width;
191 if(board_y > tetris_settings.height)
192 board_y = tetris_settings.height;
198 //printf("Board_x %d, board_y %d\n", board_x, board_y);
200 if(2 * ad->xmax / 3 > ad->ymax){
214 //printf("Board_x %d, board_y %d\n", board_x, board_y);
217 if(gai_load_int_with_default("tetris/board_x", -1) == board_x &&
218 gai_load_int_with_default("tetris/board_y", -1) == board_y && firsttime){
219 board = (int *)gai_load_raw_data("tetris/board", NULL);
222 if(board == NULL && death){
223 //printf("first time or die\n");
224 board = g_malloc0(board_x * board_y * sizeof(int));
230 location[x] = (tbx - 4) / 2 + horizontal;
232 next_piece_num = g_rand_int_range(ad->rnd, 0, PIECES);
233 curr_piece_num = g_rand_int_range(ad->rnd, 0, PIECES);
235 for(i = 0; i < 4; i++){
236 curr_piece[i][x] = pieces[curr_piece_num][i][X];
237 curr_piece[i][y] = pieces[curr_piece_num][i][Y];
242 //printf("load game over\n");
244 board = g_malloc0(board_x * board_y * sizeof(int));
245 gameover = gai_load_int_with_default("tetris/gameover", 0);
246 score = gai_load_int_with_default("tetris/score", 0);
247 lines = gai_load_int_with_default("tetris/lines", 0);
248 level = gai_load_int_with_default("tetris/level", 1);
249 location[x] = gai_load_int_with_default("tetris/location_x", (tbx - 4) / 2 + horizontal);
250 location[y] = gai_load_int_with_default("tetris/location_y", -4);
251 next_piece_num = gai_load_int_with_default("tetris/next_piece_num", g_rand_int_range(ad->rnd, 0, PIECES));
252 curr_piece_num = gai_load_int_with_default("tetris/curr_piece_num", g_rand_int_range(ad->rnd, 0, PIECES));
253 delay = gai_load_int_with_default("tetris/delay", 16);
254 curr_piece[0][x] = gai_load_int_with_default("tetris/curr_piece0X", 0);
255 curr_piece[0][y] = gai_load_int_with_default("tetris/curr_piece0Y", 0);
256 curr_piece[1][x] = gai_load_int_with_default("tetris/curr_piece1X", 0);
257 curr_piece[1][y] = gai_load_int_with_default("tetris/curr_piece1Y", 0);
258 curr_piece[2][x] = gai_load_int_with_default("tetris/curr_piece2X", 0);
259 curr_piece[2][y] = gai_load_int_with_default("tetris/curr_piece2Y", 0);
260 curr_piece[3][x] = gai_load_int_with_default("tetris/curr_piece3X", 0);
261 curr_piece[3][y] = gai_load_int_with_default("tetris/curr_piece3Y", 0);
266 prepare_tetris_background();
271 show_highscore_upper = 0;
273 has_highscore = 1979;
277 void tetris_init(void)
281 //printf("tetris init\n");
282 tetris_load_highscores();
284 load_image("tetris_pieces.png",
288 load_image("tetris_figures.png",
292 load_image("tetris_figures2.png",
297 load_image("tetris_status.png",
302 load_image("tetris_gameover.png",
310 void check_highscore(void)
314 for(i = 0; i < 10; i++){
315 if(highscores[i].score<score){
316 for(j = 9; j > i; j--){
317 highscores[i].score = highscores[j - 1].score;
318 highscores[i].level = highscores[j - 1].level;
319 highscores[i].lines = highscores[j - 1].lines;
322 highscores[i].score = score;
323 highscores[i].level = level;
324 highscores[i].lines = lines;
329 tetris_save_highscores();
333 void drawnextpiece(void)
338 if(!tetris_settings.show_next)
340 ad = aquarium_get_settings_ptr();
342 x = ad->xmax - (tetris_pieces.width * 4 + 1);
346 for(i = 0; i < 4; i++){
347 over_draw(x + tetris_pieces.width * pieces[next_piece_num][i][X],
348 y + tetris_pieces.height * pieces[next_piece_num][i][Y],
351 tetris_pieces.height,
352 tetris_pieces.image);
356 void drawfigures(int x,int y, int num)
361 figures = &tetris_figures2;
363 figures = &tetris_figures;
374 over_draw(x + figures->width, y,
380 over_draw(x + figures->width * 2,y,
388 void drawstatus(void)
394 ad = aquarium_get_settings_ptr();
396 x = ad->xmax-tetris_figures.width * 3 - 2;
398 dy = tetris_figures.height + 3;
400 drawfigures(x, y, score);
401 drawfigures(x, y + dy, level);
402 drawfigures(x, y + 2 * dy, lines);
406 void draw_gameover(void)
409 ad = aquarium_get_settings_ptr();
413 over_draw((ad->xmax-tetris_gameover.width) / 2,
414 (ad->ymax-tetris_gameover.height) / 2,
416 tetris_gameover.width,
417 tetris_gameover.height,
418 tetris_gameover.image);
421 void draw_finalscore(void)
427 //printf("draw_finalscore\n");
429 ad = aquarium_get_settings_ptr();
431 for(y = 0; y < ad->ymax; y++){
432 ypos = y * ad->xmax * 4;
433 for(x = 0; x <ad->xmax; x++){
434 tetris_background[ypos+x * 4 + 0] = 0;
435 tetris_background[ypos+x * 4 + 1] = 0;
436 tetris_background[ypos+x * 4 + 2] = 0;
437 tetris_background[ypos+x * 4 + 3] = 0xff;
440 over_draw(0, 0, 0, ad->xmax,ad->ymax,tetris_background);
442 x = (ad->xmax-tetris_status.width) / 2;
443 y = (ad->ymax-3 * (tetris_figures.height + tetris_status.height)) / 2;
444 dy = tetris_figures.height + tetris_status.height;
445 over_draw(x, y , SCORE, tetris_status.width, tetris_status.height,
446 tetris_status.image);
448 over_draw(x, y + dy, LEVEL, tetris_status.width, tetris_status.height,
449 tetris_status.image);
451 over_draw(x, y + 2 * dy, LINES, tetris_status.width, tetris_status.height,
452 tetris_status.image);
454 drawfigures(x + tetris_status.width, y + tetris_status.height, score);
455 drawfigures(x + tetris_status.width, y + tetris_status.height + dy, level);
456 drawfigures(x + tetris_status.width, y + tetris_status.height + 2 * dy, lines);
461 void draw_highscorelist(void)
463 int x, y, ypos, i, dx, sx;
467 ad = aquarium_get_settings_ptr();
468 //printf("darw_highscore\n");
470 for(y = 0; y < ad->ymax; y++){
471 ypos = y * ad->xmax * 4;
472 for(x = 0; x < ad->xmax; x++){
473 tetris_background[ypos + x * 4 + 0] = 0;
474 tetris_background[ypos + x * 4 + 1] = 0;
475 tetris_background[ypos + x * 4 + 2] = 0;
476 tetris_background[ypos + x * 4 + 3] = 0xff;
479 over_draw(0, 0, 0, ad->xmax, ad->ymax,tetris_background);
481 over_draw((ad->xmax - tetris_status.width) / 2, 1, TOP10, tetris_status.width,
482 tetris_status.height, tetris_status.image);
484 sx = -tetris_figures.width;
486 dx = ((ad->xmax-sx) - 4 * 3 * tetris_figures.width) / 4 + 3 * tetris_figures.width;
488 if(ad->ymax > (tetris_status.height + 10 * tetris_figures.height)){
489 for(i = 0; i < 10; i++){
490 if(i == has_highscore)
495 8 + tetris_status.height + i * tetris_figures.height,
499 8 + tetris_status.height + i * tetris_figures.height,
500 highscores[i].score);
502 drawfigures(sx + 2 * dx,
503 8 + tetris_status.height + i * tetris_figures.height,
504 highscores[i].lines);
506 drawfigures(sx + 3 * dx,
507 8 + tetris_status.height + i * tetris_figures.height,
508 highscores[i].level);
513 for(i = 5 * show_highscore_upper; i < (5 + 5 * show_highscore_upper); i++){
514 if(i == has_highscore)
520 8 + tetris_status.height + (i - 5 * show_highscore_upper) * tetris_figures.height, i + 1);
523 8 + tetris_status.height + (i - 5 * show_highscore_upper) * tetris_figures.height, highscores[i].score);
524 drawfigures(sx + 2 * dx,
525 8 + tetris_status.height + (i - 5 * show_highscore_upper) * tetris_figures.height, highscores[i].lines);
526 drawfigures(sx + 3 * dx,
527 8 + tetris_status.height + (i - 5 * show_highscore_upper) * tetris_figures.height, highscores[i].level);
531 show_highscore_upper = !show_highscore_upper;
540 void drawboardonscreen(void)
546 ad = aquarium_get_settings_ptr();
547 // printf("drawongscreen %d\n", gameover);
554 over_draw(0 ,0 ,0, ad->xmax, ad->ymax, tetris_background);
555 //printf("%d %d\n", board_x, board_y);
556 for(y = 0; y < board_y; y++){
557 for(x = 0;x < board_x; x++){
559 if(board[y * board_x + x] != 0)
560 over_draw(x * tetris_pieces.width + 3 * !horizontal,
561 y * tetris_pieces.height + horizontal,
562 board[y * board_x + x] - 1,
564 tetris_pieces.height,
565 tetris_pieces.image);
568 //printf("for done\n");
581 draw_highscorelist();
590 void manageboard(int piece[4][2], int location[2], int colour)
594 // printf("manageboard\n");
596 for(i = 0; i < 4; i++){
597 if(location[X] + piece[i][X] >= 0 && location[Y] + piece[i][Y] >=0)
598 board[(location[X] + piece[i][X]) + (location[Y] + piece[i][Y]) * board_x]
601 // printf("manage board done\n");
604 void removefromboard(int piece[4][2],int location[2])
606 manageboard(piece, location, 0);
610 void drawonboard(int piece[4][2],int location[2])
612 manageboard(piece, location, curr_piece_num + 1);
619 1 = Landed upon piece.
620 2 = Tried to move outside X wise.
621 3 = Landed upon piece and tried to move too far X wise.
622 4 = Landed on bottom.
623 5 = Landed on bottom & piece.
624 6 = landed on bottom & X outside.
625 7 = landed on bottom & X outside & piece.
628 int movepiece(int piece[4][2],int new_location[2])
636 // printf("movepiece\n");
653 for(i = 0;i < 4; i++){
655 if(new_location[x] + piece[i][x] >= tbx || new_location[x] + piece[i][x]<0){
660 if(new_location[y] + piece[i][y] == tby){
664 /* Upon other pieces */
665 if(new_location[y] + piece[i][y] >= 0)
666 if(board[(new_location[X] + piece[i][X]) + (new_location[Y] + piece[i][Y]) * board_x]!=0)
673 void rotatepiece(int piece[4][2], int location[2])
675 int tmp_piece[4][2], i;
677 // printf("rotate piece\n");
679 for(i= 0 ; i < 4; i++){
680 tmp_piece[i][X] = 3 - piece[i][Y];
681 tmp_piece[i][Y] = piece[i][X];
684 if(movepiece(tmp_piece, location) == 0){
685 for(i = 0; i < 4; i++){
686 piece[i][X] = tmp_piece[i][X];
687 piece[i][Y] = tmp_piece[i][Y];
693 void removeline(int line)
696 // printf("removeline\n");
699 for(x = line; x > 0; x--){
700 for(y = 0; y < board_y; y++){
701 board[x + y * board_x] = board[(x - 1) + y * board_x];
704 for(y = 0; y < board_y; y++)
705 board[y * board_x] = 0;
708 for(y = line; y > 0; y--){
709 for(x = 0; x < board_x; x++){
710 board[x + y * board_x] = board[x + (y - 1) * board_x];
713 for(x = 0; x < board_x; x++)
720 void checkforline(void)
723 int gotline = 0, tot_lines = 0;
725 int points[] = {0, 1 , 3 , 5, 9};
727 // printf("checkforline\n");
730 for(x = 0; x < board_x; x++){
732 for(y = 0; y < board_y; y++){
733 if(board[x + y * board_x] == 0)
745 for(y = 0; y < board_y; y++){
747 for(x = 0; x < board_x; x++){
748 if(board[x + y * board_x] == 0) gotline = 0;
762 score += points[tot_lines];
764 if(((lines - tot_lines) / 10) < lines / 10){
766 if(delay > 0) delay--;
768 /* printf("Score %d Lines %d Level %d\n",score,lines,level);*/
773 void tetris_update(void)
779 ad = aquarium_get_settings_ptr();
782 if(gameover != 0 || delay != counter){
790 removefromboard(curr_piece, location);
805 answer = movepiece(curr_piece, location);
808 drawonboard(curr_piece, location);
810 if((answer & 4) == 4 || (answer & 1) == 1){
814 drawonboard(curr_piece, location);
818 for(i = 0; i < 4; i++){
819 if((curr_piece[i][y] + location[y]) < 0)
825 location[x] = (tbx - 4) / 2 + horizontal;
827 for(i = 0; i < 4; i++){
828 curr_piece[i][x] = pieces[next_piece_num][i][X];
829 curr_piece[i][y] = pieces[next_piece_num][i][Y];
831 curr_piece_num = next_piece_num;
832 next_piece_num = g_rand_int_range(ad->rnd, 0, PIECES);
834 answer = movepiece(curr_piece, location);
835 if(answer != 0) gameover = 1;
849 void tetris_keypress(int key)
853 removefromboard(curr_piece, location);
872 rotatepiece(curr_piece, location);
876 if(movepiece(curr_piece, location)!=0)
882 if(movepiece(curr_piece, location)!=0)
890 if(movepiece(curr_piece, location)!=0)
898 drawonboard(curr_piece, location);
902 void tetris_joystick(GaiFlagsJoystick js)
905 if(js & GAI_JOYSTICK_LEFT)
907 if(js & GAI_JOYSTICK_RIGHT)
909 if(js & GAI_JOYSTICK_UP)
911 if(js & GAI_JOYSTICK_BUTTON_A)
913 if(js & GAI_JOYSTICK_BUTTON_B)
915 if(js & GAI_JOYSTICK_DOWN)
917 tetris_keypress(key);
921 void tetris_start(void)
923 //printf("tetris start\n");
926 void tetris_end(void)
930 //printf("tetris end\n");
932 ad = aquarium_get_settings_ptr();
934 if(2 * ad->xmax / 3 > ad->ymax){
947 //printf("Board_x %d, board_y %d\n", board_x, board_y);
949 gai_save_int("tetris/board_x", board_x);
950 gai_save_int("tetris/board_y", board_y);
951 gai_save_int("tetris/gameover", gameover);
952 gai_save_int("tetris/score", score);
953 gai_save_int("tetris/lines", lines);
954 gai_save_int("tetris/level", level);
955 gai_save_int("tetris/location_x", location[x]);
956 gai_save_int("tetris/location_y", location[y]);
957 gai_save_int("tetris/next_piece_num", next_piece_num);
958 gai_save_int("tetris/curr_piece_num", curr_piece_num);
959 gai_save_int("tetris/delay", delay);
960 gai_save_raw_data("tetris/board", (unsigned char *)board, board_y * board_x * sizeof(int));
962 gai_save_int("tetris/curr_piece0X", curr_piece[0][x]);
963 gai_save_int("tetris/curr_piece0Y", curr_piece[0][y]);
964 gai_save_int("tetris/curr_piece1X", curr_piece[1][x]);
965 gai_save_int("tetris/curr_piece1Y", curr_piece[1][y]);
966 gai_save_int("tetris/curr_piece2X", curr_piece[2][x]);
967 gai_save_int("tetris/curr_piece2Y", curr_piece[2][y]);
968 gai_save_int("tetris/curr_piece3X", curr_piece[3][x]);
969 gai_save_int("tetris/curr_piece3Y", curr_piece[3][y]);