home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
games
/
volume15
/
gtetris2
/
part01
/
utils.c
< prev
Wrap
C/C++ Source or Header
|
1993-01-27
|
20KB
|
851 lines
/*
# GENERIC X-WINDOW-BASED TETRIS
#
# tetris.c
#
###
#
# Copyright (C) 1992 Qiang Alex Zhao
# Computer Science Dept, University of Arizona
# azhao@cs.arizona.edu
#
# 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"
#include "data.h"
void
normTimeVal(tv)
struct timeval *tv;
{
while (tv->tv_usec < 0) {
tv->tv_sec--;
tv->tv_usec += MILLION;
}
while (tv->tv_usec >= MILLION) {
tv->tv_sec++;
tv->tv_usec -= MILLION;
}
return;
}
void
fallDown(field, thingp, eat)
field_t *field;
thing_t **thingp;
Bool eat;
{
int lines;
XEvent event;
putBoxes(field, *thingp);
lines = checkLine(field);
field->score += 5 + 4 * field->level * field->level * lines * lines;
field->lines += lines;
if (field->lines >= thresh[field->level])
field->level++;
updateScore(field);
free((char *) *thingp);
if (eat) {
*thingp = NULL;
while (XPending(disp)) XNextEvent(disp, &event);
}
*thingp = makeNewThing(field);
if (overlapping(field, *thingp)) die(field);
drawThing(field, *thingp);
}
void
handleEvents(field, thingp, fall_down)
field_t *field;
thing_t **thingp;
Bool fall_down;
{
static Bool frozen = False;
XEvent event;
char s[4];
if (frozen) fall_down = False;
if (!*thingp) {
*thingp = makeNewThing(field);
if (overlapping(field, *thingp)) die(field);
drawThing(field, *thingp);
XSync(disp, 0);
}
if (fall_down && atBottom(field, *thingp)) {
fallDown(field, thingp, False);
fall_down = False;
}
if (!XPending(disp) && !frozen)
moveOne(field, *thingp, NONE, fall_down);
while (XPending(disp)) {
if (overlapping(field, *thingp)) die(field);
XNextEvent(disp, &event);
switch (event.type) {
case KeyPress:
if (!XLookupString((XKeyEvent *) &event, s, 4, NULL, NULL)) break;
switch (*s) {
case 'j': /* Move left. */
case 'J':
case 's':
case 'S':
if (!frozen)
moveOne(field, *thingp, LEFT, fall_down);
break;
case 'k': /* Rotate. */
case 'K':
case 'd':
case 'D':
if (!frozen)
moveOne(field, *thingp, ROTATE, fall_down);
break;
case 'l': /* Move right. */
case 'L':
case 'f':
case 'F':
if (!frozen)
moveOne(field, *thingp, RIGHT, fall_down);
break;
case ' ': /* Drop. */
case '\n':
if (!frozen) {
moveOne(field, *thingp, DROP, fall_down);
fallDown(field, thingp, True);
}
return;
break;
case 'q': /* Quit. */
case 'Q':
die(field);
break;
case '+': /* Speed up. */
case '=':
if (field->level < NUM_LEVELS - 1) {
field->level++;
updateScore(field);
}
break;
case '-': /* Slow down. */
case '_':
if (field->level > 0) {
field->level--;
updateScore(field);
}
break;
case 'b':
case 'B':
beep = !beep;
if (beep) XBell(disp, -90);
break;
case '\023': /* Freeze / continue. */
case 'p':
case 'P':
if (beep) XBell(disp, -90);
frozen = (frozen ? False : True);
if (frozen) {
/* "... Hi Boss, I'm working hard as usual ..." */
XIconifyWindow(disp, field->frame, rootScreen);
} else {
XClearWindow(disp, field->win);
drawField(field);
if (*thingp) drawThing(field, *thingp);
}
XFlush(disp);
break;
case '\014': /* Redraw. */
XClearWindow(disp, field->win);
drawField(field);
if (*thingp)
drawThing(field, *thingp);
/* flow to next */
default:
XBell(disp, -90);
XFlush(disp);
break;
}
break; /* processing key press */
case UnmapNotify:
frozen = True;
break;
case Expose:
if (event.xexpose.count == 0) {
drawField(field);
if (*thingp) drawThing(field, *thingp);
if (frozen) banner(field, PAUSED_MESG);
}
XFlush(disp);
break;
case ClientMessage:
if ((Atom) event.xclient.data.l[0] == field->delw)
die(field);
break;
case DestroyNotify:
die(field);
break;
}
fall_down = False;
}
return;
}
void
moveOne(field, thing, what, fall_down)
field_t *field;
thing_t *thing;
command_t what;
Bool fall_down;
{
thing_t old;
old = *thing;
if (tryMove(field, thing, what, fall_down))
drawThingDiff(field, thing, &old);
XSync(disp, 0);
return;
}
Bool
tryMove(field, thing, what, fall_down)
field_t *field;
thing_t *thing;
command_t what;
Bool fall_down;
{
int x, y;
thing_t temp;
Bool ok = True;
temp = *thing;
if (fall_down) temp.ypos--;
switch (what) {
case LEFT:
temp.xpos--;
break;
case RIGHT:
temp.xpos++;
break;
case ROTATE:
rotateThing(&temp);
break;
case DROP:
while (!overlapping(field, &temp)) {
field->score += field->level;
temp.ypos--;
}
temp.ypos++;
break;
case NONE:
break;
}
for (x = 0; (x < temp.size) && ok; x++)
for (y = 0; (y < temp.size) && ok; y++) {
if (temp.map[x][y]) {
if ((temp.xpos + x < 0) ||
(temp.xpos + x >= field->width) ||
(temp.ypos + y < 0) ||
(temp.ypos + y >= field->height) ||
(field->full[temp.xpos + x]
[temp.ypos + y]))
ok = False;
}
}
if (ok) *thing = temp;
if (overlapping(field, thing)) {
return False;
} else {
return True;
}
}
Bool
atBottom(field, thing)
field_t *field;
thing_t *thing;
{
int x, y;
for (x = 0; x < thing->size; x++)
for (y = 0; y < thing->size; y++)
if (thing->map[x][y]) {
if (thing->ypos + y <= 0)
return True;
if (field->full[thing->xpos + x]
[thing->ypos + y - 1])
return True;
}
return False;
}
void
drawThing(field, thing)
field_t *field;
thing_t *thing;
{
int x, y;
for (x = 0; x < thing->size; x++)
for (y = 0; y < thing->size; y++)
if (thing->map[x][y])
doBox(field, thing->xpos + x, thing->ypos + y,
thing->map[x][y]);
return;
}
void
drawThingDiff(field, thing, oldthing)
field_t *field;
thing_t *thing, *oldthing;
{
int x, y;
int ox, oy;
for (x = 0; x < thing->size; x++)
for (y = 0; y < thing->size; y++) {
ox = x - oldthing->xpos + thing->xpos;
oy = y - oldthing->ypos + thing->ypos;
if (thing->map[x][y])
doBox(field, thing->xpos + x, thing->ypos + y,
thing->map[x][y]);
}
for (x = 0; x < thing->size; x++)
for (y = 0; y < thing->size; y++) {
ox = x - thing->xpos + oldthing->xpos;
oy = y - thing->ypos + oldthing->ypos;
if (oldthing->map[x][y] &&
((ox < 0) || (ox >= thing->size) ||
(oy < 0) || (oy >= thing->size) ||
!thing->map[ox][oy]))
doBox(field, oldthing->xpos + x,
oldthing->ypos + y,
0);
}
return;
}
void
doBox(field, x, y, pat)
field_t *field;
int x, y;
int pat;
{
if ((x < 0) || (x >= field->width) || (y < 0) || (y >= field->height))
abort();
if (pat == 0)
XFillRectangle(disp, field->win, gc_w2,
x * BOX_WIDTH + X_MARGIN,
ytr((y + 1) * BOX_HEIGHT + Y_MARGIN) - 1,
BOX_WIDTH + 1, BOX_HEIGHT + 1);
else {
if (rootDepth == 1) {
pat = pat % 16 - 1;
XCopyPlane(disp, patterns[pat].pixmap, field->win, gc_w,
0, 0,
BOX_WIDTH, BOX_HEIGHT,
x * BOX_WIDTH + X_MARGIN,
ytr((y + 1) * BOX_HEIGHT + Y_MARGIN), 1);
} else {
pat -= 1;
XCopyPlane(disp, patterns[pat].pixmap, field->win,
gc_pat[pat],
0, 0,
BOX_WIDTH, BOX_HEIGHT,
x * BOX_WIDTH + X_MARGIN,
ytr((y + 1) * BOX_HEIGHT + Y_MARGIN), 1);
}
}
return;
}
Bool
overlapping(field, thing)
field_t *field;
thing_t *thing;
{
int x, y;
for (x = 0; x < thing->size; x++)
for (y = 0; y < thing->size; y++) {
if (thing->map[x][y] && (thing->ypos + y < 0))
return True;
if (thing->map[x][y] && field->full[thing->xpos + x]
[thing->ypos + y])
return True;
}
return False;
}
int
putBoxes(field, thing)
field_t *field;
thing_t *thing;
{
int x, y;
int highest = 0;
for (x = 0; x < thing->size; x++)
for (y = 0; y < thing->size; y++)
if (thing->map[x][y]) {
if ((thing->xpos + x < 0) ||
(thing->xpos + x >= field->width) ||
(thing->ypos + y < 0) ||
(thing->ypos + y >= field->height))
abort();
field->full[thing->xpos + x][thing->ypos + y]
= thing->map[x][y];
if (thing->ypos + y > highest)
highest = thing->ypos + y;
}
return highest;
}
field_t *
initField(width, height, lines_full, argc, argv)
int width, height, lines_full, argc;
char *argv[];
{
XTextProperty wName, iName;
XWMHints wmhints;
XClassHint classhints;
unsigned int attvm;
XSetWindowAttributes att;
Cursor cursor;
XSizeHints sh;
field_t *field = (field_t *) malloc(sizeof(field_t));
int x, y, w, h;;
w = width * BOX_WIDTH + 2 * X_MARGIN;
h = height * BOX_HEIGHT + 2 * Y_MARGIN + TITLE_HEIGHT;
field->width = width;
field->height = height;
field->score = 0;
field->level = 1;
field->lines = 0;
cursor = XCreateFontCursor(disp, XC_exchange);
/* create window */
attvm = CWBackPixel | CWBorderPixel | CWEventMask |
CWDontPropagate | CWCursor;
att.background_pixel = bgcolor.pixel;
att.border_pixel = bdcolor.pixel;
att.event_mask = ExposureMask | StructureNotifyMask;
att.do_not_propagate_mask = KeyPressMask | KeyReleaseMask |
ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
ButtonMotionMask | Button1MotionMask | Button2MotionMask |
Button3MotionMask | Button4MotionMask | Button5MotionMask ;
att.cursor = cursor;
field->frame = XCreateWindow(disp, DefaultRootWindow(disp),
BASE_XPOS, BASE_YPOS, w, h, BORDER_WIDTH, CopyFromParent,
InputOutput, CopyFromParent, attvm, &att);
/* title */
assert(XStringListToTextProperty(&winName, 1, &wName), "Window Name");
assert(XStringListToTextProperty(&iconName, 1, &iName), "Icon Name");
/* size hints */
sh.flags = PSize | PMinSize | PMaxSize;
sh.width = (sh.min_width = (sh.max_width = w));
sh.height = (sh.min_height = (sh.max_height = h));
/* wm hints */
wmhints.initial_state = NormalState;
wmhints.input = True;
wmhints.icon_pixmap = None;
wmhints.flags = StateHint | InputHint | IconPixmapHint;
classhints.res_name = argv[0];
classhints.res_class = "GTetris";
/* set wm properties */
XSetWMProperties(disp, field->frame, &wName, &iName,
argv, argc, &sh, &wmhints, &classhints);
/* get ready to receive WM_DELETE_WINDOW */
field->delw = XInternAtom(disp, "WM_DELETE_WINDOW", False);
XSetWMProtocols(disp, field->frame, &(field->delw), 1);
/* "title" sub-window */
field->title = XCreateSimpleWindow(disp, field->frame,
-BORDER_WIDTH, -BORDER_WIDTH, w, TITLE_HEIGHT, BORDER_WIDTH,
bdcolor.pixel, bgcolor.pixel);
XSelectInput(disp, field->title, KeyPressMask | ExposureMask);
/* "ground" sub-window */
field->win = XCreateSimpleWindow(disp, field->frame,
-BORDER_WIDTH, TITLE_HEIGHT - BORDER_WIDTH, w, h - TITLE_HEIGHT,
BORDER_WIDTH, bdcolor.pixel, bgcolor.pixel);
XSelectInput(disp, field->win, KeyPressMask | ExposureMask);
if (rootDepth == 1)
num_patterns = NUM_BITMAPS;
field->full = (int **) malloc(sizeof(int *) * width);
for (x = 0; x < width; x++) {
field->full[x] = (int *) malloc(sizeof(int) * height);
for (y = 0; y < height; y++)
if ((y < lines_full) && nrandom(2))
field->full[x][y] = nrandom(num_patterns);
else
field->full[x][y] = 0;
}
/* loading fonts */
field->tfont = XLoadQueryFont(disp, TITLE_FONT);
field->sfont = XLoadQueryFont(disp, SCORE_FONT);
if (field->tfont == NULL) {
field->tfont = XLoadQueryFont(disp, TITLE_FONT2);
assert(field->tfont, "Title Font");
}
if (field->sfont == NULL) {
field->sfont = XLoadQueryFont(disp, SCORE_FONT2);
assert(field->sfont, "Banner Font");
}
field->winheight = field->height * BOX_HEIGHT + 2 * Y_MARGIN;
field->winwidth = field->width * BOX_WIDTH + 2 * X_MARGIN;
/* map windows */
XMapWindow(disp, field->title);
XMapWindow(disp, field->win);
XMapRaised(disp, field->frame);
gcv.function = GXcopy;
gcv.foreground = bdcolor.pixel;
gcv.background = bgcolor.pixel;
gc_t = XCreateGC(disp, field->title,
(GCForeground | GCBackground | GCFunction), &gcv);
gc_w = XCreateGC(disp, field->win,
(GCForeground | GCBackground | GCFunction), &gcv);
gcv.background = bdcolor.pixel;
gcv.foreground = bgcolor.pixel;
gc_w2 = XCreateGC(disp, field->win, (GCForeground | GCBackground |
GCFunction), &gcv);
text.function = GXcopy;
text.font = field->tfont->fid;
text.foreground = bdcolor.pixel;
text.background = bgcolor.pixel;
gc_ttx = XCreateGC(disp, field->title, (GCFunction | GCFont |
GCForeground | GCBackground), &text);
text.font = field->sfont->fid;
gc_wtx = XCreateGC(disp, field->title, (GCFunction | GCFont |
GCForeground | GCBackground), &text);
XFlush(disp);
return (field);
}
void
drawField(field)
field_t *field;
{
int x, y;
for (x = 0; x < field->width; x++)
for (y = 0; y < field->height; y++)
doBox(field, x, y, field->full[x][y]);
XDrawImageString(disp, field->title, gc_ttx, 5, 30, "TETRIS", 6);
updateScore(field);
XFlush(disp);
return;
}
void
updateScore(field)
field_t *field;
{
char buf[100];
(void) sprintf(buf, "Score: %-7d", field->score);
XDrawImageString(disp, field->title, gc_wtx,
SCORE_XPOS1, SCORE_YPOS1, buf, strlen(buf));
(void) sprintf(buf, "Level: %-7d", field->level);
XDrawImageString(disp, field->title, gc_wtx,
SCORE_XPOS1, SCORE_YPOS2, buf, strlen(buf));
(void) sprintf(buf, "Lines: %-7d", field->lines);
XDrawImageString(disp, field->title, gc_wtx,
SCORE_XPOS2, SCORE_YPOS2, buf, strlen(buf));
XFlush(disp);
return;
}
thing_t *
makeNewThing(field)
field_t *field;
{
int i, j, k;
int pat;
int whichone;
thing_t *thing = (thing_t *) malloc(sizeof(thing_t));
i = 0;
for (j = 0; j < NUM_POSSIBLE; j++)
i += possible[j].probability;
k = nrandom(i);
for (j = 0; j < NUM_POSSIBLE; j++) {
k -= possible[j].probability;
if (k < 0)
break;
}
*thing = possible[j];
whichone = j;
for (i = 0; i < thing->size; i++)
for (j = 0; j < thing->size; j++)
if (thing->map[i][j]) {
pat = 1;
if (i != 0 && thing->map[i - 1][j])
pat += 1;
if (j != 0 && thing->map[i][j - 1])
pat += 2;
if (i < thing->size - 1 && thing->map[i + 1][j])
pat += 4;
if (j < thing->size - 1 && thing->map[i][j + 1])
pat += 8;
thing->map[i][j] = pat + whichone * 16;
}
for (i = nrandom(4); i > 0; i--)
rotateThing(thing);
thing->ypos = field->height - thing->size;
thing->xpos = nrandom((field->width - 2 * thing->size) + thing->size);
return (thing);
}
void
rotateThing(thing)
thing_t *thing;
{
thing_t temp;
int lpoint = thing->size;
int nlpoint = thing->size;
int x, y;
int pattype;
temp = *thing;
for (x = 0; x < thing->size; x++)
for (y = 0; y < thing->size; y++)
if (thing->map[x][y] && (lpoint < y))
lpoint = y;
for (x = 0; x < thing->size; x++)
for (y = 0; y < thing->size; y++) {
pattype = (temp.map[y][thing->size - x - 1] - 1) / 16;
thing->map[x][y] =
((((temp.map[y][thing->size - x - 1] & 15) - 1) * 2) % 15 + 1)
+ pattype * 16;
if (thing->map[x][y] < 0)
thing->map[x][y] = 0;
}
for (x = 0; x < thing->size; x++)
for (y = 0; y < thing->size; y++)
if (thing->map[x][y] && (nlpoint < y))
nlpoint = y;
thing->ypos += lpoint - nlpoint;
return;
}
int
checkLine(field)
field_t *field;
{
int *set = (int *) malloc(sizeof(int) * field->height);
int i, x, y, nset = 0, h;
for (y = 0; y < field->height; y++) {
for (x = 0; x < field->width; x++)
if (!field->full[x][y])
break;
if (x == field->width) {
set[y] = 1;
nset++;
} else
set[y] = 0;
}
if (nset) {
for (i = 0; i < NUM_FLASHES / nset; i++) {
for (y = 0; y < field->height; y++)
if (set[y]) {
XFillRectangle(disp, field->win, gc_w,
X_MARGIN,
ytr((y + 1) * BOX_HEIGHT +
Y_MARGIN),
field->width * BOX_WIDTH,
BOX_HEIGHT);
XFlush(disp);
}
}
for (y = 0; y < field->height; y++)
if (set[y]) {
for (i = y; i < field->height - 1; i++)
for (x = 0; x < field->width; x++)
field->full[x][i] =
field->full[x][i + 1];
for (x = 0; x < field->width; x++)
field->full[x][field->height - 1] = 0;
h = (field->height - y - 1) * BOX_HEIGHT;
if (h > field->winheight - BOX_HEIGHT -
Y_MARGIN)
h = field->winheight - BOX_HEIGHT -
Y_MARGIN;
XCopyArea(disp, field->win, field->win, gc_w,
X_MARGIN, Y_MARGIN,
field->winwidth, h,
X_MARGIN, BOX_HEIGHT + Y_MARGIN);
for (i = y; i < field->height - 1; i++)
set[i] = set[i + 1];
set[field->height - 1] = 0;
y--;
}
if (beep) XBell(disp, -90);
XSync(disp, 0);
}
free((char *) set);
return nset;
}
void
initPixmaps(field)
field_t *field;
{
Pixmap bms[NUM_BITMAPS];
int i, j;
char *lastFg = "", *lastBg = "";
XColor lastFgC, lastBgC;
for (i = 0; i < NUM_BITMAPS; i++) {
bms[i] = XCreateBitmapFromData(disp, field->win,
bitmap_data[i].data,
bitmap_data[i].width,
bitmap_data[i].height);
assert(bms[i], "Bitmap");
}
if (rootDepth == 1) {
for (i = 0; i < NUM_BITMAPS; i++) {
patterns[i].pixmap = bms[i];
}
return;
}
for (i = 0; i < NUM_PATTERNS; i++) {
j = 0;
if (strcmp(patterns[i].fgname, lastFg) != 0) {
assert(XParseColor(disp, cmap,
patterns[i].fgname, &patterns[i].fg), "Parse Color");
assert(XAllocColor(disp, cmap, &patterns[i].fg), "Allocate Color");
lastFg = patterns[i].fgname;
lastFgC = patterns[i].fg;
j = 1;
} else {
patterns[i].fg = lastFgC;
}
if (strcmp(patterns[i].bgname, lastBg) != 0) {
assert(XParseColor(disp, cmap,
patterns[i].bgname, &patterns[i].bg), "Parse Color");
assert(XAllocColor(disp, cmap, &patterns[i].bg), "Allocate Color");
lastBg = patterns[i].bgname;
lastBgC = patterns[i].bg;
j = 1;
} else {
patterns[i].bg = lastBgC;
}
if (j) {
color.function = GXcopy;
color.foreground = patterns[i].fg.pixel;
color.background = patterns[i].bg.pixel;
gc_pat[i] = XCreateGC(disp, field->win, (GCForeground |
GCBackground | GCFunction), &color);
} else
gc_pat[i] = gc_pat[i - 1];
patterns[i].pixmap = bms[patterns[i].whichbitmap];
assert(patterns[i].pixmap, "Pixmap");
}
return;
}
int
nrandom(n)
int n;
{
return ((((double) random()) / ((double) 0x7fffffff)) * n);
}
void
Usage(argv)
char **argv;
{
fprintf(stderr, "Usage: %s [ starting_level [ rows_pre-filled ] ]\n\n",
argv[0]);
exit(255);
}