X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=ansitris;a=blobdiff_plain;f=src%2Fgame.c;h=f530bac4259cddeaf85ddfe1b83ee75765d05900;hp=e8b47f3ee2f4d20cf658678317bfeb37f9f44981;hb=HEAD;hpb=0bdf1f5608fc18fe9d999bd400e951df9342c831 diff --git a/src/game.c b/src/game.c index e8b47f3..f530bac 100644 --- a/src/game.c +++ b/src/game.c @@ -1,5 +1,7 @@ #include +#include #include +#include #include #include "game.h" #include "pieces.h" @@ -22,6 +24,8 @@ enum { G_CDOT = 0xf8 }; +enum { ERASE_PIECE, DRAW_PIECE }; + enum { BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, YELLOW, WHITE }; /* dimensions of the whole screen */ @@ -33,19 +37,63 @@ enum { BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, YELLOW, WHITE }; #define PF_COLS 10 /* offset of the playfield from the left side of the screen */ #define PF_XOFFS 2 +#define PF_YOFFS 0 #define CHAR(c, fg, bg) \ ((uint16_t)(c) | ((uint16_t)(fg) << 12) | ((uint16_t)(bg) << 8)) -uint16_t scr[SCR_COLS * SCR_ROWS]; +int scr[SCR_COLS * SCR_ROWS]; + +static int collision(int piece, const int *pos); +static void stick(int piece, const int *pos); +static void erase_completed(void); +static void draw_piece(int piece, const int *pos, int rot, int mode); +static void drawbg(void); +static void drawpf(void); +static void draw_line(int row, int blink); +static void wrtile(int tileid); + -static void wrchar(uint16_t c); +static int pos[2], next_pos[2]; +static int cur_piece = -1; +static int cur_rot, prev_rot; +static int complines[4] = {-1, -1, -1, -1}; +static int num_complines; + +enum { + TILE_BLACK, + TILE_PF, + TILE_PFSEP, + TILE_IPIECE, + TILE_OPIECE, + TILE_JPIECE, + TILE_LPIECE, + TILE_SPIECE, + TILE_TPIECE, + TILE_ZPIECE +}; +#define FIRST_PIECE_TILE TILE_IPIECE + +static uint16_t tiles[][2] = { + { CHAR(' ', BLACK, BLACK), CHAR(' ', BLACK, BLACK) }, /* black tile */ + { CHAR(' ', WHITE, WHITE), CHAR(' ', WHITE, WHITE) }, /* playfield background */ + { CHAR(G_CHECKER, WHITE, BLACK), CHAR(G_CHECKER, WHITE, BLACK) }, /* well separator */ + { CHAR(' ', CYAN, CYAN), CHAR(' ', CYAN, CYAN) }, /* straight */ + { CHAR(' ', BLUE, BLUE), CHAR(' ', BLUE, BLUE) }, /* box */ + { CHAR(' ', GREEN, GREEN), CHAR(' ', GREEN, GREEN) }, /* J */ + { CHAR(' ', YELLOW, YELLOW), CHAR(' ', YELLOW, YELLOW) }, /* L */ + { CHAR(' ', MAGENTA, MAGENTA), CHAR(' ', MAGENTA, MAGENTA) }, /* S */ + { CHAR(' ', RED, BLACK), CHAR(' ', RED, BLACK) }, /* T */ + { CHAR(' ', RED, RED), CHAR(' ', RED, RED) }, /* Z */ +}; int init_game(void) { int i, j; - uint16_t *row = scr; + int *row = scr; + + srand(time(0)); tick_interval = 1000; @@ -54,23 +102,20 @@ int init_game(void) /* fill the screen buffer, and draw */ for(i=0; i PF_ROWS || j < PF_XOFFS - 1 || j > PF_XOFFS + PF_COLS) { - row[j] = CHAR(' ', WHITE, BLACK); + row[j] = TILE_BLACK; } else if((i == PF_ROWS && j >= PF_XOFFS && j < PF_XOFFS + PF_COLS) || j == PF_XOFFS - 1 || j == PF_XOFFS + PF_COLS) { - row[j] = CHAR(G_CHECKER, WHITE, BLACK); + row[j] = TILE_PFSEP; } else { - row[j] = CHAR(' ', BLACK, WHITE); + row[j] = TILE_PF; } - - wrchar(row[j]); } - row += SCR_COLS; } + + drawbg(); fflush(stdout); return 0; @@ -81,8 +126,7 @@ void cleanup_game(void) ansi_reset(); } -static int pos[2] = {0, PF_COLS / 2}; -static int next_pos[2] = {0, PF_COLS / 2}; +#define BLINK_UPD_RATE 100 long update(long msec) { @@ -91,55 +135,343 @@ long update(long msec) dt = msec - prev_tick; + if(num_complines) { + /* lines where completed, we're in blinking mode */ + int i, blink = dt >> 8; + + if(blink > 6) { + erase_completed(); + num_complines = 0; + return 0; + } + + for(i=0; i= tick_interval) { - next_pos[0] = (pos[0] + 1) % PF_ROWS; + if(cur_piece >= 0) { + next_pos[0] = pos[0] + 1; + if(collision(cur_piece, next_pos)) { + next_pos[0] = pos[0]; + stick(cur_piece, next_pos); + cur_piece = -1; + return 0; + } + } else { + /* respawn */ + cur_piece = rand() % NUM_PIECES; + prev_rot = cur_rot = 0; + pos[0] = piece_spawnpos[cur_piece][0]; + next_pos[0] = pos[0] + 1; + pos[1] = next_pos[1] = PF_COLS / 2 + piece_spawnpos[cur_piece][1]; + } + dt -= tick_interval; prev_tick = msec; } - if(memcmp(pos, next_pos, sizeof pos) != 0) { - ansi_setcursor(pos[0], (PF_XOFFS + pos[1]) * 2); - wrchar(CHAR(' ', BLACK, WHITE)); - + if(cur_piece >= 0 && (memcmp(pos, next_pos, sizeof pos) != 0 || cur_rot != prev_rot)) { + draw_piece(cur_piece, pos, prev_rot, ERASE_PIECE); + draw_piece(cur_piece, next_pos, cur_rot, DRAW_PIECE); memcpy(pos, next_pos, sizeof pos); - ansi_setcursor(pos[0], (PF_XOFFS + pos[1]) * 2); - wrchar(CHAR(' ', RED, RED)); - - fflush(stdout); + prev_rot = cur_rot; } + return tick_interval - dt; } + +#define C0 0x9b +#define SS3 0x8f + +static void runesc(int csi, char *buf) +{ + if(csi != C0) return; + + if(buf[1] == 0) { + switch(buf[0]) { + case 'A': + game_input('w'); /* up */ + break; + case 'B': + game_input('s'); /* down */ + break; + case 'C': + game_input('d'); /* right */ + break; + case 'D': + game_input('a'); /* left */ + break; + default: + break; + } + } +} + void game_input(int c) { + static int esc, csi; + static int esctop; + static char escbuf[64]; + + if(esc) { + esc = 0; + if(c == 27) { + quit = 1; + return; + } + + switch(c) { + case '[': + csi = C0; + return; + case 'O': + csi = SS3; + return; + default: + break; + } + } + + if(csi) { + if(c < 0x20 || c >= 0x80) { + csi = 0; + esctop = 0; + } + + escbuf[esctop++] = c; + + if(c >= 0x40) { + int prevcsi = csi; + escbuf[esctop] = 0; + csi = 0; + esctop = 0; + runesc(prevcsi, escbuf); + } + return; + } + switch(c) { case 27: + esc = 1; + break; + + case C0: + esc = 1; + csi = C0; + break; + + case 'q': quit = 1; break; case 'a': - if(pos[1] > 0) { - next_pos[1] = pos[1] - 1; + next_pos[1] = pos[1] - 1; + if(collision(cur_piece, next_pos)) { + next_pos[1] = pos[1]; } break; case 'd': - if(pos[1] < PF_COLS - 1) { - next_pos[1] = pos[1] + 1; + next_pos[1] = pos[1] + 1; + if(collision(cur_piece, next_pos)) { + next_pos[1] = pos[1]; + } + break; + + case 'w': + case ' ': + prev_rot = cur_rot; + cur_rot = (cur_rot + 1) & 3; + if(collision(cur_piece, next_pos)) { + cur_rot = prev_rot; + } + break; + + case 's': + next_pos[0] = pos[0] + 1; + if(collision(cur_piece, next_pos)) { + next_pos[0] = pos[0]; } break; default: + fprintf(stderr, "unhandled input: %x\n", c); break; } } -static void wrchar(uint16_t c) +static int collision(int piece, const int *pos) +{ + int i; + unsigned char *p = pieces[piece][cur_rot]; + + for(i=0; i<4; i++) { + int x = PF_XOFFS + pos[1] + BLKX(*p); + int y = PF_YOFFS + pos[0] + BLKY(*p); + p++; + + if(y < 0) continue; + + if(scr[y * SCR_COLS + x] != TILE_PF) return 1; + } + + return 0; +} + +static void stick(int piece, const int *pos) +{ + int i, j, nblank; + int *pfline; + unsigned char *p = pieces[piece][cur_rot]; + + for(i=0; i<4; i++) { + int x = pos[1] + BLKX(*p); + int y = pos[0] + BLKY(*p); + p++; + + pfline = scr + (y + PF_YOFFS) * SCR_COLS + PF_XOFFS; + pfline[x] = piece + FIRST_PIECE_TILE; + + nblank = 0; + for(j=0; j complines[i]) { + int tmp = complines[j]; + complines[j] = complines[i]; + complines[i] = tmp; + } + } + } + + srow = drow = PF_ROWS - 1; + + for(i=0; i> 8; + int i; + + ansi_setcursor(row, PF_XOFFS * 2); - ansi_ibmchar(cc, ca); - ansi_ibmchar(cc, ca); + if(blink) { + int *sptr = scr + (row + PF_YOFFS) * SCR_COLS + PF_XOFFS; + + for(i=0; i> 8; + + ansi_ibmchar(cc, ca); + } }