diff options
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | dat/texts.yaml | 18 | ||||
-rw-r--r-- | include/common.h | 3 | ||||
-rw-r--r-- | include/tet_conf.h | 1 | ||||
-rw-r--r-- | src/engine.c | 173 | ||||
-rw-r--r-- | src/target/tetris.c | 1 |
6 files changed, 156 insertions, 41 deletions
@@ -62,6 +62,7 @@ Windows compilation flow currently is unsupported, but sometimes I put Windows b - [x] [Wall kick](https://tetris.wiki/Wall_kick). Implemented order: left wall, right wall, floor - [x] Hard drop - [x] Phantom shape +- [x] Game Over screen - Table of records - Settings menu with external `config.yml` file which allows - Change key bindings diff --git a/dat/texts.yaml b/dat/texts.yaml index 6f8f480..d24f3bd 100644 --- a/dat/texts.yaml +++ b/dat/texts.yaml @@ -68,3 +68,21 @@ size: 36 x: 60 y: 188 + +- + type: "title" + scene: "game_over" + text: "Game Over" + font: "Arial" + size: 36 + x: 42 + y: 188 + +- + type: "press_key" + scene: "game_over" + text: "press any key" + font: "Arial" + size: 24 + x: 57 + y: 240 diff --git a/include/common.h b/include/common.h index 76293c5..2273e4d 100644 --- a/include/common.h +++ b/include/common.h @@ -2,10 +2,13 @@ struct game { size_t level; int started; int paused; + int over_wait; + int over; int scoreCurrent; int moveLatency; int lines; sfClock *gameTick; + sfClock *over_wait_tick; sfClock *putTick; sfClock *mTick; sfClock *repPushDown; // repeat latency when hold Down arrow diff --git a/include/tet_conf.h b/include/tet_conf.h index 33a637f..08f8079 100644 --- a/include/tet_conf.h +++ b/include/tet_conf.h @@ -12,6 +12,7 @@ #define ICOLOR {94, 141, 135, 255} #define TCOLOR {133, 103, 143, 255} +#define GAMEOVERWAIT 700000 // 0.7 second #define moveRepeatLatency1 150000 // microseconds, only for left-right arrows, // first repeat move when long push #define moveRepeatLatency2 30000 // microseconds, for Left, Right and Down diff --git a/src/engine.c b/src/engine.c index 46507c1..41bdc4a 100644 --- a/src/engine.c +++ b/src/engine.c @@ -5,10 +5,18 @@ * the main tetris module (tetris.c), see engine.h. * * The game has simple state machine: + * legend: [transition]--> STATE -->[transition]--> STATE * - * Menu --[start]-> Started --[pause]-> Paused - * ^ | ^ | - * +---[gameover]---+ +---[unpause]----+ + * (start) + * | + * [init] + * | +------------------+ +------[unpause]<------+ + * V | V V | + * +-[menu]-> MENU ----[game_start]--> GAME -->[game_over_wait]----+ + * | | | | | | + * | +----[put_shape]---+ +-->[pause]--> PAUSE --+ | + * | | + * +----- GAME_OVER <-----[game_over]<----- GAME_OVER_WAIT <-------+ * * Transitions between states are implemented in a distinct functions. Each * transition function name starts with "transition_". State functions has names @@ -42,6 +50,7 @@ #define HARDDROP (1 << 5) #define PAUSE (1 << 6) #define LEFTHOLD (1 << 7) +#define GAMEOVER (1 << 8) int level_move_latency[] = { L00LATENCY, @@ -88,7 +97,7 @@ int rmlines_score[] = { extern struct game game; extern struct field fld, nxt; extern struct idlist *texts; -char arrKeys = 0; +int keys = 0; static void render_score_value(void *obj) { @@ -175,6 +184,34 @@ static void show_pause_text(void *obj) text->attr &= ~TXT_ATTR_INVISIBLE; } +static void hide_game_over_text(void *obj) +{ + struct text *text = obj; + if (!strcmp(text->scene, "game_over")) + text->attr |= TXT_ATTR_INVISIBLE; +} + +static void show_game_over_title_text(void *obj) +{ + struct text *text = obj; + if (!strcmp(text->scene, "game_over") && !strcmp(text->type, "title")) + text->attr &= ~TXT_ATTR_INVISIBLE; +} + +static void show_game_over_press_any_key_text(void *obj) +{ + struct text *text = obj; + if (!strcmp(text->scene, "game_over") && !strcmp(text->type, "press_key")) + text->attr &= ~TXT_ATTR_INVISIBLE; +} + +static void update_game_over_text(void *obj) +{ + struct text *text = obj; + if (!strcmp(text->scene, "game_over")) + painter_update_text(text->id, text); +} + static void update_menu_text(void *obj) { struct text *text = obj; @@ -189,8 +226,9 @@ static void update_game_text(void *obj) painter_update_text(text->id, text); } -static void transition_game_over() +static void transition_menu() { + game.over = 0; game.started = 0; game.scoreCurrent = 0; game.level = 1; @@ -205,12 +243,30 @@ static void transition_game_over() field_fill_random(&fld); painter_update_field(fld.id, &fld); + list_foreach(texts, hide_game_over_text); list_foreach(texts, show_menu_text); list_foreach(texts, hide_game_text); + list_foreach(texts, update_game_over_text); list_foreach(texts, update_menu_text); list_foreach(texts, update_game_text); } +static void transition_game_over_wait() +{ + game.over_wait = 1; + sfClock_restart(game.over_wait_tick); + list_foreach(texts, show_game_over_title_text); + list_foreach(texts, update_game_over_text); +} + +static void transition_game_over() +{ + game.over_wait = 0; + game.over = 1; + list_foreach(texts, show_game_over_press_any_key_text); + list_foreach(texts, update_game_over_text); +} + static void project_ghost_shape(struct field *fld, size_t idreal, size_t idghost) { fld->shape[idghost].t = fld->shape[idreal].t; @@ -272,7 +328,7 @@ static void game_tick() } if (sfClock_getElapsedTime(game.putTick).microseconds >= PUT_LATENCY) { if (field_shape_out_of_bounds(&fld, &fld.shape[ACTIVE_SHAPE_INDEX])) - transition_game_over(); + transition_game_over_wait(); else transition_put_shape(); sfClock_restart(game.putTick); @@ -296,7 +352,7 @@ static void signal_harddrop() while (field_move_shape_down(&fld, 1)) game.scoreCurrent++; if (field_shape_out_of_bounds(&fld, &fld.shape[ACTIVE_SHAPE_INDEX])) - transition_game_over(); + transition_game_over_wait(); else transition_put_shape(); sfClock_restart(game.gameTick); @@ -341,86 +397,86 @@ static void game_keys() { /* PAUSE */ if (sfKeyboard_isKeyPressed(sfKeyP)) { - if (!(arrKeys & PAUSE)) { - arrKeys = arrKeys | PAUSE; + if (!(keys & PAUSE)) { + keys = keys | PAUSE; signal_pause(); } } else { - arrKeys = arrKeys & ~PAUSE; + keys = keys & ~PAUSE; } /* UP */ if (sfKeyboard_isKeyPressed(sfKeyUp)) { - if (!(arrKeys & UP)) { - arrKeys = arrKeys | UP; + if (!(keys & UP)) { + keys = keys | UP; signal_up(); } } else { - arrKeys = arrKeys & ~UP; + keys = keys & ~UP; } /* HARDDROP */ if (sfKeyboard_isKeyPressed(sfKeySpace)) { - if (!(arrKeys & HARDDROP)) { - arrKeys = arrKeys | HARDDROP; + if (!(keys & HARDDROP)) { + keys = keys | HARDDROP; signal_harddrop(); } } else { - arrKeys = arrKeys & ~HARDDROP; + keys = keys & ~HARDDROP; } /* DOWN */ if (sfKeyboard_isKeyPressed(sfKeyDown)) { - if (!(arrKeys & DOWN)) { - arrKeys = arrKeys | DOWN; + if (!(keys & DOWN)) { + keys = keys | DOWN; signal_down(); sfClock_restart(game.repPushDown); } else { if (sfClock_getElapsedTime(game.repPushDown).microseconds >= moveRepeatLatency2) - arrKeys = arrKeys & ~DOWN; + keys = keys & ~DOWN; } } else { - arrKeys = arrKeys & ~DOWN; + keys = keys & ~DOWN; } /* LEFT */ if (sfKeyboard_isKeyPressed(sfKeyLeft) && !sfKeyboard_isKeyPressed(sfKeyRight)) { - if (!(arrKeys & LEFT)) { - arrKeys = arrKeys | LEFT; + if (!(keys & LEFT)) { + keys = keys | LEFT; signal_left(); sfClock_restart(game.repKeyLeft); - } else if (!(arrKeys & LEFTHOLD)) { + } else if (!(keys & LEFTHOLD)) { if (sfClock_getElapsedTime(game.repKeyLeft).microseconds >= moveRepeatLatency1) { - arrKeys = arrKeys | LEFTHOLD; - arrKeys = arrKeys & ~LEFT; + keys = keys | LEFTHOLD; + keys = keys & ~LEFT; } } else { if (sfClock_getElapsedTime(game.repKeyLeft).microseconds >= moveRepeatLatency2) - arrKeys = arrKeys & ~LEFT; + keys = keys & ~LEFT; } } else { - arrKeys = arrKeys & ~LEFT; - arrKeys = arrKeys & ~LEFTHOLD; + keys = keys & ~LEFT; + keys = keys & ~LEFTHOLD; } /* RIGHT */ if (sfKeyboard_isKeyPressed(sfKeyRight) && !sfKeyboard_isKeyPressed(sfKeyLeft)) { - if (!(arrKeys & RIGHT)) { - arrKeys = arrKeys | RIGHT; + if (!(keys & RIGHT)) { + keys = keys | RIGHT; signal_right(); sfClock_restart(game.repKeyRight); - } else if (!(arrKeys & RIGHTHOLD)) { + } else if (!(keys & RIGHTHOLD)) { if (sfClock_getElapsedTime(game.repKeyRight).microseconds >= moveRepeatLatency1) { - arrKeys = arrKeys | RIGHTHOLD; - arrKeys = arrKeys & ~RIGHT; + keys = keys | RIGHTHOLD; + keys = keys & ~RIGHT; } } else { if (sfClock_getElapsedTime(game.repKeyRight).microseconds >= moveRepeatLatency2) - arrKeys = arrKeys & ~RIGHT; + keys = keys & ~RIGHT; } } else { - arrKeys = arrKeys & ~RIGHT; - arrKeys = arrKeys & ~RIGHTHOLD; + keys = keys & ~RIGHT; + keys = keys & ~RIGHTHOLD; } } @@ -428,12 +484,12 @@ static void pause_keys() { /* PAUSE */ if (sfKeyboard_isKeyPressed(sfKeyP)) { - if (!(arrKeys & PAUSE)) { - arrKeys = arrKeys | PAUSE; + if (!(keys & PAUSE)) { + keys = keys | PAUSE; signal_pause(); } } else { - arrKeys = arrKeys & ~PAUSE; + keys = keys & ~PAUSE; } } @@ -448,8 +504,10 @@ void transition_init(void) { list_foreach(texts, show_menu_text); list_foreach(texts, hide_game_text); + list_foreach(texts, hide_game_over_text); list_foreach(texts, update_menu_text); list_foreach(texts, update_game_text); + list_foreach(texts, update_game_over_text); } static void transition_game_start() @@ -478,8 +536,13 @@ static void menu_loop() { if (sfClock_getElapsedTime(game.mTick).microseconds >= basicLatency) menu_tick(); - if (sfKeyboard_isKeyPressed(sfKeyS) == 1) - transition_game_start(); + + if (sfKeyboard_isKeyPressed(sfKeyS)) { + if (!(keys & GAMEOVER)) + transition_game_start(); + } else { + keys = 0; + } } static void game_loop() @@ -494,6 +557,30 @@ static void game_loop() painter_update_field(nxt.id, &nxt); } +static void game_over_wait_loop() +{ + if (sfClock_getElapsedTime(game.over_wait_tick).microseconds > GAMEOVERWAIT) + transition_game_over(); +} + +static void game_over_loop() +{ + int anykey = 0; + + for (int keycode = sfKeyUnknown; keycode < sfKeyCount; keycode++) + if (sfKeyboard_isKeyPressed(keycode)) + anykey = 1; + + if (anykey) { + if (!(keys & GAMEOVER)) { + keys |= GAMEOVER; + transition_menu(); + } + } else { + keys &= ~GAMEOVER; + } +} + static void pause_loop() { pause_keys(); @@ -504,6 +591,10 @@ void main_loop() if (game.started) { if (game.paused) pause_loop(); + else if (game.over_wait) + game_over_wait_loop(); + else if (game.over) + game_over_loop(); else game_loop(); } else { diff --git a/src/target/tetris.c b/src/target/tetris.c index eab3c7d..81b2afc 100644 --- a/src/target/tetris.c +++ b/src/target/tetris.c @@ -48,6 +48,7 @@ int main() { srand(time(NULL)); game.gameTick = sfClock_create(); + game.over_wait_tick = sfClock_create(); game.putTick = sfClock_create(); game.mTick = sfClock_create(); game.repPushDown = sfClock_create(); |