home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / XAP / XGAMES / XHEXTRIS.TAR / hextris.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-04-27  |  15.8 KB  |  577 lines

  1. /*
  2.  * hextris Copyright 1990 David Markley, dm3e@+andrew.cmu.edu, dam@cs.cmu.edu
  3.  *
  4.  * Permission to use, copy, modify, and distribute, this software and its
  5.  * documentation for any purpose is hereby granted without fee, provided that
  6.  * the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of the copyright holders be used in
  9.  * advertising or publicity pertaining to distribution of the software with
  10.  * specific, written prior permission, and that no fee is charged for further
  11.  * distribution of this software, or any modifications thereof.  The copyright
  12.  * holder make no representations about the suitability of this software for
  13.  * any purpose.  It is provided "as is" without express or implied warranty.
  14.  *
  15.  * THE COPYRIGHT HOLDER DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  16.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  17.  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  18.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  19.  * DATA, PROFITS, QPA OR GPA, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
  20.  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  21.  * PERFORMANCE OF THIS SOFTWARE.
  22.  */
  23.  
  24. /* This file contains the heart of hextris. It contains absolutely no
  25.  * direct I/O calls, for maximum portability. All I/O that is performed is
  26.  * done so by either the I/O handler directly, calls from the I/O handler
  27.  * to functions in this file that call functions in the I/O handler, or by
  28.  * functions in this file that call functions in the I/O handler.
  29.  */
  30.  
  31. #include "header.h"
  32.  
  33. /* This places the piece on the board in its starting position. All the
  34.  * hexes in the piece are displayed.
  35.  */
  36. init_piece(piece)
  37. piece_t *piece;
  38. {
  39.     int base, form, i;
  40.     base = (piece->column % 2) ? 0 : 8;
  41.     form = piece->type * 6 + piece->rotation;
  42.  
  43.     for (i = 0; i < 7; i += 2)
  44.       draw_hex(piece->row+shape[form][base+i],
  45.          piece->column+shape[form][base+1+i],1,piece->type);
  46. }
  47.  
  48. /* This places the piece in its new position. This is done by comparing
  49.  * the current piece's position (piece) to the new position (tpiece),
  50.  * removing any hexes that will no longer be covered, and placing
  51.  * any hexes that will be covered. In this way, any piece that is already
  52.  * covered, and will be covered, is not redrawn.
  53.  */
  54. place_piece(piece,tpiece)
  55. piece_t *piece, *tpiece;
  56. {
  57.     int base, form, tbase, tform, i, j, diff;
  58.     base = (piece->column % 2) ? 0 : 8;
  59.     form = piece->type * 6 + piece->rotation;
  60.     tbase = (tpiece->column % 2) ? 0 : 8;
  61.     tform = tpiece->type * 6 + tpiece->rotation;
  62.     
  63.     for (i = 0; i < 7; i += 2) {
  64.     for (j = 0; j < 7; j += 2) {
  65.         diff = 1;
  66.         if ((tpiece->row+shape[tform][tbase+i] == 
  67.          piece->row+shape[form][base+j])
  68.         && (tpiece->column+shape[tform][tbase+1+i] == 
  69.             piece->column+shape[form][base+1+j])) {
  70.         diff = 0;
  71.         break;
  72.             }
  73.     }
  74.     if (diff)
  75.       draw_hex(tpiece->row+shape[tform][tbase+i],
  76.              tpiece->column+shape[tform][tbase+1+i],1,tpiece->type);
  77.     }
  78.  
  79.     for (i = 0; i < 7; i += 2) {
  80.     for (j = 0; j < 7; j += 2) {
  81.         diff = 1;
  82.         if ((piece->row+shape[form][base+i] == 
  83.             tpiece->row+shape[tform][tbase+j])
  84.            && (piece->column+shape[form][base+1+i] == 
  85.                tpiece->column+shape[tform][tbase+1+j])) {
  86.         diff = 0;
  87.         break;
  88.                }
  89.     }
  90.     if (diff)
  91.       draw_hex(piece->row+shape[form][base+i],
  92.              piece->column+shape[form][base+1+i],0,piece->type);
  93.     }
  94. }
  95.  
  96. /* This checks to see if the proposed position of the piece (tpiece) will
  97.  * legally fit in the grid.
  98.  */
  99. check_piece(tpiece,grid)
  100. piece_t *tpiece;
  101. position_t grid[MAXROW][MAXCOLUMN];
  102. {
  103.     int base, form, i;
  104.     base = (tpiece->column % 2) ? 0 : 8;
  105.     form = tpiece->type * 6 + tpiece->rotation;
  106.  
  107.  
  108.     for (i = 0; i < 7; i += 2)
  109.       if (grid[tpiece->row+shape[form][base+i]]
  110.       [tpiece->column+shape[form][base+1+i]].filled)
  111.     return 1;
  112.  
  113.     if ((tpiece->row+3) >= MAXROW) /* If the piece is near the bottom */
  114.       for (i = 0; i < 7; i += 2)
  115.     if (((tpiece->row)+shape[form][base+i]) >= MAXROW)
  116.       return 1;
  117.  
  118.     if ((tpiece->column+3) >= MAXCOLUMN) /* If the piece is near the right */
  119.       for (i = 1; i < 8; i += 2)
  120.     if (tpiece->column+shape[form][base+i] >= MAXCOLUMN)
  121.       return 1;
  122.  
  123.     if ((tpiece->column-2) < 1) /* If the piece is near the left */
  124.       for (i = 1; i < 8; i += 2)
  125.     if (tpiece->column + shape[form][base+i] < 0)
  126.       return 1;
  127.  
  128.     return 0;
  129. }
  130.  
  131. /* This drops the piece into the grid, in its final resting place.
  132.  */
  133. drop_piece(piece,grid)
  134. piece_t *piece;
  135. position_t grid[MAXROW][MAXCOLUMN];
  136. {
  137.     int base, form, i;
  138.     base = (piece->column & 1) ? 0 : 8;
  139.     form = piece->type * 6 + piece->rotation;
  140.  
  141.     for (i = 0; i < 7; i += 2) {
  142.     grid[piece->row+shape[form][base+i]]
  143.       [piece->column+shape[form][base+1+i]].type = piece->type;
  144.     grid[piece->row+shape[form][base+i]]
  145.       [piece->column+shape[form][base+1+i]].filled = 1;
  146.     }
  147. }
  148.  
  149. /* This redraws the entire grid.
  150.  */
  151. redraw_grid(grid)
  152. position_t grid[MAXROW][MAXCOLUMN];
  153. {
  154.     int row, column;
  155.  
  156.     for (row = MAXROW - 1; row >= 0; row--)
  157.     for (column = 0; column < MAXCOLUMN; column++)
  158.         draw_hex(row,column,grid[row][column].filled,
  159.                grid[row][column].type);
  160. }
  161.  
  162. /* This clears the current, normal row, and moves the rest of the
  163.  * grid down.
  164.  */
  165. shift_redraw_grid(start_row,grid)
  166. int start_row;
  167. position_t grid[MAXROW][MAXCOLUMN];
  168. {
  169.     int row, column;
  170.  
  171.     start_row = (start_row < MAXROW) ? start_row : MAXROW - 1;
  172.  
  173.     for (row = start_row; row > 0; row--)
  174.     for (column = 0; column < MAXCOLUMN; column++) {
  175.         if (grid[row][column].filled)
  176.           draw_hex(row,column,0,0);
  177.         grid[row][column].type = grid[row-1][column].type;
  178.         grid[row][column].filled = grid[row-1][column].filled;
  179.         if (grid[row][column].filled)
  180.           draw_hex(row,column,grid[row][column].filled,
  181.              grid[row][column].type);
  182.     }
  183.     row = 0;
  184.     for (column = 0; column < MAXCOLUMN; column++) {
  185.     grid[row][column].filled = 0;
  186.     draw_hex(row,column,grid[row][column].filled,grid[row][column].type);
  187.     }
  188. }
  189.  
  190. /* This clears the current, offset row, and moves the rest of the
  191.  * grid down.
  192.  */
  193. shift_offset_redraw_grid(start_row,grid)
  194. int start_row;
  195. position_t grid[MAXROW][MAXCOLUMN];
  196. {
  197.     int row, column;
  198.  
  199.     start_row = (start_row < MAXROW) ? start_row : MAXROW - 1;
  200.  
  201.     for (row = start_row; row > 1; row--)
  202.     for (column = 0; column < MAXCOLUMN; column++) {
  203.         if (grid[row-(column & 1)][column].filled)
  204.           draw_hex(row-(column & 1),column,0,0);
  205.         grid[row-(column & 1)][column].type =
  206.           grid[row-1-(column & 1)][column].type;
  207.         grid[row-(column & 1)][column].filled =
  208.           grid[row-1-(column & 1)][column].filled;
  209.         if (grid[row-(column & 1)][column].filled)
  210.           draw_hex(row-(column & 1),column,
  211.              grid[row-(column & 1)][column].filled,
  212.              grid[row-(column & 1)][column].type);
  213.     }
  214.     row = 1;
  215.     for (column = 0; column < MAXCOLUMN; column++) {
  216.     grid[row-(column & 1)][column].filled = 0;
  217.     draw_hex(row-(column & 1),column,
  218.            grid[row-(column & 1)][column].filled,
  219.            grid[row-(column & 1)][column].type);
  220.     }
  221. }
  222.  
  223. /* This checks for any cleared rows, be they normal or offset.
  224.  */
  225. check_rows(grid)
  226. position_t grid[MAXROW][MAXCOLUMN];
  227. {
  228.     int row, column, clear_row, clear_offset_row, total_clear;
  229.  
  230.     total_clear = 0;
  231.     for (row = MAXROW-1; row >= 0; row--) {
  232.     clear_row = 1;
  233.     for (column = 0; column < MAXCOLUMN; column++)
  234.       if (! grid[row][column].filled) {
  235.           clear_row = 0;
  236.           break;
  237.       }
  238.     if (clear_row) {
  239.         shift_redraw_grid(row,grid);
  240.         total_clear++;
  241.     }
  242.     clear_offset_row = 1;
  243.     for (column = 0; column < MAXCOLUMN; column++)
  244.       if (! grid[row-(column & 1)][column].filled) {
  245.           clear_offset_row = 0;
  246.           break;
  247.       }
  248.     if (clear_offset_row) {
  249.         shift_offset_redraw_grid(row,grid);
  250.         total_clear++;
  251.     }
  252.     if (clear_row || clear_offset_row)
  253.       row++;
  254.     }
  255.     return total_clear;
  256. }
  257.  
  258. /* This handles the users choices.
  259.  *
  260.  * Choices:
  261.  * 0 - Left
  262.  * 1 - Right
  263.  * 2 - Rotate CCW
  264.  * 3 - Rotate CW
  265.  * 4 - Drop
  266.  * 6 - Quit
  267.  */
  268. update(choice,grid,npiece,piece,score,rows)
  269. int choice;
  270. position_t grid[MAXROW][MAXCOLUMN];
  271. piece_t *npiece,*piece;
  272. int *score, *rows;
  273. {
  274.     piece_t tpiece;
  275.  
  276.     tpiece.row = piece->row;
  277.     tpiece.column = piece->column;
  278.     tpiece.type = piece->type;
  279.     tpiece.rotation = piece->rotation;
  280.     
  281.     switch (choice) {
  282.     case 0:
  283.     tpiece.column--;
  284.     if (! check_piece(&tpiece,grid)) {
  285.         place_piece(piece,&tpiece);
  286.         piece->column = tpiece.column;
  287.         piece->row = tpiece.row;
  288.     } else {
  289.         tpiece.row -= (1-((piece->column & 1)*2));
  290.         if (! check_piece(&tpiece,grid)) {
  291.         place_piece(piece,&tpiece);
  292.         piece->column = tpiece.column;
  293.         piece->row = tpiece.row;
  294.         }
  295.     }
  296.     break;
  297.     case 1:
  298.     tpiece.column++;
  299.     if (! check_piece(&tpiece,grid)) {
  300.         place_piece(piece,&tpiece);
  301.         piece->column = tpiece.column;
  302.         piece->row = tpiece.row;
  303.     } else {
  304.         tpiece.row -= (1-((piece->column & 1)*2));
  305.         if (! check_piece(&tpiece,grid)) {
  306.         place_piece(piece,&tpiece);
  307.         piece->column = tpiece.column;
  308.         piece->row = tpiece.row;
  309.         }
  310.     }
  311.     break;
  312.     case 2:
  313.     tpiece.rotation++;
  314.     tpiece.rotation = (tpiece.rotation > 5) ? 0 : tpiece.rotation;
  315.     if (! check_piece(&tpiece,grid)) {
  316.         place_piece(piece,&tpiece);
  317.         piece->rotation = tpiece.rotation;
  318.         piece->column = tpiece.column;
  319.         piece->row = tpiece.row;
  320.     }
  321.     break;
  322.     case 3:
  323.     tpiece.rotation--;
  324.     tpiece.rotation = (tpiece.rotation < 0) ? 5 : tpiece.rotation;
  325.     if (! check_piece(&tpiece,grid)) {
  326.         place_piece(piece,&tpiece);
  327.         piece->rotation = tpiece.rotation;
  328.         piece->column = tpiece.column;
  329.         piece->row = tpiece.row;
  330.     }
  331.     break;
  332.     case 4:
  333.     tpiece.row++;
  334.     while (! check_piece(&tpiece,grid)) {
  335.         place_piece(piece,&tpiece);
  336.         piece->row++;
  337.         tpiece.row++;
  338.         *score += 10;
  339.     }
  340.     return update_drop(grid,npiece,piece,score,rows);
  341.     break;
  342.     case 6:
  343.     return 1;
  344.     break;
  345.     }
  346.     return 0;
  347. }
  348.  
  349. /* This process the normal dropping caused by the passage of time. The io
  350.  * handler calls this, when it is time to drop the piece.
  351.  */
  352. update_drop(grid,npiece,piece,score,rows)
  353. position_t grid[MAXROW][MAXCOLUMN];
  354. piece_t *npiece,*piece;
  355. int *score, *rows;
  356. {
  357.     int cleared_rows, game_over;
  358.     piece_t tpiece;
  359.  
  360.     tpiece.row = piece->row;
  361.     tpiece.column = piece->column;
  362.     tpiece.type = piece->type;
  363.     tpiece.rotation = piece->rotation;
  364.  
  365.     tpiece.row++;
  366.     if (check_piece(&tpiece,grid)) {
  367.     *score += 25;
  368.     drop_piece(piece,grid);
  369.     cleared_rows = check_rows(grid);
  370.     *score += (cleared_rows * 5000);
  371.     *rows += cleared_rows;
  372.     display_scores(score,rows);
  373.     game_over =  (piece->row < 2) ? 1 : 0;
  374.     new_piece(npiece,piece);
  375.     init_piece(piece);
  376.     show_next_piece(npiece);
  377.     } else {
  378.     tpiece.row--;
  379.     piece->row++;
  380.     place_piece(&tpiece,piece);
  381.     game_over = 0;
  382.     }
  383.     return game_over;
  384. }
  385.  
  386. /* This sets up things for a new game.
  387.  */
  388. new_game(grid,npiece,piece,score,rows)
  389. position_t grid[MAXROW][MAXCOLUMN];
  390. piece_t *npiece,*piece;
  391. int *score, *rows;
  392. {
  393.     int row, column;
  394.  
  395.     for (row = 0; row < MAXROW; row++)
  396.       for (column = 0; column < MAXCOLUMN; column++)
  397.     grid[row][column].filled = 0;
  398.  
  399.     npiece->rotation = -1;
  400.     new_piece(npiece,piece);
  401.     *score = 0;
  402.     *rows = 0;
  403.     init_piece(piece);
  404.     show_next_piece(npiece);
  405. }
  406.  
  407. /* This draws the borders of the game.
  408.  */
  409. draw_borders()
  410. {
  411.     int i;
  412.  
  413.     for (i = 0; i <= MAXROW; i++) {
  414.     draw_hex(i,-1,1,10); 
  415.     draw_hex(i,MAXCOLUMN,1,10); 
  416.     }
  417.     for (i = 0; i < MAXCOLUMN; i++)
  418.       draw_hex(MAXROW,i,1,10);
  419. }
  420.  
  421. /* This checks to see if the score received from a game is high enough
  422.  * to be in the high scores. If the user already has his limit of
  423.  * high scores, it also makes sure he beat one of his own. If he did beat
  424.  * one of his own, the lowest of hist scores is removed, and the new one
  425.  * is placed.
  426.  */
  427. is_high_score(name,userid,score,rows,high_scores)
  428. char name[MAXNAMELENGTH];
  429. char userid[MAXUSERIDLENGTH];
  430. int score;
  431. int rows;
  432. high_score_t high_scores[MAXHIGHSCORES];
  433. {
  434.     int i,j, user_highs, added, equal, over;
  435.  
  436.     user_highs = added = over = equal = 0;
  437.     for (i = 0; i < MAXHIGHSCORES; i++) {
  438.     equal = (! strcmp(userid,high_scores[i].userid));
  439.     if (equal)
  440.         over = (++user_highs > MAXUSERHIGHS) ? 1 : 0;
  441.     if (over && equal) {
  442.         for (j = i; j < (MAXHIGHSCORES - 1); j++) {
  443.         strcpy(high_scores[j].name, high_scores[j+1].name);
  444.         strcpy(high_scores[j].userid, high_scores[j+1].userid);
  445.         high_scores[j].score = high_scores[j+1].score;
  446.         high_scores[j].rows = high_scores[j+1].rows;
  447.         }
  448.         strcpy(high_scores[MAXHIGHSCORES-1].name, "David Markley");
  449.         strcpy(high_scores[MAXHIGHSCORES-1].userid, "CMU");
  450.         high_scores[MAXHIGHSCORES-1].score = 0;
  451.         high_scores[MAXHIGHSCORES-1].rows = 0;
  452.         i--;
  453.         continue;
  454.     }
  455.     if ((high_scores[i].score <= score)
  456.         && ((equal && (user_highs == MAXUSERHIGHS))
  457.         || (user_highs < MAXUSERHIGHS)) && (! added))  {
  458.         if (! equal)
  459.           over = (++user_highs > MAXUSERHIGHS);
  460.         for (j = MAXHIGHSCORES - 1; j > i; j--) {
  461.         strcpy(high_scores[j].name, high_scores[j-1].name);
  462.         strcpy(high_scores[j].userid, high_scores[j-1].userid);
  463.         high_scores[j].score = high_scores[j-1].score;
  464.         high_scores[j].rows = high_scores[j-1].rows;
  465.         }
  466.         strcpy(high_scores[i].name, name);
  467.         strcpy(high_scores[i].userid, userid);
  468.         high_scores[i].score = score;
  469.         high_scores[i].rows = rows;
  470.         added = 1;
  471.         }
  472.     }
  473.     return added;
  474. }
  475.  
  476. /* This takes the raw information from the I/O handler, and breaks down the
  477.  * key stroke into a choice. Notice: It also transfers the variable the
  478.  * I/O handler supplies it.
  479.  */
  480. do_choice(choice,grid,npiece,piece,score,rows,game_over,game_view,high_scores)
  481. char choice;
  482. position_t grid[MAXROW][MAXCOLUMN];
  483. piece_t *npiece,*piece;
  484. int *score, *rows, *game_over, *game_view;
  485. high_score_t high_scores[MAXHIGHSCORES];
  486. {
  487.     switch (choice) {
  488.     case 'j': case 'J': case '4':
  489.     if (! *game_over)
  490.       update(0,grid,npiece,piece,score,rows);
  491.     break;
  492.     case 'l': case 'L': case '6':
  493.     if (! *game_over)
  494.       update(1,grid,npiece,piece,score,rows);
  495.     break;
  496.     case 'k': case 'K': case '5':
  497.     if (! *game_over)
  498.       update(2,grid,npiece,piece,score,rows);
  499.     break;
  500.     case 'i': case 'I': case '8':
  501.     if (! *game_over)
  502.       update(3,grid,npiece,piece,score,rows);
  503.     break;
  504.     case ' ': case '0':
  505.     if (! *game_over)
  506.       *game_over = update(4,grid,npiece,piece,score,rows);
  507.     break;
  508.     case 'r': case 'R':
  509.     clear_display();
  510.     redraw_game(grid,npiece,piece,score,rows,*game_view,high_scores);
  511.     break;
  512.     case 'q': case 'Q':
  513.     update(6,grid,npiece,piece,score,rows);
  514.     end_game();
  515.     break;
  516.     case 'p': case 'P':
  517.     if (! *game_over) {
  518.         *game_over = 2;
  519.         display_high_scores(high_scores);
  520.         display_help();
  521.     }
  522.     break;
  523.     case 'u': case 'U':
  524.     if (*game_over == 2) {
  525.         *game_over = *game_view = 0;    
  526.         clear_display();
  527.         redraw_game(grid,npiece,piece,score,rows,*game_view,high_scores);
  528.     }
  529.     break;
  530.     case 'H': case 'h':
  531.     if (*game_over) {
  532.         *game_view = 1;
  533.         clear_display();
  534.         redraw_game(grid,npiece,piece,score,rows,*game_view,high_scores);
  535.     }
  536.     break;
  537.     case 'G': case 'g':
  538.     if (*game_over) {
  539.         *game_view = 0;
  540.         clear_display();
  541.         redraw_game(grid,npiece,piece,score,rows,*game_view,high_scores);
  542.     }
  543.     break;
  544.     case 'n': case 'N':
  545.     *game_over = *game_view = 0;
  546.     new_game(grid, npiece, piece, score, rows);
  547.     clear_display();
  548.     redraw_game(grid,npiece,piece,score,rows,*game_view,high_scores);
  549. #ifdef LOG
  550.     loguse(LOGHOST,"xhexlog",log_message);
  551. #endif
  552.     }
  553. }
  554.  
  555. /* This redraws all the parts of the game through the I/O handler.
  556.  */
  557. redraw_game(grid,npiece,piece,score,rows,game_view,high_scores)
  558. position_t grid[MAXROW][MAXCOLUMN];
  559. piece_t *npiece,*piece;
  560. int *score, *rows, game_view;
  561. high_score_t high_scores[MAXHIGHSCORES];
  562. {
  563.     if (! game_view) {
  564.     redraw_grid(grid);
  565.     draw_borders();
  566.     init_piece(piece);
  567.     display_scores(score,rows);
  568.     display_help();
  569.     show_next_piece(npiece);
  570.     } else {
  571.     if (read_high_scores(high_scores))
  572.       display_high_scores(high_scores);
  573.     display_help();
  574.     display_scores(score,rows);
  575.     }
  576. }
  577.