From 2d3a51877ba45ed5a64d2c9acee3d3300f55c5fa Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Sat, 13 Apr 2019 17:12:12 -0400 Subject: general cleanup and add ghost piece for preview --- "core/\\" | 277 +++++++++++++++++++++++++++++++++++++++++++ core/include/cetris.h | 12 +- core/include/matrix.h | 7 +- core/include/types.h | 11 +- core/src/cetris.c | 118 ++++++++++-------- core/src/input.c | 12 +- core/src/matrix.c | 100 ++++++++-------- core/src/test.c | 4 +- frontends/curses/curses_ui.c | 31 +++-- frontends/gl/main.c | 4 +- 10 files changed, 443 insertions(+), 133 deletions(-) create mode 100644 "core/\\" diff --git "a/core/\\" "b/core/\\" new file mode 100644 index 0000000..80e819a --- /dev/null +++ "b/core/\\" @@ -0,0 +1,277 @@ +#include + +#include "matrix.h" +#include "types.h" +#include "cetris.h" + +/* SRS WALL KICK VALUES */ + +// https://tetris.wiki/SRS +static const vec2 srs_wall_kicks[8][5] = { + { {0, 0}, {-1, 0}, {-1,1}, {0,-2}, {-1,-2} }, // 0->R + { {0, 0}, {1, 0}, {1,-1}, {0,2}, {1,2} }, // R->0 + { {0, 0}, {1, 0}, {1,-1}, {0,2}, {1,2} }, // R->2 + { {0, 0}, {-1, 0}, {-1,1}, {0,-2}, {-1,-2} }, // 2->R + { {0, 0}, {1, 0}, {1,1}, {0,-2}, {1,-2} }, // 2->L + { {0, 0}, {-1, 0}, {-1,-1}, {0,2}, {-1,2} }, // L->2 + { {0, 0}, {-1, 0}, {-1,-1}, {0,2}, {-1,2} }, // L->0 + { {0, 0}, {1, 0}, {1,1}, {0,-2}, {1,-2} } // 0->L +}; + +static const vec2 srs_wall_kicks_i[8][5] = { + { {0, 0}, {-2, 0}, {1, 0}, {-2,-1}, {1,2} }, // 0->R + { {0, 0}, {2, 0}, {-1, 0}, {2,1}, {-1,-2} }, // R->0 + { {0, 0}, {-1, 0}, {2, 0}, {-1,2}, {2,-1} }, // R->2 + { {0, 0}, {1, 0}, {-2, 0}, {1,-2}, {-2,1} }, // 2->R + { {0, 0}, {2, 0}, {-1, 0}, {2,1}, {-1,-2} }, // 2->L + { {0, 0}, {-2, 0}, {1, 0}, {-2,-1}, {1,2} }, // L->2 + { {0, 0}, {1, 0}, {-2, 0}, {1,-2}, {-2,1} }, // L->0 + { {0, 0}, {-1, 0}, {2, 0}, {-1,2}, {2,-1} } // 0->L +}; + +/* DEFAULT MATRIX FOR EACH POSSIBLE TETRIMINO */ + +const piece_matrix default_matrices[7] = { + { + { 0, 0, 0, 0 }, + { 0, 1, 1, 0 }, + { 0, 1, 1, 0 }, + { 0, 0, 0, 0 } + }, + + { + { 0, 0, 0, 0 }, + { 1, 1, 1, 1 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 } + }, + + { + { 0, 0, 0, 0 }, + { 0, 1, 1, 0 }, + { 1, 1, 0, 0 }, + { 0, 0, 0, 0 } + }, + + { + { 0, 0, 0, 0 }, + { 1, 1, 0, 0 }, + { 0, 1, 1, 0 }, + { 0, 0, 0, 0 } + }, + + { + { 0, 0, 0, 0 }, + { 0, 0, 1, 0 }, + { 1, 1, 1, 0 }, + { 0, 0, 0, 0 } + }, + + { + { 0, 0, 0, 0 }, + { 1, 0, 0, 0 }, + { 1, 1, 1, 0 }, + { 0, 0, 0, 0 } + }, + + { + { 0, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 1, 1, 1, 0 }, + { 0, 0, 0, 0 } + } +}; + +/* MATRIX MODIFICATION */ + +const vec2 basic_movements[4] = { + {0, 0}, {0, 1}, {1, 0}, {-1, 0} // NONE, DOWN, RIGHT, LEFT +}; + +void move_current(struct cetris_game* g, vec2 offset) { + if (g->game_over) return; +g->current.pos.y += offset.y; g->current.pos.x += offset.x; + + i8 check = check_new_matrix(g, g->current.m); + if (check <= 0) { + g->current.pos.y -= offset.y; + g->current.pos.x -= offset.x; + + if (check == -1 && g->current.lock_tick == 0) { + g->current.lock_tick = g->tick + 30; + } + } + + update_board(g); +} + +i8 overlay_matrix(struct cetris_game* g, piece_matrix m, bool set_board) { + for (i8 y = 0; y < 4; y++) { + for (i8 x = 0; x < 4; x++) { + vec2 r = (vec2){x + g->current.pos.x, y + g->current.pos.y}; + if (r.x > CETRIS_BOARD_X || r.x < 0 || r.y > CETRIS_BOARD_Y) + return 0; + if (m[y][x] && r.y >= 0) { + if (g->board[r.x][r.y].occupied) return -1; + if (set_board) { + g->board[r.x][r.y].occupied = 1; + g->board[r.x][r.y].c = g->current.c; + } + } + } + } + return 1; +} + +void hard_drop(struct cetris_game* g) { + if (g->game_over) return; + + bool drop = false; + u8 drop_count = 0; + while (!drop) { + g->current.pos.y++; + drop_count++; + i8 check = check_new_matrix(g, g->current.m); + if (check <= 0) { + g->current.pos.y--; + drop_count--; + drop = true; + } + } + + g->score += 2 * drop_count; // 2 score for each hard-drop'd cell + + update_board(g); + next_piece(g); +} + +void rotate_matrix(struct cetris_game* g, bool clockwise) { + if (g->game_over) return; + if (g->current.t == O) return; + + rstate next = 0; + u8 wall_kick = 0; + switch (g->current.r) { + case INIT: + if (clockwise) { + next = ONCE_RIGHT; + wall_kick = 0; + } else { + next = ONCE_LEFT; + wall_kick = 7; + } break; + case ONCE_RIGHT: + if (clockwise) { + next = TWICE; + wall_kick = 2; + } else { + next = INIT; + wall_kick = 1; + } break; + case ONCE_LEFT: + if (clockwise) { + next = INIT; + wall_kick = 6; + } else { + next = TWICE; + wall_kick = 5; + } break; + case TWICE: + if (clockwise) { + next = ONCE_LEFT; + wall_kick = 4; + } else { + next = ONCE_RIGHT; + wall_kick = 3; + } break; + } + + piece_matrix m; + memset(m, 0, sizeof(piece_matrix)); + + for (u8 x = 0; x < 4; x++) { + for (u8 y = 0; y < 4; y++) { + if (g->current.m[y][x]) { + u8 new_x = (clockwise) ? 1 - (y - 2) : 1 + (y - 2); + u8 new_y = (clockwise) ? 2 + (x - 1) : 2 - (x - 1); + + if (g->current.t == I) { + if (clockwise) new_y--; + else new_x++; + } + + m[new_y][new_x] = 1; + } + } + } + + vec2 kick; + bool set_current = false; + bool did_kick = false; + for (u8 i = 0; i < 5; i++) { + if (g->current.t == I) { + kick = srs_wall_kicks_i[wall_kick][i]; + } else { + kick = srs_wall_kicks[wall_kick][i]; + } + g->current.pos.x += kick.x; + g->current.pos.y += kick.y; + if (check_new_matrix(g, m) > 0) { + set_current = true; + if (i > 0) did_kick = true; + break; + } else { + g->current.pos.x -= kick.x; + g->current.pos.y -= kick.y; + } + } + + if (set_current) { + memcpy(g->current.m, m, sizeof(piece_matrix)); + + /* check for tspin */ + if (g->current.t == T) { + u8 did_tspin = 1; + for (int i = 0; i < 4; i++) { + g->current.pos.x += basic_movements[i].x; + g->current.pos.y += basic_movements[i].y; + + if (overlay_current_matrix(g, false) == 1) + did_tspin = 0; + + g->current.pos.x -= basic_movements[i].x; + g->current.pos.y -= basic_movements[i].y; + } + + if (did_tspin) { + if (did_kick) g->mini_tspin = 1; + else g->tspin = 1; + } + } + + g->current.r = next; + update_board(g); + } +} + + +/* +i8 check_new_matrix(struct cetris_game* g, piece_matrix m) { + for (u8 x = 0; x < 4; x++) { + for (u8 y = 0; y < 4; y++) { + vec2 r = (vec2){g->current.pos.x + x, g->current.pos.y + y}; + if (m[y][x]) { + if (r.x > CETRIS_BOARD_X - 1 || r.x < 0) + return 0; + + if (r.y > CETRIS_BOARD_Y - 1) + return -1; + + if (g->board[r.x][r.y].occupied && g->board[r.x][r.y].constant) + return -1; + } + } + } + return 1; +} +*/ diff --git a/core/include/cetris.h b/core/include/cetris.h index e41abdf..9e3cf83 100644 --- a/core/include/cetris.h +++ b/core/include/cetris.h @@ -6,14 +6,18 @@ #include "types.h" #define CETRIS_BOARD_X 10 -#define CETRIS_BOARD_Y 43 -#define CETRIS_BOARD_VISABLE 23 +#define CETRIS_BOARD_Y 20 +#define CETRIS_INITIAL_X 3 +#define CETRIS_INITIAL_Y 0 +#define CETRIS_INITIAL_Y_OFFSET 2 +//#define CETRIS_BOARD_VISABLE 21 #define CETRIS_HZ 60 #define CETRIS_DAS_DELAY 11 #define CETRIS_DAS_PERIOD 3 #define CETRIS_DROP_PERIOD 2 #define CETRIS_LINE_CLEAR_DELAY 40 +#define CETRIS_LOCK_DELAY 40 #define CETRIS_WAIT_ON_CLEAR 0 typedef enum { @@ -43,12 +47,14 @@ struct tetrimino { rstate r; color c; piece_matrix m; + u8 ghost_y; vec2 pos; u32 lock_tick; }; typedef struct { bool occupied; + bool ghost; bool constant; u32 remove_tick; color c; @@ -90,7 +96,7 @@ struct cetris_game { }; void next_piece(struct cetris_game* g); -void wipe_board(struct cetris_game* g); +void update_board(struct cetris_game* g); /* API PROTOTYPES FUNCTIONS */ diff --git a/core/include/matrix.h b/core/include/matrix.h index 658906c..050a32e 100644 --- a/core/include/matrix.h +++ b/core/include/matrix.h @@ -6,10 +6,9 @@ #include "cetris.h" extern const piece_matrix default_matrices[7]; -extern const vec2 basic_movements[4]; -void move_current(struct cetris_game* g, vec2 offset); -void overlay_current_matrix(struct cetris_game* g); +void move_current(struct cetris_game* g, input_t move); void hard_drop(struct cetris_game* g); void rotate_matrix(struct cetris_game* g, bool clockwise); -i8 check_new_matrix(struct cetris_game* g, piece_matrix m); +void set_matrix(struct cetris_game* g, piece_matrix *m); +i8 check_matrix(struct cetris_game* g, piece_matrix *m); diff --git a/core/include/types.h b/core/include/types.h index 0431de1..3471f3c 100644 --- a/core/include/types.h +++ b/core/include/types.h @@ -20,9 +20,10 @@ typedef u8 piece_matrix[4][4]; typedef enum { DOWN = 1, - RIGHT = 2, - LEFT = 3, - ROTATE_CCW = 4, - ROTATE_CW = 5, - HARD_DROP = 6 + USER_DOWN = 2, + RIGHT = 3, + LEFT = 4, + ROTATE_CCW = 5, + ROTATE_CW = 6, + HARD_DROP = 7 } input_t; diff --git a/core/src/cetris.c b/core/src/cetris.c index 5466327..a3f2ded 100644 --- a/core/src/cetris.c +++ b/core/src/cetris.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -20,6 +19,7 @@ static void init_piece_queue(struct cetris_game* g); static void shuffle_queue(struct cetris_game* g); static void set_constants(struct cetris_game* g); +static void add_score(struct cetris_game* g, u8 lines); /* LEVEL DROP SPEED VALUES */ @@ -71,7 +71,8 @@ void init_piece_queue(struct cetris_game* g) { memcpy(g->piece_queue[i].m, default_matrices[i], sizeof(piece_matrix)); g->piece_queue[i].r = INIT; g->piece_queue[i].lock_tick = 0; - g->piece_queue[i].pos = (vec2){3, 20}; // y = 22 - 1 for matrix + g->piece_queue[i].pos = (vec2){CETRIS_INITIAL_X, CETRIS_INITIAL_Y - CETRIS_INITIAL_Y_OFFSET}; + g->piece_queue[i].ghost_y = 0; } } @@ -88,16 +89,20 @@ void update_game_tick(struct cetris_game* g) { if (g->game_over) return; bool did_move = false; - if (g->tick == g->next_drop_tick) { - move_current(g, basic_movements[DOWN]); + if (g->tick >= g->next_drop_tick || !g->next_drop_tick) { + if (g->next_drop_tick) move_current(g, DOWN); did_move = true; - g->next_drop_tick = g->tick + level_drop_delay[g->level - 1]; + if (g->level <= 20) { + g->next_drop_tick = g->tick + level_drop_delay[g->level - 1]; + } else { + g->next_drop_tick = g->tick + level_drop_delay[19]; + } } /* lock piece if it was hovering for CETRIS_LOCK_DELAY */ if (g->current.lock_tick && g->current.lock_tick <= g->tick) { g->current.pos.y++; - if (check_new_matrix(g, g->current.m) <= 0) { + if (check_matrix(g, &g->current.m) <= 0) { next_piece(g); } g->current.pos.y--; @@ -108,16 +113,18 @@ void update_game_tick(struct cetris_game* g) { did_move = true; } - if (did_move) wipe_board(g); + if (did_move) update_board(g); g->tick++; } void next_piece(struct cetris_game* g) { set_constants(g); + + g->next_drop_tick = 0; g->current = g->piece_queue[g->current_index]; - if (check_new_matrix(g, g->current.m) <= 0) { + if (check_matrix(g, &g->current.m) <= 0) { g->game_over = true; } g->current_index++; @@ -136,34 +143,20 @@ void set_constants(struct cetris_game* g) { } } -void add_score(struct cetris_game* g, u8 lines) { - if (!g->tspin && !g->mini_tspin) { - switch (lines) { - case 1: g->score += 100 * g->level; break; - case 2: g->score += 300 * g->level; break; - case 3: g->score += 500 * g->level; break; - case 4: g->score += 800 * g->level; break; - } - } else if (g->tspin) { - switch (lines) { - case 0: g->score += 400 * g->level; break; - case 1: g->score += 800 * g->level; break; - case 2: g->score += 1200 * g->level; break; - case 3: g->score += 1600 * g->level; break; - } - g->tspin = false; - } else if (g->mini_tspin) { - switch (lines) { - case 0: g->score += 100 * g->level; break; - case 1: g->score += 200 * g->level; break; - case 2: g->score += 400 * g->level; break; +void make_ghosts(struct cetris_game* g) { + u8 orig_y = g->current.pos.y; + while (true) { + g->current.pos.y++; + if (check_matrix(g, &g->current.m) <= 0) { + g->current.ghost_y = g->current.pos.y - 1; + g->current.pos.y = orig_y; + break; } - g->mini_tspin = false; } } -void wipe_board(struct cetris_game* g) { - uint32_t lines_cleared = 0; +void update_board(struct cetris_game* g) { + u8 lines_cleared = 0; for (u8 y = 0; y < CETRIS_BOARD_Y; y++) { bool clear_line = true; for (u8 x = 0; x < CETRIS_BOARD_X; x++) { @@ -171,34 +164,60 @@ void wipe_board(struct cetris_game* g) { memset(&g->board[x][y], 0, sizeof(slot)); } - if (g->board[x][y].remove_tick && g->board[x][y].remove_tick <= g->tick) { - memset(&g->board[x][y], 0, sizeof(slot)); - for (i8 s = y - 1; s >= 0; s--) { - g->board[x][s + 1] = g->board[x][s]; - } - } - - if (!g->board[x][y].occupied || g->board[x][y].remove_tick > 0) { + if (!g->board[x][y].occupied || g->board[0][y].remove_tick > 0) { clear_line = false; } } - if (clear_line) { - lines_cleared++; - for (u8 x = 0; x < CETRIS_BOARD_X; x++) { - g->board[x][y].remove_tick = g->tick + CETRIS_LINE_CLEAR_DELAY; + // remove tick only tracked on first block of line + if (g->board[0][y].remove_tick && g->board[0][y].remove_tick <= g->tick) { + for (i8 s = y - 1; s >= 0; s--) { + for (u8 x = 0; x < CETRIS_BOARD_X; x++) { + g->board[x][s + 1] = g->board[x][s]; + } } + lines_cleared++; } + if (clear_line) g->board[0][y].remove_tick = g->tick + CETRIS_LINE_CLEAR_DELAY; } - overlay_current_matrix(g); + make_ghosts(g); + set_matrix(g, &g->current.m); assert(lines_cleared <= 4); - if (lines_cleared > 0) { + if (lines_cleared > 0 || g->tspin || g->mini_tspin) { add_score(g, lines_cleared); if (lines_cleared > 0) { g->lines += lines_cleared; - if (g->lines >= (g->level * 10) && g->level <= 20) g->level++; + if (g->lines >= (g->level * 10)) g->level++; + } + } +} + +/* SCORE FUNCTIONS */ + +void add_score(struct cetris_game* g, u8 lines) { + if (!g->tspin && !g->mini_tspin) { + switch (lines) { + case 1: g->score += 100 * g->level; break; + case 2: g->score += 300 * g->level; break; + case 3: g->score += 500 * g->level; break; + case 4: g->score += 800 * g->level; break; } + } else if (g->tspin) { + switch (lines) { + case 0: g->score += 400 * g->level; break; + case 1: g->score += 800 * g->level; break; + case 2: g->score += 1200 * g->level; break; + case 3: g->score += 1600 * g->level; break; + } + g->tspin = false; + } else if (g->mini_tspin) { + switch (lines) { + case 0: g->score += 100 * g->level; break; + case 1: g->score += 200 * g->level; break; + case 2: g->score += 400 * g->level; break; + } + g->mini_tspin = false; } } @@ -210,7 +229,8 @@ void move_piece(struct cetris_game* g, input_t move) { case LEFT: case RIGHT: case DOWN: - move_current(g, basic_movements[move]); + case USER_DOWN: + move_current(g, move); break; case HARD_DROP: hard_drop(g); @@ -231,5 +251,5 @@ void stop_holding(struct cetris_game* g, input_t move) { if (move == RIGHT || move == LEFT) { g->das_move_tick = 0; g->das_repeat = 0; - } else if (move == DOWN) g->down_move_tick = 0; + } else if (move == USER_DOWN) g->down_move_tick = 0; } diff --git a/core/src/input.c b/core/src/input.c index edcd450..2904158 100644 --- a/core/src/input.c +++ b/core/src/input.c @@ -15,7 +15,7 @@ bool handle_inputs(struct cetris_game* g) { } } - if (g->held_moves[DOWN] && !g->down_move_tick) { + if (g->held_moves[USER_DOWN] && !g->down_move_tick) { g->down_move_tick = g->tick + CETRIS_DROP_PERIOD; } @@ -24,14 +24,14 @@ bool handle_inputs(struct cetris_game* g) { if (g->held_moves[RIGHT]) { if (g->prev_das_move == RIGHT || g->das_repeat == 0) g->das_repeat++; else g->das_repeat = 0; - move_current(g, basic_movements[RIGHT]); + move_current(g, RIGHT); g->prev_das_move = RIGHT; } if (g->held_moves[LEFT]) { if (g->prev_das_move == LEFT || g->das_repeat == 0) g->das_repeat++; else g->das_repeat = 0; - move_current(g, basic_movements[LEFT]); + move_current(g, LEFT); g->prev_das_move = LEFT; } @@ -40,12 +40,12 @@ bool handle_inputs(struct cetris_game* g) { } if (g->down_move_tick && g->tick >= g->down_move_tick) { - if (g->held_moves[DOWN]) { - move_current(g, basic_movements[DOWN]); + if (g->held_moves[USER_DOWN]) { + move_current(g, USER_DOWN); + did_move = true; } g->down_move_tick = 0; - did_move = true; } return did_move; } diff --git a/core/src/matrix.c b/core/src/matrix.c index 265fe05..86e9ad2 100644 --- a/core/src/matrix.c +++ b/core/src/matrix.c @@ -84,36 +84,58 @@ const piece_matrix default_matrices[7] = { /* MATRIX MODIFICATION */ -const vec2 basic_movements[4] = { - {0, 0}, {0, 1}, {1, 0}, {-1, 0} // NONE, DOWN, RIGHT, LEFT +const vec2 basic_movements[5] = { + {0, 0}, {0, 1}, {0, 1}, {1, 0}, {-1, 0} // NONE, DOWN, USER_DOWN, RIGHT, LEFT }; -void move_current(struct cetris_game* g, vec2 offset) { +void move_current(struct cetris_game* g, input_t move) { if (g->game_over) return; - g->current.pos.y += offset.y; - g->current.pos.x += offset.x; + g->current.pos.y += basic_movements[move].y; + g->current.pos.x += basic_movements[move].x; - int32_t check = check_new_matrix(g, g->current.m); + i8 check = check_matrix(g, &g->current.m); if (check <= 0) { - g->current.pos.y -= offset.y; - g->current.pos.x -= offset.x; + g->current.pos.y -= basic_movements[move].y; + g->current.pos.x -= basic_movements[move].x; - if (check == -1 && g->current.lock_tick == 0) { - g->current.lock_tick = g->tick + 30; + if (move == USER_DOWN) g->score++; + if (move == DOWN && check == -1 && !g->current.lock_tick) { + g->current.lock_tick = g->tick + CETRIS_LOCK_DELAY; } } - wipe_board(g); + update_board(g); } -void overlay_current_matrix(struct cetris_game* g) { - for (uint32_t y = 0; y < 4; y++) { - for (uint32_t x = 0; x < 4; x++) { +i8 check_matrix(struct cetris_game* g, piece_matrix *m) { + for (i8 y = 0; y < 4; y++) { + for (i8 x = 0; x < 4; x++) { vec2 r = (vec2){x + g->current.pos.x, y + g->current.pos.y}; - if (g->current.m[y][x]) { - g->board[r.x][r.y].occupied = 1; - g->board[r.x][r.y].c = g->current.c; + if (r.y < 0) continue; + if ((*m)[y][x]) { + if (r.x >= CETRIS_BOARD_X || r.x < 0) return 0; + if (r.y >= CETRIS_BOARD_Y) return -1; + if (g->board[r.x][r.y].occupied && + g->board[r.x][r.y].constant) return -1; + } + } + } + return 1; +} + +void set_matrix(struct cetris_game *g, piece_matrix *m) { + for (i8 y = 0; y < 4; y++) { + for (i8 x = 0; x < 4; x++) { + vec2 r = (vec2){x + g->current.pos.x, y + g->current.pos.y}; + if ((*m)[y][x]) { + if (r.y >= 0) { + g->board[r.x][r.y].occupied = true; + g->board[r.x][r.y].c = g->current.c; + } + if (g->current.ghost_y + y >= 0) { + g->board[r.x][g->current.ghost_y + y].ghost = true; + } } } } @@ -127,17 +149,16 @@ void hard_drop(struct cetris_game* g) { while (!drop) { g->current.pos.y++; drop_count++; - i8 check = check_new_matrix(g, g->current.m); - if (check <= 0) { + if (check_matrix(g, &g->current.m) <= 0) { g->current.pos.y--; drop_count--; drop = true; } } - g->score += 2 * drop_count; // 2 score for each harddrop cell + g->score += 2 * drop_count; // 2 score for each hard-drop'd cell - wipe_board(g); + update_board(g); next_piece(g); } @@ -145,7 +166,7 @@ void rotate_matrix(struct cetris_game* g, bool clockwise) { if (g->game_over) return; if (g->current.t == O) return; - rstate next; + rstate next = 0; u8 wall_kick = 0; switch (g->current.r) { case INIT: @@ -212,7 +233,7 @@ void rotate_matrix(struct cetris_game* g, bool clockwise) { } g->current.pos.x += kick.x; g->current.pos.y += kick.y; - if (check_new_matrix(g, m) > 0) { + if (check_matrix(g, &m) > 0) { set_current = true; if (i > 0) did_kick = true; break; @@ -223,47 +244,28 @@ void rotate_matrix(struct cetris_game* g, bool clockwise) { } if (set_current) { + /* check for tspin */ if (g->current.t == T) { - u8 did_tspin = 1; - for (u8 i = 0; i < 4; i++) { + bool did_tspin = true; + for (int i = 1; i < 5; i++) { g->current.pos.x += basic_movements[i].x; g->current.pos.y += basic_movements[i].y; - if (check_new_matrix(g, m) == 1) - did_tspin = 0; + if (check_matrix(g, &m) == 1) did_tspin = false; g->current.pos.x -= basic_movements[i].x; g->current.pos.y -= basic_movements[i].y; } if (did_tspin) { - if (did_kick) g->mini_tspin = 1; - else g->tspin = 1; + if (did_kick) g->mini_tspin = true; + else g->tspin = true; } } g->current.r = next; memcpy(g->current.m, m, sizeof(piece_matrix)); - wipe_board(g); + update_board(g); } } - -i8 check_new_matrix(struct cetris_game* g, piece_matrix m) { - for (u8 x = 0; x < 4; x++) { - for (u8 y = 0; y < 4; y++) { - vec2 r = (vec2){g->current.pos.x + x, g->current.pos.y + y}; - if (m[y][x]) { - if (r.x > CETRIS_BOARD_X - 1 || r.x < 0) - return 0; - - if (r.y > CETRIS_BOARD_Y - 1 || r.y < 0) - return -1; - - if (g->board[r.x][r.y].occupied && g->board[r.x][r.y].constant) - return -1; - } - } - } - return 1; -} diff --git a/core/src/test.c b/core/src/test.c index e9ce23e..7db2fe5 100644 --- a/core/src/test.c +++ b/core/src/test.c @@ -59,9 +59,9 @@ void apply_test_board(struct cetris_game* g, enum tests t) { default: return; } - for (u8 y = CETRIS_BOARD_VISABLE; y < CETRIS_BOARD_Y; y++) { + for (u8 y = 0; y < CETRIS_BOARD_Y; y++) { for (u8 x = 0; x < 10; x++) { - if ((*board)[y - CETRIS_BOARD_VISABLE][x]) { + if ((*board)[y][x]) { g->board[x][y].occupied = 1; g->board[x][y].constant = 1; g->board[x][y].c = COLOR_I; diff --git a/frontends/curses/curses_ui.c b/frontends/curses/curses_ui.c index 60d930a..1f1440c 100644 --- a/frontends/curses/curses_ui.c +++ b/frontends/curses/curses_ui.c @@ -111,17 +111,22 @@ void *game_loop(void) { void draw_board() { mvaddstr(0, 0, PLAY_FIELD_STR); for (int x = 0; x < CETRIS_BOARD_X; x++) { - for (int y = CETRIS_BOARD_VISABLE; y < CETRIS_BOARD_Y; y++) { + for (int y = 0; y < CETRIS_BOARD_Y; y++) { + if (game.board[x][y].ghost) { + attron(A_DIM); + mvaddstr((y) + 1, x * 2 + X_OFFSET, BLOCK); + attroff(A_DIM); + } if (game.board[x][y].occupied) { - attron(COLOR_PAIR(game.board[x][y].c)); - if (game.board[x][y].remove_tick > 0) { + attron(COLOR_PAIR(game.board[x][y].c) | A_BOLD); + if (game.board[0][y].remove_tick > 0) { if (game.tick % 2 == 0) { - mvaddstr((y - CETRIS_BOARD_VISABLE) + 1, x * 2 + X_OFFSET, BLOCK); + mvaddstr((y) + 1, x * 2 + X_OFFSET, BLOCK); } } else { - mvaddstr((y - CETRIS_BOARD_VISABLE) + 1, x * 2 + X_OFFSET, BLOCK); + mvaddstr((y) + 1, x * 2 + X_OFFSET, BLOCK); } - attroff(COLOR_PAIR(game.board[x][y].c)); + attroff(COLOR_PAIR(game.board[x][y].c) | A_BOLD); } } @@ -152,8 +157,8 @@ void draw_board() { mvaddstr(4, 40 - strlen(level), level); if (game.game_over) { - mvaddstr(10, 6 + X_OFFSET, "GAME OVER"); - mvaddstr(11, 5 + X_OFFSET, "r to restart"); + mvaddstr(10, 5 + X_OFFSET, "GAME OVER"); + mvaddstr(11, 4 + X_OFFSET, "r to restart"); } attroff(A_BOLD); @@ -169,15 +174,15 @@ int main(void) { HANDLE thread = CreateThread(NULL, 0, game_loop, NULL, 0, NULL); #else pthread_t thread; - pthread_create(&thread, NULL, game_loop, (void*)0); + pthread_create(&thread, NULL, (void*)game_loop, (void*)0); #endif int down = 0; while(1) { int keys[50]; int key_count = 0; - int moves[7]; memset(moves, 0, sizeof(int) * 7); + int moves[8]; memset(moves, 0, sizeof(int) * 8); while((keys[key_count] = getch()) != ERR) key_count++; - if (down) move_piece(&game, DOWN); + if (down) move_piece(&game, USER_DOWN); for (int i = 0; i < key_count; i++) { switch (keys[i]) { case 'q': endwin(); exit(1); @@ -189,7 +194,7 @@ int main(void) { moves[RIGHT] = 1; break; case KEY_DOWN: down = 1; - moves[DOWN] = 1; break; + moves[USER_DOWN] = 1; break; case KEY_UP: move_piece(&game, ROTATE_CW); moves[ROTATE_CW] = 1; break; @@ -203,7 +208,7 @@ int main(void) { break; } } - if (!moves[DOWN]) down = 0; + if (!moves[USER_DOWN]) down = 0; for (int i = 1; i < 8; i++) { if (!moves[i]) stop_holding(&game, i); } diff --git a/frontends/gl/main.c b/frontends/gl/main.c index 06ddab6..a105290 100644 --- a/frontends/gl/main.c +++ b/frontends/gl/main.c @@ -143,7 +143,7 @@ void update_block(struct block_drawable *b, int x, int y, int color) { memcpy(block, default_rect, sizeof(GLfloat) * 32); block[0] = block[8] = (x + 1.0f) / 10.0f; - block[1] = block[25] = (((y - CETRIS_BOARD_VISABLE) * -1.0f) + 1.0f) / 20.0f; + block[1] = block[25] = (((y) * -1.0f) + 1.0f) / 20.0f; block[9] = block[17] = block[1] - .05f; block[16] = block[24] = block[0] - .1f; @@ -203,7 +203,7 @@ int main(void) { glUseProgram(shader_program); glBindVertexArray(block.vao); for (int x = 0; x < CETRIS_BOARD_X; x++) { - for (int y = CETRIS_BOARD_VISABLE; y < CETRIS_BOARD_Y; y++) { + for (int y = 0; y < CETRIS_BOARD_Y; y++) { if (cetris.board[x][y].occupied) { update_block(&block, x, y, cetris.board[x][y].c); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); -- cgit v1.2.3-101-g0448