2024-05-14 04:20:20 +00:00
|
|
|
#include "tetra.h"
|
|
|
|
|
|
|
|
|
2024-05-15 22:10:47 +00:00
|
|
|
bool CreateTetra(struct Tetra *tetra, u16 wid, u16 hgt)
|
2024-05-14 04:20:20 +00:00
|
|
|
{
|
|
|
|
u8 *blks = calloc(wid * hgt, sizeof(u8));
|
|
|
|
|
|
|
|
if (blks == nullptr)
|
|
|
|
return false;
|
|
|
|
|
2024-05-15 22:10:47 +00:00
|
|
|
*tetra = (struct Tetra) {
|
|
|
|
.blks = blks,
|
2024-05-14 04:20:20 +00:00
|
|
|
|
2024-05-15 22:10:47 +00:00
|
|
|
.wid = wid,
|
|
|
|
.hgt = hgt,
|
|
|
|
|
|
|
|
.x = 0,
|
|
|
|
.y = 0,
|
|
|
|
|
|
|
|
.rot = 0
|
|
|
|
};
|
2024-05-14 04:20:20 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreeTetra(struct Tetra *tetra)
|
|
|
|
{
|
|
|
|
free(tetra->blks);
|
|
|
|
}
|
|
|
|
|
2024-05-15 22:10:47 +00:00
|
|
|
void TetraSet(struct Tetra *tetra, struct TetraTemplate *template)
|
2024-05-14 04:20:20 +00:00
|
|
|
{
|
2024-05-15 22:10:47 +00:00
|
|
|
tetra->blks = template->blks;
|
|
|
|
tetra->wid = template->wid;
|
|
|
|
tetra->hgt = template->hgt;
|
|
|
|
|
|
|
|
tetra->x = 0;
|
|
|
|
tetra->y = 0;
|
|
|
|
tetra->rot = 0;
|
2024-05-14 04:20:20 +00:00
|
|
|
}
|
|
|
|
|
2024-05-15 22:10:47 +00:00
|
|
|
usize rotate_index(usize i, usize wid, u8 rot)
|
2024-05-14 04:20:20 +00:00
|
|
|
{
|
2024-05-15 22:10:47 +00:00
|
|
|
if(rot == 0)
|
|
|
|
return i;
|
2024-05-14 04:20:20 +00:00
|
|
|
|
2024-05-15 22:10:47 +00:00
|
|
|
usize row = i / wid;
|
|
|
|
usize col = i % wid;
|
|
|
|
|
|
|
|
switch (rot) {
|
|
|
|
case 1:
|
|
|
|
return (wid - col - 1) * wid + row;
|
|
|
|
case 2:
|
|
|
|
return (wid - row - 1) * wid + (wid - col - 1);
|
|
|
|
case 3:
|
|
|
|
return col * wid + (wid - row - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2024-05-14 04:20:20 +00:00
|
|
|
}
|
|
|
|
|
2024-05-19 06:56:14 +00:00
|
|
|
bool TetraIsCollision(struct Tetra *piece, struct Tetra *board)
|
2024-05-14 04:20:20 +00:00
|
|
|
{
|
|
|
|
usize i = 0;
|
2024-05-19 06:56:14 +00:00
|
|
|
for (i16 y = piece->y; y < piece->y + piece->hgt; y++) {
|
|
|
|
for (i16 x = piece->x; x < piece->x + piece->wid; x++, i++) {
|
|
|
|
usize rot_i = rotate_index(i, piece->wid, piece->rot);
|
2024-05-15 22:10:47 +00:00
|
|
|
|
2024-05-19 06:56:14 +00:00
|
|
|
if(piece->blks[rot_i] == 0)
|
2024-05-14 04:20:20 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if(x < 0 or x >= board->wid or y < 0 or y >= board->hgt)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if(board->blks[board->wid * y + x] != 0)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-05-15 22:10:47 +00:00
|
|
|
bool TetraMove(struct Tetra *t, struct Tetra *board, i16 dx, i16 dy)
|
|
|
|
{
|
|
|
|
t->x += dx;
|
|
|
|
t->y += dy;
|
|
|
|
|
|
|
|
if (TetraIsCollision(t, board)) {
|
|
|
|
t->x -= dx;
|
|
|
|
t->y -= dy;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TetraRotate(struct Tetra *t, struct Tetra *board, i8 dr)
|
|
|
|
{
|
|
|
|
u8 rot = t->rot;
|
|
|
|
t->rot = (t->rot + 4 + dr) % 4;
|
|
|
|
|
|
|
|
if (TetraIsCollision(t, board)) {
|
|
|
|
t->rot = rot;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TetraOverlay(struct Tetra *t, struct Tetra *board)
|
|
|
|
{
|
|
|
|
usize i = 0;
|
|
|
|
for (i16 y = t->y; y < t->y + t->hgt; y++) {
|
|
|
|
for (i16 x = t->x; x < t->x + t->wid; x++, i++) {
|
|
|
|
usize rot_i = rotate_index(i, t->wid, t->rot);
|
|
|
|
|
|
|
|
if(t->blks[rot_i] == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if(x < 0 or x >= board->wid or y < 0 or y >= board->hgt)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
board->blks[board->wid * y + x] = t->blks[rot_i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-19 06:56:14 +00:00
|
|
|
void TetraTerminalClear(struct Tetra *board, struct Terminal *term, u16 OFS_X, u16 OFS_Y)
|
2024-05-14 04:20:20 +00:00
|
|
|
{
|
2024-05-19 06:56:14 +00:00
|
|
|
for (i16 y = board->y; y < board->y + board->hgt; y++) {
|
|
|
|
for (i16 x = board->x; x < board->x + board->wid; x++) {
|
|
|
|
struct Char4 *ch4 = TerminalGet(term, (x * 2) + OFS_X, y + OFS_Y);
|
2024-05-14 04:20:20 +00:00
|
|
|
|
2024-05-19 06:56:14 +00:00
|
|
|
ch4[0] = (struct Char4) { .ch = '.', .color.fg = 8 };
|
|
|
|
ch4[1] = (struct Char4) { .ch = ' ', .color.fg = 8 };
|
|
|
|
}
|
2024-05-14 04:20:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-19 06:56:14 +00:00
|
|
|
void TetraTerminalDraw(struct Tetra *piece, struct Terminal *term, u16 OFS_X, u16 OFS_Y)
|
2024-05-14 04:20:20 +00:00
|
|
|
{
|
|
|
|
static const u8f blk_colors[8] = { 8, 14, 11, 13, 10, 9, 12, 3 };
|
|
|
|
|
|
|
|
usize i = 0;
|
2024-05-19 06:56:14 +00:00
|
|
|
for (i16 y = piece->y; y < piece->y + piece->hgt; y++) {
|
|
|
|
for (i16 x = piece->x; x < piece->x + piece->wid; x++, i++) {
|
|
|
|
usize rot_i = rotate_index(i, piece->wid, piece->rot);
|
2024-05-15 22:10:47 +00:00
|
|
|
|
2024-05-19 06:56:14 +00:00
|
|
|
if (piece->blks[rot_i] == 0)
|
2024-05-14 04:20:20 +00:00
|
|
|
continue;
|
|
|
|
|
2024-05-19 06:56:14 +00:00
|
|
|
struct Char4 *ch4 = TerminalGet(term, (x * 2) + OFS_X, y + OFS_Y);
|
|
|
|
|
|
|
|
u8 fg = blk_colors[piece->blks[rot_i]];
|
|
|
|
|
|
|
|
ch4[0] = (struct Char4) { .ch = '[', .color.fg = fg };
|
|
|
|
ch4[1] = (struct Char4) { .ch = ']', .color.fg = fg };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TetraTerminalDrawGhost(struct Tetra *t, struct Tetra *board, struct Terminal *term, u16 OFS_X, u16 OFS_Y)
|
|
|
|
{
|
|
|
|
struct Tetra ghost = *t;
|
|
|
|
while(TetraMove(&ghost, board, 0, 1));
|
|
|
|
|
|
|
|
usize i = 0;
|
|
|
|
for (i16 y = ghost.y; y < ghost.y + ghost.hgt; y++) {
|
|
|
|
for (i16 x = ghost.x; x < ghost.x + ghost.wid; x++, i++) {
|
|
|
|
usize rot_i = rotate_index(i, ghost.wid, ghost.rot);
|
2024-05-14 04:20:20 +00:00
|
|
|
|
2024-05-19 06:56:14 +00:00
|
|
|
if (ghost.blks[rot_i] == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
struct Char4 *ch4 = TerminalGet(term, (x * 2) + OFS_X, y + OFS_Y);
|
|
|
|
|
|
|
|
ch4[0] = (struct Char4) { .ch = '[', .color.fg = 8 };
|
|
|
|
ch4[1] = (struct Char4) { .ch = ']', .color.fg = 8 };
|
2024-05-14 04:20:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|