summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/include/cetris.h35
-rw-r--r--core/include/input.h6
-rw-r--r--core/include/matrix.h10
-rw-r--r--core/include/test.h8
-rw-r--r--core/src/cetris.c105
-rw-r--r--core/src/input.c2
-rw-r--r--core/src/matrix.c31
-rw-r--r--core/src/test.c2
8 files changed, 111 insertions, 88 deletions
diff --git a/core/include/cetris.h b/core/include/cetris.h
index 9e3cf83..1606f2a 100644
--- a/core/include/cetris.h
+++ b/core/include/cetris.h
@@ -10,16 +10,18 @@
#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_NEXT_PIECE_DELAY 40
#define CETRIS_LINE_CLEAR_DELAY 40
#define CETRIS_LOCK_DELAY 40
#define CETRIS_WAIT_ON_CLEAR 0
+#define CETRIS_STARTING_LEVEL 1
+
typedef enum {
O, I, S, Z, L, J, T
} type;
@@ -42,15 +44,16 @@ typedef enum {
TWICE
} rstate;
-struct tetrimino {
+typedef struct {
type t;
rstate r;
color c;
piece_matrix m;
- u8 ghost_y;
+ i8 ghost_y;
vec2 pos;
u32 lock_tick;
-};
+ bool locked;
+} tetrimino;
typedef struct {
bool occupied;
@@ -60,15 +63,15 @@ typedef struct {
color c;
} slot;
-struct cetris_game {
+typedef struct {
/* playfield represented by a 2d array */
slot board[CETRIS_BOARD_X][CETRIS_BOARD_Y];
/* constant queue of all 7 possible tetrimino */
- struct tetrimino piece_queue[7];
+ tetrimino piece_queue[7];
/* current tetrimino */
- struct tetrimino current;
+ tetrimino current;
u8 current_index;
/* input_manager */
@@ -81,6 +84,7 @@ struct cetris_game {
/* internal game tick */
u32 tick;
u32 next_drop_tick;
+ u32 next_piece_tick;
/* progress trackers */
u32 lines;
@@ -92,15 +96,16 @@ struct cetris_game {
bool mini_tspin;
/* score counter */
- u64 score;
-};
+ u32 score;
+} cetris_game;
-void next_piece(struct cetris_game* g);
-void update_board(struct cetris_game* g);
+void next_piece(cetris_game* g);
+void update_board(cetris_game* g);
+void lock_current(cetris_game* g);
/* API PROTOTYPES FUNCTIONS */
-void init_game(struct cetris_game* g);
-void update_game_tick(struct cetris_game* g);
-void move_piece(struct cetris_game* g, input_t move);
-void stop_holding(struct cetris_game* g, input_t move);
+void init_game(cetris_game* g);
+void update_game_tick(cetris_game* g);
+void move_piece(cetris_game* g, input_t move);
+void stop_holding(cetris_game* g, input_t move);
diff --git a/core/include/input.h b/core/include/input.h
index 3cfa947..95cb2aa 100644
--- a/core/include/input.h
+++ b/core/include/input.h
@@ -3,7 +3,7 @@
#include <stdint.h>
#include <stdbool.h>
-struct cetris_game;
+#include "cetris.h"
-bool handle_inputs(struct cetris_game* g);
-void clear_held_key(struct cetris_game* g);
+bool handle_inputs(cetris_game *g);
+void clear_held_key(cetris_game *g);
diff --git a/core/include/matrix.h b/core/include/matrix.h
index 050a32e..eb9e272 100644
--- a/core/include/matrix.h
+++ b/core/include/matrix.h
@@ -7,8 +7,8 @@
extern const piece_matrix default_matrices[7];
-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);
-void set_matrix(struct cetris_game* g, piece_matrix *m);
-i8 check_matrix(struct cetris_game* g, piece_matrix *m);
+void move_current(cetris_game* g, input_t move);
+void hard_drop(cetris_game* g);
+void rotate_matrix(cetris_game* g, bool clockwise);
+void set_matrix(cetris_game* g, piece_matrix* m);
+i8 check_matrix(cetris_game* g, piece_matrix* m);
diff --git a/core/include/test.h b/core/include/test.h
index d700627..4b8622e 100644
--- a/core/include/test.h
+++ b/core/include/test.h
@@ -1,8 +1,8 @@
-struct cetris_game;
+#include "cetris.h"
-enum tests {
+typedef enum {
TSPIN,
TSPIN_NO_LINES
-};
+} test;
-void apply_test_board(struct cetris_game* g, enum tests t);
+void apply_test_board( cetris_game* g, test t);
diff --git a/core/src/cetris.c b/core/src/cetris.c
index a3f2ded..4e404d6 100644
--- a/core/src/cetris.c
+++ b/core/src/cetris.c
@@ -1,4 +1,3 @@
-#include <locale.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
@@ -16,10 +15,9 @@
/* FUNCTION PROTOTYPES */
-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);
+static void init_piece_queue(cetris_game* g);
+static void shuffle_queue(cetris_game* g);
+static void add_score(cetris_game* g, u8 lines);
/* LEVEL DROP SPEED VALUES */
@@ -29,34 +27,20 @@ static const u32 level_drop_delay[20] = {
/* GAME FUNCTIONS */
-void init_game(struct cetris_game* g) {
- srand(time(NULL));
+void init_game(cetris_game* g) {
+
+ /* check for config errors */
+ assert(CETRIS_NEXT_PIECE_DELAY >= CETRIS_LINE_CLEAR_DELAY);
- memset(g->board, 0, sizeof(slot) * CETRIS_BOARD_X * CETRIS_BOARD_Y);
+ srand(time(NULL));
#ifdef BUILD_TESTS
apply_test_board(g, TSPIN_NO_LINES);
#endif
- g->tick = 0;
- g->next_drop_tick = level_drop_delay[0];
-
- g->current_index = 0;
+ memset(g, 0, sizeof(cetris_game));
- memset(g->held_moves, 0, sizeof(bool) * 7);
- g->das_repeat = 0;
- g->prev_das_move = 0;
- g->das_move_tick = 0;
- g->down_move_tick = 0;
-
- g->lines = 0;
- g->level = 1;
- g->game_over = false;
-
- g->tspin = false;
- g->mini_tspin = false;
-
- g->score = 0;
+ g->level = CETRIS_STARTING_LEVEL;
init_piece_queue(g);
shuffle_queue(g);
@@ -64,34 +48,46 @@ void init_game(struct cetris_game* g) {
next_piece(g);
}
-void init_piece_queue(struct cetris_game* g) {
+void init_piece_queue(cetris_game* g) {
for (u8 i = 0; i < 7; i++) {
g->piece_queue[i].t = i;
g->piece_queue[i].c = i + 1;
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){CETRIS_INITIAL_X, CETRIS_INITIAL_Y - CETRIS_INITIAL_Y_OFFSET};
+ g->piece_queue[i].locked = false;
g->piece_queue[i].ghost_y = 0;
+ g->piece_queue[i].pos = (vec2){CETRIS_INITIAL_X, CETRIS_INITIAL_Y - CETRIS_INITIAL_Y_OFFSET};
}
}
-void shuffle_queue(struct cetris_game* g) {
+void shuffle_queue(cetris_game* g) {
for (u8 i = 0; i < 7; i++) {
- struct tetrimino t = g->piece_queue[i];
+ tetrimino t = g->piece_queue[i];
u8 rand_index = rand() % 7;
g->piece_queue[i] = g->piece_queue[rand_index];
g->piece_queue[rand_index] = t;
}
}
-void update_game_tick(struct cetris_game* g) {
+void update_game_tick(cetris_game* g) {
if (g->game_over) return;
+ g->tick++;
+
+ if (g->next_piece_tick && g->tick >= g->next_piece_tick) {
+ next_piece(g);
+ }
+
+ if (g->next_piece_tick) return;
+
bool did_move = false;
if (g->tick >= g->next_drop_tick || !g->next_drop_tick) {
- if (g->next_drop_tick) move_current(g, DOWN);
- did_move = true;
+ if (g->next_drop_tick) {
+ move_current(g, DOWN);
+ did_move = true;
+ }
+
if (g->level <= 20) {
g->next_drop_tick = g->tick + level_drop_delay[g->level - 1];
} else {
@@ -100,10 +96,11 @@ void update_game_tick(struct cetris_game* g) {
}
/* lock piece if it was hovering for CETRIS_LOCK_DELAY */
- if (g->current.lock_tick && g->current.lock_tick <= g->tick) {
+ if (!g->next_piece_tick && g->current.lock_tick && g->current.lock_tick <= g->tick) {
g->current.pos.y++;
if (check_matrix(g, &g->current.m) <= 0) {
- next_piece(g);
+ lock_current(g);
+ did_move = true;
}
g->current.pos.y--;
g->current.lock_tick = 0;
@@ -114,14 +111,11 @@ void update_game_tick(struct cetris_game* g) {
}
if (did_move) update_board(g);
-
- g->tick++;
}
-void next_piece(struct cetris_game* g) {
- set_constants(g);
-
+void next_piece(cetris_game* g) {
g->next_drop_tick = 0;
+ g->next_piece_tick = 0;
g->current = g->piece_queue[g->current_index];
if (check_matrix(g, &g->current.m) <= 0) {
@@ -133,17 +127,21 @@ void next_piece(struct cetris_game* g) {
g->current_index = 0;
shuffle_queue(g);
}
+
+ update_board(g);
}
-void set_constants(struct cetris_game* g) {
+void lock_current(cetris_game* g) {
+ g->current.locked = true;
for (u8 x = 0; x < CETRIS_BOARD_X; x++) {
for (u8 y = 0; y < CETRIS_BOARD_Y; y++) {
if (g->board[x][y].occupied) g->board[x][y].constant = 1;
}
}
+ update_board(g);
}
-void make_ghosts(struct cetris_game* g) {
+void make_ghosts(cetris_game* g) {
u8 orig_y = g->current.pos.y;
while (true) {
g->current.pos.y++;
@@ -155,7 +153,9 @@ void make_ghosts(struct cetris_game* g) {
}
}
-void update_board(struct cetris_game* g) {
+void update_board(cetris_game* g) {
+ if (g->game_over) return;
+
u8 lines_cleared = 0;
for (u8 y = 0; y < CETRIS_BOARD_Y; y++) {
bool clear_line = true;
@@ -175,15 +175,26 @@ void update_board(struct cetris_game* g) {
g->board[x][s + 1] = g->board[x][s];
}
}
+ }
+ if (clear_line) {
+ g->board[0][y].remove_tick = g->tick + CETRIS_LINE_CLEAR_DELAY;
lines_cleared++;
}
- if (clear_line) g->board[0][y].remove_tick = g->tick + CETRIS_LINE_CLEAR_DELAY;
}
make_ghosts(g);
set_matrix(g, &g->current.m);
assert(lines_cleared <= 4);
+
+ if (g->current.locked && !g->next_piece_tick) {
+ if (lines_cleared > 0) {
+ g->next_piece_tick = g->tick + CETRIS_NEXT_PIECE_DELAY;
+ } else {
+ next_piece(g);
+ }
+ }
+
if (lines_cleared > 0 || g->tspin || g->mini_tspin) {
add_score(g, lines_cleared);
if (lines_cleared > 0) {
@@ -195,7 +206,7 @@ void update_board(struct cetris_game* g) {
/* SCORE FUNCTIONS */
-void add_score(struct cetris_game* g, u8 lines) {
+void add_score(cetris_game* g, u8 lines) {
if (!g->tspin && !g->mini_tspin) {
switch (lines) {
case 1: g->score += 100 * g->level; break;
@@ -223,7 +234,7 @@ void add_score(struct cetris_game* g, u8 lines) {
/* MOVEMENT FUNCTIONS */
-void move_piece(struct cetris_game* g, input_t move) {
+void move_piece(cetris_game* g, input_t move) {
if (!g->held_moves[move]) {
switch (move) {
case LEFT:
@@ -246,7 +257,7 @@ void move_piece(struct cetris_game* g, input_t move) {
g->held_moves[move] = true;
}
-void stop_holding(struct cetris_game* g, input_t move) {
+void stop_holding(cetris_game* g, input_t move) {
g->held_moves[move] = false;
if (move == RIGHT || move == LEFT) {
g->das_move_tick = 0;
diff --git a/core/src/input.c b/core/src/input.c
index 2904158..65dead1 100644
--- a/core/src/input.c
+++ b/core/src/input.c
@@ -6,7 +6,7 @@
#include "matrix.h"
#include "cetris.h"
-bool handle_inputs(struct cetris_game* g) {
+bool handle_inputs(cetris_game* g) {
if ((g->held_moves[RIGHT] || g->held_moves[LEFT]) && !g->das_move_tick) {
if (g->das_repeat == 0) {
g->das_move_tick = g->tick + CETRIS_DAS_DELAY;
diff --git a/core/src/matrix.c b/core/src/matrix.c
index 86e9ad2..caae107 100644
--- a/core/src/matrix.c
+++ b/core/src/matrix.c
@@ -88,8 +88,8 @@ 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, input_t move) {
- if (g->game_over) return;
+void move_current(cetris_game* g, input_t move) {
+ if (g->game_over || g->next_piece_tick) return;
g->current.pos.y += basic_movements[move].y;
g->current.pos.x += basic_movements[move].x;
@@ -108,7 +108,7 @@ void move_current(struct cetris_game* g, input_t move) {
update_board(g);
}
-i8 check_matrix(struct cetris_game* g, piece_matrix *m) {
+i8 check_matrix(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};
@@ -124,7 +124,7 @@ i8 check_matrix(struct cetris_game* g, piece_matrix *m) {
return 1;
}
-void set_matrix(struct cetris_game *g, piece_matrix *m) {
+void set_matrix(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};
@@ -134,15 +134,17 @@ void set_matrix(struct cetris_game *g, piece_matrix *m) {
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;
+ if (r.y != (g->current.ghost_y + y)) {
+ g->board[r.x][g->current.ghost_y + y].ghost = true;
+ }
}
}
}
}
}
-void hard_drop(struct cetris_game* g) {
- if (g->game_over) return;
+void hard_drop(cetris_game* g) {
+ if (g->game_over || g->next_piece_tick) return;
bool drop = false;
u8 drop_count = 0;
@@ -159,11 +161,11 @@ void hard_drop(struct cetris_game* g) {
g->score += 2 * drop_count; // 2 score for each hard-drop'd cell
update_board(g);
- next_piece(g);
+ lock_current(g);
}
-void rotate_matrix(struct cetris_game* g, bool clockwise) {
- if (g->game_over) return;
+void rotate_matrix(cetris_game* g, bool clockwise) {
+ if (g->game_over || g->next_piece_tick) return;
if (g->current.t == O) return;
rstate next = 0;
@@ -213,8 +215,11 @@ void rotate_matrix(struct cetris_game* g, bool clockwise) {
u8 new_y = (clockwise) ? 2 + (x - 1) : 2 - (x - 1);
if (g->current.t == I) {
- if (clockwise) new_y--;
- else new_x++;
+ if (clockwise) {
+ new_y--;
+ } else {
+ new_x++;
+ }
}
m[new_y][new_x] = 1;
@@ -231,8 +236,10 @@ void rotate_matrix(struct cetris_game* g, bool clockwise) {
} else {
kick = srs_wall_kicks[wall_kick][i];
}
+
g->current.pos.x += kick.x;
g->current.pos.y += kick.y;
+
if (check_matrix(g, &m) > 0) {
set_current = true;
if (i > 0) did_kick = true;
diff --git a/core/src/test.c b/core/src/test.c
index 7db2fe5..bad50d8 100644
--- a/core/src/test.c
+++ b/core/src/test.c
@@ -47,7 +47,7 @@ u8 tspin_no_lines_board[20][10] = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }
};
-void apply_test_board(struct cetris_game* g, enum tests t) {
+void apply_test_board(cetris_game* g, test t) {
u8 (*board)[20][10];
switch (t) {
case TSPIN: