summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.c390
1 files changed, 221 insertions, 169 deletions
diff --git a/src/main.c b/src/main.c
index 268c53e..2fee6bd 100644
--- a/src/main.c
+++ b/src/main.c
@@ -15,19 +15,6 @@
#define SOFT_DROP_MULT 4.0
#define LOCK_TICK 0.5
-enum Phases {
- GENERATION,
- FALL,
- LOCK,
- PATTERN,
- //MARK,
- //ITERATE,
- //ANIMATE,
- //ELIMINATE,
- //COMPLETE,
- GAME_OVER,
-} game_phase;
-
enum InputResult {
NONE = 0,
MOVED,
@@ -37,21 +24,32 @@ enum InputResult {
#include "tetromino.h"
struct {
- int pos_x;
- int pos_y;
- int rotation;
- int type;
-} current_piece;
-
-struct Color matrix[MATRIX_WIDTH][MATRIX_HEIGHT];
-int piece_queue[TETROMINO_COUNT*2];
-int current_bag = 0;
-int current_piece_index = 0;
-int hold = 7;
-int held = 0;
-int game_over = 0;
-double phase_time;
-double fall_tick;
+ enum {
+ GENERATION,
+ FALL,
+ LOCK,
+ PATTERN,
+ //MARK,
+ //ITERATE,
+ //ANIMATE,
+ //ELIMINATE,
+ //COMPLETE,
+ GAME_OVER,
+ } phase;
+ struct Color matrix[MATRIX_WIDTH][MATRIX_HEIGHT];
+ struct {
+ int pos_x;
+ int pos_y;
+ int rotation;
+ int type;
+ } current_piece;
+ int piece_queue[TETROMINO_COUNT*2];
+ int current_piece_index;
+ int hold_piece;
+ int held;
+ double phase_time;
+ double fall_tick;
+} game_state;
void draw_block(int x, int y, int width, int height, struct Color color)
{
@@ -60,14 +58,25 @@ void draw_block(int x, int y, int width, int height, struct Color color)
int is_overlap(int x, int y)
{
- for (int i = 0; i < tetrominos[current_piece.type].size; i++) {
- for (int j = 0; j < tetrominos[current_piece.type].size; j++) {
- if (tetrominos[current_piece.type].directions[current_piece.rotation][j][i] == 1) {
- if (current_piece.pos_x + i - 1 + x >= MATRIX_WIDTH
- || current_piece.pos_x + i - 1 + x < 0
- || current_piece.pos_y + j - 1 + y < 0
- || (!ColorIsEqual(BLACK, matrix[current_piece.pos_x + i - 1 + x][current_piece.pos_y + j - 1 + y])
- && !ColorIsEqual(WHITE, matrix[current_piece.pos_x + i - 1 + x][current_piece.pos_y + j - 1 + y]))) {
+ int piece = game_state.current_piece.type;
+ int p_x = game_state.current_piece.pos_x;
+ int p_y = game_state.current_piece.pos_y;
+ int rot = game_state.current_piece.rotation;
+ int c_x;
+ int c_y;
+ int i;
+ int j;
+
+ for (i = 0; i < tetrominos[piece].size; i++) {
+ for (j = 0; j < tetrominos[piece].size; j++) {
+ if (tetrominos[piece].directions[rot][j][i] == 1) {
+ c_x = p_x + i - 1 + x;
+ c_y = p_y + j - 1 + y;
+ if (p_x + i - 1 + x >= MATRIX_WIDTH
+ || p_x + i - 1 + x < 0
+ || p_y + j - 1 + y < 0
+ || (!ColorIsEqual(BLACK, game_state.matrix[c_x][c_y])
+ && !ColorIsEqual(WHITE, game_state.matrix[c_x][c_y]))) {
return 1;
}
}
@@ -98,31 +107,31 @@ void render_matrix(void)
,matrix_origin_y + j * BLOCK_SIZE + 1
,BLOCK_SIZE - 2
,BLOCK_SIZE - 2
- ,matrix[i][j]
+ ,game_state.matrix[i][j]
);
}
}
int ghost_y = 0;
- if (game_phase == FALL || game_phase == LOCK) {
+ if (game_state.phase == FALL || game_state.phase == LOCK) {
/* draw ghost piece */
while(!is_overlap(0, ghost_y)) {
ghost_y--;
}
- for (int i = 0; i < tetrominos[current_piece.type].size; i++) {
- for (int j = 0; j < tetrominos[current_piece.type].size; j++) {
- if (tetrominos[current_piece.type].directions[current_piece.rotation][j][i] == 1) {
+ for (int i = 0; i < tetrominos[game_state.current_piece.type].size; i++) {
+ for (int j = 0; j < tetrominos[game_state.current_piece.type].size; j++) {
+ if (tetrominos[game_state.current_piece.type].directions[game_state.current_piece.rotation][j][i] == 1) {
draw_block(
- (matrix_origin_x + ((current_piece.pos_x + i - 1) * BLOCK_SIZE)) + 3
- ,(matrix_origin_y + ((current_piece.pos_y + j + ghost_y) * BLOCK_SIZE)) + 3
+ (matrix_origin_x + ((game_state.current_piece.pos_x + i - 1) * BLOCK_SIZE)) + 3
+ ,(matrix_origin_y + ((game_state.current_piece.pos_y + j + ghost_y) * BLOCK_SIZE)) + 3
,BLOCK_SIZE - 6
,BLOCK_SIZE - 6
- ,tetrominos[current_piece.type].color
+ ,tetrominos[game_state.current_piece.type].color
);
draw_block(
- (matrix_origin_x + ((current_piece.pos_x + i - 1) * BLOCK_SIZE)) + 4
- ,(matrix_origin_y + ((current_piece.pos_y + j + ghost_y) * BLOCK_SIZE)) + 4
+ (matrix_origin_x + ((game_state.current_piece.pos_x + i - 1) * BLOCK_SIZE)) + 4
+ ,(matrix_origin_y + ((game_state.current_piece.pos_y + j + ghost_y) * BLOCK_SIZE)) + 4
,BLOCK_SIZE - 8
,BLOCK_SIZE - 8
,BLACK
@@ -131,15 +140,15 @@ void render_matrix(void)
}
}
/* draw current piece */
- for (int i = 0; i < tetrominos[current_piece.type].size; i++) {
- for (int j = 0; j < tetrominos[current_piece.type].size; j++) {
- if (tetrominos[current_piece.type].directions[current_piece.rotation][j][i] == 1) {
+ for (int i = 0; i < tetrominos[game_state.current_piece.type].size; i++) {
+ for (int j = 0; j < tetrominos[game_state.current_piece.type].size; j++) {
+ if (tetrominos[game_state.current_piece.type].directions[game_state.current_piece.rotation][j][i] == 1) {
draw_block(
- (matrix_origin_x + ((current_piece.pos_x + i - 1) * BLOCK_SIZE)) + 1
- ,(matrix_origin_y + ((current_piece.pos_y + j - 1) * BLOCK_SIZE)) + 1
+ (matrix_origin_x + ((game_state.current_piece.pos_x + i - 1) * BLOCK_SIZE)) + 1
+ ,(matrix_origin_y + ((game_state.current_piece.pos_y + j - 1) * BLOCK_SIZE)) + 1
,BLOCK_SIZE - 2
,BLOCK_SIZE - 2
- ,tetrominos[current_piece.type].color
+ ,tetrominos[game_state.current_piece.type].color
);
}
}
@@ -155,18 +164,18 @@ void render_matrix(void)
4*BLOCK_SIZE,
BLACK
);
- if (hold != 7) {
- for (int i = 0; i < tetrominos[hold].size; i++) {
- for (int j = 0; j < tetrominos[hold].size; j++) {
- if (tetrominos[hold].directions[NORTH][j][i] == 1) {
+ if (game_state.hold_piece != 7) {
+ for (int i = 0; i < tetrominos[game_state.hold_piece].size; i++) {
+ for (int j = 0; j < tetrominos[game_state.hold_piece].size; j++) {
+ if (tetrominos[game_state.hold_piece].directions[NORTH][j][i] == 1) {
draw_block(
((matrix_origin_x - BLOCK_SIZE * 5) + (i * BLOCK_SIZE)) + 1
- + ((hold != I && hold != O)?(BLOCK_SIZE/2):0)
+ + ((game_state.hold_piece != I && game_state.hold_piece != O)?(BLOCK_SIZE/2):0)
,matrix_origin_y + (MATRIX_HEIGHT/2 * BLOCK_SIZE) + ((j-4) * BLOCK_SIZE)
- - ((hold == I)?BLOCK_SIZE/2:0)
+ - ((game_state.hold_piece == I)?BLOCK_SIZE/2:0)
,BLOCK_SIZE - 2
,BLOCK_SIZE - 2
- ,tetrominos[hold].color
+ ,tetrominos[game_state.hold_piece].color
);
}
}
@@ -182,16 +191,17 @@ void render_matrix(void)
BLACK
);
for (int y = 0; y < 5; y++) {
- for (int i = 0; i < tetrominos[piece_queue[(y+current_piece_index)%14]].size; i++) {
- for (int j = 0; j < tetrominos[piece_queue[(y+current_piece_index)%14]].size; j++) {
- if (tetrominos[piece_queue[(y+current_piece_index)%14]].directions[NORTH][j][i] == 1) {
+ for (int i = 0; i < tetrominos[game_state.piece_queue[(y+game_state.current_piece_index)%14]].size; i++) {
+ for (int j = 0; j < tetrominos[game_state.piece_queue[(y+game_state.current_piece_index)%14]].size; j++) {
+ if (tetrominos[game_state.piece_queue[(y+game_state.current_piece_index)%14]].directions[NORTH][j][i] == 1) {
draw_block(
(((SCREEN_WIDTH/2 + 1 - (BLOCK_SIZE)) + (i * BLOCK_SIZE)) + 1) + (BLOCK_SIZE * 4)
- + ((piece_queue[(y+current_piece_index)%14] != I && piece_queue[(y+current_piece_index)%14] != O)?(BLOCK_SIZE/2):0)
- ,((matrix_origin_y + MATRIX_HEIGHT/2 * BLOCK_SIZE - 15 * BLOCK_SIZE) + ((j - 1) * BLOCK_SIZE)) + 1 + ((3 - y) * BLOCK_SIZE * 4) - ((piece_queue[(y+current_piece_index)%14] == I)?BLOCK_SIZE/2:0)
+ + ((game_state.piece_queue[(y+game_state.current_piece_index)%14] != I && game_state.piece_queue[(y+game_state.current_piece_index)%14] != O)?(BLOCK_SIZE/2):0)
+ ,((matrix_origin_y + MATRIX_HEIGHT/2 * BLOCK_SIZE - 15 * BLOCK_SIZE) + ((j - 1) * BLOCK_SIZE)) + 1 + ((3 - y) * BLOCK_SIZE * 4)
+ - ((game_state.piece_queue[(y+game_state.current_piece_index)%14] == I)?BLOCK_SIZE/2:0)
,BLOCK_SIZE - 2
,BLOCK_SIZE - 2
- ,tetrominos[piece_queue[(y+current_piece_index)%14]].color
+ ,tetrominos[game_state.piece_queue[(y+game_state.current_piece_index)%14]].color
);
}
}
@@ -201,12 +211,17 @@ void render_matrix(void)
void shuffle_bag(int *bag)
{
- for (int i = 0; i < TETROMINO_COUNT; i++) {
+ int i;
+ int r;
+ int t;
+
+ for (i = 0; i < TETROMINO_COUNT; i++) {
bag[i] = i;
}
- for (int i = 0; i < TETROMINO_COUNT; i++) {
- int r = i + rand() / (RAND_MAX / (TETROMINO_COUNT - i) + 1);
- int t = bag[r];
+
+ for (i = 0; i < TETROMINO_COUNT; i++) {
+ r = i + rand() / (RAND_MAX / (TETROMINO_COUNT - i) + 1);
+ t = bag[r];
bag[r] = bag[i];
bag[i] = t;
}
@@ -214,31 +229,32 @@ void shuffle_bag(int *bag)
void generation_phase(void)
{
- if (phase_time < 0.2) {
+ if (game_state.phase_time < 0.2) {
return;
}
// bag generation
- if (current_piece_index == 14) {
- shuffle_bag(&(piece_queue[7]));
- current_piece_index = 0;
+ if (game_state.current_piece_index == 14) {
+ shuffle_bag(&(game_state.piece_queue[7]));
+ game_state.current_piece_index = 0;
}
- if (current_piece_index == 7) {
- shuffle_bag(piece_queue);
+ if (game_state.current_piece_index == 7) {
+ shuffle_bag(game_state.piece_queue);
}
// set current piece
- current_piece.type = piece_queue[current_piece_index++];
- current_piece.rotation = NORTH;
- current_piece.pos_x = 4;
- current_piece.pos_y = 20;
- held = 0;
- phase_time = 0.0;
+ game_state.current_piece.type =
+ game_state.piece_queue[game_state.current_piece_index++];
+ game_state.current_piece.rotation = NORTH;
+ game_state.current_piece.pos_x = 4;
+ game_state.current_piece.pos_y = 20;
+ game_state.held = 0;
+ game_state.phase_time = 0.0;
// blockout lose condition
if (is_overlap(0, 0)) {
- game_phase = GAME_OVER;
+ game_state.phase = GAME_OVER;
} else {
- game_phase = FALL;
+ game_state.phase = FALL;
}
}
@@ -247,35 +263,34 @@ int rotate_piece(int dir)
int *kick_table;
int i;
int can_rotate = 0;
+ int piece = game_state.current_piece.type;
+ int rot = game_state.current_piece.rotation;
+ int init_rot = game_state.current_piece.rotation;
if (dir == 1) {
- kick_table = tetrominos[current_piece.type].cw_kick_table[current_piece.rotation];
+ kick_table = tetrominos[piece].cw_kick_table[rot];
} else if (dir == -1) {
- kick_table = tetrominos[current_piece.type].ccw_kick_table[current_piece.rotation];
+ kick_table = tetrominos[piece].ccw_kick_table[rot];
}
- current_piece.rotation += dir;
- if (current_piece.rotation < 0) {
- current_piece.rotation = 3;
+ rot += dir;
+ if (rot < 0) {
+ rot = 3;
} else {
- current_piece.rotation = current_piece.rotation % 4;
+ rot = rot % 4;
}
+ game_state.current_piece.rotation = rot;
for (i = 0; i < 10 && !can_rotate; i += 2) {
if (!is_overlap(kick_table[i], kick_table[i+1])) {
- current_piece.pos_x += kick_table[i];
- current_piece.pos_y += kick_table[i+1];
+ game_state.current_piece.pos_x += kick_table[i];
+ game_state.current_piece.pos_y += kick_table[i+1];
can_rotate = 1;
}
}
if (!can_rotate) {
- current_piece.rotation -= dir;
- if (current_piece.rotation < 0) {
- current_piece.rotation = 3;
- } else {
- current_piece.rotation = current_piece.rotation % 4;
- }
+ game_state.current_piece.rotation = init_rot;
}
return can_rotate;
@@ -286,16 +301,24 @@ int move_piece(int dir)
if (is_overlap(dir, 0)) {
return 0;
}
- current_piece.pos_x += dir;
+ game_state.current_piece.pos_x += dir;
return 1;
}
void move_piece_to_matrix(void)
{
- for (int i = 0; i < tetrominos[current_piece.type].size; i++) {
- for (int j = 0; j < tetrominos[current_piece.type].size; j++) {
- if (tetrominos[current_piece.type].directions[current_piece.rotation][j][i] == 1) {
- matrix[current_piece.pos_x + i - 1][current_piece.pos_y + j - 1] = tetrominos[current_piece.type].color;
+ int piece = game_state.current_piece.type;
+ int rot = game_state.current_piece.rotation;
+ int x = game_state.current_piece.pos_x;
+ int y = game_state.current_piece.pos_y;
+ int i;
+ int j;
+
+ for (i = 0; i < tetrominos[piece].size; i++) {
+ for (j = 0; j < tetrominos[piece].size; j++) {
+ if (tetrominos[piece].directions[rot][j][i] == 1) {
+ game_state.matrix[x + i - 1][y + j - 1] =
+ tetrominos[piece].color;
}
}
}
@@ -303,26 +326,30 @@ void move_piece_to_matrix(void)
void hold_piece(void)
{
- if (!held) {
- if (hold == 7) {
- hold = current_piece.type;
- current_piece.type = piece_queue[current_piece_index];
- current_piece_index++;
- current_piece_index = current_piece_index % 14;
+ int temp;
+
+ if (!game_state.held) {
+ if (game_state.hold_piece == 7) {
+ game_state.hold_piece = game_state.current_piece.type;
+ game_state.current_piece.type =
+ game_state.piece_queue[game_state.current_piece_index];
+ game_state.current_piece_index++;
+ game_state.current_piece_index =
+ game_state.current_piece_index % 14;
} else {
- int temp = current_piece.type;
- current_piece.type = hold;
- hold = temp;
+ temp = game_state.current_piece.type;
+ game_state.current_piece.type = game_state.hold_piece;
+ game_state.hold_piece = temp;
}
- phase_time = 0.0;
- game_phase = FALL;
- current_piece.rotation = NORTH;
- current_piece.pos_x = 4;
- current_piece.pos_y = 20;
+ game_state.phase_time = 0.0;
+ game_state.phase = FALL;
+ game_state.current_piece.rotation = NORTH;
+ game_state.current_piece.pos_x = 4;
+ game_state.current_piece.pos_y = 20;
if (is_overlap(0,0)) {
CloseWindow();
}
- held = 1;
+ game_state.held = 1;
}
}
@@ -373,7 +400,7 @@ int handle_input(void) {
if (!hard_dropped) {
hard_dropped = 1;
while (!is_overlap(0, -1)) {
- current_piece.pos_y--;
+ game_state.current_piece.pos_y--;
}
return HARD_DROPPED;
}
@@ -382,9 +409,9 @@ int handle_input(void) {
}
if (IsKeyDown(KEY_S)) {
- fall_tick = FALL_TICK / SOFT_DROP_MULT;
+ game_state.fall_tick = FALL_TICK / SOFT_DROP_MULT;
} else {
- fall_tick = FALL_TICK;
+ game_state.fall_tick = FALL_TICK;
}
if (IsKeyDown(KEY_SPACE)) {
@@ -397,15 +424,15 @@ int handle_input(void) {
void lock_phase(void) {
enum InputResult action = handle_input();
if (action == MOVED) {
- phase_time = 0.0;
+ game_state.phase_time = 0.0;
}
if (!is_overlap(0, -1)) {
- phase_time = 0.0;
- game_phase = FALL;
- } else if (phase_time >= LOCK_TICK || action == HARD_DROPPED) {
+ game_state.phase_time = 0.0;
+ game_state.phase = FALL;
+ } else if (game_state.phase_time >= LOCK_TICK || action == HARD_DROPPED) {
move_piece_to_matrix();
- phase_time = 0.0;
- game_phase = PATTERN;
+ game_state.phase_time = 0.0;
+ game_state.phase = PATTERN;
}
}
@@ -413,26 +440,30 @@ void fall_phase(void)
{
enum InputResult action = handle_input();
if (action == HARD_DROPPED) {
- phase_time = 0.0;
- game_phase = PATTERN;
+ game_state.phase_time = 0.0;
+ game_state.phase = PATTERN;
} else {
if (is_overlap(0, -1)) {
- phase_time = 0.0;
- game_phase = LOCK;
- } else if (phase_time >= fall_tick || action == HARD_DROPPED) {
- phase_time = 0.0;
- current_piece.pos_y--;
+ game_state.phase_time = 0.0;
+ game_state.phase = LOCK;
+ } else if (game_state.phase_time >= game_state.fall_tick
+ || action == HARD_DROPPED) {
+ game_state.phase_time = 0.0;
+ game_state.current_piece.pos_y--;
}
}
}
void clear_line(int line)
{
- for (int y = line; y < MATRIX_HEIGHT - 1; y++) {
- for (int x = 0; x < MATRIX_WIDTH; x++) {
- matrix[x][y] = matrix[x][y+1];
- if (ColorIsEqual(matrix[x][y], WHITE) && y < 20) {
- matrix[x][y] = BLACK;
+ int y;
+ int x;
+
+ for (y = line; y < MATRIX_HEIGHT - 1; y++) {
+ for (x = 0; x < MATRIX_WIDTH; x++) {
+ game_state.matrix[x][y] = game_state.matrix[x][y+1];
+ if (ColorIsEqual(game_state.matrix[x][y], WHITE) && y < 20) {
+ game_state.matrix[x][y] = BLACK;
}
}
}
@@ -440,13 +471,17 @@ void clear_line(int line)
int check_lockout(void)
{
+ int piece = game_state.current_piece.type;
+ int rot = game_state.current_piece.rotation;
+ int y = game_state.current_piece.pos_y;
int fully_above = 1;
- for (int i = 0; i < tetrominos[current_piece.type].size; i++) {
- for (int j = 0; j < tetrominos[current_piece.type].size; j++) {
- if (tetrominos[current_piece.type].directions[current_piece.rotation][j][i] == 1) {
- if (current_piece.pos_y + j - 1 < 20) {
- fully_above = 0;
- }
+ int i;
+ int j;
+
+ for (i = 0; i < tetrominos[piece].size; i++) {
+ for (j = 0; j < tetrominos[piece].size; j++) {
+ if (tetrominos[piece].directions[rot][j][i] == 1) {
+ if (y + j - 1 < 20) fully_above = 0;
}
}
}
@@ -455,17 +490,22 @@ int check_lockout(void)
void pattern_phase(void)
{
+ int y;
+ int x;
+ int line_full;
+
if (check_lockout()) {
- phase_time = 0.0;
- game_phase = GAME_OVER;
+ game_state.phase_time = 0.0;
+ game_state.phase = GAME_OVER;
return;
}
move_piece_to_matrix();
- for (int y = 0; y < MATRIX_HEIGHT; y++) {
- int line_full = 1;
- for (int x = 0; x < MATRIX_WIDTH; x++) {
- if (ColorIsEqual(matrix[x][y], BLACK) || ColorIsEqual(matrix[x][y], WHITE)) {
+ for (y = 0; y < MATRIX_HEIGHT; y++) {
+ line_full = 1;
+ for (x = 0; x < MATRIX_WIDTH; x++) {
+ if (ColorIsEqual(game_state.matrix[x][y], BLACK)
+ || ColorIsEqual(game_state.matrix[x][y], WHITE)) {
line_full = 0;
}
}
@@ -473,14 +513,14 @@ void pattern_phase(void)
clear_line(y--);
}
}
- phase_time = 0.0;
- game_phase = GENERATION;
+ game_state.phase_time = 0.0;
+ game_state.phase = GENERATION;
}
void game_logic(void)
{
- phase_time += GetFrameTime();
- switch (game_phase) {
+ game_state.phase_time += GetFrameTime();
+ switch (game_state.phase) {
case GENERATION:
generation_phase();
break;
@@ -494,34 +534,46 @@ void game_logic(void)
pattern_phase();
break;
case GAME_OVER:
- game_over = 1;
break;
}
}
-int main(void)
+void init(void)
{
- srand(time(NULL));
- InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "~turnipGod's Tetris");
- SetTargetFPS(60);
-
+ int y;
+ int x;
// set default block colors
- for (int y = 0; y < 40; y++) {
- for (int x = 0; x < 10; x++) {
+ for (y = 0; y < 40; y++) {
+ for (x = 0; x < 10; x++) {
if (y < 20) {
- matrix[x][y] = BLACK;
+ game_state.matrix[x][y] = BLACK;
} else {
- matrix[x][y] = WHITE;
+ game_state.matrix[x][y] = WHITE;
}
}
}
- shuffle_bag(piece_queue);
- shuffle_bag(&(piece_queue[7]));
- phase_time = 0.0;
- game_phase = GENERATION;
- while (!WindowShouldClose() && !game_over) {
+ shuffle_bag(game_state.piece_queue);
+ shuffle_bag(&(game_state.piece_queue[7]));
+ game_state.phase_time = 0.0;
+ game_state.phase = GENERATION;
+ game_state.hold_piece = 7;
+ game_state.current_piece_index = 0;
+ game_state.held = 0;
+ game_state.fall_tick = FALL_TICK;
+
+}
+
+int main(void)
+{
+ srand(time(NULL));
+ InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "~turnipGod's Tetris");
+ SetTargetFPS(60);
+
+ init();
+
+ while (!WindowShouldClose() && game_state.phase != GAME_OVER) {
game_logic();
BeginDrawing();
ClearBackground(WHITE);