diff --git a/overlay/rootfs/usr/bin/snake b/overlay/rootfs/usr/bin/snake index aafc972..eb21fd5 100755 Binary files a/overlay/rootfs/usr/bin/snake and b/overlay/rootfs/usr/bin/snake differ diff --git a/overlay/rootfs/usr/bin/tetris b/overlay/rootfs/usr/bin/tetris index a6cae25..ece86ab 100755 Binary files a/overlay/rootfs/usr/bin/tetris and b/overlay/rootfs/usr/bin/tetris differ diff --git a/prebuilt/games/usr/bin/snake b/prebuilt/games/usr/bin/snake index aafc972..eb21fd5 100755 Binary files a/prebuilt/games/usr/bin/snake and b/prebuilt/games/usr/bin/snake differ diff --git a/prebuilt/games/usr/bin/tetris b/prebuilt/games/usr/bin/tetris index a6cae25..ece86ab 100755 Binary files a/prebuilt/games/usr/bin/tetris and b/prebuilt/games/usr/bin/tetris differ diff --git a/src/games/snake.cpp b/src/games/snake.cpp index 77dabe6..08a96a0 100644 --- a/src/games/snake.cpp +++ b/src/games/snake.cpp @@ -102,12 +102,13 @@ static State state = PLAYING; static int snake[COLS * ROWS][2]; // x,y per segment (0 = tail) static int snakelen = 4; static int dirx = 1, diry = 0; // current direction -static int ndirx = 1, ndiry = 0; // buffered next direction +static int tqx[4], tqy[4]; // queued pending turns (rapid presses not lost) +static int tqh = 0, tqt = 0, tqn = 0; static int foodx, foody; static int score = 0; static int best = 0; static int speed = 90; // ms per step (derived from pps below) -static int pps = 100; // base speed px/sec; +1 px/sec per 5 food eaten +static int pps = 130; // base speed px/sec; +1 px/sec per 5 food eaten static unsigned long nextTick = 0; static bool running = true; static unsigned long now_ms() { @@ -163,19 +164,33 @@ static void reset_game() { snake[i][1] = cy; } dirx = 1; diry = 0; - ndirx = 1; ndiry = 0; + tqh = tqt = tqn = 0; score = 0; - pps = 100; + pps = 130; update_speed(); place_food(); state = PLAYING; nextTick = now_ms() + speed; } +// Queue a pending direction change; rapid key presses are stored so none are lost. +static void tq_push(int dx, int dy) { + if (tqn >= 4) return; // queue full: drop the new turn + tqx[(tqh + tqn) % 4] = dx; + tqy[(tqh + tqn) % 4] = dy; + tqn++; +} + static void step() { - // apply buffered direction (no reversing) - if (!(ndirx == -dirx && ndiry == -diry) && !(ndirx == 0 && ndiry == 0)) { - dirx = ndirx; diry = ndiry; + // apply the oldest queued turn (no reversing); rapid presses are not lost + int tdx = 0, tdy = 0; + if (tqn > 0) { + tdx = tqx[tqt]; tdy = tqy[tqt]; + tqt = (tqt + 1) % 4; + tqn--; + } + if (!(tdx == -dirx && tdy == -diry) && !(tdx == 0 && tdy == 0)) { + dirx = tdx; diry = tdy; } int hx = snake[snakelen - 1][0] + dirx; int hy = snake[snakelen - 1][1] + diry; @@ -202,7 +217,7 @@ static void step() { score += 10; if (score > best) best = score; int food = score / 10; // food items eaten so far - pps = 70 + food / 5; // +1 px/sec per 5 food eaten (progressive difficulty) + pps = 130 + food / 5; // +1 px/sec per 5 food eaten (progressive difficulty) update_speed(); place_food(); } @@ -273,13 +288,13 @@ static void render() { static void handle_key(KeySym ks) { switch (ks) { case XK_Up: case XK_w: case XK_KP_Up: case XK_2: - ndirx = 0; ndiry = -1; break; + tq_push(0, -1); break; case XK_Down: case XK_s: case XK_KP_Down: case XK_8: case XK_x: - ndirx = 0; ndiry = 1; break; + tq_push(0, 1); break; case XK_Left: case XK_a: case XK_KP_Left: case XK_4: - ndirx = -1; ndiry = 0; break; + tq_push(-1, 0); break; case XK_Right: case XK_d: case XK_KP_Right: case XK_6: - ndirx = 1; ndiry = 0; break; + tq_push(1, 0); break; case XK_5: case XK_Return: case XK_KP_Enter: case XK_space: case XK_p: if (state == PLAYING) state = PAUSED; else if (state == PAUSED) { state = PLAYING; nextTick = now_ms() + speed; } diff --git a/src/games/tetris.cpp b/src/games/tetris.cpp index 98bb297..8d5576d 100644 --- a/src/games/tetris.cpp +++ b/src/games/tetris.cpp @@ -93,6 +93,7 @@ static Pixmap back; static int screen; static int winW = 240, winH = 296; // overridden at runtime from the actual screen static unsigned long C_BG, C_FG, C_HEAD, C_FOOD, C_DIM; +static unsigned long C_GB_DARK, C_GB_MED, C_GB_LIGHT, C_GB_PALE; // ---- tetromino definitions (state 0 within a 4x4 box) ---- // type 0..6 -> I,O,T,S,Z,J,L @@ -263,6 +264,19 @@ static void draw_text(int x, int y, int scale, unsigned long col, const char* s) } } +// Draw a Gameboy-style beveled cell: medium body, pale top/left highlight, +// dark bottom/right shadow. bodycol is the fill shade (settled vs active). +static void draw_gb_cell(int x, int y, int size, unsigned long bodycol) { + XSetForeground(dpy, gc, bodycol); + XFillRectangle(dpy, back, gc, x + 1, y + 1, size - 2, size - 2); + XSetForeground(dpy, gc, C_GB_PALE); + XFillRectangle(dpy, back, gc, x + 1, y, size - 2, 1); + XFillRectangle(dpy, back, gc, x, y + 1, 1, size - 2); + XSetForeground(dpy, gc, C_GB_DARK); + XFillRectangle(dpy, back, gc, x + 1, y + size - 1, size - 2, 1); + XFillRectangle(dpy, back, gc, x + size - 1, y + 1, 1, size - 2); +} + static void render() { int px0 = 8, py0 = 8; XSetForeground(dpy, gc, C_BG); @@ -275,21 +289,18 @@ static void render() { // settled blocks for (int x = 0; x < PCOLS; x++) for (int y = 0; y < PROWS; y++) - if (board[x][y]) { - XSetForeground(dpy, gc, C_FG); - XFillRectangle(dpy, back, gc, px0 + x * CELL, py0 + y * CELL, CELL, CELL); - } + if (board[x][y]) + draw_gb_cell(px0 + x * CELL, py0 + y * CELL, CELL, C_GB_MED); // active piece if (state == PLAYING) { int cells[4][2]; piece_cells(curType, curRot, cells); - XSetForeground(dpy, gc, C_HEAD); for (int i = 0; i < 4; i++) { int cx = curX + cells[i][0]; int cy = curY + cells[i][1]; if (cy >= 0) - XFillRectangle(dpy, back, gc, px0 + cx * CELL, py0 + cy * CELL, CELL, CELL); + draw_gb_cell(px0 + cx * CELL, py0 + cy * CELL, CELL, C_GB_LIGHT); } } @@ -320,11 +331,10 @@ static void render() { int prows = maxy - miny + 1; int nx0 = sx + ((winW - sx - 4) - pcols * pcell) / 2; int ny0 = boxY + (boxH - prows * pcell) / 2 + 12; // sit lower in the frame - XSetForeground(dpy, gc, C_HEAD); for (int i = 0; i < 4; i++) { int cx = nx0 + (nc[i][0] - minx) * pcell; int cy = ny0 + (nc[i][1] - miny) * pcell; - XFillRectangle(dpy, back, gc, cx, cy, pcell, pcell); + draw_gb_cell(cx, cy, pcell, C_HEAD); } int ty = boxY + boxH + 6; char buf[32]; @@ -402,6 +412,11 @@ static void setup_window() { C_HEAD = 0x99ff99; C_FOOD = 0x66ff66; C_DIM = 0x2f9f2f; + // Gameboy-style four-shade green palette + C_GB_DARK = 0x1f7f1f; // bottom/right shadow + C_GB_MED = 0x3faf3f; // settled block body + C_GB_LIGHT = 0x7fdf7f; // active piece body + C_GB_PALE = 0xbfffbf; // top/left highlight XSelectInput(dpy, win, KeyPressMask | StructureNotifyMask | ExposureMask); XMapWindow(dpy, win);