[BACK]Return to screen.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / games / tetris

Annotation of src/games/tetris/screen.c, Revision 1.34

1.34    ! rillig      1: /*     $NetBSD: screen.c,v 1.33 2017/03/20 22:05:27 christos Exp $     */
1.2       cgd         2:
1.1       cgd         3: /*-
                      4:  * Copyright (c) 1992, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to Berkeley by
                      8:  * Chris Torek and Darren F. Provine.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
1.18      agc        18:  * 3. Neither the name of the University nor the names of its contributors
1.1       cgd        19:  *    may be used to endorse or promote products derived from this software
                     20:  *    without specific prior written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     25:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     32:  * SUCH DAMAGE.
                     33:  *
                     34:  *     @(#)screen.c    8.1 (Berkeley) 5/31/93
                     35:  */
                     36:
                     37: /*
                     38:  * Tetris screen control.
                     39:  */
                     40:
1.20      perry      41: #include <sys/cdefs.h>
1.1       cgd        42: #include <sys/ioctl.h>
                     43:
                     44: #include <setjmp.h>
                     45: #include <signal.h>
                     46: #include <stdio.h>
                     47: #include <stdlib.h>
                     48: #include <string.h>
1.26      roy        49: #include <term.h>
1.3       mycroft    50: #include <termios.h>
1.1       cgd        51: #include <unistd.h>
                     52:
                     53: #ifndef sigmask
                     54: #define sigmask(s) (1 << ((s) - 1))
                     55: #endif
                     56:
                     57: #include "screen.h"
                     58: #include "tetris.h"
                     59:
                     60: static cell curscreen[B_SIZE]; /* 1 => standout (or otherwise marked) */
                     61: static int curscore;
                     62: static int isset;              /* true => terminal is in game mode */
1.3       mycroft    63: static struct termios oldtt;
1.19      jsm        64: static void (*tstp)(int);
1.1       cgd        65:
1.19      jsm        66: static void    scr_stop(int);
1.21      perry      67: static void    stopset(int) __dead;
1.1       cgd        68:
                     69:
                     70: /*
                     71:  * Routine used by tputs().
                     72:  */
1.13      lukem      73: int
1.23      dholland   74: put(int c)
1.1       cgd        75: {
                     76:
1.13      lukem      77:        return (putchar(c));
1.1       cgd        78: }
                     79:
                     80: /*
                     81:  * putstr() is for unpadded strings (either as in termcap(5) or
                     82:  * simply literal strings); putpad() is for padded strings with
                     83:  * count=1.  (See screen.h for putpad().)
                     84:  */
                     85: #define        putstr(s)       (void)fputs(s, stdout)
1.14      blymn      86:
1.24      dholland   87: static void
1.14      blymn      88: moveto(int r, int c)
                     89: {
1.26      roy        90:        char *buf;
1.14      blymn      91:
1.27      roy        92:        buf = tiparm(cursor_address, r, c);
1.26      roy        93:        if (buf != NULL)
1.14      blymn      94:                putpad(buf);
                     95: }
1.1       cgd        96:
1.28      christos   97: static void
                     98: setcolor(int c)
                     99: {
                    100:        char *buf;
1.30      nat       101:        char monochrome[] = "\033[0m";
1.29      pgoyette  102:        if (nocolor == 1)
                    103:                return;
1.28      christos  104:        if (set_a_foreground == NULL)
                    105:                return;
                    106:
1.30      nat       107:        if (c == 0 || c == 7)
                    108:                buf = monochrome;
                    109:        else
                    110:                buf = tiparm(set_a_foreground, c);
1.28      christos  111:        if (buf != NULL)
                    112:                putpad(buf);
                    113: }
                    114:
1.1       cgd       115: /*
                    116:  * Set up from termcap.
                    117:  */
                    118: void
1.23      dholland  119: scr_init(void)
1.1       cgd       120: {
                    121:
1.26      roy       122:        setupterm(NULL, 0, NULL);
                    123:        if (clear_screen == NULL)
1.1       cgd       124:                stop("cannot clear screen");
1.26      roy       125:        if (cursor_address == NULL || cursor_up == NULL)
                    126:                stop("cannot do random cursor positioning");
1.1       cgd       127: }
                    128:
                    129: /* this foolery is needed to modify tty state `atomically' */
                    130: static jmp_buf scr_onstop;
                    131:
                    132: static void
1.23      dholland  133: stopset(int sig)
1.1       cgd       134: {
1.22      dholland  135:        sigset_t set;
1.3       mycroft   136:
1.1       cgd       137:        (void) signal(sig, SIG_DFL);
                    138:        (void) kill(getpid(), sig);
1.22      dholland  139:        sigemptyset(&set);
                    140:        sigaddset(&set, sig);
                    141:        (void) sigprocmask(SIG_UNBLOCK, &set, (sigset_t *)0);
1.1       cgd       142:        longjmp(scr_onstop, 1);
                    143: }
                    144:
                    145: static void
1.23      dholland  146: scr_stop(int sig)
1.1       cgd       147: {
1.22      dholland  148:        sigset_t set;
1.3       mycroft   149:
1.1       cgd       150:        scr_end();
1.3       mycroft   151:        (void) kill(getpid(), sig);
1.22      dholland  152:        sigemptyset(&set);
                    153:        sigaddset(&set, sig);
                    154:        (void) sigprocmask(SIG_UNBLOCK, &set, (sigset_t *)0);
1.1       cgd       155:        scr_set();
                    156:        scr_msg(key_msg, 1);
                    157: }
                    158:
                    159: /*
                    160:  * Set up screen mode.
                    161:  */
                    162: void
1.23      dholland  163: scr_set(void)
1.1       cgd       164: {
                    165:        struct winsize ws;
1.3       mycroft   166:        struct termios newtt;
1.22      dholland  167:        sigset_t nsigset, osigset;
1.19      jsm       168:        void (*ttou)(int);
1.1       cgd       169:
1.22      dholland  170:        sigemptyset(&nsigset);
                    171:        sigaddset(&nsigset, SIGTSTP);
                    172:        sigaddset(&nsigset, SIGTTOU);
                    173:        (void) sigprocmask(SIG_BLOCK, &nsigset, &osigset);
1.1       cgd       174:        if ((tstp = signal(SIGTSTP, stopset)) == SIG_IGN)
                    175:                (void) signal(SIGTSTP, SIG_IGN);
1.3       mycroft   176:        if ((ttou = signal(SIGTTOU, stopset)) == SIG_IGN)
                    177:                (void) signal(SIGTTOU, SIG_IGN);
1.1       cgd       178:        /*
                    179:         * At last, we are ready to modify the tty state.  If
                    180:         * we stop while at it, stopset() above will longjmp back
                    181:         * to the setjmp here and we will start over.
                    182:         */
                    183:        (void) setjmp(scr_onstop);
1.3       mycroft   184:        (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
1.1       cgd       185:        Rows = 0, Cols = 0;
                    186:        if (ioctl(0, TIOCGWINSZ, &ws) == 0) {
                    187:                Rows = ws.ws_row;
                    188:                Cols = ws.ws_col;
                    189:        }
                    190:        if (Rows == 0)
1.26      roy       191:                Rows = lines;
1.1       cgd       192:        if (Cols == 0)
1.26      roy       193:            Cols = columns;
1.1       cgd       194:        if (Rows < MINROWS || Cols < MINCOLS) {
                    195:                (void) fprintf(stderr,
1.8       hubertf   196:                    "the screen is too small: must be at least %dx%d, ",
                    197:                    MINCOLS, MINROWS);
1.1       cgd       198:                stop("");       /* stop() supplies \n */
                    199:        }
1.32      nat       200:        Offset = (Rows - D_LAST + D_FIRST - 2) / 2;
1.3       mycroft   201:        if (tcgetattr(0, &oldtt) < 0)
                    202:                stop("tcgetattr() fails");
1.1       cgd       203:        newtt = oldtt;
1.3       mycroft   204:        newtt.c_lflag &= ~(ICANON|ECHO);
                    205:        newtt.c_oflag &= ~OXTABS;
                    206:        if (tcsetattr(0, TCSADRAIN, &newtt) < 0)
                    207:                stop("tcsetattr() fails");
                    208:        ospeed = cfgetospeed(&newtt);
1.22      dholland  209:        (void) sigprocmask(SIG_BLOCK, &nsigset, &osigset);
1.1       cgd       210:
                    211:        /*
                    212:         * We made it.  We are now in screen mode, modulo TIstr
                    213:         * (which we will fix immediately).
                    214:         */
1.33      christos  215:        const char *tstr;
                    216:        if ((tstr = enter_ca_mode) != NULL)
                    217:                putstr(tstr);
                    218:        if ((tstr = cursor_invisible) != NULL)
                    219:                putstr(tstr);
1.1       cgd       220:        if (tstp != SIG_IGN)
                    221:                (void) signal(SIGTSTP, scr_stop);
1.3       mycroft   222:        if (ttou != SIG_IGN)
                    223:                (void) signal(SIGTTOU, ttou);
1.1       cgd       224:
                    225:        isset = 1;
1.3       mycroft   226:        (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
1.1       cgd       227:        scr_clear();
                    228: }
                    229:
                    230: /*
                    231:  * End screen mode.
                    232:  */
                    233: void
1.23      dholland  234: scr_end(void)
1.1       cgd       235: {
1.22      dholland  236:        sigset_t nsigset, osigset;
1.1       cgd       237:
1.22      dholland  238:        sigemptyset(&nsigset);
                    239:        sigaddset(&nsigset, SIGTSTP);
                    240:        sigaddset(&nsigset, SIGTTOU);
                    241:        (void) sigprocmask(SIG_BLOCK, &nsigset, &osigset);
1.1       cgd       242:        /* move cursor to last line */
1.33      christos  243:        const char *tstr;
                    244:        if ((tstr = cursor_to_ll) != NULL)
                    245:                putstr(tstr);
1.1       cgd       246:        else
                    247:                moveto(Rows - 1, 0);
                    248:        /* exit screen mode */
1.33      christos  249:        if ((tstr = exit_ca_mode) != NULL)
                    250:                putstr(tstr);
                    251:        if ((tstr = cursor_normal) != NULL)
                    252:                putstr(tstr);
1.1       cgd       253:        (void) fflush(stdout);
1.3       mycroft   254:        (void) tcsetattr(0, TCSADRAIN, &oldtt);
1.1       cgd       255:        isset = 0;
                    256:        /* restore signals */
                    257:        (void) signal(SIGTSTP, tstp);
1.3       mycroft   258:        (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
1.1       cgd       259: }
                    260:
                    261: void
1.23      dholland  262: stop(const char *why)
1.1       cgd       263: {
                    264:
                    265:        if (isset)
                    266:                scr_end();
                    267:        (void) fprintf(stderr, "aborting: %s\n", why);
                    268:        exit(1);
                    269: }
                    270:
                    271: /*
                    272:  * Clear the screen, forgetting the current contents in the process.
                    273:  */
                    274: void
1.23      dholland  275: scr_clear(void)
1.1       cgd       276: {
                    277:
1.26      roy       278:        putpad(clear_screen);
1.1       cgd       279:        curscore = -1;
1.7       perry     280:        memset((char *)curscreen, 0, sizeof(curscreen));
1.1       cgd       281: }
                    282:
                    283: #if vax && !__GNUC__
                    284: typedef int regcell;   /* pcc is bad at `register char', etc */
                    285: #else
                    286: typedef cell regcell;
                    287: #endif
                    288:
                    289: /*
                    290:  * Update the screen.
                    291:  */
                    292: void
1.23      dholland  293: scr_update(void)
1.1       cgd       294: {
1.17      wiz       295:        cell *bp, *sp;
                    296:        regcell so, cur_so = 0;
                    297:        int i, ccol, j;
1.22      dholland  298:        sigset_t nsigset, osigset;
1.11      jsm       299:        static const struct shape *lastshape;
1.3       mycroft   300:
1.22      dholland  301:        sigemptyset(&nsigset);
                    302:        sigaddset(&nsigset, SIGTSTP);
                    303:        (void) sigprocmask(SIG_BLOCK, &nsigset, &osigset);
1.1       cgd       304:
                    305:        /* always leave cursor after last displayed point */
                    306:        curscreen[D_LAST * B_COLS - 1] = -1;
                    307:
                    308:        if (score != curscore) {
1.26      roy       309:                if (cursor_home)
                    310:                        putpad(cursor_home);
1.1       cgd       311:                else
                    312:                        moveto(0, 0);
1.30      nat       313:                setcolor(0);
1.8       hubertf   314:                (void) printf("Score: %d", score);
1.1       cgd       315:                curscore = score;
                    316:        }
                    317:
1.8       hubertf   318:        /* draw preview of nextpattern */
1.9       hubertf   319:        if (showpreview && (nextshape != lastshape)) {
1.8       hubertf   320:                static int r=5, c=2;
1.34    ! rillig    321:                int tr, tc, t;
1.8       hubertf   322:
                    323:                lastshape = nextshape;
1.34    ! rillig    324:
1.8       hubertf   325:                /* clean */
1.26      roy       326:                putpad(exit_standout_mode);
1.8       hubertf   327:                moveto(r-1, c-1); putstr("          ");
                    328:                moveto(r,   c-1); putstr("          ");
                    329:                moveto(r+1, c-1); putstr("          ");
                    330:                moveto(r+2, c-1); putstr("          ");
                    331:
                    332:                moveto(r-3, c-2);
                    333:                putstr("Next shape:");
1.34    ! rillig    334:
1.8       hubertf   335:                /* draw */
1.31      christos  336:                setcolor(nextshape->color);
1.26      roy       337:                putpad(enter_standout_mode);
1.8       hubertf   338:                moveto(r, 2*c);
                    339:                putstr("  ");
                    340:                for(i=0; i<3; i++) {
                    341:                        t = c + r*B_COLS;
                    342:                        t += nextshape->off[i];
                    343:
                    344:                        tr = t / B_COLS;
                    345:                        tc = t % B_COLS;
                    346:
                    347:                        moveto(tr, 2*tc);
                    348:                        putstr("  ");
                    349:                }
1.26      roy       350:                putpad(exit_standout_mode);
1.8       hubertf   351:        }
1.34    ! rillig    352:
1.1       cgd       353:        bp = &board[D_FIRST * B_COLS];
                    354:        sp = &curscreen[D_FIRST * B_COLS];
                    355:        for (j = D_FIRST; j < D_LAST; j++) {
                    356:                ccol = -1;
                    357:                for (i = 0; i < B_COLS; bp++, sp++, i++) {
                    358:                        if (*sp == (so = *bp))
                    359:                                continue;
                    360:                        *sp = so;
                    361:                        if (i != ccol) {
1.26      roy       362:                                if (cur_so && move_standout_mode) {
                    363:                                        putpad(exit_standout_mode);
1.1       cgd       364:                                        cur_so = 0;
                    365:                                }
1.32      nat       366:                                moveto(RTOD(j + Offset), CTOD(i));
1.1       cgd       367:                        }
1.26      roy       368:                        if (enter_standout_mode) {
1.1       cgd       369:                                if (so != cur_so) {
1.30      nat       370:                                        setcolor(so);
1.26      roy       371:                                        putpad(so ?
                    372:                                            enter_standout_mode :
                    373:                                            exit_standout_mode);
1.1       cgd       374:                                        cur_so = so;
                    375:                                }
1.28      christos  376: #ifdef DEBUG
                    377:                                char buf[3];
                    378:                                snprintf(buf, sizeof(buf), "%d%d", so, so);
                    379:                                putstr(buf);
                    380: #else
1.1       cgd       381:                                putstr("  ");
1.28      christos  382: #endif
1.1       cgd       383:                        } else
                    384:                                putstr(so ? "XX" : "  ");
                    385:                        ccol = i + 1;
                    386:                        /*
                    387:                         * Look ahead a bit, to avoid extra motion if
                    388:                         * we will be redrawing the cell after the next.
                    389:                         * Motion probably takes four or more characters,
                    390:                         * so we save even if we rewrite two cells
                    391:                         * `unnecessarily'.  Skip it all, though, if
                    392:                         * the next cell is a different color.
                    393:                         */
                    394: #define        STOP (B_COLS - 3)
                    395:                        if (i > STOP || sp[1] != bp[1] || so != bp[1])
                    396:                                continue;
                    397:                        if (sp[2] != bp[2])
                    398:                                sp[1] = -1;
                    399:                        else if (i < STOP && so == bp[2] && sp[3] != bp[3]) {
                    400:                                sp[2] = -1;
                    401:                                sp[1] = -1;
                    402:                        }
                    403:                }
                    404:        }
                    405:        if (cur_so)
1.26      roy       406:                putpad(exit_standout_mode);
1.1       cgd       407:        (void) fflush(stdout);
1.3       mycroft   408:        (void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
1.1       cgd       409: }
                    410:
                    411: /*
                    412:  * Write a message (set!=0), or clear the same message (set==0).
                    413:  * (We need its length in case we have to overwrite with blanks.)
                    414:  */
                    415: void
1.23      dholland  416: scr_msg(char *s, int set)
1.1       cgd       417: {
1.34    ! rillig    418:
1.26      roy       419:        if (set || clr_eol == NULL) {
1.17      wiz       420:                int l = strlen(s);
1.1       cgd       421:
                    422:                moveto(Rows - 2, ((Cols - l) >> 1) - 1);
                    423:                if (set)
                    424:                        putstr(s);
                    425:                else
                    426:                        while (--l >= 0)
                    427:                                (void) putchar(' ');
                    428:        } else {
                    429:                moveto(Rows - 2, 0);
1.26      roy       430:                putpad(clr_eol);
1.1       cgd       431:        }
                    432: }

CVSweb <webmaster@jp.NetBSD.org>