summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Opalach <andrew@akon.city> 2019-10-26 16:27:34 -0400
committerAndrew Opalach <andrew@akon.city> 2019-10-26 16:27:34 -0400
commitd118ad41559a5137703597d0be86e3eaaf85a92f (patch)
tree56b7aa85e21547b4ffc4362fbe2b09aa137dfdfb
parent330f4f2c8abdaf694d64c73d0c11c597787a3be7 (diff)
downloadcetris-d118ad41559a5137703597d0be86e3eaaf85a92f.tar.gz
cetris-d118ad41559a5137703597d0be86e3eaaf85a92f.tar.bz2
cetris-d118ad41559a5137703597d0be86e3eaaf85a92f.zip
add das and almost finish sdl ui
-rw-r--r--.gitmodules3
-rw-r--r--frontends/sdl/config.ini9
-rw-r--r--frontends/sdl/meson.build4
-rw-r--r--frontends/sdl/sdl_ui.c119
m---------ini0
-rw-r--r--lib/cetris.h183
-rw-r--r--meson.build2
7 files changed, 244 insertions, 76 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..98561ca
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "ini"]
+ path = ini
+ url = https://github.com/Pizzabelly/ini.git
diff --git a/frontends/sdl/config.ini b/frontends/sdl/config.ini
new file mode 100644
index 0000000..5ca9c34
--- /dev/null
+++ b/frontends/sdl/config.ini
@@ -0,0 +1,9 @@
+[das]
+das = 220
+arr = 15
+
+[game]
+drop_delay = 20
+next_piece_delay = 40
+lock_delay = 30
+wait_on_clear = 0
diff --git a/frontends/sdl/meson.build b/frontends/sdl/meson.build
index 64d70e4..d7e7f44 100644
--- a/frontends/sdl/meson.build
+++ b/frontends/sdl/meson.build
@@ -4,6 +4,10 @@ threads = dependency('threads')
sdl = dependency('SDl2')
ttf = dependency('SDL2_ttf')
+configure_file(input: 'config.ini',
+ output: 'config.ini',
+ copy: true, install: false)
+
executable('cetris', src,
dependencies: [threads, sdl, ttf],
include_directories: cetris_inc,
diff --git a/frontends/sdl/sdl_ui.c b/frontends/sdl/sdl_ui.c
index 0efd9cb..c29fd1d 100644
--- a/frontends/sdl/sdl_ui.c
+++ b/frontends/sdl/sdl_ui.c
@@ -7,19 +7,24 @@
#include <pthread.h>
#include <unistd.h>
#include <time.h>
+
#include <cetris.h>
+#include <ini.h>
#define W 480
#define H 640
-#define X_OFFSET 60
-#define Y_OFFSET 30
+#define BLOCK_SIZE 25
+
+#define X_OFFSET (W/2) - (BLOCK_SIZE * 5)
+#define Y_OFFSET (H/2) - (BLOCK_SIZE * 10)
SDL_Renderer* render;
TTF_Font* font;
cetris_game g;
+/*
uint8_t colors[8][3] = {
{0, 0, 0}, // Black
{127,219,255}, // Aqua
@@ -30,6 +35,17 @@ uint8_t colors[8][3] = {
{0,31,63}, // Navy
{255,220,0} // Yellow
};
+*/
+
+uint8_t colors[7][3] = {
+ {174,198,207}, // Aqua
+ {170,221,119}, // Olive
+ {177,156,217}, // Purple
+ {255,209,220}, // Fuchsia
+ {255,179,71}, // Orange
+ {119,158,203}, // Navy
+ {253,253,150} // Yellow
+};
#ifdef _WIN32
DWORD WINAPI game_loop(void* data) {
@@ -56,6 +72,7 @@ void setup() {
render = SDL_CreateRenderer(win, -1, SDL_RENDERER_PRESENTVSYNC|SDL_RENDERER_ACCELERATED);
SDL_RenderSetLogicalSize(render, W, H);
if (!render) exit(fprintf(stderr, "err: could not create SDL renderer\n"));
+ SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_BLEND);
//TTF_Init();
//font = TTF_OpenFont("LiberationMono-Regular.ttf", 18);
@@ -66,36 +83,47 @@ void draw() {
SDL_RenderClear(render);
SDL_Rect board = {X_OFFSET, Y_OFFSET, 250, 500};
- SDL_SetRenderDrawColor(render, 240, 240, 240, 255);
+ SDL_SetRenderDrawColor(render, 235, 235, 235, 255);
SDL_RenderFillRect(render, &board);
SDL_RenderDrawRect(render, &board);
SDL_SetRenderDrawColor(render, 255, 255, 255, 255);
for (int x = 0; x < CETRIS_BOARD_X + 1; x++) {
- int rx = X_OFFSET + 1 + (x * 25);
+ int rx = X_OFFSET + 1 + (x * BLOCK_SIZE);
SDL_RenderDrawLine(render, rx, Y_OFFSET + 1, rx, Y_OFFSET + 500);
}
for (int y = 0; y < CETRIS_BOARD_Y - CETRIS_BOARD_VISABLE + 1; y++) {
- int ry = Y_OFFSET + (y * 25);
+ int ry = Y_OFFSET + (y * BLOCK_SIZE);
SDL_RenderDrawLine(render, X_OFFSET + 1, ry, X_OFFSET + 250, ry);
}
- SDL_Rect b = {0, 0, 25, 25};
+ SDL_Rect b = {0, 0, BLOCK_SIZE - 1, BLOCK_SIZE - 1};
+ SDL_Rect w = {0, 0, BLOCK_SIZE + 1, BLOCK_SIZE + 1};
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if ((g.current.m[y]>>(3 - x))&1) {
- b.x = X_OFFSET + ((x + g.current.pos.x) * 25);
- b.y = (Y_OFFSET + ((y + g.current.pos.y) * 25)) - (CETRIS_BOARD_VISABLE * 25);
-
+ b.x = X_OFFSET + ((x + g.current.pos.x) * BLOCK_SIZE);
+ b.y = (Y_OFFSET + ((y + g.current.pos.y) * BLOCK_SIZE)) - (CETRIS_BOARD_VISABLE * BLOCK_SIZE);
+
uint8_t (*color)[3] = &(colors[g.current.t]);
SDL_SetRenderDrawColor(render, (*color)[0], (*color)[1], (*color)[2], 255);
-
+
+ SDL_RenderFillRect(render, &b);
SDL_RenderDrawRect(render, &b);
- b.y = (Y_OFFSET + ((y + g.current.ghost_y) * 25)) - (CETRIS_BOARD_VISABLE * 25);
+ SDL_SetRenderDrawColor(render, 240, 240, 240, 255);
+ w.y = b.y - 1;
+ w.x = b.x - 1;
+ SDL_RenderDrawRect(render, &w);
+
+ b.y = (Y_OFFSET + ((y + g.current.ghost_y) * BLOCK_SIZE)) - (CETRIS_BOARD_VISABLE * BLOCK_SIZE);
+
+ w.y = b.y - 1;
+ SDL_RenderDrawRect(render, &w);
- SDL_SetRenderDrawColor(render, 0, 0, 0, 255);
+ SDL_SetRenderDrawColor(render, (*color)[0], (*color)[1], (*color)[2], 180);
+ SDL_RenderFillRect(render, &b);
SDL_RenderDrawRect(render, &b);
}
@@ -108,22 +136,29 @@ void draw() {
for (int x = 0; x < CETRIS_BOARD_X; x++) {
for (int y = g.highest_line; y < CETRIS_BOARD_Y; y++) {
if (g.board[x][y] & SLOT_OCCUPIED) {
- b.x = X_OFFSET + (x * 25);
- b.y = (Y_OFFSET + (y * 25)) - (CETRIS_BOARD_VISABLE * 25);
+ b.x = X_OFFSET + (x * BLOCK_SIZE);
+ b.y = (Y_OFFSET + (y * BLOCK_SIZE)) - (CETRIS_BOARD_VISABLE * BLOCK_SIZE);
- uint8_t (*color)[3] = &(colors[(g.board[x][y] >> 5)]);
- SDL_SetRenderDrawColor(render, (*color)[0], (*color)[1], (*color)[2], 255);
-
if (g.line_remove_tick[y]) {
- if (g.tick % 2 == 0) {
- SDL_RenderDrawRect(render, &b);
+ if ((int)g.tick % 2 == 0) {
+ continue;
}
- } else {
- SDL_RenderDrawRect(render, &b);
}
+
+ SDL_SetRenderDrawColor(render, 240, 240, 240, 255);
+ w.y = b.y - 1;
+ w.x = b.x - 1;
+ SDL_RenderDrawRect(render, &w);
+
+ uint8_t (*color)[3] = &(colors[(g.board[x][y] >> 5)]);
+ SDL_SetRenderDrawColor(render, (*color)[0], (*color)[1], (*color)[2], 255);
+ SDL_RenderFillRect(render, &b);
+
+ SDL_RenderDrawRect(render, &b);
}
}
}
+
SDL_RenderPresent(render);
}
@@ -131,6 +166,20 @@ int main(void) {
setup();
init_game(&g);
+
+ ini_parser p;
+ load_ini_file(&p, "config.ini");
+
+ int das = atoi(get_ini_value(&p, "das", "das"));
+ g.config.das_das = das * .06f;
+
+ int arr = atoi(get_ini_value(&p, "das", "arr"));
+ g.config.das_arr = arr * .06f;
+
+ g.config.drop_period = atoi(get_ini_value(&p, "game", "drop_delay")) * .06f;
+ g.config.next_piece_delay = atoi(get_ini_value(&p, "game", "next_piece_delay"));
+ g.config.lock_delay = atoi(get_ini_value(&p, "game", "lock_delay"));
+ g.config.wait_on_clear = atoi(get_ini_value(&p, "game", "wait_on_clear"));
#ifdef _WIN32
HANDLE thread = CreateThread(NULL, 0, game_loop, NULL, 0, NULL);
@@ -152,16 +201,40 @@ int main(void) {
case SDLK_RIGHT:
move_piece(&g, RIGHT); break;
case SDLK_DOWN:
- move_piece(&g, DOWN); break;
+ move_piece(&g, USER_DOWN); break;
case SDLK_SPACE:
move_piece(&g, HARD_DROP); break;
case SDLK_UP:
move_piece(&g, ROTATE_CW); break;
+ case 'c':
+ hold_piece(&g); break;
+ case 'x':
+ move_piece(&g, ROTATE_CW); break;
+ case 'z':
+ move_piece(&g, ROTATE_CCW); break;
+ }
+ break;
+ case SDL_KEYUP:
+ switch (e.key.keysym.sym) {
+ case SDLK_LEFT:
+ unhold_piece(&g, LEFT); break;
+ case SDLK_RIGHT:
+ unhold_piece(&g, RIGHT); break;
+ case SDLK_DOWN:
+ unhold_piece(&g, USER_DOWN); break;
+ case SDLK_SPACE:
+ unhold_piece(&g, HARD_DROP); break;
+ case SDLK_UP:
+ unhold_piece(&g, ROTATE_CW); break;
+ case 'x':
+ unhold_piece(&g, ROTATE_CW); break;
+ case 'z':
+ unhold_piece(&g, ROTATE_CCW); break;
}
}
}
draw();
- SDL_Delay(1000 / 60);
+ SDL_Delay(1000 / 144);
}
}
diff --git a/ini b/ini
new file mode 160000
+Subproject 3401f2ed3153c6093c2f434e205cf6e7775a02d
diff --git a/lib/cetris.h b/lib/cetris.h
index 0ccbb9f..8b804a1 100644
--- a/lib/cetris.h
+++ b/lib/cetris.h
@@ -18,7 +18,18 @@
#define CETRIS_BOARD_Y 40
#define CETRIS_BOARD_VISABLE 20
+#define CETRIS_HI_RES 1
+
+#if CETRIS_HI_RES
+#define CETRIS_HZ 6000
+typedef float ctick;
+#else
#define CETRIS_HZ 60
+typedef uint16_t ctick;
+#endif
+
+#define CETRIS_ENABLE_DAS 1
+
#define CETRIS_DROP_PERIOD 2
#define CETRIS_NEXT_PIECE_DELAY 40
#define CETRIS_LINE_CLEAR_DELAY 40
@@ -77,37 +88,61 @@ typedef enum {
} input_t;
typedef struct {
- /* playfield represented by a 2d array */
+#if CETRIS_ENABLE_DAS
+ ctick das_arr;
+ ctick das_das;
+#endif
+
+ ctick drop_period;
+ ctick next_piece_delay;
+ ctick line_delay_clear;
+ ctick lock_delay;
+
+ bool wait_on_clear;
+} cetris_config;
+
+typedef struct {
+ // playfield represented by a 2d array
uint8_t board[CETRIS_BOARD_X][CETRIS_BOARD_Y];
int8_t highest_line;
- /* constant queue of all 7 possible tetrimino */
+ // constant queue of all 7 possible tetrimino
uint8_t piece_queue[7];
- /* current tetrimino */
+ // current tetrimino
tetrimino current;
tetrimino held;
bool piece_held;
uint8_t current_index;
- /* internal game tick */
- uint16_t tick;
- uint16_t next_drop_tick;
- uint16_t next_piece_tick;
- uint16_t down_move_tick;
- uint16_t line_remove_tick[CETRIS_BOARD_Y];
+ // internal game tick
+ ctick tick;
+ ctick next_drop_tick;
+ ctick next_piece_tick;
+ ctick down_move_tick;
+ ctick line_remove_tick[CETRIS_BOARD_Y];
+
+#if CETRIS_ENABLE_DAS
+ ctick das_wait;
+ ctick next_das_move;
+ uint8_t das_move;
+ uint8_t held_moves[8];
+#endif
- /* progress trackers */
+ // progress trackers
uint8_t lines;
uint8_t level;
bool game_over;
- /* scoring flags */
+ // scoring flags
bool tspin;
bool mini_tspin;
- /* score counter */
+ // score counter
uint16_t score;
+
+ // config
+ cetris_config config;
} cetris_game;
const piece_matrix default_matrices[7] = {
@@ -211,25 +246,6 @@ static int check_matrix(cetris_game *g, piece_matrix *m) {
return 1;
}
-static void set_matrix(cetris_game *g, piece_matrix *m) {
- for (int y = 0; y < 4; y++) {
- for (int x = 0; x < 4; x++) {
- if (((*m)[y]>>(3 - x))&1) {
- vec2 r = (vec2){x + g->current.pos.x, y + g->current.pos.y};
- if (r.y >= 0) {
- if (!(g->board[r.x][r.y] & SLOT_OCCUPIED)) {
- g->board[r.x][r.y] |= SLOT_OCCUPIED;
- g->board[r.x][r.y] |= g->current.t << 5;
- }
- }
- if (g->current.ghost_y + y >= 0)
- if (r.y != (g->current.ghost_y + y))
- g->board[r.x][g->current.ghost_y + y] |= SLOT_GHOST;
- }
- }
- }
-}
-
// TODO: hard score
static void add_score(cetris_game *g, int lines) {
if (!g->tspin && !g->mini_tspin) {
@@ -292,10 +308,14 @@ static void make_ghosts(cetris_game *g) {
g->current.pos.y = orig_y;
}
-static void move_current(cetris_game *g, input_t move) {
+static void move_current(cetris_game *g, uint8_t move) {
if (g->game_over || g->next_piece_tick)
return;
+#if CETRIS_ENABLE_DAS
+ if (move == USER_DOWN) return;
+#endif
+
g->current.pos.y += basic_movements[move].y;
g->current.pos.x += basic_movements[move].x;
@@ -305,7 +325,7 @@ static void move_current(cetris_game *g, input_t move) {
g->current.pos.x -= basic_movements[move].x;
if (move == DOWN && check == -1 && !g->current.lock_tick) {
- g->current.lock_tick = g->tick + CETRIS_LOCK_DELAY;
+ g->current.lock_tick = g->tick + g->config.lock_delay;
}
} else {
if (move == USER_DOWN)
@@ -477,29 +497,37 @@ void update_board(cetris_game *g) {
clear_line = false;
}
}
- // remove tick only tracked on first block of line
- if (g->line_remove_tick[y] && g->line_remove_tick[y] <= g->tick) {
- g->line_remove_tick[y] = 0;
+
+ if (g->config.wait_on_clear) {
+ // remove tick only tracked on first block of line
+ if (g->line_remove_tick[y] && g->line_remove_tick[y] <= g->tick) {
+ g->line_remove_tick[y] = 0;
+ for (int s = y - 1; s >= 0; s--) {
+ for (int x = 0; x < CETRIS_BOARD_X; x++) {
+ g->board[x][s + 1] = g->board[x][s];
+ }
+ }
+ }
+ if (clear_line) {
+ g->line_remove_tick[y] = g->tick + g->config.line_delay_clear;
+ lines_cleared++;
+ }
+ } else if (clear_line) {
for (int s = y - 1; s >= 0; s--) {
for (int x = 0; x < CETRIS_BOARD_X; x++) {
g->board[x][s + 1] = g->board[x][s];
}
}
}
- if (clear_line) {
- g->line_remove_tick[y] = g->tick + CETRIS_LINE_CLEAR_DELAY;
- lines_cleared++;
- }
}
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;
+ g->next_piece_tick = g->tick + g->config.next_piece_delay;
} else {
next_piece(g);
}
@@ -528,7 +556,39 @@ CETRIS_EXPORT void hold_piece(cetris_game *g) {
update_board(g);
}
-CETRIS_EXPORT void move_piece(cetris_game *g, input_t move) {
+#if CETRIS_ENABLE_DAS
+CETRIS_EXPORT void unhold_piece(cetris_game* g, input_t move) {
+ if (g->das_move == move) {
+ if (move == LEFT && g->held_moves[RIGHT]) {
+ g->das_move = RIGHT;
+ g->das_wait = g->tick + g->config.das_das;
+ } else if (move == RIGHT && g->held_moves[LEFT]) {
+ g->das_move = LEFT;
+ g->das_wait = g->tick + g->config.das_das;
+ } else {
+ g->das_wait = 0;
+ }
+ g->next_das_move = 0;
+ }
+ g->held_moves[move] = 0;
+}
+#endif
+
+CETRIS_EXPORT void move_piece(cetris_game *g, uint8_t move) {
+#if CETRIS_ENABLE_DAS
+ if (g->held_moves[move]) return;
+ if (move == LEFT || move == RIGHT) {
+ if ((move != g->das_move) || !g->das_wait) {
+ g->das_move = move;
+ g->das_wait = g->tick + g->config.das_das;
+ g->next_das_move = 0;
+ }
+ }
+ if (move == USER_DOWN)
+ g->next_drop_tick = g->tick + g->config.drop_period;
+ g->held_moves[move] = 1;
+#endif
+
switch (move) {
case LEFT:
case RIGHT:
@@ -546,6 +606,7 @@ CETRIS_EXPORT void move_piece(cetris_game *g, input_t move) {
rotate_piece(g, 0);
break;
}
+
}
CETRIS_EXPORT void init_game(cetris_game *g) {
@@ -573,8 +634,12 @@ CETRIS_EXPORT void init_game(cetris_game *g) {
CETRIS_EXPORT void update_game_tick(cetris_game *g) {
if (g->game_over)
return;
-
+
+#if CETRIS_HI_RES
+ g->tick += .01f;
+#else
g->tick++;
+#endif
if (g->next_piece_tick && g->tick >= g->next_piece_tick) {
next_piece(g);
@@ -584,16 +649,21 @@ CETRIS_EXPORT void update_game_tick(cetris_game *g) {
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 && g->tick >= g->next_drop_tick) {
+ move_current(g, DOWN);
+ g->next_drop_tick = 0;
+ did_move = true;
+ }
- if (g->level <= 20) {
- g->next_drop_tick = g->tick + level_drop_delay[g->level - 1];
+ if (!g->next_drop_tick) {
+ if (g->held_moves[USER_DOWN]) {
+ g->next_drop_tick = g->tick + g->config.drop_period;
} else {
- g->next_drop_tick = g->tick + level_drop_delay[19];
+ 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];
+ }
}
}
@@ -610,6 +680,15 @@ CETRIS_EXPORT void update_game_tick(cetris_game *g) {
g->current.lock_tick = 0;
}
+#if CETRIS_ENABLE_DAS
+ if (g->next_das_move && g->tick >= g->next_das_move) {
+ g->next_das_move = g->tick + g->config.das_arr;
+ move_current(g, g->das_move);
+ } else if (!g->next_das_move && g->das_wait && g->tick >= g->das_wait) {
+ g->next_das_move = g->tick + g->config.das_arr;
+ }
+#endif
+
if (did_move) update_board(g);
}
diff --git a/meson.build b/meson.build
index 91577b5..3cee4ae 100644
--- a/meson.build
+++ b/meson.build
@@ -4,7 +4,7 @@ project('cetris', 'c',
compiler = meson.get_compiler('c')
-cetris_inc = include_directories('lib')
+cetris_inc = include_directories(['lib', 'ini'])
if get_option('debug') == true
if host_machine.system() == 'windows'