crashtest-r0ket/firmware/l0dable/tedliz.c

220 lines
4.3 KiB
C

// tedliz
// ======
// a kick ass tetris clone
// code by twobit (c3d2 at pentagon ville)
////////////////////////////////////////////////////////////////////////////////
#include <sysinit.h>
#include <string.h>
#include "basic/basic.h"
#include "basic/config.h"
#include "basic/random.h"
#include "lcd/render.h"
#include "lcd/display.h"
#include "lcd/fonts.h"
#include "lcd/fonts/invaders.h"
#include "funk/mesh.h"
#include "usetable.h"
////////////////////////////////////////////////////////////////////////////////
enum {
GRID_WIDTH = 10,
GRID_HEIGHT = 20,
TICK_LENGTH = 30,
KEY_REPEAT_DELEAY = 5,
STARTING_SPEED = 12
};
// key repeat delay stuff
int key_rep[] = { 0, 0, 0, 0, 0 };
int ticks_per_drop = STARTING_SPEED;
int lines = 0;
int ticks = 0;
int rot;
int stone;
int next_rot;
int next_stone;
int x_pos;
int y_pos;
uint8_t grid[GRID_HEIGHT][GRID_WIDTH];
const uint8_t stones[7][16] = {
{ 0, 0, 0, 0, 0,15,15, 0, 0,15,15, 0, 0, 0, 0, 0 },
{ 0, 0,10, 0, 5, 5,15, 5, 0, 0,10, 0, 0, 0,10, 0 },
{ 0, 0, 5, 0, 0, 0,15,15, 0,10,10, 5, 0, 0, 0, 0 },
{ 0, 0, 0, 5, 0,10,15, 5, 0, 0,15,10, 0, 0, 0, 0 },
{ 0, 4, 5, 8, 0,10,15,10, 0, 2, 5, 1, 0, 0, 0, 0 },
{ 0, 8, 5, 1, 0,10,15,10, 0, 4, 5, 2, 0, 0, 0, 0 },
{ 0, 0,11, 0, 0,13,15, 7, 0, 0,14, 0, 0, 0, 0, 0 }
};
void draw_grid();
void new_stone();
int collision(int top_also);
void ram() {
int raw_key, key;
int i, j;
new_stone();
new_stone();
// epmty grid
for(i = 0; i < GRID_HEIGHT; i++)
for(j = 0; j < GRID_WIDTH; j++)
grid[i][j] = 0;
// prepare screen
lcdClear();
for(i = 0; i < 96; i++) {
lcdSetPixel(i, 2, 1);
lcdSetPixel(i, 65, 1);
}
for(i = 3; i < 65; i++) {
lcdSetPixel(2, i, 1);
lcdSetPixel(35, i, 1);
lcdSetPixel(93, i, 1);
}
for(;;) {
// handle input
raw_key = getInputRaw();
key = 0;
for(i = 0; i < 5; i++) {
if(raw_key & (1 << i)) {
if(!key_rep[i] || key_rep[i] == KEY_REPEAT_DELEAY) key |= 1 << i;
key_rep[i] += key_rep[i] < KEY_REPEAT_DELEAY;
}
else key_rep[i] = 0;
}
// rotate
if(key & BTN_UP) {
i = rot;
rot = (rot << 1) % 15;
if(collision(0)) rot = i;
}
// horizontal movement
i = x_pos;
x_pos += !!(key & BTN_RIGHT) - !!(key & BTN_LEFT);
if(i != x_pos && collision(0)) x_pos = i;
// vertical movement
ticks++;
if(key & BTN_DOWN || ticks >= ticks_per_drop) {
ticks = 0;
y_pos++;
if(collision(0)) {
y_pos--;
// check for game over
if(collision(1)) return;
// copy stone to grid
int x, y;
for(y = 0; y < 4; y++) {
for(x = 0; x < 4; x++) {
if(stones[stone][(x << 2) + y] & rot)
grid[y + y_pos][x + x_pos] = 1;
}
}
// check for complete lines
for(y = 0; y < GRID_HEIGHT; y++) {
for(x = 0; x < GRID_WIDTH; x++)
if(!grid[y][x]) break;
if(x == GRID_WIDTH) {
lines++;
ticks_per_drop = STARTING_SPEED - lines / 10;
if(ticks_per_drop < 1) ticks_per_drop = 1;
for(i = y; i > 0; i--)
for(x = 0; x < GRID_WIDTH; x++)
grid[i][x] = grid[i - 1][x];
}
}
// get a new stone
new_stone();
}
}
draw_grid();
lcdDisplay();
delayms(TICK_LENGTH);
}
return;
}
int collision(int top_also) {
int x, y;
for(y = 0; y < 4; y++) {
for(x = 0; x < 4; x++) {
if(stones[stone][(x << 2) + y] & rot && (
x + x_pos < 0 || x + x_pos >= GRID_WIDTH ||
(top_also && y + y_pos < 0) || y + y_pos >= GRID_HEIGHT ||
grid[y + y_pos][x + x_pos]))
return 1;
}
}
return 0;
}
void new_stone() {
x_pos = 3;
y_pos = -3;
rot = next_rot;
stone = next_stone;
next_rot = 1 << getRandom() % 4;
next_stone = getRandom() % 7;
}
void draw_block(int x, int y, int b) {
lcdSetPixel(0 + x, 0 + y, b);
lcdSetPixel(1 + x, 0 + y, b);
lcdSetPixel(2 + x, 0 + y, b);
lcdSetPixel(0 + x, 1 + y, b);
lcdSetPixel(1 + x, 1 + y, b);
lcdSetPixel(2 + x, 1 + y, b);
lcdSetPixel(0 + x, 2 + y, b);
lcdSetPixel(1 + x, 2 + y, b);
lcdSetPixel(2 + x, 2 + y, b);
}
void draw_grid() {
int b, y, x;
for(y = 0; y < GRID_HEIGHT; y++) {
for(x = 0; x < GRID_WIDTH; x++) {
b = grid[y][x] ||
(x >= x_pos && x < x_pos + 4 && y >= y_pos && y < y_pos + 4 &&
stones[stone][((x - x_pos) << 2) + (y - y_pos)] & rot);
draw_block(4 + x * 3, 4 + y * 3, b);
}
}
// look adhead
for(y = 0; y < 4; y++)
for(x = 0; x < 4; x++)
draw_block(40 + x * 3, 7 + y * 3, !!(stones[next_stone][(x << 2) + y] & next_rot));
}