summaryrefslogtreecommitdiff
path: root/core/\
diff options
context:
space:
mode:
authorAndrew Opalach <andrew@akon.city> 2019-04-13 17:12:12 -0400
committerAndrew Opalach <andrew@akon.city> 2019-04-13 17:12:12 -0400
commit2d3a51877ba45ed5a64d2c9acee3d3300f55c5fa (patch)
treeb2997a5c5377f402a5e43f299b6b6949e16ba8fd /core/\
parent98cb2cda6e9baa7836c76e78bc4c021b6bea39cc (diff)
downloadcetris-2d3a51877ba45ed5a64d2c9acee3d3300f55c5fa.tar.gz
cetris-2d3a51877ba45ed5a64d2c9acee3d3300f55c5fa.tar.bz2
cetris-2d3a51877ba45ed5a64d2c9acee3d3300f55c5fa.zip
general cleanup and add ghost piece for preview
Diffstat (limited to 'core/\')
-rw-r--r--core/\277
1 files changed, 277 insertions, 0 deletions
diff --git a/core/\ b/core/\
new file mode 100644
index 0000000..80e819a
--- /dev/null
+++ b/core/\
@@ -0,0 +1,277 @@
+#include <string.h>
+
+#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;
+}
+*/