home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
games
/
volume15
/
gtetris3
/
part01
/
playing.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-27
|
9KB
|
414 lines
/*
# GENERIC X-WINDOW-BASED TETRIS
#
# playing.c
#
###
#
# Copyright (C) 1992, 1993 Qiang Alex Zhao, azhao@cs.arizona.edu
# Computer Science Dept, University of Arizona
#
# All Rights Reserved
#
# Permission to use, copy, modify, and distribute this software and
# its documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appear in all copies and
# that both that copyright notice and this permission notice appear in
# supporting documentation, and that the name of the author not be
# used in advertising or publicity pertaining to distribution of the
# software without specific, written prior permission.
#
# This program is distributed in the hope that it will be "playable",
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
*/
#include "tetris.h"
static Bool paused = False;
static int speeds[NUM_LEVELS] = {
100, 92, 84, 76, 68, 60, 53, 46, 39, 32, 26, 20, 15, 10, 6, 3, 1, 0};
static int thresh[NUM_LEVELS] = {
10, 20, 30, 40, 50, 60, 70, 80, 90,
100, 110, 120, 130, 140, 150, 160, 170, 180};
static struct timeval nextFall, now, delay;
static struct timezone tzone = {0, 0};
/* ------------------------------------------------------------------ */
void
playing()
{
Bool resetTime = True;
score = prefilled * level * 10;
while (True) {
if (resetTime) {
(void) gettimeofday(&nextFall, &tzone);
nextFall.tv_usec += 10000 * speeds[level];
realTime(&nextFall);
} else {
int writefd = 0, exceptfd = 0;
int readfd = 1 << ConnectionNumber(display);
(void) gettimeofday(&now, &tzone);
delay.tv_sec = nextFall.tv_sec - now.tv_sec;
delay.tv_usec = nextFall.tv_usec - now.tv_usec;
realTime(&delay);
if (delay.tv_sec >= 0) { /* sleep */
(void) select(sizeof(int) * 8, (fd_set *) &readfd,
(fd_set *) & writefd, (fd_set *) & exceptfd, &delay);
}
}
(void) gettimeofday(&now, &tzone);
if ((now.tv_sec > nextFall.tv_sec) ||
((now.tv_sec == nextFall.tv_sec) &&
(now.tv_usec > nextFall.tv_usec))) {
(void) evGotNewThing(True);
resetTime = True;
} else {
resetTime = evGotNewThing(False);
}
}
/* never come to here */
}
/* ------------------------------------------------------------------ */
Bool
evGotNewThing(falldown)
Bool falldown;
{
XEvent ev;
Bool gotNew = False;
char buf[4];
if (!paused && falldown)
gotNew = moveOne(FALL) || gotNew;
while (XPending(display)) {
XNextEvent(display, &ev);
switch (ev.type) {
case KeyPress:
if (!XLookupString(&ev.xkey, buf, 4, NULL, NULL))
break;
switch (buf[0]) {
case 'j':
case 's':
if (!paused)
gotNew = moveOne(LEFT) || gotNew;
break;
case 'k':
case 'd':
if (!paused)
gotNew = moveOne(ROTATE) || gotNew;
break;
case 'l':
case 'f':
if (!paused)
gotNew = moveOne(RIGHT) || gotNew;
break;
case ' ':
case '\n':
if (!paused)
gotNew = moveOne(DROP) || gotNew;
break;
case 'q':
case 'Q':
gameOver();
break;
case '+':
case '=':
if (!paused)
if (level < NUM_LEVELS - 1) {
level++;
drawStatus();
}
break;
case '-':
case '_':
if (!paused)
if (level > 0) {
level--;
drawStatus();
}
break;
case 'b':
case 'B':
beep = !beep;
if (beep)
XBell(display, BVOLUME);
break;
case 'p':
case 'P':
if (beep)
XBell(display, BVOLUME);
paused = !paused;
if (paused) {
/* "... Hi boss, I'm working hard as usual ..." */
banner(MSG_PAUSED);
(void) XIconifyWindow(display, mainWin, screen_num);
} else {
clearNext();
if (showNext)
drawNext();
}
XSync(display, False);
break;
case '\014':
XClearWindow(display, mainWin);
XClearWindow(display, blockWin);
redrawAll();
if (paused)
banner(MSG_PAUSED);
XSync(display, False);
break;
case 'n':
case 'N':
if (!paused) {
showNext = !showNext;
if (showNext) {
drawNext();
} else {
clearNext();
}
XSync(display, False);
}
break;
default:
XBell(display, 0);
XSync(display, False);
break;
}
break;
case UnmapNotify:
paused = True;
break;
case FocusOut:
paused = True;
banner(MSG_PAUSED);
break;
case Expose:
if (ev.xexpose.count == 0) {
redrawAll();
if (paused)
banner(MSG_PAUSED);
}
break;
case ClientMessage:
if ((Atom) ev.xclient.data.l[0] == delw)
gameOver();
break;
case DestroyNotify:
exit(0);
break;
}
}
XSync(display, False);
return gotNew;
}
/* ------------------------------------------------------------------ */
void
redrawAll()
{
drawTitle();
drawStatus();
drawField();
drawThing();
if (showNext)
drawNext();
}
/* ------------------------------------------------------------------ */
Bool
moveOne(move)
move_t move;
{
XEvent ev;
int lines;
if ((move == DROP) || ((move == FALL) && atBottom())) {
tryMove(move);
putBox();
lines = checkLines();
score += prefilled * prefilled + lines + 1;
score += (showNext ? 3 : 5) * level * level * lines * lines;
rows += lines;
if (rows > thresh[level])
level ++;
drawStatus();
newThing();
if (showNext) {
clearNext();
drawNext();
}
XSync(display, False);
while (XPending(display))
XNextEvent(display, &ev);
if (overlapping())
gameOver();
drawThing();
return True;
} else {
tryMove(move);
if (rows > thresh[level]) {
level ++;
drawStatus();
}
return False;
}
}
/* ------------------------------------------------------------------ */
static void
addScore()
{
time_t tloc;
char buff[2][SCORESIZE];
char lockfile[FILENAMELEN];
int fd, lfd;
int tmp, ptmp, s1;
int mycount = 0;
Bool saved = False, trickle = False;
time(&tloc);
(void) strcpy(myscore.mydate, asctime(localtime(&tloc)));
(void) sprintf(myscore.score, "%9d", score);
(void) sprintf(myscore.level, "%3d", level);
(void) sprintf(myscore.rows, "%4d", rows);
(void) fprintf(stderr, "\n- %s", myscore.mydate);
(void) fprintf(stderr, "- Your final score is %d,", score);
(void) fprintf(stderr, " at level %d with %d rows.\n\n", level, rows);
if ((fd = open(SCOREFILE, O_CREAT | O_RDWR, 0644)) < 0) {
(void) fprintf(stderr, "Cannot write the score-file!\n");
return;
}
/* lock */
(void) strcpy(lockfile, SCOREFILE);
(void) strcat(lockfile, ".lock");
while (((lfd = open(lockfile, O_CREAT | O_EXCL, 0644)) < 0) &&
errno == EEXIST)
sleep(1);
if (lfd < 0) {
(void) perror("Error in creating the score-file lock-file");
(void) fprintf(stderr, "Score not recorded - sorry.\n");
return;
}
tmp = 0;
ptmp = 1;
bcopy((char *) &myscore, buff[1], SCORESIZE);
while (read(fd, buff[tmp], SCORESIZE) == SCORESIZE) {
sscanf(((score_t *)buff[tmp])->score, " %d", &s1);
if (!saved && (s1 <= score)) {
trickle = True;
saved = True;
mycount++;
}
if (!strncmp(myscore.myname, ((score_t *) buff[tmp])->myname,
NAMELEN)) {
mycount++;
}
/* Then check if we should trickle the score */
if (trickle) {
lseek(fd, (off_t) -SCORESIZE, SEEK_CUR);
write(fd, buff[ptmp], SCORESIZE);
ptmp = tmp;
tmp = (tmp + 1) % 2;
}
/*
* As we trickle, we add up records owned by me. Once we hit max,
* we throw it away, and stop trickling.
*/
if ((mycount > MAXSCORES) || ((mycount == MAXSCORES) && !trickle)) {
trickle = False;
break;
}
} /* while */
if (trickle) {
write(fd, buff[ptmp], SCORESIZE);
}
if (!saved && (mycount < MAXSCORES)) {
write(fd, (char *) &myscore, SCORESIZE);
}
/* unlock */
close(lfd);
(void) unlink(lockfile);
close(fd);
}
/* ------------------------------------------------------------------ */
void
gameOver()
{
banner(MSG_END);
XFlush(display);
addScore();
showScores(SHOWSCORES);
XCloseDisplay(display);
exit(0);
}
/* ------------------------------------------------------------------ */
void
showScores(num)
int num;
{
int fd, i = 0;
score_t curs;
if ((fd = open(SCOREFILE, O_RDONLY, 0644)) < 0)
return;
(void) fprintf(stderr, " GENERIC TETRIS HALL OF FAME\n\n");
(void) fprintf(stderr,
" # USER SCORE L R HOST DATE\n");
while (read(fd, (char *) &curs, SCORESIZE) == SCORESIZE) {
i++;
if ((num == 0) || (i <= num))
(void) fprintf(stderr, "%4d %-12s%9s %3s %4s %-12s %-s",
i, curs.myname, curs.score, curs.level, curs.rows,
curs.myhost, curs.mydate);
}
close(fd);
(void) fprintf(stderr, "There are %d scores to date.\n", i);
}
/* ------------------------------------------------------------------ */