aboutsummaryrefslogtreecommitdiff
path: root/config/tetris.c
diff options
context:
space:
mode:
authorDavid Moc <personal@cdatgoose.org>2026-06-02 13:50:21 +0200
committerDavid Moc <personal@cdatgoose.org>2026-06-02 13:50:21 +0200
commita15cb041654ae307add0b998b526c87c3f42bf5f (patch)
tree225bb4b70e9fa05aa5f4d2722a1a9cf5fc6fca7f /config/tetris.c
parent6aeaa171dc1ca43392f53cbd02097f76e1b1c5a0 (diff)
Add plugin hooks and mode plugins
Diffstat (limited to 'config/tetris.c')
-rw-r--r--config/tetris.c188
1 files changed, 110 insertions, 78 deletions
diff --git a/config/tetris.c b/config/tetris.c
index 542963a..e86ab75 100644
--- a/config/tetris.c
+++ b/config/tetris.c
@@ -9,8 +9,7 @@
#define TETRIS_VAR_NEXT "next_piece"
typedef struct tetris_state {
- ecex_t *ed;
- int *board;
+ ecex_plugin_t *plugin;
int piece;
int rot;
int x;
@@ -34,28 +33,61 @@ static int tetris_idx(int x, int y) {
}
static int tetris_shape_cell(int piece, int rot, int col, int row) {
- return ecex_tetris_shape_cell(piece, rot, col, row);
+ int p = piece % 7;
+ int r = rot & 3;
+ if (p < 0) p += 7;
+ if (col < 0 || col >= 4 || row < 0 || row >= 4) return 0;
+
+ if (p == 0) {
+ if ((r & 1) == 0) return row == 1;
+ return col == 1;
+ }
+ if (p == 1) return (row == 1 || row == 2) && (col == 1 || col == 2);
+ if (p == 2) {
+ if (r == 0) return (row == 1 && col >= 0 && col <= 2) || (row == 2 && col == 1);
+ if (r == 1) return (col == 1 && row >= 0 && row <= 2) || (row == 1 && col == 2);
+ if (r == 2) return (row == 1 && col >= 0 && col <= 2) || (row == 0 && col == 1);
+ return (col == 1 && row >= 0 && row <= 2) || (row == 1 && col == 0);
+ }
+ if (p == 3) {
+ if ((r & 1) == 0) return (row == 1 && (col == 1 || col == 2)) || (row == 2 && (col == 0 || col == 1));
+ return (col == 1 && (row == 0 || row == 1)) || (col == 2 && (row == 1 || row == 2));
+ }
+ if (p == 4) {
+ if ((r & 1) == 0) return (row == 1 && (col == 0 || col == 1)) || (row == 2 && (col == 1 || col == 2));
+ return (col == 2 && (row == 0 || row == 1)) || (col == 1 && (row == 1 || row == 2));
+ }
+ if (p == 5) {
+ if (r == 0) return (row == 1 && col >= 0 && col <= 2) || (row == 0 && col == 0);
+ if (r == 1) return (col == 1 && row >= 0 && row <= 2) || (row == 0 && col == 2);
+ if (r == 2) return (row == 1 && col >= 0 && col <= 2) || (row == 2 && col == 2);
+ return (col == 1 && row >= 0 && row <= 2) || (row == 2 && col == 0);
+ }
+ if (r == 0) return (row == 1 && col >= 0 && col <= 2) || (row == 0 && col == 2);
+ if (r == 1) return (col == 1 && row >= 0 && row <= 2) || (row == 2 && col == 2);
+ if (r == 2) return (row == 1 && col >= 0 && col <= 2) || (row == 2 && col == 0);
+ return (col == 1 && row >= 0 && row <= 2) || (row == 0 && col == 0);
}
-static int *tetris_board(ecex_t *ed, tetris_state_t *s) {
- if (!ed || !s) return 0;
- return (int *)ecex_var_get_or_alloc(ed, s, TETRIS_VAR_BOARD, (size_t)TETRIS_CELLS, sizeof(int));
+static int *tetris_board(tetris_state_t *s) {
+ if (!s) return 0;
+ return (int *)ecex_plugin_slot_alloc(s->plugin, TETRIS_VAR_BOARD, (size_t)TETRIS_CELLS, sizeof(int));
}
-static int tetris_next_piece(ecex_t *ed, tetris_state_t *s) {
- return ecex_var_i32(ed, s, TETRIS_VAR_NEXT, 0);
+static int tetris_next_piece(tetris_state_t *s) {
+ return ecex_plugin_slot_i32_get_scalar(s ? s->plugin : 0, TETRIS_VAR_NEXT, 0);
}
-static void tetris_set_next_piece(ecex_t *ed, tetris_state_t *s, int piece) {
+static void tetris_set_next_piece(tetris_state_t *s, int piece) {
if (piece < 0) piece = 0;
if (piece > 6) piece = piece % 7;
- ecex_var_i32_set_scalar(ed, s, TETRIS_VAR_NEXT, piece);
+ ecex_plugin_slot_i32_set_scalar(s ? s->plugin : 0, TETRIS_VAR_NEXT, piece);
}
-static void tetris_clear_board(ecex_t *ed, tetris_state_t *s) {
+static void tetris_clear_board(tetris_state_t *s) {
int *board;
if (!s) { ecex_log("tetris_clear_board: null state"); return; }
- board = tetris_board(ed, s);
+ board = tetris_board(s);
ecex_log_ptr("tetris_clear_board: board=", board);
ecex_mem_zero(board, (size_t)TETRIS_CELLS * sizeof(int));
ecex_log("tetris_clear_board: done");
@@ -71,11 +103,11 @@ static int tetris_pick(tetris_state_t *s) {
return piece;
}
-static int tetris_collides(ecex_t *ed, tetris_state_t *s, int piece, int rot, int px, int py) {
+static int tetris_collides(tetris_state_t *s, int piece, int rot, int px, int py) {
int r;
int c;
- int *board = tetris_board(ed, s);
+ int *board = tetris_board(s);
if (!s || !board) return 1;
for (r = 0; r < 4; ++r) {
for (c = 0; c < 4; ++c) {
@@ -93,44 +125,44 @@ static int tetris_collides(ecex_t *ed, tetris_state_t *s, int piece, int rot, in
return 0;
}
-static void tetris_spawn(ecex_t *ed, tetris_state_t *s) {
+static void tetris_spawn(tetris_state_t *s) {
int queued;
ecex_log_ptr("tetris_spawn: state=", s);
if (!s) return;
/* The sidebar must show the piece that will become active on the next
- * spawn. Keep that queued value in the host variable registry, then consume
+ * spawn. Keep that queued value in a plugin slot, then consume
* it here and immediately replace it with a freshly-picked preview. */
- queued = tetris_next_piece(ed, s);
+ queued = tetris_next_piece(s);
if (queued < 0 || queued > 6) queued = tetris_pick(s);
s->piece = queued;
- tetris_set_next_piece(ed, s, tetris_pick(s));
+ tetris_set_next_piece(s, tetris_pick(s));
ecex_log_int("tetris_spawn: current_piece=", s->piece);
- ecex_log_int("tetris_spawn: preview_piece=", tetris_next_piece(ed, s));
+ ecex_log_int("tetris_spawn: preview_piece=", tetris_next_piece(s));
s->rot = 0;
s->x = 3;
s->y = -1;
s->last_drop_ms = 0;
- if (tetris_collides(ed, s, s->piece, s->rot, s->x, s->y)) {
+ if (tetris_collides(s, s->piece, s->rot, s->x, s->y)) {
ecex_log("tetris_spawn: immediate collision -> game over");
s->game_over = 1;
}
}
-static void tetris_reset(ecex_t *ed, tetris_state_t *s) {
+static void tetris_reset(tetris_state_t *s) {
ecex_log_ptr("tetris_reset: state=", s);
if (!s) return;
- tetris_clear_board(ed, s);
+ tetris_clear_board(s);
ecex_log("tetris_reset: after clear");
/* Avoid calling libc/time-returning host functions from CCDJIT plugin code.
* Seed from stable host-owned addresses instead; good enough for a toy game
* and much safer for the tiny JIT ABI. */
- s->rng = 0x9e3779b9u ^ (unsigned int)(size_t)s ^ (unsigned int)(size_t)tetris_board(ed, s);
+ s->rng = 0x9e3779b9u ^ (unsigned int)(size_t)s ^ (unsigned int)(size_t)tetris_board(s);
ecex_log_int("tetris_reset: rng=", (int)s->rng);
s->score = 0;
s->lines = 0;
@@ -139,15 +171,15 @@ static void tetris_reset(ecex_t *ed, tetris_state_t *s) {
s->paused = 0;
s->last_drop_ms = 0;
s->drop_interval_ms = 650;
- tetris_set_next_piece(ed, s, tetris_pick(s));
+ tetris_set_next_piece(s, tetris_pick(s));
s->log_tick_count = 0;
s->log_draw_count = 0;
ecex_log("tetris_reset: spawning first piece");
- tetris_spawn(ed, s);
+ tetris_spawn(s);
ecex_log("tetris_reset: done");
}
-static void tetris_lock(ecex_t *ed, tetris_state_t *s) {
+static void tetris_lock(tetris_state_t *s) {
ecex_log_ptr("tetris_lock: state=", s);
int r;
int c;
@@ -156,7 +188,7 @@ static void tetris_lock(ecex_t *ed, tetris_state_t *s) {
int *board;
if (!s) return;
- board = tetris_board(ed, s);
+ board = tetris_board(s);
if (!board) return;
for (r = 0; r < 4; ++r) {
@@ -214,7 +246,7 @@ static void tetris_lock(ecex_t *ed, tetris_state_t *s) {
}
ecex_log_int("tetris_lock: cleared=", cleared);
- tetris_spawn(ed, s);
+ tetris_spawn(s);
}
@@ -244,11 +276,11 @@ static int tetris_top_out_if_hidden(tetris_state_t *s, const char *where) {
return 1;
}
-static int tetris_soft_drop(ecex_t *ed, tetris_state_t *s) {
+static int tetris_soft_drop(tetris_state_t *s) {
if (!s) { ecex_log("tetris_soft_drop: null state"); return 0; }
if (s->game_over || s->paused) return 0;
- if (!tetris_collides(ed, s, s->piece, s->rot, s->x, s->y + 1)) {
+ if (!tetris_collides(s, s->piece, s->rot, s->x, s->y + 1)) {
++s->y;
return 1;
}
@@ -256,12 +288,12 @@ static int tetris_soft_drop(ecex_t *ed, tetris_state_t *s) {
ecex_log_int("tetris_soft_drop: locking piece=", s->piece);
ecex_log_int("tetris_soft_drop: y=", s->y);
if (tetris_top_out_if_hidden(s, "tetris_soft_drop: hidden lock -> game over")) return 1;
- tetris_lock(ed, s);
+ tetris_lock(s);
return 0;
}
-static int tetris_move_horizontal(ecex_t *ed, tetris_state_t *s, int dx) {
+static int tetris_move_horizontal(tetris_state_t *s, int dx) {
int old_x;
int old_y;
int old_rot;
@@ -273,7 +305,7 @@ static int tetris_move_horizontal(ecex_t *ed, tetris_state_t *s, int dx) {
old_y = s->y;
old_rot = s->rot;
- if (!tetris_collides(ed, s, s->piece, s->rot, old_x + dx, old_y)) {
+ if (!tetris_collides(s, s->piece, s->rot, old_x + dx, old_y)) {
s->x = old_x + dx;
/* Horizontal movement must never vertical-kick the active piece.
* Keep these assignments explicit because plugin/JIT callback bugs are
@@ -296,18 +328,18 @@ static int tetris_move_horizontal(ecex_t *ed, tetris_state_t *s, int dx) {
return 0;
}
-static void tetris_hard_drop(ecex_t *ed, tetris_state_t *s) {
+static void tetris_hard_drop(tetris_state_t *s) {
int moved = 0;
if (!s || s->game_over || s->paused) return;
- while (!tetris_collides(ed, s, s->piece, s->rot, s->x, s->y + 1)) {
+ while (!tetris_collides(s, s->piece, s->rot, s->x, s->y + 1)) {
++s->y;
++moved;
}
s->score += moved * 2;
if (tetris_top_out_if_hidden(s, "tetris_hard_drop: hidden lock -> game over")) return;
- tetris_lock(ed, s);
+ tetris_lock(s);
}
static tetris_state_t *tetris_state_for_ed(ecex_t *ed) {
@@ -330,14 +362,14 @@ static int tetris_alpha8(int alpha) {
static void tetris_color(ecex_draw_context_t *ctx, int cell, int alpha) {
alpha = tetris_alpha8(alpha);
- if (cell == 1) ecex_draw_color_rgba8(ctx, 51, 191, 242, alpha);
- else if (cell == 2) ecex_draw_color_rgba8(ctx, 242, 217, 51, alpha);
- else if (cell == 3) ecex_draw_color_rgba8(ctx, 179, 89, 242, alpha);
- else if (cell == 4) ecex_draw_color_rgba8(ctx, 77, 217, 89, alpha);
- else if (cell == 5) ecex_draw_color_rgba8(ctx, 242, 64, 64, alpha);
- else if (cell == 6) ecex_draw_color_rgba8(ctx, 64, 102, 242, alpha);
- else if (cell == 7) ecex_draw_color_rgba8(ctx, 242, 140, 51, alpha);
- else ecex_draw_color_rgba8(ctx, 41, 41, 46, alpha);
+ if (cell == 1) ecex_draw_color_rgba8_i(ctx, 51, 191, 242, alpha);
+ else if (cell == 2) ecex_draw_color_rgba8_i(ctx, 242, 217, 51, alpha);
+ else if (cell == 3) ecex_draw_color_rgba8_i(ctx, 179, 89, 242, alpha);
+ else if (cell == 4) ecex_draw_color_rgba8_i(ctx, 77, 217, 89, alpha);
+ else if (cell == 5) ecex_draw_color_rgba8_i(ctx, 242, 64, 64, alpha);
+ else if (cell == 6) ecex_draw_color_rgba8_i(ctx, 64, 102, 242, alpha);
+ else if (cell == 7) ecex_draw_color_rgba8_i(ctx, 242, 140, 51, alpha);
+ else ecex_draw_color_rgba8_i(ctx, 41, 41, 46, alpha);
}
static void tetris_draw_piece(ecex_draw_context_t *ctx,
@@ -386,7 +418,7 @@ static int tetris_tick(ecex_t *ed, buffer_t *buffer, int now_ms, void *userdata)
if (!s->game_over && !s->paused && now_ms - s->last_drop_ms >= s->drop_interval_ms) {
ecex_log("tetris_tick: dropping piece");
- tetris_soft_drop(ed, s);
+ tetris_soft_drop(s);
s->last_drop_ms = now_ms;
return 1;
}
@@ -413,8 +445,8 @@ static int tetris_draw(ecex_t *ed, buffer_t *buffer, ecex_draw_context_t *ctx, v
if (!s) { ecex_log("tetris_draw: null state"); return 0; }
if (!ctx) { ecex_log("tetris_draw: null ctx"); return 0; }
- board = tetris_board(ed, s);
- if (!board) { ecex_log("tetris_draw: no registry board"); return 0; }
+ board = tetris_board(s);
+ if (!board) { ecex_log("tetris_draw: no plugin board slot"); return 0; }
s->log_draw_count += 1;
if (s->log_draw_count <= 8 || (s->log_draw_count % 60) == 0) {
ecex_log_int("tetris_draw: count=", s->log_draw_count);
@@ -423,7 +455,7 @@ static int tetris_draw(ecex_t *ed, buffer_t *buffer, ecex_draw_context_t *ctx, v
}
if (s->log_draw_count <= 3) ecex_log("tetris_draw: background");
- ecex_draw_color_rgba8(ctx, 20, 23, 28, 255);
+ ecex_draw_color_rgba8_i(ctx, 20, 23, 28, 255);
ecex_draw_rect_i(ctx, 0, 0, (int)ctx->w, (int)ctx->h);
max_board_w = ((int)ctx->content_w * 62) / 100;
@@ -438,9 +470,9 @@ static int tetris_draw(ecex_t *ed, buffer_t *buffer, ecex_draw_context_t *ctx, v
oy = (int)ctx->content_y + 12;
if (s->log_draw_count <= 3) ecex_log("tetris_draw: board frame");
- ecex_draw_color_rgba8(ctx, 8, 9, 12, 255);
+ ecex_draw_color_rgba8_i(ctx, 8, 9, 12, 255);
ecex_draw_rect_i(ctx, ox - 6, oy - 6, board_w + 12, board_h + 12);
- ecex_draw_color_rgba8(ctx, 97, 102, 115, 255);
+ ecex_draw_color_rgba8_i(ctx, 97, 102, 115, 255);
ecex_draw_rect_outline_i(ctx, ox - 6, oy - 6, board_w + 12, board_h + 12, 2);
if (s->log_draw_count <= 3) ecex_log("tetris_draw: cells");
@@ -459,7 +491,7 @@ static int tetris_draw(ecex_t *ed, buffer_t *buffer, ecex_draw_context_t *ctx, v
sy = oy;
if (s->log_draw_count <= 3) ecex_log("tetris_draw: sidebar");
- ecex_draw_color_rgba8(ctx, 235, 235, 214, 255);
+ ecex_draw_color_rgba8_i(ctx, 235, 235, 214, 255);
ecex_log("tetris_draw: sidebar title");
ecex_draw_label_i(ctx, sx, sy, 1);
sy += ((int)ctx->line_height * 16) / 10;
@@ -475,11 +507,11 @@ static int tetris_draw(ecex_t *ed, buffer_t *buffer, ecex_draw_context_t *ctx, v
ecex_draw_label_i(ctx, sx, sy, 5);
sy += ((int)ctx->line_height * 8) / 10;
- ecex_log_int("tetris_draw: preview_piece=", tetris_next_piece(ed, s));
- ecex_draw_tetris_preview_i(ctx, tetris_next_piece(ed, s), sx, sy, (cell * 72) / 100, 255);
+ ecex_log_int("tetris_draw: preview_piece=", tetris_next_piece(s));
+ ecex_draw_tetris_preview_i(ctx, tetris_next_piece(s), sx, sy, (cell * 72) / 100, 255);
sy += cell * 4;
- ecex_draw_color_rgba8(ctx, 184, 189, 199, 255);
+ ecex_draw_color_rgba8_i(ctx, 184, 189, 199, 255);
ecex_log("tetris_draw: sidebar help");
ecex_draw_label_i(ctx, sx, sy, 6); sy += (int)ctx->line_height;
ecex_draw_label_i(ctx, sx, sy, 7); sy += (int)ctx->line_height;
@@ -489,9 +521,9 @@ static int tetris_draw(ecex_t *ed, buffer_t *buffer, ecex_draw_context_t *ctx, v
ecex_draw_label_i(ctx, sx, sy, 11);
if (s->paused || s->game_over) {
- ecex_draw_color_rgba8(ctx, 0, 0, 0, 174);
+ ecex_draw_color_rgba8_i(ctx, 0, 0, 0, 174);
ecex_draw_rect_i(ctx, ox, oy + (board_h * 43) / 100, board_w, ((int)ctx->line_height * 22) / 10);
- ecex_draw_color_rgba8(ctx, 255, 235, 89, 255);
+ ecex_draw_color_rgba8_i(ctx, 255, 235, 89, 255);
ecex_draw_label_i(ctx, ox + cell, oy + (board_h * 43) / 100 + ((int)ctx->line_height * 55) / 100, s->game_over ? 12 : 13);
}
@@ -502,8 +534,7 @@ static int tetris_draw(ecex_t *ed, buffer_t *buffer, ecex_draw_context_t *ctx, v
static void tetris_free_state(void *userdata) {
tetris_state_t *s = (tetris_state_t *)userdata;
if (!s) return;
- ecex_var_free_owner(s->ed, s);
- ecex_config_free(s);
+ ecex_plugin_object_free(s->plugin, s);
}
static int cmd_tetris(ecex_t *ed) {
@@ -527,25 +558,25 @@ static int cmd_tetris(ecex_t *ed) {
ecex_log_ptr("cmd_tetris: existing state=", s);
if (!s) {
ecex_log_int("cmd_tetris: allocating state bytes=", (int)sizeof(*s));
- s = (tetris_state_t *)ecex_config_calloc(1, sizeof(*s));
+ ecex_plugin_t *plugin = ecex_plugin_find(ed, "tetris");
+ s = (tetris_state_t *)ecex_plugin_object_calloc(plugin, "state", 1, sizeof(*s));
ecex_log_ptr("cmd_tetris: allocated state=", s);
if (!s) { ecex_log("cmd_tetris: allocation failed"); return -1; }
- s->ed = ed;
- ecex_log_int("cmd_tetris: registry board bytes=", (int)((size_t)TETRIS_CELLS * sizeof(int)));
- ecex_log_ptr("cmd_tetris: registry board=", tetris_board(ed, s));
- if (!tetris_board(ed, s)) {
- ecex_log("cmd_tetris: registry board allocation failed");
- ecex_var_free_owner(ed, s);
- ecex_config_free(s);
+ s->plugin = plugin;
+ ecex_log_int("cmd_tetris: board slot bytes=", (int)((size_t)TETRIS_CELLS * sizeof(int)));
+ ecex_log_ptr("cmd_tetris: board slot=", tetris_board(s));
+ if (!tetris_board(s)) {
+ ecex_log("cmd_tetris: board slot allocation failed");
+ ecex_plugin_object_free(plugin, s);
return -1;
}
- tetris_reset(ed, s);
+ tetris_reset(s);
ecex_log("cmd_tetris: setting renderer");
if (ecex_buffer_set_renderer(buffer, tetris_draw, s, tetris_free_state, ECEX_RENDER_REPLACE_CONTENT) != 0) {
ecex_log("cmd_tetris: set_renderer failed");
- ecex_config_free(s);
+ ecex_plugin_object_free(plugin, s);
return -1;
}
@@ -577,19 +608,19 @@ static int cmd_tetris_new(ecex_t *ed) {
ecex_log("cmd_tetris_new: enter");
tetris_state_t *s = tetris_state_for_ed(ed);
if (!s) return cmd_tetris(ed);
- tetris_reset(ed, s);
+ tetris_reset(s);
return 0;
}
static int cmd_tetris_left(ecex_t *ed) {
ecex_log("cmd_tetris_left: enter");
- tetris_move_horizontal(ed, tetris_state_for_ed(ed), -1);
+ tetris_move_horizontal(tetris_state_for_ed(ed), -1);
return 0;
}
static int cmd_tetris_right(ecex_t *ed) {
ecex_log("cmd_tetris_right: enter");
- tetris_move_horizontal(ed, tetris_state_for_ed(ed), 1);
+ tetris_move_horizontal(tetris_state_for_ed(ed), 1);
return 0;
}
@@ -597,7 +628,7 @@ static int cmd_tetris_down(ecex_t *ed) {
ecex_log("cmd_tetris_down: enter");
tetris_state_t *s = tetris_state_for_ed(ed);
if (s) {
- if (tetris_soft_drop(ed, s)) s->score += 1;
+ if (tetris_soft_drop(s)) s->score += 1;
s->last_drop_ms = 0;
}
return 0;
@@ -611,12 +642,12 @@ static int cmd_tetris_rotate(ecex_t *ed) {
if (!s || s->game_over || s->paused) return 0;
nr = (s->rot + 1) & 3;
- if (!tetris_collides(ed, s, s->piece, nr, s->x, s->y)) {
+ if (!tetris_collides(s, s->piece, nr, s->x, s->y)) {
s->rot = nr;
- } else if (!tetris_collides(ed, s, s->piece, nr, s->x - 1, s->y)) {
+ } else if (!tetris_collides(s, s->piece, nr, s->x - 1, s->y)) {
--s->x;
s->rot = nr;
- } else if (!tetris_collides(ed, s, s->piece, nr, s->x + 1, s->y)) {
+ } else if (!tetris_collides(s, s->piece, nr, s->x + 1, s->y)) {
++s->x;
s->rot = nr;
}
@@ -626,7 +657,7 @@ static int cmd_tetris_rotate(ecex_t *ed) {
static int cmd_tetris_drop(ecex_t *ed) {
ecex_log("cmd_tetris_drop: enter");
- tetris_hard_drop(ed, tetris_state_for_ed(ed));
+ tetris_hard_drop(tetris_state_for_ed(ed));
return 0;
}
@@ -645,8 +676,9 @@ static int cmd_tetris_quit(ecex_t *ed) {
return ecex_execute_command(ed, "quit-window");
}
-int ecex_tetris_plugin(ecex_t *ed) {
+ECEX_PLUGIN_BEGIN(ecex_tetris_plugin, "tetris")
ecex_log("ecex_tetris_plugin: enter");
+ (void)plugin;
ECEX_CONFIG_MODE(TETRIS_MODE);
ECEX_CONFIG_COMMAND("tetris", cmd_tetris);
ECEX_CONFIG_COMMAND("tetris-new", cmd_tetris_new);
@@ -673,7 +705,7 @@ int ecex_tetris_plugin(ecex_t *ed) {
ecex_log("ecex_tetris_plugin: registered all commands and keybinds");
return 0;
-}
+ECEX_PLUGIN_END
#ifndef ECEX_NO_STANDALONE_CONFIG
ECEX_CONFIG_BEGIN