home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / games / volume15 / gtetris / part01 / tetris.c < prev    next >
C/C++ Source or Header  |  1993-01-27  |  23KB  |  940 lines

  1. /*
  2. # GENERIC X-WINDOW-BASED TETRIS
  3. #
  4. #    tetris.c
  5. #
  6. ###
  7. #
  8. #  Copyright (C) 1992    Qiang Alex Zhao
  9. #            Computer Science Dept, University of Arizona
  10. #            azhao@cs.arizona.edu
  11. #
  12. #            All Rights Reserved
  13. #
  14. #  Permission to use, copy, modify, and distribute this software and
  15. #  its documentation for any purpose and without fee is hereby granted,
  16. #  provided that the above copyright notice appear in all copies and
  17. #  that both that copyright notice and this permission notice appear in
  18. #  supporting documentation, and that the name of the author not be
  19. #  used in advertising or publicity pertaining to distribution of the
  20. #  software without specific, written prior permission.
  21. #
  22. #  This program is distributed in the hope that it will be "playable",
  23. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  25. #
  26. */
  27.  
  28. /* first tetris.h, then data.h */
  29. #include "tetris.h"
  30. #include "data.h"
  31.  
  32. void
  33. main(argc, argv)
  34.     int             argc;
  35.     char          **argv;
  36. {
  37.     int             start_level = 0, lines_full = 0;
  38.     field_t        *field;
  39.     thing_t        *thing = NULL;
  40.     int             readfds, writefds, exceptfds;
  41.     struct timeval  nextfall, now, delay;
  42.     struct timezone tzone;
  43.     Bool            reset_time = True;
  44.     char            buf[100];
  45.  
  46.  
  47.     fprintf(stderr, "\t\tGENERIC TETRIS V1.3\n");
  48.     fprintf(stderr, "\tCopyright (C) 1992    Qiang Alex Zhao\n\n");
  49.     fprintf(stderr, "GENERIC TETRIS comes with ABSOLUTELY NO WARRANTY.\n");
  50.     fprintf(stderr, "Send bug-reports/fixes/comments to:\n");
  51.     fprintf(stderr, "\tQiang Alex Zhao,    azhao@cs.arizona.edu\n");
  52.     fprintf(stderr, "\tComputer Science Dept, University of Arizona, Tucson\n\n");
  53.  
  54.     /* initialization */
  55.  
  56.     start_level = 3;
  57.     lines_full = 0;
  58.  
  59.     if (argc > 3) {
  60.     Usage(argv);
  61.     }
  62.     if (argc > 1) {
  63.     if (sscanf(argv[1], "%d", &start_level) < 1) {
  64.         Usage(argv);
  65.     }
  66.     }
  67.     if (argc > 2) {
  68.     if (sscanf(argv[2], "%d", &lines_full) < 1) {
  69.         Usage(argv);
  70.     }
  71.     }
  72.  
  73.     if (start_level < 0) start_level = 0;
  74.     if (start_level >= NUM_LEVELS) start_level = NUM_LEVELS - 1;
  75.     if (lines_full < 0) lines_full = 0;
  76.     if (lines_full >= DEF_HEIGHT - 2) lines_full = DEF_HEIGHT - 3;
  77.  
  78.     srandom((int) time(NULL));
  79.  
  80.     if ((disp = XOpenDisplay(NULL)) == NULL) {
  81.     fprintf(stderr, "Error: can't open display \"%s\".\n\n",
  82.         XDisplayName(NULL));
  83.     showHighScores(SHOWNSCORES/2);
  84.     exit(1);
  85.     }
  86.  
  87.     /* rebinding keypad */
  88.     XRebindKeysym(disp, XK_R7,    NULL, 0, "j", sizeof(char));
  89.     XRebindKeysym(disp, XK_R10,   NULL, 0, "j", sizeof(char));
  90.     XRebindKeysym(disp, XK_R13,   NULL, 0, "j", sizeof(char));
  91.     XRebindKeysym(disp, XK_Left,  NULL, 0, "j", sizeof(char));
  92.     XRebindKeysym(disp, XK_R8,    NULL, 0, "k", sizeof(char));
  93.     XRebindKeysym(disp, XK_R11,   NULL, 0, "k", sizeof(char));
  94.     XRebindKeysym(disp, XK_R14,   NULL, 0, "k", sizeof(char));
  95.     XRebindKeysym(disp, XK_Up,    NULL, 0, "k", sizeof(char));
  96.     XRebindKeysym(disp, XK_Down,  NULL, 0, "k", sizeof(char));
  97.     XRebindKeysym(disp, XK_R9,    NULL, 0, "l", sizeof(char));
  98.     XRebindKeysym(disp, XK_R12,   NULL, 0, "l", sizeof(char));
  99.     XRebindKeysym(disp, XK_R15,   NULL, 0, "l", sizeof(char));
  100.     XRebindKeysym(disp, XK_Right, NULL, 0, "l", sizeof(char));
  101.  
  102.     /* setting color */
  103.     if (XDisplayPlanes(disp, DefaultScreen(disp)) == 1) {
  104.     bgcolor.pixel = WhitePixel(disp, DefaultScreen(disp));
  105.     bdcolor.pixel = BlackPixel(disp, DefaultScreen(disp));
  106.     titlecolor.pixel = BlackPixel(disp, DefaultScreen(disp));
  107.     textcolor.pixel = BlackPixel(disp, DefaultScreen(disp));
  108.     } else {
  109.     cmap = XDefaultColormap(disp, DefaultScreen(disp));
  110.     XParseColor(disp, cmap, BG_COLOR, &bgcolor);
  111.     XAllocColor(disp, cmap, &bgcolor);
  112.     XParseColor(disp, cmap, BD_COLOR, &bdcolor);
  113.     XAllocColor(disp, cmap, &bdcolor);
  114.     XParseColor(disp, cmap, TITLE_COLOR, &titlecolor);
  115.     XAllocColor(disp, cmap, &titlecolor);
  116.     XParseColor(disp, cmap, TEXT_COLOR, &textcolor);
  117.     XAllocColor(disp, cmap, &textcolor);
  118.     }
  119.  
  120.     /* initialize the playground */
  121.  
  122.     field = initField(DEF_WIDTH, DEF_HEIGHT, lines_full);
  123.     XSelectInput(disp, field->title, ExposureMask);
  124.  
  125.     initPixmaps(field);
  126.  
  127.     field->level = start_level;
  128.  
  129.     drawField(field);
  130.  
  131.     sleep(1);
  132.     XSelectInput(disp, field->frame, KeyPressMask | ExposureMask | 
  133.     StructureNotifyMask);
  134.  
  135.     while (True) {
  136.     if (reset_time) {
  137.         gettimeofday(&nextfall, &tzone);
  138.         nextfall.tv_usec += 10000 * speeds[field->level];
  139.         normTimeVal(&nextfall);
  140.     }
  141.     if (XPending(disp))
  142.         handleEvents(field, &thing, False);
  143.     gettimeofday(&now, &tzone);
  144.     delay.tv_sec = nextfall.tv_sec - now.tv_sec;
  145.     delay.tv_usec = nextfall.tv_usec - now.tv_usec;
  146.     normTimeVal(&delay);
  147.     if (delay.tv_sec >= 0) {
  148.         writefds = exceptfds = 0;
  149.         readfds = 1 << ConnectionNumber(disp);
  150.         (void) select(sizeof(int) * 8, (fd_set *) &readfds, (fd_set *)
  151.         &writefds, (fd_set *) &exceptfds, &delay);
  152.     }
  153.     gettimeofday(&now, &tzone);
  154.     if ((now.tv_sec > nextfall.tv_sec) ||
  155.         ((now.tv_sec == nextfall.tv_sec) &&
  156.          (now.tv_usec > nextfall.tv_usec))) {
  157.         handleEvents(field, &thing, True);
  158.         reset_time = True;
  159.     } else {
  160.         handleEvents(field, &thing, False);
  161.         reset_time = False;
  162.     }
  163.     }
  164.     /* never come to here */
  165. }
  166.  
  167. void
  168. normTimeVal(tv)
  169.     struct timeval *tv;
  170. {
  171.     while (tv->tv_usec < 0) {
  172.     tv->tv_sec--;
  173.     tv->tv_usec += MILLION;
  174.     }
  175.     while (tv->tv_usec >= MILLION) {
  176.     tv->tv_sec++;
  177.     tv->tv_usec -= MILLION;
  178.     }
  179.  
  180.     return;
  181. }
  182.  
  183. void
  184. fallDown(field, thingp, eat)
  185.     field_t        *field;
  186.     thing_t       **thingp;
  187.     Bool            eat;
  188. {
  189.     int             lines;
  190.     XEvent          event;
  191.  
  192.     putBoxes(field, *thingp);
  193.  
  194.     lines = checkLine(field);
  195.     field->score += 5 + 5 * field->level * field->level * lines;
  196.     field->lines += lines;
  197.     if (field->lines >= thresh[field->level])
  198.         field->level++;
  199.     updateScore(field);
  200.  
  201.     free((char *) *thingp);
  202.     if (eat) {
  203.     *thingp = NULL;
  204.     while (XPending(disp)) XNextEvent(disp, &event);
  205.     }
  206.     *thingp = makeNewThing(field);
  207.     if (overlapping(field, *thingp)) die(field);
  208.     drawThing(field, *thingp);
  209. }
  210.  
  211. void
  212. handleEvents(field, thingp, fall_down)
  213.     field_t        *field;
  214.     thing_t       **thingp;
  215.     Bool            fall_down;
  216. {
  217.     static Bool     frozen = False;
  218.     XEvent          event;
  219.     int             highest;
  220.     char            s[4];
  221.     int             n;
  222.  
  223.     if (frozen) fall_down = False;
  224.  
  225.     if (!*thingp) {
  226.     *thingp = makeNewThing(field);
  227.     if (overlapping(field, *thingp))
  228.         die(field);
  229.     drawThing(field, *thingp);
  230.     XSync(disp, 0);
  231.     }
  232.     if (fall_down && atBottom(field, *thingp)) {
  233.     fallDown(field, thingp, False);
  234.     fall_down = False;
  235.     }
  236.     if (!XPending(disp) && !frozen)
  237.     moveOne(field, *thingp, NONE, fall_down);
  238.  
  239.     while (XPending(disp)) {
  240.     if (overlapping(field, *thingp))
  241.         die(field);
  242.  
  243.     XNextEvent(disp, &event);
  244.     switch (event.type) {
  245.     case KeyPress:
  246.         n = XLookupString(&event, s, 4, NULL, NULL);
  247.         if (!n)
  248.         break;
  249.         switch (*s) {
  250.         case 'j':        /* Move left. */
  251.         case 'J':
  252.         case 's':
  253.         case 'S':
  254.         if (!frozen)
  255.             moveOne(field, *thingp, LEFT,
  256.                 fall_down);
  257.         break;
  258.  
  259.         case 'k':        /* Rotate. */
  260.         case 'K':
  261.         case 'd':
  262.         case 'D':
  263.         if (!frozen)
  264.             moveOne(field, *thingp, ROTATE,
  265.                 fall_down);
  266.         break;
  267.  
  268.         case 'l':        /* Move right. */
  269.         case 'L':
  270.         case 'f':
  271.         case 'F':
  272.         if (!frozen)
  273.             moveOne(field, *thingp, RIGHT,
  274.                 fall_down);
  275.         break;
  276.  
  277.         case ' ':        /* Drop. */
  278.         case '\n':
  279.         if (!frozen) {
  280.             moveOne(field, *thingp, DROP, fall_down);
  281.             fallDown(field, thingp, True);
  282.         }
  283.         return;
  284.         break;
  285.  
  286.         case 'q':        /* Quit. */
  287.         case 'Q':
  288.         die(field);
  289.         break;
  290.  
  291.         case '+':        /* Speed up. */
  292.         case '=':
  293.         if (field->level < NUM_LEVELS - 1) {
  294.             field->level++;
  295.             updateScore(field);
  296.         }
  297.         break;
  298.  
  299.         case '-':        /* Slow down. */
  300.         case '_':
  301.         if (field->level > 0) {
  302.             field->level--;
  303.             updateScore(field);
  304.         }
  305.         break;
  306.  
  307.         case '\023':    /* Freeze / continue. */
  308.         case 'p':
  309.         case 'P':
  310.         frozen = (frozen ? False : True);
  311.         /* flow to next */
  312.  
  313.         case '\014':        /* Redraw. */
  314.         /* "... Hi Boss, I'm working hard as usual ..." */
  315.         XClearWindow(disp, field->win);
  316.         drawField(field);
  317.         if (*thingp)
  318.             drawThing(field, *thingp);
  319.         if (frozen) {
  320.             banner(field, PAUSED_MESG);
  321.             XIconifyWindow(disp, field->frame, DefaultScreen(disp));
  322.         }
  323.         /* flow to next */
  324.  
  325.         default:
  326.         XBell(disp, -25);
  327.         XFlush(disp);
  328.         break;
  329.         }
  330.         break;        /* processing key press */
  331.  
  332.     case UnmapNotify:
  333.         frozen = True;
  334.         break;
  335.  
  336.     case Expose:
  337.         drawField(field);
  338.         if (*thingp)
  339.         drawThing(field, *thingp);
  340.         if (frozen) {
  341.         banner(field, PAUSED_MESG);
  342.         }
  343.         XFlush(disp);
  344.         break;
  345.  
  346.     }
  347.  
  348.     fall_down = False;
  349.     }
  350.  
  351.     return;
  352. }
  353.  
  354. void
  355. moveOne(field, thing, what, fall_down)
  356.     field_t        *field;
  357.     thing_t        *thing;
  358.     command_t       what;
  359.     Bool            fall_down;
  360. {
  361.     thing_t         old;
  362.  
  363.     old = *thing;
  364.  
  365.     if (tryMove(field, thing, what, fall_down))
  366.     drawThingDiff(field, thing, &old);
  367.  
  368.     XSync(disp, 0);
  369.     return;
  370. }
  371.  
  372. Bool
  373. tryMove(field, thing, what, fall_down)
  374.     field_t        *field;
  375.     thing_t        *thing;
  376.     command_t       what;
  377.     Bool            fall_down;
  378. {
  379.     int             x, y;
  380.     thing_t         temp;
  381.     Bool            ok = True;
  382.  
  383.     temp = *thing;
  384.  
  385.     if (fall_down)
  386.     temp.ypos--;
  387.     switch (what) {
  388.     case LEFT:
  389.     temp.xpos--;
  390.     break;
  391.  
  392.     case RIGHT:
  393.     temp.xpos++;
  394.     break;
  395.  
  396.     case ROTATE:
  397.     rotateThing(&temp);
  398.     break;
  399.  
  400.     case DROP:
  401.     while (!overlapping(field, &temp)) {
  402.         field->score += field->level;
  403.         temp.ypos--;
  404.     }
  405.     temp.ypos++;
  406.     break;
  407.  
  408.     case NONE:
  409.     break;
  410.     }
  411.  
  412.     for (x = 0; x < temp.size; x++)
  413.     for (y = 0; y < temp.size; y++) {
  414.         if (temp.map[x][y]) {
  415.         if ((temp.xpos + x < 0) ||
  416.             (temp.xpos + x >= field->width) ||
  417.             (temp.ypos + y < 0) ||
  418.             (temp.ypos + y >= field->height) ||
  419.             (field->full[temp.xpos + x]
  420.              [temp.ypos + y]))
  421.             ok = False;
  422.         }
  423.     }
  424.  
  425.     if (ok)
  426.     *thing = temp;
  427.  
  428.     if (overlapping(field, thing)) {
  429.     return (False);
  430.     } else {
  431.     return (True);
  432.     }
  433. }
  434.  
  435. Bool
  436. atBottom(field, thing)
  437.     field_t        *field;
  438.     thing_t        *thing;
  439. {
  440.     int             x, y;
  441.  
  442.     for (x = 0; x < thing->size; x++)
  443.     for (y = 0; y < thing->size; y++)
  444.         if (thing->map[x][y]) {
  445.         if (thing->ypos + y <= 0)
  446.             return (True);
  447.         if (field->full[thing->xpos + x]
  448.             [thing->ypos + y - 1])
  449.             return (True);
  450.         }
  451.     return (False);
  452. }
  453.  
  454. void
  455. drawThing(field, thing)
  456.     field_t        *field;
  457.     thing_t        *thing;
  458. {
  459.     int             x, y;
  460.  
  461.     for (x = 0; x < thing->size; x++)
  462.     for (y = 0; y < thing->size; y++)
  463.         if (thing->map[x][y])
  464.         doBox(field, thing->xpos + x, thing->ypos + y,
  465.               thing->map[x][y]);
  466.     return;
  467. }
  468.  
  469. void
  470. drawThingDiff(field, thing, oldthing)
  471.     field_t        *field;
  472.     thing_t        *thing, *oldthing;
  473. {
  474.     int             x, y;
  475.     int             ox, oy;
  476.  
  477.     for (x = 0; x < thing->size; x++)
  478.     for (y = 0; y < thing->size; y++) {
  479.         ox = x - oldthing->xpos + thing->xpos;
  480.         oy = y - oldthing->ypos + thing->ypos;
  481.         if (thing->map[x][y])
  482.         doBox(field, thing->xpos + x, thing->ypos + y,
  483.               thing->map[x][y]);
  484.     }
  485.     for (x = 0; x < thing->size; x++)
  486.     for (y = 0; y < thing->size; y++) {
  487.         ox = x - thing->xpos + oldthing->xpos;
  488.         oy = y - thing->ypos + oldthing->ypos;
  489.         if (oldthing->map[x][y] &&
  490.             ((ox < 0) || (ox >= thing->size) ||
  491.              (oy < 0) || (oy >= thing->size) ||
  492.              !thing->map[ox][oy]))
  493.         doBox(field, oldthing->xpos + x,
  494.               oldthing->ypos + y,
  495.               0);
  496.     }
  497.     return;
  498. }
  499.  
  500. void
  501. doBox(field, x, y, pat)
  502.     field_t        *field;
  503.     int             x, y;
  504.     int             pat;
  505. {
  506.     if ((x < 0) || (x >= field->width) || (y < 0) || (y >= field->height))
  507.     abort();
  508.     if (pat == 0)
  509.     XFillRectangle(disp, field->win, gc_w2,
  510.                x * BOX_WIDTH + X_MARGIN,
  511.                ytr((y + 1) * BOX_HEIGHT + Y_MARGIN) - 1,
  512.                BOX_WIDTH + 1, BOX_HEIGHT + 1);
  513.     else {
  514.     if (XDisplayPlanes(disp, DefaultScreen(disp)) == 1) {
  515.         pat = pat % 16 - 1;
  516.         XCopyPlane(disp, patterns[pat].pixmap, field->win, gc_w,
  517.                0, 0,
  518.                BOX_WIDTH, BOX_HEIGHT,
  519.                x * BOX_WIDTH + X_MARGIN,
  520.                ytr((y + 1) * BOX_HEIGHT + Y_MARGIN), 1);
  521.     } else {
  522.         pat -= 1;
  523.         XCopyPlane(disp, patterns[pat].pixmap, field->win,
  524.                gc_pat[pat],
  525.                0, 0,
  526.                BOX_WIDTH, BOX_HEIGHT,
  527.                x * BOX_WIDTH + X_MARGIN,
  528.                ytr((y + 1) * BOX_HEIGHT + Y_MARGIN), 1);
  529.     }
  530.     }
  531.     return;
  532. }
  533.  
  534. Bool
  535. overlapping(field, thing)
  536.     field_t        *field;
  537.     thing_t        *thing;
  538. {
  539.     int             x, y;
  540.  
  541.     for (x = 0; x < thing->size; x++)
  542.     for (y = 0; y < thing->size; y++) {
  543.         if (thing->map[x][y] && (thing->ypos + y < 0))
  544.         return (True);
  545.         if (thing->map[x][y] && field->full[thing->xpos + x]
  546.             [thing->ypos + y])
  547.         return (True);
  548.     }
  549.     return (False);
  550. }
  551.  
  552. int
  553. putBoxes(field, thing)
  554.     field_t        *field;
  555.     thing_t        *thing;
  556. {
  557.     int             x, y;
  558.     int             highest = 0;
  559.  
  560.     for (x = 0; x < thing->size; x++)
  561.     for (y = 0; y < thing->size; y++)
  562.         if (thing->map[x][y]) {
  563.         if ((thing->xpos + x < 0) ||
  564.             (thing->xpos + x >= field->width) ||
  565.             (thing->ypos + y < 0) ||
  566.             (thing->ypos + y >= field->height))
  567.             abort();
  568.         field->full[thing->xpos + x][thing->ypos + y]
  569.             = thing->map[x][y];
  570.         if (thing->ypos + y > highest)
  571.             highest = thing->ypos + y;
  572.         }
  573.     return (highest);
  574. }
  575.  
  576. field_t        *
  577. initField(width, height, lines_full)
  578.     int             width, height;
  579.     int             lines_full;
  580. {
  581.     Cursor          cursor;
  582.     XSizeHints      sh;
  583.     field_t        *field = (field_t *) malloc(sizeof(field_t));
  584.     int             x, y, w, h;;
  585.  
  586.     w = width * BOX_WIDTH + 2 * X_MARGIN;
  587.     h = height * BOX_HEIGHT + 2 * Y_MARGIN + TITLE_HEIGHT;
  588.  
  589.     field->width = width;
  590.     field->height = height;
  591.     field->score = 0;
  592.     field->level = 1;
  593.     field->lines = 0;
  594.  
  595.     field->frame = XCreateSimpleWindow(disp, DefaultRootWindow(disp),
  596.     BASE_XPOS, BASE_YPOS, w, h, BORDER_WIDTH, bdcolor.pixel, bgcolor.pixel);
  597.  
  598.     cursor = XCreateFontCursor(disp, XC_exchange);
  599.     XDefineCursor(disp, field->frame, cursor);
  600.     XSetStandardProperties(disp, field->frame, "GENERIC TETRIS",
  601.     "GENERIC TETRIS", None, NULL, 0, NULL);
  602.  
  603.     sh.flags = PSize | PMinSize | PMaxSize;
  604.     sh.width = (sh.min_width = (sh.max_width = w));
  605.     sh.height = (sh.min_height = (sh.max_height = h));
  606.     XSetWMNormalHints(disp, field->frame, &sh);
  607.  
  608.     field->title = XCreateSimpleWindow(disp, field->frame,
  609.     -BORDER_WIDTH, -BORDER_WIDTH, w, TITLE_HEIGHT, BORDER_WIDTH,
  610.     bdcolor.pixel, bgcolor.pixel);
  611.  
  612.     field->win = XCreateSimpleWindow(disp, field->frame,
  613.     -BORDER_WIDTH, TITLE_HEIGHT - BORDER_WIDTH, w, h - TITLE_HEIGHT,
  614.     BORDER_WIDTH, bdcolor.pixel, bgcolor.pixel);
  615.  
  616.     if (XDisplayPlanes(disp, DefaultScreen(disp)) == 1)
  617.     num_patterns = NUM_BITMAPS;
  618.  
  619.     field->full = (int **) malloc(sizeof(int *) * width);
  620.     for (x = 0; x < width; x++) {
  621.     field->full[x] = (int *) malloc(sizeof(int) * height);
  622.     for (y = 0; y < height; y++)
  623.         if ((y < lines_full) && nrandom(2))
  624.         field->full[x][y] = nrandom(num_patterns);
  625.         else
  626.         field->full[x][y] = 0;
  627.     }
  628.  
  629.     /* loading fonts */
  630.     field->tfont = XLoadQueryFont(disp, TITLE_FONT);
  631.     field->sfont = XLoadQueryFont(disp, SCORE_FONT);
  632.     if (field->tfont == NULL) {
  633.     field->tfont = XLoadQueryFont(disp, "-*-fixed-*-r-*-*-24-*-*-*-*-*-*-*");
  634.     assert(field->tfont);
  635.     }
  636.     if (field->sfont == NULL) {
  637.     field->sfont = XLoadQueryFont(disp, "-*-fixed-*-r-*-*-12-*-*-*-*-*-*-*");
  638.     assert(field->sfont);
  639.     }
  640.  
  641.     field->winheight = field->height * BOX_HEIGHT + 2 * Y_MARGIN;
  642.     field->winwidth = field->width * BOX_WIDTH + 2 * X_MARGIN;
  643.  
  644.     XMapWindow(disp, field->title);
  645.     XMapWindow(disp, field->win);
  646.     XMapRaised(disp, field->frame);
  647.  
  648.     gcv.function = GXcopy;
  649.     gcv.foreground = bdcolor.pixel;
  650.     gcv.background = bgcolor.pixel;
  651.  
  652.     gc_t = XCreateGC(disp, field->title, (GCForeground | GCBackground |
  653.                       GCFunction), &gcv);
  654.     gc_w = XCreateGC(disp, field->win, (GCForeground | GCBackground |
  655.                     GCFunction), &gcv);
  656.  
  657.     gcv.background = bdcolor.pixel;
  658.     gcv.foreground = bgcolor.pixel;
  659.  
  660.     gc_w2 = XCreateGC(disp, field->win, (GCForeground | GCBackground |
  661.                      GCFunction), &gcv);
  662.  
  663.     text.function = GXcopy;
  664.     text.font = field->tfont->fid;
  665.     text.foreground = bdcolor.pixel;
  666.     text.background = bgcolor.pixel;
  667.     gc_ttx = XCreateGC(disp, field->title, (GCFunction | GCFont |
  668.                        GCForeground | GCBackground), &text);
  669.     text.font = field->sfont->fid;
  670.     gc_wtx = XCreateGC(disp, field->title, (GCFunction | GCFont |
  671.                        GCForeground | GCBackground), &text);
  672.  
  673.     XFlush(disp);
  674.     return (field);
  675. }
  676.  
  677. void
  678. drawField(field)
  679.     field_t        *field;
  680. {
  681.     int             x, y;
  682.  
  683.     for (x = 0; x < field->width; x++)
  684.     for (y = 0; y < field->height; y++)
  685.         doBox(field, x, y, field->full[x][y]);
  686.  
  687.     XDrawImageString(disp, field->title, gc_ttx, 3, 30, "TETRIS", 6);
  688.  
  689.     updateScore(field);
  690.  
  691.     XFlush(disp);
  692.     return;
  693. }
  694.  
  695. void
  696. updateScore(field)
  697.     field_t        *field;
  698. {
  699.     char            buf[100];
  700.  
  701.     (void) sprintf(buf, "Score: %-7d", field->score);
  702.     XDrawImageString(disp, field->title, gc_wtx,
  703.              SCORE_XPOS1, SCORE_YPOS1, buf, strlen(buf));
  704.  
  705.     (void) sprintf(buf, "Level: %-7d", field->level);
  706.     XDrawImageString(disp, field->title, gc_wtx,
  707.              SCORE_XPOS1, SCORE_YPOS2, buf, strlen(buf));
  708.  
  709.     (void) sprintf(buf, "Lines: %-7d", field->lines);
  710.     XDrawImageString(disp, field->title, gc_wtx,
  711.              SCORE_XPOS2, SCORE_YPOS2, buf, strlen(buf));
  712.  
  713.     XFlush(disp);
  714.     return;
  715. }
  716.  
  717. thing_t        *
  718. makeNewThing(field)
  719.     field_t        *field;
  720. {
  721.     int             i, j, k;
  722.     int             pat;
  723.     int             whichone;
  724.     thing_t        *thing = (thing_t *) malloc(sizeof(thing_t));
  725.  
  726.     i = 0;
  727.     for (j = 0; j < NUM_POSSIBLE; j++)
  728.     i += possible[j].probability;
  729.  
  730.     k = nrandom(i);
  731.  
  732.     for (j = 0; j < NUM_POSSIBLE; j++) {
  733.     k -= possible[j].probability;
  734.     if (k < 0)
  735.         break;
  736.     }
  737.  
  738.     *thing = possible[j];
  739.     whichone = j;
  740.     for (i = 0; i < thing->size; i++)
  741.     for (j = 0; j < thing->size; j++)
  742.         if (thing->map[i][j]) {
  743.         pat = 1;
  744.         if (i != 0 && thing->map[i - 1][j])
  745.             pat += 1;
  746.         if (j != 0 && thing->map[i][j - 1])
  747.             pat += 2;
  748.         if (i < thing->size - 1 && thing->map[i + 1][j])
  749.             pat += 4;
  750.         if (j < thing->size - 1 && thing->map[i][j + 1])
  751.             pat += 8;
  752.         thing->map[i][j] = pat + whichone * 16;
  753.         }
  754.     for (i = nrandom(4); i > 0; i--)
  755.     rotateThing(thing);
  756.  
  757.     thing->ypos = field->height - thing->size;
  758.     thing->xpos = nrandom((field->width - 2 * thing->size) + thing->size);
  759.  
  760.     return (thing);
  761. }
  762.  
  763. void
  764. rotateThing(thing)
  765.     thing_t        *thing;
  766. {
  767.     thing_t         temp;
  768.     int             lpoint = thing->size;
  769.     int             nlpoint = thing->size;
  770.     int             x, y;
  771.     int             pattype;
  772.  
  773.     temp = *thing;
  774.     for (x = 0; x < thing->size; x++)
  775.     for (y = 0; y < thing->size; y++)
  776.         if (thing->map[x][y] && (lpoint < y))
  777.         lpoint = y;
  778.  
  779.     for (x = 0; x < thing->size; x++)
  780.     for (y = 0; y < thing->size; y++) {
  781.         pattype = (temp.map[y][thing->size - x - 1] - 1) / 16;
  782.         thing->map[x][y] =
  783.         ((((temp.map[y][thing->size - x - 1] & 15) - 1) * 2) % 15 + 1)
  784.         + pattype * 16;
  785.         if (thing->map[x][y] < 0)
  786.         thing->map[x][y] = 0;
  787.     }
  788.  
  789.     for (x = 0; x < thing->size; x++)
  790.     for (y = 0; y < thing->size; y++)
  791.         if (thing->map[x][y] && (nlpoint < y))
  792.         nlpoint = y;
  793.  
  794.     thing->ypos += lpoint - nlpoint;
  795.  
  796.     return;
  797. }
  798.  
  799. int
  800. checkLine(field)
  801.     field_t        *field;
  802. {
  803.     int            *set = (int *) malloc(sizeof(int) * field->height);
  804.     int             i, x, y, nset = 0, h;
  805.  
  806.     for (y = 0; y < field->height; y++) {
  807.     for (x = 0; x < field->width; x++)
  808.         if (!field->full[x][y])
  809.         break;
  810.     if (x == field->width) {
  811.         set[y] = 1;
  812.         nset++;
  813.     } else
  814.         set[y] = 0;
  815.     }
  816.  
  817.     if (nset) {
  818.     for (i = 0; i < NUM_FLASHES / nset; i++) {
  819.         for (y = 0; y < field->height; y++)
  820.         if (set[y]) {
  821.             XFillRectangle(disp, field->win, gc_w,
  822.                    X_MARGIN,
  823.                    ytr((y + 1) * BOX_HEIGHT +
  824.                        Y_MARGIN),
  825.                    field->width * BOX_WIDTH,
  826.                    BOX_HEIGHT);
  827.             XFlush(disp);
  828.         }
  829.     }
  830.     for (y = 0; y < field->height; y++)
  831.         if (set[y]) {
  832.         for (i = y; i < field->height - 1; i++)
  833.             for (x = 0; x < field->width; x++)
  834.             field->full[x][i] =
  835.                 field->full[x][i + 1];
  836.         for (x = 0; x < field->width; x++)
  837.             field->full[x][field->height - 1] = 0;
  838.  
  839.         h = (field->height - y - 1) * BOX_HEIGHT;
  840.         if (h > field->winheight - BOX_HEIGHT -
  841.             Y_MARGIN)
  842.             h = field->winheight - BOX_HEIGHT -
  843.             Y_MARGIN;
  844.         XCopyArea(disp, field->win, field->win, gc_w,
  845.               X_MARGIN, Y_MARGIN,
  846.               field->winwidth, h,
  847.               X_MARGIN, BOX_HEIGHT + Y_MARGIN);
  848.  
  849.         for (i = y; i < field->height - 1; i++)
  850.             set[i] = set[i + 1];
  851.         set[field->height - 1] = 0;
  852.         y--;
  853.         }
  854.     XBell(disp, -60);
  855.     XSync(disp, 0);
  856.     }
  857.     free((char *) set);
  858.  
  859.     return (nset);
  860. }
  861.  
  862. void
  863. initPixmaps(field)
  864.     field_t        *field;
  865. {
  866.     Pixmap          bms[NUM_BITMAPS];
  867.     int             i, j;
  868.     char           *lastFg = "", *lastBg = "";
  869.     XColor          lastFgC, lastBgC;
  870.  
  871.     for (i = 0; i < NUM_BITMAPS; i++) {
  872.     bms[i] = XCreateBitmapFromData(disp, field->win,
  873.                        bitmap_data[i].data,
  874.                        bitmap_data[i].width,
  875.                        bitmap_data[i].height);
  876.     assert(bms[i]);
  877.     }
  878.     if (XDisplayPlanes(disp, DefaultScreen(disp)) == 1) {
  879.     for (i = 0; i < NUM_BITMAPS; i++) {
  880.         patterns[i].pixmap = bms[i];
  881.     }
  882.     return;
  883.     }
  884.     for (i = 0; i < NUM_PATTERNS; i++) {
  885.     j = 0;
  886.     if (strcmp(patterns[i].fgname, lastFg) != 0) {
  887.         assert(XParseColor(disp, cmap,
  888.                    patterns[i].fgname, &patterns[i].fg));
  889.         assert(XAllocColor(disp, cmap, &patterns[i].fg));
  890.         lastFg = patterns[i].fgname;
  891.         lastFgC = patterns[i].fg;
  892.         j = 1;
  893.     } else {
  894.         patterns[i].fg = lastFgC;
  895.     }
  896.     if (strcmp(patterns[i].bgname, lastBg) != 0) {
  897.         assert(XParseColor(disp, cmap,
  898.                    patterns[i].bgname, &patterns[i].bg));
  899.         assert(XAllocColor(disp, cmap, &patterns[i].bg));
  900.         lastBg = patterns[i].bgname;
  901.         lastBgC = patterns[i].bg;
  902.         j = 1;
  903.     } else {
  904.         patterns[i].bg = lastBgC;
  905.     }
  906.  
  907.     if (j) {
  908.         color.function = GXcopy;
  909.         color.foreground = patterns[i].fg.pixel;
  910.         color.background = patterns[i].bg.pixel;
  911.  
  912.         gc_pat[i] = XCreateGC(disp, field->win, (GCForeground |
  913.                     GCBackground | GCFunction), &color);
  914.     } else
  915.         gc_pat[i] = gc_pat[i - 1];
  916.  
  917.     patterns[i].pixmap = bms[patterns[i].whichbitmap];
  918.     assert(patterns[i].pixmap);
  919.     }
  920.     return;
  921. }
  922.  
  923. int
  924. nrandom(n)
  925.     int             n;
  926. {
  927.     return ((((double) random()) / ((double) 0x7fffffff)) * n);
  928. }
  929.  
  930. void
  931. Usage(argv)
  932.     char          **argv;
  933. {
  934.     fprintf(stderr, "Usage:\t%s [ starting_level [ raws_pre-filled ] ]\n\n",
  935.     argv[0]);
  936.     showHighScores(SHOWNSCORES/2);
  937.     exit(255);
  938. }
  939.  
  940.