summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2025-05-14 00:47:02 +0200
committerRichard Braun <rbraun@sceen.net>2025-05-14 00:47:02 +0200
commitf3c676a6a7b45888279f952f64fa3cbeb871b780 (patch)
tree5f938b57e6e3b1941c1f2727d3e086e611b27844
parent7615f0310ca90ad2d6f89dece90d73267596dbf2 (diff)
Erase rows (incomplete)
-rw-r--r--src/eetg.c83
-rw-r--r--src/eetg.h4
-rw-r--r--src/ei/ei.c4
-rw-r--r--src/et/et.c126
-rw-r--r--src/et/et.h6
5 files changed, 171 insertions, 52 deletions
diff --git a/src/eetg.c b/src/eetg.c
index 890f659..6bc2129 100644
--- a/src/eetg.c
+++ b/src/eetg.c
@@ -202,6 +202,26 @@ eetg_layer_remove(struct eetg_layer *layer, struct eetg_object *object)
return false;
}
+static struct eetg_object *
+eetg_layer_lookup(struct eetg_layer *layer, int x, int y)
+{
+ assert(layer);
+
+ for (struct eetg_object *object = layer->objects;
+ object;
+ object = object->next) {
+ char c;
+
+ c = eetg_object_get_char(object, x, y);
+
+ if ((c > 0) && (c != ' ')) {
+ return object;
+ }
+ }
+
+ return NULL;
+}
+
static void
eetg_view_cell_set(struct eetg_view_cell *view_cell,
char c, int color)
@@ -309,12 +329,11 @@ eetg_world_clear(struct eetg_world *world)
}
void
-eetg_world_register_collision_fn(struct eetg_world *world,
- eetg_handle_collision_fn handle_collision_fn,
- void *arg)
+eetg_world_set_collision_fn(struct eetg_world *world,
+ eetg_handle_collision_fn handle_collision_fn,
+ void *arg)
{
assert(world);
- assert(handle_collision_fn);
world->handle_collision_fn = handle_collision_fn;
world->handle_collision_fn_arg = arg;
@@ -386,6 +405,27 @@ eetg_world_add(struct eetg_world *world, struct eetg_object *object,
return hit;
}
+struct eetg_object *
+eetg_world_lookup(struct eetg_world *world, int x, int y, int layer_id)
+{
+ assert(world);
+
+ for (int i = ARRAY_SIZE(world->layers) - 1; i >= 0; i--) {
+ if ((layer_id < 0) || (i == layer_id)) {
+ struct eetg_layer *layer = &world->layers[i];
+ struct eetg_object *object;
+
+ object = eetg_layer_lookup(layer, x, y);
+
+ if (object) {
+ return object;
+ }
+ }
+ }
+
+ return NULL;
+}
+
void
eetg_world_remove(struct eetg_world *world, struct eetg_object *object)
{
@@ -664,31 +704,22 @@ eetg_world_render(struct eetg_world *world, bool sync)
eetg_world_swap_views(world);
}
-void
-eetg_object_init(struct eetg_object *object, int type, const char *sprite)
+static void
+eetg_object_compute_dimensions(struct eetg_object *object)
{
size_t width;
char *ptr;
assert(object);
- object->world = NULL;
- object->next = NULL;
- object->sprite = sprite;
- object->type = type;
- object->x = 0;
- object->y = 0;
- object->color = EETG_FG_COLOR;
-
- ptr = strchr(sprite, '\n');
+ ptr = strchr(object->sprite, '\n');
assert(ptr);
- width = ptr - sprite;
+ width = ptr - object->sprite;
assert(width <= INT_MAX);
object->width = (int)width;
object->height = 1;
- object->layer_id = -1;
for (;;) {
char *next;
@@ -712,6 +743,23 @@ eetg_object_init(struct eetg_object *object, int type, const char *sprite)
}
void
+eetg_object_init(struct eetg_object *object, int type, const char *sprite)
+{
+ assert(object);
+
+ object->world = NULL;
+ object->next = NULL;
+ object->sprite = sprite;
+ object->color = EETG_FG_COLOR;
+ object->type = type;
+ object->x = 0;
+ object->y = 0;
+ object->layer_id = -1;
+
+ eetg_object_compute_dimensions(object);
+}
+
+void
eetg_object_set_color(struct eetg_object *object, int color)
{
assert(object);
@@ -823,6 +871,7 @@ eetg_object_update(struct eetg_object *object)
{
assert(object);
+ eetg_object_compute_dimensions(object);
return eetg_object_move(object, object->x, object->y);
}
diff --git a/src/eetg.h b/src/eetg.h
index ee4582e..2ad9436 100644
--- a/src/eetg.h
+++ b/src/eetg.h
@@ -96,10 +96,12 @@ struct eetg_world {
void eetg_world_init(struct eetg_world *world,
eetg_write_fn write_fn, void *arg);
void eetg_world_clear(struct eetg_world *world);
-void eetg_world_register_collision_fn(struct eetg_world *world,
+void eetg_world_set_collision_fn(struct eetg_world *world,
eetg_handle_collision_fn handle_collision_fn, void *arg);
bool eetg_world_add(struct eetg_world *world, struct eetg_object *object,
int x, int y, int layer_id);
+struct eetg_object *eetg_world_lookup(struct eetg_world *world,
+ int x, int y, int layer_id);
void eetg_world_remove(struct eetg_world *world, struct eetg_object *object);
void eetg_world_render(struct eetg_world *world, bool sync);
diff --git a/src/ei/ei.c b/src/ei/ei.c
index f55e648..665ebf0 100644
--- a/src/ei/ei.c
+++ b/src/ei/ei.c
@@ -1103,9 +1103,7 @@ ei_game_init(struct ei_game *game, eetg_write_fn write_fn, void *arg)
ei_game_reset_history(game);
eetg_world_init(&game->world, write_fn, arg);
- eetg_world_register_collision_fn(&game->world,
- ei_game_handle_collision,
- game);
+ eetg_world_set_collision_fn(&game->world, ei_game_handle_collision, game);
eetg_object_init(&game->title, EI_TYPE_TITLE, EI_TITLE_SPRITE);
eetg_object_set_color(&game->title, EETG_COLOR_BLUE);
diff --git a/src/et/et.c b/src/et/et.c
index f8758c4..bc1b673 100644
--- a/src/et/et.c
+++ b/src/et/et.c
@@ -192,6 +192,14 @@ et_piece_init(struct et_piece *piece)
piece->type = -1;
}
+static struct et_piece *
+et_piece_get(struct eetg_object *object)
+{
+ assert(eetg_object_get_type(object) == ET_TYPE_PIECE);
+
+ return structof(object, struct et_piece, object);
+}
+
static struct eetg_object *
et_piece_get_object(struct et_piece *piece)
{
@@ -574,6 +582,40 @@ et_piece_move_right(struct et_piece *piece)
eetg_object_get_y(object));
}
+static bool
+et_piece_erase_row(struct et_piece *piece, int row)
+{
+ struct eetg_object *object;
+ int width, height, src_index, dest_index;
+ char *src, *dest;
+ bool empty = false;
+
+ assert(piece);
+
+ object = &piece->object;
+
+ row -= eetg_object_get_y(object);
+ width = eetg_object_get_width(object);
+ height = eetg_object_get_height(object);
+
+ assert((row >= 0) && (row < eetg_object_get_height(object)));
+
+ dest_index = row * (width + 1);
+ src_index = dest_index + width + 1;
+ src = &piece->sprite[src_index];
+ dest = &piece->sprite[dest_index];
+
+ memmove(dest, src, ((height - row - 1) * (width + 1)) + 1);
+
+ if (piece->sprite[0] == '\0') {
+ empty = true;
+ } else {
+ eetg_object_update(object);
+ }
+
+ return empty;
+}
+
static struct et_piece *
et_game_alloc_piece(struct et_game *game)
{
@@ -747,35 +789,79 @@ et_game_switch_to_next_piece(struct et_game *game)
}
static bool
+et_game_handle_collision(struct eetg_object *object1,
+ struct eetg_object *object2,
+ int x, int y, void *arg)
+{
+ (void)x;
+ (void)y;
+ (void)arg;
+
+ if (et_has_type(object1, object2, ET_TYPE_BG)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool
et_game_scan_row(struct et_game *game, int row)
{
-#if 0
- for (int i = 0; i < ET_FRAME_WIDTH; i += 2) {
- int cell;
+ struct et_piece *pieces[ET_FRAME_WIDTH], *prev;
+
+ for (int i = 0; i < (int)ARRAY_SIZE(pieces); i++) {
+ struct eetg_object *object;
+
+ object = eetg_world_lookup(&game->world, ET_FRAME_X + (i * 2), row, 1);
- cell = eetg_object_get_cell(
+ if (!object) {
+ return false;
+ }
+
+ pieces[i] = et_piece_get(object);
}
-#endif
- return false;
+ eetg_world_set_collision_fn(&game->world, NULL, NULL);
+
+ for (int i = 0; i < (int)ARRAY_SIZE(pieces); i++) {
+ struct et_piece *piece = pieces[i];
+ bool empty;
+
+ if (piece == prev) {
+ continue;
+ }
+
+ empty = et_piece_erase_row(piece, row);
+
+ if (empty) {
+ eetg_world_remove(&game->world, et_piece_get_object(piece));
+ /* TODO Free piece. */
+ } else {
+ et_piece_move_down(piece);
+ }
+
+ prev = piece;
+ }
+
+ eetg_world_set_collision_fn(&game->world, et_game_handle_collision, game);
+
+ return true;
}
static void
et_game_scan_rows(struct et_game *game)
{
- int cleared_rows[4];
int nr_cleared_rows = 0;
for (int i = 0; i < ET_FRAME_HEIGHT; i++) {
bool cleared;
- cleared = et_game_scan_row(game, i);
+ cleared = et_game_scan_row(game, ET_FRAME_Y + i);
if (cleared) {
- cleared_rows[nr_cleared_rows] = i;
nr_cleared_rows++;
- if (nr_cleared_rows == ARRAY_SIZE(cleared_rows)) {
+ if (nr_cleared_rows == 4) {
break;
}
}
@@ -847,22 +933,6 @@ et_game_start_lockdown(struct et_game *game, bool nodelay)
}
}
-static bool
-et_game_handle_collision(struct eetg_object *object1,
- struct eetg_object *object2,
- int x, int y, void *arg)
-{
- (void)x;
- (void)y;
- (void)arg;
-
- if (et_has_type(object1, object2, ET_TYPE_BG)) {
- return false;
- }
-
- return true;
-}
-
static void
et_game_reset_history(struct et_game *game)
{
@@ -1017,9 +1087,7 @@ et_game_init(struct et_game *game, eetg_write_fn write_fn, void *arg)
et_bag_init(&game->bag);
eetg_world_init(&game->world, write_fn, arg);
- eetg_world_register_collision_fn(&game->world,
- et_game_handle_collision,
- game);
+ eetg_world_set_collision_fn(&game->world, et_game_handle_collision, game);
eetg_object_init(&game->title, ET_TYPE_TITLE, ET_TITLE_SPRITE);
eetg_object_set_color(&game->title, EETG_COLOR_BLUE);
diff --git a/src/et/et.h b/src/et/et.h
index dce0e9a..2c2098e 100644
--- a/src/et/et.h
+++ b/src/et/et.h
@@ -54,8 +54,10 @@
/*
* Take into account the following :
- * - Square of the longest piece, with 2 characters per cell when horizontal
- * - newlines
+ * - the longest piece is 4 squares long
+ * - tetromino squares are one character high, two characters wide
+ * - each row ends with a newline
+ * - all sprites are initially squares
* - null terminating character
*/
#define ET_PIECE_SPRITE_SIZE ((((4 * 2) + 1) * 4) + 1)