36,30 → 36,25 |
*/ |
|
/** @addtogroup tetris Tetris |
* @brief Tetris ported from OpenBSD |
* @{ |
* @brief Tetris ported from OpenBSD |
* @{ |
*/ |
/** @file |
*/ |
|
#ifndef lint |
static const char copyright[] = |
"@(#) Copyright (c) 1992, 1993\n\ |
The Regents of the University of California. All rights reserved.\n"; |
#endif /* not lint */ |
"@(#) Copyright (c) 1992, 1993\n" |
"\tThe Regents of the University of California. All rights reserved.\n"; |
|
/* |
* Tetris (or however it is spelled). |
*/ |
|
#include <sys/time.h> |
#include <sys/types.h> |
|
#include <err.h> |
#include <errno.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <unistd.h> |
#include <getopt.h> |
|
#include "input.h" |
#include "scores.h" |
66,66 → 61,76 |
#include "screen.h" |
#include "tetris.h" |
|
cell board[B_SIZE]; |
int Rows, Cols; |
cell board[B_SIZE]; |
|
int Rows; |
int Cols; |
|
const struct shape *curshape; |
const struct shape *nextshape; |
long fallrate; |
int score; |
//gid_t gid, egid; |
char key_msg[100]; |
int showpreview, classic; |
|
static void elide(void); |
static void setup_board(void); |
const struct shape *randshape(void); |
void onintr(int); |
void usage(void); |
long fallrate; |
int score; |
char key_msg[100]; |
int showpreview; |
int classic; |
|
static void elide(void); |
static void setup_board(void); |
static const struct shape *randshape(void); |
|
static void usage(void); |
|
static int firstgame = 1; |
|
/* |
* Set up the initial board. The bottom display row is completely set, |
* along with another (hidden) row underneath that. Also, the left and |
* Set up the initial board. The bottom display row is completely set, |
* along with another (hidden) row underneath that. Also, the left and |
* right edges are set. |
*/ |
static void |
setup_board(void) |
static void setup_board(void) |
{ |
int i; |
cell *p; |
|
p = board; |
cell *p = board; |
|
for (i = B_SIZE; i; i--) |
*p++ = i <= (2 * B_COLS) || (i % B_COLS) < 2; |
*p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 0x0000ff : 0x000000; |
} |
|
/* |
* Elide any full active rows. |
*/ |
static void |
elide(void) |
static void elide(void) |
{ |
int rows = 0; |
int i, j, base; |
int i; |
int j; |
int base; |
cell *p; |
|
|
for (i = A_FIRST; i < A_LAST; i++) { |
base = i * B_COLS + 1; |
p = &board[base]; |
for (j = B_COLS - 2; *p++ != 0;) { |
if (--j <= 0) { |
/* this row is to be elided */ |
/* This row is to be elided */ |
rows++; |
memset(&board[base], 0, B_COLS - 2); |
memset(&board[base], 0, sizeof(cell) * (B_COLS - 2)); |
|
scr_update(); |
tsleep(); |
|
while (--base != 0) |
board[base + B_COLS] = board[base]; |
|
scr_update(); |
tsleep(); |
|
break; |
} |
} |
} |
|
switch (rows) { |
case 1: |
score += 10; |
144,16 → 149,15 |
} |
} |
|
const struct shape * |
randshape(void) |
const struct shape *randshape(void) |
{ |
const struct shape *tmp; |
int i, j; |
|
tmp = &shapes[random() % 7]; |
j = random() % 4; |
const struct shape *tmp = &shapes[random() % 7]; |
int i; |
int j = random() % 4; |
|
for (i = 0; i < j; i++) |
tmp = &shapes[classic? tmp->rotc : tmp->rot]; |
tmp = &shapes[classic ? tmp->rotc : tmp->rot]; |
|
return (tmp); |
} |
|
160,7 → 164,7 |
static void srandomdev(void) |
{ |
struct timeval tv; |
|
|
gettimeofday(&tv, NULL); |
srandom(tv.tv_sec + tv.tv_usec / 100000); |
} |
167,61 → 171,43 |
|
static void tetris_menu_draw(int level) |
{ |
clear_screen(); |
moveto(5,10); |
puts("Tetris\n\n"); |
|
moveto(8,10); |
printf("Level = %d (press keys 1 - 9 to change)",level); |
moveto(9,10); |
printf("Preview is %s (press 'p' to change)", (showpreview?"on ":"off")); |
moveto(12,10); |
printf("Press 'h' to show hiscore table."); |
moveto(13,10); |
printf("Press 's' to start game."); |
moveto(14,10); |
printf("Press 'q' to quit game."); |
moveto(20,10); |
printf("In game controls:"); |
moveto(21,0); |
puts(key_msg); |
clear_screen(); |
moveto(5, 10); |
puts("Tetris\n\n"); |
|
moveto(8, 10); |
printf("Level = %d (press keys 1 - 9 to change)", level); |
moveto(9, 10); |
printf("Preview is %s (press 'p' to change)", (showpreview ? "on ": "off")); |
moveto(12, 10); |
printf("Press 'h' to show hiscore table."); |
moveto(13, 10); |
printf("Press 's' to start game."); |
moveto(14, 10); |
printf("Press 'q' to quit game."); |
moveto(20, 10); |
printf("In game controls:"); |
moveto(21, 0); |
puts(key_msg); |
} |
|
static int tetris_menu(int *level) |
static int tetris_menu(int *level) |
{ |
static int firstgame = 1; |
int i; |
/* if (showpreview == 0) |
(void)printf("Your score: %d point%s x level %d = %d\n", |
score, score == 1 ? "" : "s", level, score * level); |
else { |
(void)printf("Your score: %d point%s x level %d x preview penalty %0.3f = %d\n", |
score, score == 1 ? "" : "s", level, (double)PRE_PENALTY, |
(int)(score * level * PRE_PENALTY)); |
score = score * PRE_PENALTY; |
} |
savescore(level); |
|
showscores(level); |
|
printf("\nHit 's' to new game, 'q' to quit.\n"); |
*/ |
tetris_menu_draw(*level); |
while (1) { |
|
i = getchar(); |
int i = getchar(); |
|
switch(i) { |
case 'p': |
showpreview = !showpreview; |
moveto(9,21); |
moveto(9, 21); |
if (showpreview) |
printf("on "); |
else |
printf("off"); |
|
break; |
case 'h': |
loadscores(); |
showscores(firstgame); |
tetris_menu_draw(*level); |
break; |
235,112 → 221,103 |
case '3': |
case '4': |
case '5': |
case '6': |
case '6': |
case '7': |
case '8': |
case '9': |
*level = i - '0'; |
moveto(8,18); |
moveto(8, 18); |
printf("%d", *level); |
break; |
} |
} |
|
} |
|
int |
main(int argc, char *argv[]) |
int main(int argc, char *argv[]) |
{ |
int pos, c; |
char *keys; |
int pos; |
int c; |
const char *keys; |
int level = 2; |
char key_write[6][10]; |
int i, j; |
|
int i; |
int j; |
int ch; |
|
keys = "jkl pq"; |
|
// gid = getgid(); |
// egid = getegid(); |
// setegid(gid); |
|
|
classic = 0; |
showpreview = 1; |
|
/* while ((ch = getopt(argc, argv, "ck:l:ps")) != -1) */ |
/* switch(ch) { */ |
/* case 'c': */ |
/* /\* */ |
/* * this means: */ |
/* * - rotate the other way; */ |
/* * - no reverse video. */ |
/* *\/ */ |
/* classic = 1; */ |
/* break; */ |
/* case 'k': */ |
/* if (str_size(keys = optarg) != 6) */ |
/* usage(); */ |
/* break; */ |
/* case 'l': */ |
/* level = (int)strtonum(optarg, MINLEVEL, MAXLEVEL, */ |
/* &errstr); */ |
/* if (errstr) */ |
/* errx(1, "level must be from %d to %d", */ |
/* MINLEVEL, MAXLEVEL); */ |
/* break; */ |
/* case 'p': */ |
/* showpreview = 1; */ |
/* break; */ |
/* case 's': */ |
/* showscores(0); */ |
/* exit(0); */ |
/* default: */ |
/* usage(); */ |
/* } */ |
|
/* argc -= optind; */ |
/* argv += optind; */ |
|
/* if (argc) */ |
/* usage(); */ |
|
|
|
while ((ch = getopt(argc, argv, "ck:ps")) != -1) |
switch(ch) { |
case 'c': |
/* |
* this means: |
* - rotate the other way |
* - no reverse video |
*/ |
classic = 1; |
break; |
case 'k': |
if (str_size(keys = optarg) != 6) |
usage(); |
break; |
case 'p': |
showpreview = 1; |
break; |
case 's': |
showscores(0); |
exit(0); |
default: |
usage(); |
} |
|
argc -= optind; |
argv += optind; |
|
if (argc) |
usage(); |
|
for (i = 0; i <= 5; i++) { |
for (j = i+1; j <= 5; j++) { |
for (j = i + 1; j <= 5; j++) { |
if (keys[i] == keys[j]) |
errx(1, "duplicate command keys specified."); |
} |
|
if (keys[i] == ' ') |
str_cpy(key_write[i], sizeof key_write[i], "<space>"); |
str_cpy(key_write[i], sizeof(key_write[i]), "<space>"); |
else { |
key_write[i][0] = keys[i]; |
key_write[i][1] = '\0'; |
} |
} |
|
snprintf(key_msg, sizeof(key_msg), |
"%s - left %s - rotate %s - right %s - drop %s - pause %s - quit", |
key_write[0], key_write[1], key_write[2], key_write[3], |
key_write[4], key_write[5]); |
|
scr_init(); |
if (loadscores() != EOK) |
initscores(); |
|
snprintf(key_msg, sizeof key_msg, |
"%s - left %s - rotate %s - right %s - drop %s - pause %s - quit", |
key_write[0], key_write[1], key_write[2], key_write[3], |
key_write[4], key_write[5]); |
|
scr_init(); |
initscores(); |
while (tetris_menu(&level)) { |
fallrate = 1000000 / level; |
|
scr_clear(); |
setup_board(); |
|
|
srandomdev(); |
scr_set(); |
|
pos = A_FIRST*B_COLS + (B_COLS/2)-1; |
|
pos = A_FIRST * B_COLS + (B_COLS / 2) - 1; |
nextshape = randshape(); |
curshape = randshape(); |
|
|
scr_msg(key_msg, 1); |
|
for (;;) { |
|
while (1) { |
place(curshape, pos, 1); |
scr_update(); |
place(curshape, pos, 0); |
353,7 → 330,7 |
pos += B_COLS; |
continue; |
} |
|
|
/* |
* Put up the current shape `permanently', |
* bump score, and elide any full rows. |
361,7 → 338,7 |
place(curshape, pos, 1); |
score++; |
elide(); |
|
|
/* |
* Choose a new shape. If it does not fit, |
* the game is over. |
368,12 → 345,14 |
*/ |
curshape = nextshape; |
nextshape = randshape(); |
pos = A_FIRST*B_COLS + (B_COLS/2)-1; |
pos = A_FIRST * B_COLS + (B_COLS / 2) - 1; |
|
if (!fits_in(curshape, pos)) |
break; |
|
continue; |
} |
|
|
/* |
* Handle command keys. |
*/ |
381,10 → 360,11 |
/* quit */ |
break; |
} |
|
if (c == keys[4]) { |
static char msg[] = |
"paused - press RETURN to continue"; |
|
|
place(curshape, pos, 1); |
do { |
scr_update(); |
391,12 → 371,14 |
scr_msg(key_msg, 0); |
scr_msg(msg, 1); |
(void) fflush(stdout); |
} while (rwait((struct timeval *)NULL) == -1); |
} while (rwait((struct timeval *) NULL) == -1); |
|
scr_msg(msg, 0); |
scr_msg(key_msg, 1); |
place(curshape, pos, 0); |
continue; |
} |
|
if (c == keys[0]) { |
/* move left */ |
if (fits_in(curshape, pos - 1)) |
403,15 → 385,17 |
pos--; |
continue; |
} |
|
if (c == keys[1]) { |
/* turn */ |
const struct shape *new = &shapes[ |
classic? curshape->rotc : curshape->rot]; |
|
const struct shape *new = |
&shapes[classic ? curshape->rotc : curshape->rot]; |
|
if (fits_in(new, pos)) |
curshape = new; |
continue; |
} |
|
if (c == keys[2]) { |
/* move right */ |
if (fits_in(curshape, pos + 1)) |
418,6 → 402,7 |
pos++; |
continue; |
} |
|
if (c == keys[3]) { |
/* move to bottom */ |
while (fits_in(curshape, pos + B_COLS)) { |
426,6 → 411,7 |
} |
continue; |
} |
|
if (c == '\f') { |
scr_clear(); |
scr_msg(key_msg, 1); |
433,37 → 419,24 |
} |
|
scr_clear(); |
loadscores(); |
insertscore(score, level); |
score=0; |
savescores(); |
score = 0; |
} |
|
scr_clear(); |
printf("\n\n\n\t\tGame over.\n"); |
/* |
while ((i = getchar()) != '\n') |
if (i == EOF) |
break |
*/ |
printf("\nGame over.\n"); |
scr_end(); |
|
|
return 0; |
} |
|
/* void */ |
/* onintr(int signo) */ |
/* { */ |
/* scr_clear(); /\* XXX signal race *\/ */ |
/* scr_end(); /\* XXX signal race *\/ */ |
/* _exit(0); */ |
/* } */ |
|
void |
usage(void) |
void usage(void) |
{ |
(void)fprintf(stderr, "usage: tetris [-ps] [-k keys] [-l level]\n"); |
fprintf(stderr, "usage: tetris [-ps] [-k keys]\n"); |
exit(1); |
} |
|
/** @} |
*/ |
|