|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 11377 (0x2c71) Types: TextFile Names: »screen.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Tt/screen.c«
/***************************************************************************\ |* *| |* screen.c: A version of Tetris to run on ordinary terminals, *| |* (ie., not needing a workstation, so should available *| |* to peasant Newwords+ users. This module handles all *| |* the icky curses(3x) bits. *| |* *| |* Author: Mike Taylor (mirk@uk.ac.warwick.cs) *| |* Started: Fri May 26 12:26:05 BST 1989 *| |* *| \***************************************************************************/ #include <curses.h> #include <sys/types.h> #include <sys/time.h> #include <errno.h> #include "screen.h" #include "tt.h" #include "pieces.h" #include "utils.h" #include "game.h" /***************************************************************************\ |* *| |* The function myrefresh() calls the curses(3x) function refresh() *| |* after first moving the cursor out of harm's way at the bottom of *| |* the screen. *| |* *| \***************************************************************************/ void myrefresh () { int x; if ((x = screen_depth-2) < GAME_DEPTH+1) x = GAME_DEPTH+1; move (x, 0); refresh (); } /***************************************************************************\ |* *| |* The function hoopy_refresh() touches the screen, then refreshes it, *| |* so curses(3X) doesn't get any chance to phlegm about with only doing *| |* the bits that it thinks are OK. So this should fix up screens that *| |* have been interfered with by biff(1), mesg(1) etc. *| |* *| \***************************************************************************/ void hoopy_refresh () { clear (); setup_screen (); draw_board (); update_scores (); myrefresh (); } /***************************************************************************\ |* *| |* The function print_msg() prints a short message centered on the *| |* floor of the playing area, with a space before and after it. *| |* If the message is NULL (ie. (char*)0), or null, (ie. ""), then *| |* no message is printed. *| |* *| \***************************************************************************/ void print_msg (line) char *line; { int i; move (GAME_DEPTH, 2); for (i = 0; i < 2*GAME_WIDTH; i++) addch (FLOOR_CHAR); if ((line != NULL) && (*line != '\0')) mvaddstr (GAME_DEPTH, GAME_WIDTH+1-(strlen (line))/2, form (" %s ", line)); myrefresh (); } /***************************************************************************\ |* *| |* The function clear_area() fills the playing area with BLANK_CHARs. *| |* It is used to clear the screen before each game, and also clearing *| |* the screen while displaying pieces one at a time when in debug mode. *| |* *| \***************************************************************************/ void clear_area () { int i, j, status, fastflag = 0; fd_set fds; struct timeval timeout; static char buffer[LINELEN]; for (i = 0; i < GAME_DEPTH; i++) { move (i, 2); for (j = 0; j < 2*GAME_WIDTH; j++) addch (BLANK_CHAR); if (fastflag == 0) { move (i+1, 2); for (j = 0; j < 2*GAME_WIDTH; j++) addch (FLOOR_CHAR); myrefresh (); FD_ZERO (&fds); FD_SET (0, &fds); timeout.tv_sec = 0L; /* Future implementations of select(2) */ timeout.tv_usec = 50000L; /* might change this value on return */ if ((status = select (1, &fds, (fd_set*) NULL, (fd_set*) NULL, &timeout)) == -1) if (errno != EINTR) die (LE_SELECT, "select(2) failed in clear_area()"); if (status != 0) { fastflag = 1; (void) read (0, buffer, LINELEN); } } } move (GAME_DEPTH, 2); for (j = 0; j < 2*GAME_WIDTH; j++) addch (FLOOR_CHAR); mvaddch (GAME_DEPTH, 0, CORNER_CHAR); addch (CORNER_CHAR); mvaddch (GAME_DEPTH, 2*GAME_WIDTH+2, CORNER_CHAR); addch (CORNER_CHAR); myrefresh (); } /***************************************************************************\ |* *| |* The function setup_screen should be called exactly once, near the *| |* beginning of execution. It initialises curses(3x), and prints the *| |* game titles, the walls and the floor of the game area, and clears *| |* this area using clear_area() (perhaps unsurprisingly) *| |* *| |* STOP PRESS: It no longer calls clear_area(), since play_game() *| |* does that fairly immediately after this function returns. *| |* *| |* STOP PRESS^2: It now does do it again, since play_game() does the *| |* sneaky-but-slow clear that it fine at times, but cruddy for *| |* initialisation. *| |* *| \***************************************************************************/ void setup_screen () { int i; for (i = 0; i < GAME_DEPTH; i++) { mvaddch (i, 0, WALL_CHAR); addch (WALL_CHAR); mvaddch (i, 2*GAME_WIDTH+2, WALL_CHAR); addch (WALL_CHAR); } move (GAME_DEPTH, 2); for (i = 0; i < 2*GAME_WIDTH; i++) addch (FLOOR_CHAR); mvaddch (GAME_DEPTH, 0, CORNER_CHAR); addch (CORNER_CHAR); mvaddch (GAME_DEPTH, 2*GAME_WIDTH+2, CORNER_CHAR); addch (CORNER_CHAR); mvaddstr (0, 2*GAME_WIDTH+6, form ("%sTETRIS FOR TERMINALS%*s%s", so_str, so_gunk, "", se_str)); mvaddstr (2, 2*GAME_WIDTH+6, "Written by Mike Taylor"); mvaddstr (3, 2*GAME_WIDTH+6, "Email: mirk@uk.ac.warwick.cs"); mvaddstr (4, 2*GAME_WIDTH+6, "Started: Fri May 26 12:26:05 BST 1989"); mvaddstr (6, 2*GAME_WIDTH+6, form ("Game level: %d", game_level)); mvaddstr (8, 2*GAME_WIDTH+6, "Score:"); mvaddstr (9, 2*GAME_WIDTH+6, "Pieces:"); mvaddstr (10, 2*GAME_WIDTH+6, "Levels:"); mvaddstr (12, 2*GAME_WIDTH+8, "Use keys:"); mvaddstr (13, 2*GAME_WIDTH+8, "========="); mvaddstr (14, 2*GAME_WIDTH+8, form ("Move left: '%c'", left_key)); mvaddstr (15, 2*GAME_WIDTH+8, form ("Move right: '%c'", right_key)); mvaddstr (16, 2*GAME_WIDTH+8, form ("Rotate: '%c'", rotate_key)); mvaddstr (17, 2*GAME_WIDTH+8, form ("Drop: '%c'", drop_key)); mvaddstr (18, 2*GAME_WIDTH+8, form ("Pause: '%c'", susp_key)); mvaddstr (19, 2*GAME_WIDTH+8, form ("Quit: '%c'", quit_key)); mvaddstr (20, 2*GAME_WIDTH+8, "Refresh: '^L'"); } /***************************************************************************\ |* *| |* The function setup_curses should be called exactly once, near the *| |* beginning of execution. It initialises curses(3x), and notes that *| |* this has been done, by setting the global variable in_curses. *| |* *| \***************************************************************************/ void setup_curses () { initscr (); clear (); #ifndef LINT noecho (); cbreak (); #endif /* LINT */ in_curses = 1; } /***************************************************************************\ |* *| |* The function update_scores() puts the sepecified values of score, *| |* no_pieces and no_levels on the screen in the specified positions. *| |* *| \***************************************************************************/ void update_scores () { move (8, 34); clrtoeol (); addstr (form ("%d", score)); move (9, 34); clrtoeol (); addstr (form ("%d", no_pieces)); move (10, 34); clrtoeol (); addstr (form ("%d", no_levels)); } /***************************************************************************\ |* *| |* The function draw_board() puts the current state of the global array *| |* board[] ontop the curses(3x) screen, then refresh()es it. *| |* *| \***************************************************************************/ void draw_board () { int i, j; for (i = 0; i < GAME_DEPTH; i++) for (j = 0; j < GAME_WIDTH; j++) if (board[i+4][j] == PI_EMPTY) { mvaddch (i, 2*j+2, BLANK_CHAR); addch (BLANK_CHAR); } else mvaddstr (i, 2*j+2, pieces[board[i+4][j]].app); } /***************************************************************************\ |* *| |* The function draw_piece draws or erases one of the tetris pieces on *| |* the screen in a specified orientation and position. The form of the *| |* function is: *| |* *| |* draw_piece (piece_no, orientation, y, x, flag) *| |* *| |* All the arrguments are integers. Flag is either PD_DRAW or *| |* PD_ERASE, specifying the effect of the function. Piece_no is *| |* between 0 and 6 inclusive, and specifies what sort of piece is *| |* required. Orientation is between 0 and 3 inclusive, and states *| |* which way up the piece is to be drawn, and y and x express the *| |* position as an index into the GAME_DEPTH by GAME_WIDTH array *| |* that is the board. *| |* *| \***************************************************************************/ void draw_piece (piece_no, orient, y, x, flag) int piece_no; int orient; int y; int x; int flag; { int i; extern WINDOW *stdscr; for (i = 0; i < NO_SQUARES; i++) if (y+pieces[piece_no].index[orient][i][0] >= 0) if (flag == PD_ERASE) { mvaddch (y+pieces[piece_no].index[orient][i][0], (2*(x+pieces[piece_no].index[orient][i][1]))+2, BLANK_CHAR); addch (BLANK_CHAR); } else mvaddstr (y+pieces[piece_no].index[orient][i][0], (2*(x+pieces[piece_no].index[orient][i][1]))+2, pieces[piece_no].app); } /***************************************************************************\ |* *| |* The function place_piece takes the same parameters as draw_piece, *| |* except for the flag, and does not draw the piece, but places it *| |* on the board. No checking is done to see if it will fit, since *| |* should already have been done by can_place(). *| |* *| \***************************************************************************/ void place_piece (piece_no, orient, y, x) int piece_no; int orient; int y; int x; { int i; for (i = 0; i < NO_SQUARES; i++) board[y+4+pieces[piece_no].index[orient][i][0]] [x+pieces[piece_no].index[orient][i][1]] = piece_no; } /***************************************************************************\ |* *| |* The function can_place takes the same parameters as place_piece, *| |* It does not draw the piece, nor place it on the board, but returns *| |* an integer value -- 0 if the piece will not fit on the board, 1 if *| |* it will (with the specified orientation, position, etc.) *| |* *| \***************************************************************************/ #define HERE(x) pieces[piece_no].index[orient][i][x] int can_place (piece_no, orient, y, x) int piece_no; int orient; int y; int x; { int i; for (i = 0; i < NO_SQUARES; i++) if (((x+HERE(1) >= GAME_WIDTH) || /* Off right of screen or */ (x+HERE(1) < 0)) || /* Off left of screen */ (y+HERE(0) >= GAME_DEPTH) || /* Off bottom of screen */ (board[y+4+HERE(0)][x+HERE(1)] != PI_EMPTY)) /* Board position not empty */ return (0); return (1); } /*-------------------------------------------------------------------------*/