summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cetris.c132
-rw-r--r--cetris.h13
-rw-r--r--frontend/ncurses/ncurses_ui.c (renamed from ncurses_ui.c)0
-rw-r--r--meson.build20
-rw-r--r--meson_options.txt1
-rw-r--r--test.c44
-rw-r--r--test.h7
7 files changed, 149 insertions, 68 deletions
diff --git a/cetris.c b/cetris.c
index fb3379d..b36efb0 100644
--- a/cetris.c
+++ b/cetris.c
@@ -7,6 +7,10 @@
#include "cetris.h"
+#ifdef BUILD_TESTS
+#include "test.h"
+#endif
+
/* FUNCTION PROTOTYPES */
static void init_piece_queue(struct cetris_game* g);
@@ -99,6 +103,10 @@ static const vec2 srs_wall_kicks_i[8][5] = {
/* MATRIX MODIFICATION */
+static const vec2 cardinal_movements[4] = {
+ {0, 1}, {0, -1}, {1, 0}, {-1, 0} // DOWN, UP, RIGHT, LEFT
+};
+
void move_current(struct cetris_game* g, vec2 offset) {
g->current.pos.y += offset.y;
g->current.pos.x += offset.x;
@@ -206,8 +214,9 @@ void rotate_matrix(struct cetris_game* g, int clockwise) {
assert(0);
}
- int set_current = 0;
vec2 kick;
+ int set_current = 0;
+ int did_kick = 0;
for (int i = 0; i < 5; i++) {
if (g->current.t == I) {
kick = srs_wall_kicks_i[wall_kick][i];
@@ -218,6 +227,7 @@ void rotate_matrix(struct cetris_game* g, int clockwise) {
g->current.pos.y += kick.y;
if (check_new_matrix(g, m) > 0) {
set_current = 1;
+ if (i > 0) did_kick = 1;
break;
} else {
g->current.pos.x -= kick.x;
@@ -226,6 +236,25 @@ void rotate_matrix(struct cetris_game* g, int clockwise) {
}
if (set_current) {
+ /* check for tspin */
+ if (g->current.t == T) {
+ int did_tspin = 1;
+ for (int i = 0; i < 4; i++) {
+ g->current.pos.x += cardinal_movements[i].x;
+ g->current.pos.y += cardinal_movements[i].y;
+ if (check_new_matrix(g, m) == 1) {
+ did_tspin = 0;
+ break;
+ }
+ g->current.pos.x -= cardinal_movements[i].x;
+ g->current.pos.y -= cardinal_movements[i].y;
+ }
+ if (did_tspin) {
+ if (did_kick) g->mini_tspin = 1;
+ else g->tspin = 1;
+ }
+ }
+
g->current.r = next;
memcpy(g->current.mat, m, sizeof(piece_matrix));
}
@@ -264,39 +293,8 @@ void init_game(struct cetris_game* g) {
memset(g->board, 0, sizeof(slot) * BOARD_X * BOARD_Y);
-#if 1
- int tspinboard[20][10] = {
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 1, 1, 1, 1, 0, 0, 1, 1, 1, 1 },
- { 1, 1, 1, 0, 0, 0, 1, 1, 1, 1 },
- { 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 },
- { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }
- };
-
- for (int y = 0; y < 20; y++) {
- for (int x = 0; x < 10; x++) {
- if (tspinboard[y][x]) {
- g->board[x][y].occupied = 1;
- g->board[x][y].constant = 1;
- }
- }
- }
-
+#ifdef BUILD_TESTS
+ apply_test_board(g, TSPIN);
#endif
g->tick = 0;
@@ -307,6 +305,9 @@ void init_game(struct cetris_game* g) {
g->lines = 0;
g->level = 0;
+ g->tspin = 0;
+ g->mini_tspin = 0;
+
init_piece_queue(g);
shuffle_queue(g);
@@ -323,33 +324,33 @@ void init_piece_queue(struct cetris_game* g) {
for (int i = 0; i < 7; i++) {
switch (i) {
case 0:
- g->piece_queue[i].t = O;
- g->piece_queue[i].c = COLOR_O;
- break;
+ g->piece_queue[i].t = O;
+ g->piece_queue[i].c = COLOR_O;
+ break;
case 1:
- g->piece_queue[i].t = I;
- g->piece_queue[i].c = COLOR_I;
- break;
+ g->piece_queue[i].t = I;
+ g->piece_queue[i].c = COLOR_I;
+ break;
case 2:
- g->piece_queue[i].t = S;
- g->piece_queue[i].c = COLOR_S;
- break;
+ g->piece_queue[i].t = S;
+ g->piece_queue[i].c = COLOR_S;
+ break;
case 3:
- g->piece_queue[i].t = Z;
- g->piece_queue[i].c = COLOR_Z;
- break;
+ g->piece_queue[i].t = Z;
+ g->piece_queue[i].c = COLOR_Z;
+ break;
case 4:
- g->piece_queue[i].t = L;
- g->piece_queue[i].c = COLOR_L;
- break;
+ g->piece_queue[i].t = L;
+ g->piece_queue[i].c = COLOR_L;
+ break;
case 5:
- g->piece_queue[i].t = J;
- g->piece_queue[i].c = COLOR_J;
- break;
+ g->piece_queue[i].t = J;
+ g->piece_queue[i].c = COLOR_J;
+ break;
case 6:
- g->piece_queue[i].t = T;
- g->piece_queue[i].c = COLOR_T;
- break;
+ g->piece_queue[i].t = T;
+ g->piece_queue[i].c = COLOR_T;
+ break;
}
memcpy(g->piece_queue[i].mat, default_matrices[i], sizeof(piece_matrix));
g->piece_queue[i].r = INIT;
@@ -367,8 +368,6 @@ void shuffle_queue(struct cetris_game* g) {
}
void update_game_tick(struct cetris_game* g) {
- wipe_board(g);
-
if ((g->tick % CETRIS_HZ) == 0) move_down(g);
enum movements current_move = g->move_queue[g->move_queue_pos];
@@ -388,16 +387,17 @@ void update_game_tick(struct cetris_game* g) {
}
if (!delay || g->tick % delay == 0) {
+ wipe_board(g);
if (current_move > 0) {
switch (current_move) {
case DOWN:
- move_current(g, (vec2){0, 1});
+ move_current(g, cardinal_movements[0]);
break;
case LEFT:
- move_current(g, (vec2){-1, 0});
+ move_current(g, cardinal_movements[3]);
break;
case RIGHT:
- move_current(g, (vec2){1, 0});
+ move_current(g, cardinal_movements[2]);
break;
}
if (g->move_queue_count != 0) g->move_queue_pos++;
@@ -450,7 +450,7 @@ void wipe_board(struct cetris_game* g) {
if (clear_line) {
lines_cleared++;
-
+
for (int x = 0; x < BOARD_X; x++) {
g->board[x][y].remove_tick = g->tick + CETRIS_LINE_CLEAR_DELAY;
}
@@ -469,6 +469,12 @@ void wipe_board(struct cetris_game* g) {
}
assert(lines_cleared <= 4);
- g->lines += lines_cleared;
- if (g->lines >= (g->level * 10) && g->level <= 20) g->level++;
+ if (lines_cleared > 0) {
+ if (g->tspin || g->mini_tspin) {
+ g->tspin = 0;
+ g->mini_tspin = 0;
+ }
+ g->lines += lines_cleared;
+ if (g->lines >= (g->level * 10) && g->level <= 20) g->level++;
+ }
}
diff --git a/cetris.h b/cetris.h
index a7dea7d..3ca728d 100644
--- a/cetris.h
+++ b/cetris.h
@@ -1,3 +1,5 @@
+#pragma once
+
#define BOARD_X 10
#define BOARD_Y 20
@@ -57,22 +59,33 @@ enum movements {
};
struct cetris_game {
+ /* playfield represented by a 2d array */
slot board[BOARD_X][BOARD_Y];
+ /* constant queue of all 7 possible tetrimino */
struct tetrimino piece_queue[7];
+ /* current tetrimino */
struct tetrimino current;
int current_index;
+ /* 20 action movment queue so das
+ * can be input independedent */
enum movements move_queue[20];
int move_queue_count;
int move_queue_pos;
+ /* internal game tick */
int tick;
+ /* progress trackers */
int lines;
int level;
+ /* scoring flags */
+ int tspin;
+ int mini_tspin;
+
/* long int just incase */
long int score;
};
diff --git a/ncurses_ui.c b/frontend/ncurses/ncurses_ui.c
index 1ae07b2..1ae07b2 100644
--- a/ncurses_ui.c
+++ b/frontend/ncurses/ncurses_ui.c
diff --git a/meson.build b/meson.build
index c472081..18eab8e 100644
--- a/meson.build
+++ b/meson.build
@@ -4,12 +4,22 @@ project('cetris', 'c',
compiler = meson.get_compiler('c')
-if host_machine.system() == 'windows'
- curses = compiler.find_library('pdcurses/pdcurses.a', dirs: meson.source_root())
-else
- curses = dependency('ncursesw')
+src = ['cetris.c']
+
+if get_option('build_frontends') == true
+ if host_machine.system() == 'windows'
+ curses = compiler.find_library('pdcurses/pdcurses.a', dirs: meson.source_root())
+ else
+ curses = dependency('ncursesw')
+ endif
+ src += ['frontend/ncurses/ncurses_ui.c']
+endif
+
+if get_option('debug') == true
+ src += ['test.c']
+ add_global_arguments('-DBUILD_TESTS', language : 'c')
endif
-executable('cetris', ['cetris.c', 'ncurses_ui.c'],
+executable('cetris', src,
dependencies: curses,
install : true)
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..8636f78
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1 @@
+option('build_frontends', type : 'boolean', value : true)
diff --git a/test.c b/test.c
new file mode 100644
index 0000000..c5465c6
--- /dev/null
+++ b/test.c
@@ -0,0 +1,44 @@
+#include "test.h"
+
+int tspin_test_board[20][10] = {
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 1, 1, 1, 1, 0, 0, 1, 1, 1, 1 },
+ { 1, 1, 1, 0, 0, 0, 1, 1, 1, 1 },
+ { 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }
+};
+
+void apply_test_board(struct cetris_game* g, enum tests t) {
+ int (*board)[20][10];
+ switch (t) {
+ case TSPIN:
+ board = &tspin_test_board;
+ break;
+ default:
+ return;
+ }
+ for (int y = 0; y < 20; y++) {
+ for (int x = 0; x < 10; x++) {
+ if ((*board)[y][x]) {
+ g->board[x][y].occupied = 1;
+ g->board[x][y].constant = 1;
+ }
+ }
+ }
+}
+
diff --git a/test.h b/test.h
new file mode 100644
index 0000000..c4ed20e
--- /dev/null
+++ b/test.h
@@ -0,0 +1,7 @@
+#include "cetris.h"
+
+enum tests {
+ TSPIN
+};
+
+void apply_test_board(struct cetris_game* g, enum tests t);