00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00045 static const char copyright[] =
00046 "@(#) Copyright (c) 1992, 1993\n"
00047 "\tThe Regents of the University of California. All rights reserved.\n";
00048
00049 #include <sys/time.h>
00050 #include <sys/types.h>
00051 #include <err.h>
00052 #include <errno.h>
00053 #include <stdio.h>
00054 #include <stdlib.h>
00055 #include <str.h>
00056 #include <unistd.h>
00057 #include <getopt.h>
00058
00059 #include "input.h"
00060 #include "scores.h"
00061 #include "screen.h"
00062 #include "tetris.h"
00063
00064 cell board[B_SIZE];
00065
00066 int Rows;
00067 int Cols;
00068
00069 const struct shape *curshape;
00070 const struct shape *nextshape;
00071
00072 long fallrate;
00073 int score;
00074 char key_msg[100];
00075 int showpreview;
00076 int classic;
00077
00078 static void elide(void);
00079 static void setup_board(void);
00080 static const struct shape *randshape(void);
00081
00082 static void usage(void);
00083
00084 static int firstgame = 1;
00085
00086
00087
00088
00089
00090
00091 static void setup_board(void)
00092 {
00093 int i;
00094 cell *p = board;
00095
00096 for (i = B_SIZE; i; i--)
00097 *p++ = (i <= (2 * B_COLS) || (i % B_COLS) < 2) ? 0x0000ff : 0x000000;
00098 }
00099
00100
00101
00102
00103 static void elide(void)
00104 {
00105 int rows = 0;
00106 int i;
00107 int j;
00108 int base;
00109 cell *p;
00110
00111 for (i = A_FIRST; i < A_LAST; i++) {
00112 base = i * B_COLS + 1;
00113 p = &board[base];
00114 for (j = B_COLS - 2; *p++ != 0;) {
00115 if (--j <= 0) {
00116
00117 rows++;
00118 memset(&board[base], 0, sizeof(cell) * (B_COLS - 2));
00119
00120 scr_update();
00121 tsleep();
00122
00123 while (--base != 0)
00124 board[base + B_COLS] = board[base];
00125
00126 scr_update();
00127 tsleep();
00128
00129 break;
00130 }
00131 }
00132 }
00133
00134 switch (rows) {
00135 case 1:
00136 score += 10;
00137 break;
00138 case 2:
00139 score += 30;
00140 break;
00141 case 3:
00142 score += 70;
00143 break;
00144 case 4:
00145 score += 150;
00146 break;
00147 default:
00148 break;
00149 }
00150 }
00151
00152 const struct shape *randshape(void)
00153 {
00154 const struct shape *tmp = &shapes[random() % 7];
00155 int i;
00156 int j = random() % 4;
00157
00158 for (i = 0; i < j; i++)
00159 tmp = &shapes[classic ? tmp->rotc : tmp->rot];
00160
00161 return (tmp);
00162 }
00163
00164 static void srandomdev(void)
00165 {
00166 struct timeval tv;
00167
00168 gettimeofday(&tv, NULL);
00169 srandom(tv.tv_sec + tv.tv_usec / 100000);
00170 }
00171
00172 static void tetris_menu_draw(int level)
00173 {
00174 clear_screen();
00175 moveto(5, 10);
00176 puts("Tetris\n\n");
00177
00178 moveto(8, 10);
00179 printf("Level = %d (press keys 1 - 9 to change)", level);
00180 moveto(9, 10);
00181 printf("Preview is %s (press 'p' to change)", (showpreview ? "on ": "off"));
00182 moveto(12, 10);
00183 printf("Press 'h' to show hiscore table.");
00184 moveto(13, 10);
00185 printf("Press 's' to start game.");
00186 moveto(14, 10);
00187 printf("Press 'q' to quit game.");
00188 moveto(20, 10);
00189 printf("In game controls:");
00190 moveto(21, 0);
00191 puts(key_msg);
00192 }
00193
00194 static int tetris_menu(int *level)
00195 {
00196 tetris_menu_draw(*level);
00197 while (1) {
00198 int i = getchar();
00199
00200 switch(i) {
00201 case 'p':
00202 showpreview = !showpreview;
00203 moveto(9, 21);
00204 if (showpreview)
00205 printf("on ");
00206 else
00207 printf("off");
00208 break;
00209 case 'h':
00210 loadscores();
00211 showscores(firstgame);
00212 tetris_menu_draw(*level);
00213 break;
00214 case 's':
00215 firstgame = 0;
00216 return 1;
00217 case 'q':
00218 return 0;
00219 case '1':
00220 case '2':
00221 case '3':
00222 case '4':
00223 case '5':
00224 case '6':
00225 case '7':
00226 case '8':
00227 case '9':
00228 *level = i - '0';
00229 moveto(8, 18);
00230 printf("%d", *level);
00231 break;
00232 }
00233 }
00234 }
00235
00236 int main(int argc, char *argv[])
00237 {
00238 int pos;
00239 int c;
00240 const char *keys;
00241 int level = 2;
00242 char key_write[6][10];
00243 int i;
00244 int j;
00245 int ch;
00246
00247 keys = "jkl pq";
00248
00249 classic = 0;
00250 showpreview = 1;
00251
00252 while ((ch = getopt(argc, argv, "ck:ps")) != -1)
00253 switch(ch) {
00254 case 'c':
00255
00256
00257
00258
00259
00260 classic = 1;
00261 break;
00262 case 'k':
00263 if (str_size(keys = optarg) != 6)
00264 usage();
00265 break;
00266 case 'p':
00267 showpreview = 1;
00268 break;
00269 case 's':
00270 showscores(0);
00271 exit(0);
00272 default:
00273 usage();
00274 }
00275
00276 argc -= optind;
00277 argv += optind;
00278
00279 if (argc)
00280 usage();
00281
00282 for (i = 0; i <= 5; i++) {
00283 for (j = i + 1; j <= 5; j++) {
00284 if (keys[i] == keys[j])
00285 errx(1, "duplicate command keys specified.");
00286 }
00287
00288 if (keys[i] == ' ')
00289 str_cpy(key_write[i], sizeof(key_write[i]), "<space>");
00290 else {
00291 key_write[i][0] = keys[i];
00292 key_write[i][1] = '\0';
00293 }
00294 }
00295
00296 snprintf(key_msg, sizeof(key_msg),
00297 "%s - left %s - rotate %s - right %s - drop %s - pause %s - quit",
00298 key_write[0], key_write[1], key_write[2], key_write[3],
00299 key_write[4], key_write[5]);
00300
00301 scr_init();
00302 if (loadscores() != EOK)
00303 initscores();
00304
00305 while (tetris_menu(&level)) {
00306 fallrate = 1000000 / level;
00307
00308 scr_clear();
00309 setup_board();
00310
00311 srandomdev();
00312 scr_set();
00313
00314 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
00315 nextshape = randshape();
00316 curshape = randshape();
00317
00318 scr_msg(key_msg, 1);
00319
00320 while (1) {
00321 place(curshape, pos, 1);
00322 scr_update();
00323 place(curshape, pos, 0);
00324 c = tgetchar();
00325 if (c < 0) {
00326
00327
00328
00329 if (fits_in(curshape, pos + B_COLS)) {
00330 pos += B_COLS;
00331 continue;
00332 }
00333
00334
00335
00336
00337
00338 place(curshape, pos, 1);
00339 score++;
00340 elide();
00341
00342
00343
00344
00345
00346 curshape = nextshape;
00347 nextshape = randshape();
00348 pos = A_FIRST * B_COLS + (B_COLS / 2) - 1;
00349
00350 if (!fits_in(curshape, pos))
00351 break;
00352
00353 continue;
00354 }
00355
00356
00357
00358
00359 if (c == keys[5]) {
00360
00361 break;
00362 }
00363
00364 if (c == keys[4]) {
00365 static char msg[] =
00366 "paused - press RETURN to continue";
00367
00368 place(curshape, pos, 1);
00369 do {
00370 scr_update();
00371 scr_msg(key_msg, 0);
00372 scr_msg(msg, 1);
00373 (void) fflush(stdout);
00374 } while (rwait((struct timeval *) NULL) == -1);
00375
00376 scr_msg(msg, 0);
00377 scr_msg(key_msg, 1);
00378 place(curshape, pos, 0);
00379 continue;
00380 }
00381
00382 if (c == keys[0]) {
00383
00384 if (fits_in(curshape, pos - 1))
00385 pos--;
00386 continue;
00387 }
00388
00389 if (c == keys[1]) {
00390
00391 const struct shape *new =
00392 &shapes[classic ? curshape->rotc : curshape->rot];
00393
00394 if (fits_in(new, pos))
00395 curshape = new;
00396 continue;
00397 }
00398
00399 if (c == keys[2]) {
00400
00401 if (fits_in(curshape, pos + 1))
00402 pos++;
00403 continue;
00404 }
00405
00406 if (c == keys[3]) {
00407
00408 while (fits_in(curshape, pos + B_COLS)) {
00409 pos += B_COLS;
00410 score++;
00411 }
00412 continue;
00413 }
00414
00415 if (c == '\f') {
00416 scr_clear();
00417 scr_msg(key_msg, 1);
00418 }
00419 }
00420
00421 scr_clear();
00422 loadscores();
00423 insertscore(score, level);
00424 savescores();
00425 score = 0;
00426 }
00427
00428 scr_clear();
00429 printf("\nGame over.\n");
00430 scr_end();
00431
00432 return 0;
00433 }
00434
00435 void usage(void)
00436 {
00437 fprintf(stderr, "usage: tetris [-ps] [-k keys]\n");
00438 exit(1);
00439 }
00440