home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / games / snake / snake / move.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-08  |  13.4 KB  |  661 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)move.c    5.8 (Berkeley) 2/28/91";
  36. #endif /* not lint */
  37.  
  38. /*************************************************************************
  39.  *
  40.  *    MOVE LIBRARY
  41.  *
  42.  *    This set of subroutines moves a cursor to a predefined
  43.  *    location, independent of the terminal type.  If the
  44.  *    terminal has an addressable cursor, it uses it.  If
  45.  *    not, it optimizes for tabs (currently) even if you don't
  46.  *      have them.
  47.  *
  48.  *    At all times the current address of the cursor must be maintained,
  49.  *    and that is available as structure cursor.
  50.  *
  51.  *    The following calls are allowed:
  52.  *        move(sp)    move to point sp.
  53.  *        up()        move up one line.
  54.  *        down()        move down one line.
  55.  *        bs()        move left one space (except column 0).
  56.  *        nd()        move right one space(no write).
  57.  *        clear()        clear screen.
  58.  *        home()        home.
  59.  *        ll()        move to lower left corner of screen.
  60.  *        cr()        carriage return (no line feed).
  61.  *        pr()        just like standard printf, but keeps track
  62.  *                of cursor position. (Uses pstring).
  63.  *        apr()        same as printf, but first argument is &point.
  64.  *                (Uses pstring).
  65.  *        pstring(s)    output the string of printing characters.
  66.  *                However, '\r' is interpreted to mean return
  67.  *                to column of origination AND do linefeed.
  68.  *                '\n' causes <cr><lf>.
  69.  *        putpad(str)    calls tputs to output character with proper
  70.  *                    padding.
  71.  *        outch()        the output routine for a character used by
  72.  *                    tputs. It just calls putchar.
  73.  *        pch(ch)        output character to screen and update
  74.  *                    cursor address (must be a standard
  75.  *                    printing character). WILL SCROLL.
  76.  *        pchar(ps,ch)    prints one character if it is on the
  77.  *                    screen at the specified location;
  78.  *                    otherwise, dumps it.(no wrap-around).
  79.  *
  80.  *        getcap()    initializes strings for later calls.
  81.  *        cap(string)    outputs the string designated in the termcap
  82.  *                    data base. (Should not move the cursor.)
  83.  *        done()        returns the terminal to intial state and exits.
  84.  *
  85.  *        point(&p,x,y)    return point set to x,y.
  86.  *
  87.  *        baudrate(x)    returns the baudrate of the terminal.
  88.  *        delay(t)    causes an approximately constant delay
  89.  *                    independent of baudrate.
  90.  *                    Duration is ~ t/20 seconds.
  91.  *
  92.  ******************************************************************************/
  93.  
  94. #include <stdarg.h>
  95. #include "snake.h"
  96.  
  97. int CMlength;
  98. int NDlength;
  99. int BSlength;
  100. int delaystr[10];
  101. short ospeed;
  102.  
  103. static char str[80];
  104.  
  105. move(sp)
  106. struct point *sp;
  107. {
  108.     int distance;
  109.     int tabcol,ct;
  110.     struct point z;
  111.  
  112.     if (sp->line <0 || sp->col <0 || sp->col > COLUMNS){
  113.         pr("move to [%d,%d]?",sp->line,sp->col);
  114.         return;
  115.     }
  116.     if (sp->line >= LINES){
  117.         move(point(&z,sp->col,LINES-1));
  118.         while(sp->line-- >= LINES)putchar('\n');
  119.         return;
  120.     }
  121.  
  122.     if (CM != 0) {
  123.         char *cmstr = tgoto(CM, sp->col, sp->line);
  124.  
  125.         CMlength = strlen(cmstr);
  126.         if(cursor.line == sp->line){
  127.             distance = sp->col - cursor.col;
  128.             if(distance == 0)return;    /* Already there! */
  129.             if(distance > 0){    /* Moving to the right */
  130.                 if(distance*NDlength < CMlength){
  131.                     right(sp);
  132.                     return;
  133.                 }
  134.                 if(TA){
  135.                     ct=sp->col&7;
  136.                     tabcol=(cursor.col|7)+1;
  137.                     do{
  138.                         ct++;
  139.                         tabcol=(tabcol|7)+1;
  140.                     }
  141.                     while(tabcol<sp->col);
  142.                     if(ct<CMlength){
  143.                         right(sp);
  144.                         return;
  145.                     }
  146.                 }
  147.             } else {        /* Moving to the left */
  148.                 if (-distance*BSlength < CMlength){
  149.                     gto(sp);
  150.                     return;
  151.                 }
  152.             }
  153.             if(sp->col < CMlength){
  154.                 cr();
  155.                 right(sp);
  156.                 return;
  157.             }
  158.                 /* No more optimizations on same row. */
  159.         }
  160.         distance = sp->col - cursor.col;
  161.         distance = distance > 0 ?
  162.             distance*NDlength : -distance * BSlength;
  163.         if (distance < 0)
  164.             pr("ERROR: distance is negative: %d",distance);
  165.         distance += abs(sp->line - cursor.line);
  166.         if(distance >= CMlength){
  167.             putpad(cmstr);
  168.             cursor.line = sp->line;
  169.             cursor.col = sp->col;
  170.             return;
  171.         }
  172.     }
  173.  
  174.     /*
  175.      * If we get here we have a terminal that can't cursor
  176.      * address but has local motions or one which can cursor
  177.      * address but can get there quicker with local motions.
  178.      */
  179.      gto(sp);
  180. }
  181. gto(sp)
  182. struct point *sp;
  183. {
  184.  
  185.     int distance,f,tfield,j;
  186.  
  187.     if (cursor.line > LINES || cursor.line <0 ||
  188.         cursor.col <0 || cursor.col > COLUMNS)
  189.         pr("ERROR: cursor is at %d,%d\n",
  190.             cursor.line,cursor.col);
  191.     if (sp->line > LINES || sp->line <0 ||
  192.         sp->col <0 || sp->col >  COLUMNS)
  193.         pr("ERROR: target is %d,%d\n",sp->line,sp->col);
  194.     tfield = (sp->col) >> 3;
  195.     if (sp->line == cursor.line){
  196.         if (sp->col > cursor.col)right(sp);
  197.         else{
  198.             distance = (cursor.col -sp->col)*BSlength;
  199.             if (((TA) && 
  200.                  (distance > tfield+((sp->col)&7)*NDlength)
  201.                 ) ||
  202.                 (((cursor.col)*NDlength) < distance)
  203.                ){
  204.                 cr();
  205.                 right(sp);
  206.             }
  207.             else{
  208.                 while(cursor.col > sp->col) bs();
  209.             }
  210.         }
  211.         return;
  212.     }
  213.                 /*must change row */
  214.     if (cursor.col - sp->col > (cursor.col >> 3)){
  215.         if (cursor.col == 0)f = 0;
  216.         else f = -1;
  217.     }
  218.     else f = cursor.col >> 3;
  219.     if (((sp->line << 1) + 1 < cursor.line - f) && (HO != 0)){
  220.             /*
  221.              * home quicker than rlf:
  222.              * (sp->line + f > cursor.line - sp->line)
  223.              */
  224.         putpad(HO);
  225.         cursor.col = cursor.line = 0;
  226.         gto(sp);
  227.         return;
  228.     }
  229.     if (((sp->line << 1) > cursor.line + LINES+1 + f) && (LL != 0)){
  230.         /* home,rlf quicker than lf
  231.          * (LINES+1 - sp->line + f < sp->line - cursor.line) 
  232.          */
  233.         if (cursor.line > f + 1){
  234.         /* is home faster than wraparound lf?
  235.          * (cursor.line + 20 - sp->line > 21 - sp->line + f)
  236.          */
  237.             ll();
  238.             gto(sp);
  239.             return;
  240.         }
  241.     }
  242.     if ((LL != 0) && (sp->line > cursor.line + (LINES >> 1) - 1))
  243.         cursor.line += LINES;
  244.     while(sp->line > cursor.line)down();
  245.     while(sp->line < cursor.line)up();
  246.     gto(sp);        /*can recurse since cursor.line = sp->line */
  247. }
  248.  
  249. right(sp)
  250. struct point *sp;
  251. {
  252.     int field,tfield;
  253.     int tabcol,strlength;
  254.  
  255.     if (sp->col < cursor.col)
  256.         pr("ERROR:right() can't move left\n");
  257.     if(TA){        /* If No Tabs: can't send tabs because ttydrive
  258.              * loses count with control characters.
  259.              */
  260.         field = cursor.col >> 3;
  261. /*
  262.  *    This code is useful for a terminal which wraps around on backspaces.
  263.  *    (Mine does.)  Unfortunately, this is not specified in termcap, and
  264.  *    most terminals don't work that way.  (Of course, most terminals
  265.  *    have addressible cursors, too).
  266.  */
  267.         if (BW && (CM == 0) &&
  268.             ((sp->col << 1) - field > (COLUMNS - 8) << 1 )
  269.            ){
  270.              if (cursor.line == 0){  
  271.                  outch('\n');
  272.              }
  273.              outch('\r');
  274.              cursor.col = COLUMNS + 1;
  275.              while(cursor.col > sp->col)bs();
  276.              if (cursor.line != 0) outch('\n');
  277.              return;
  278.          }
  279.  
  280.         tfield = sp->col >> 3;
  281.  
  282.         while (field < tfield){
  283.             putpad(TA);
  284.             cursor.col = ++field << 3;
  285.         }
  286.         tabcol = (cursor.col|7) + 1;
  287.         strlength = (tabcol - sp->col)*BSlength + 1;
  288.         /* length of sequence to overshoot */
  289.         if (((sp->col - cursor.col)*NDlength > strlength) &&
  290.             (tabcol < COLUMNS)
  291.            ){
  292.             /*
  293.              * Tab past and backup
  294.              */
  295.             putpad(TA);
  296.             cursor.col = (cursor.col | 7) + 1;
  297.             while(cursor.col > sp->col)bs();
  298.         }
  299.     }
  300.     while (sp->col > cursor.col){
  301.         nd();
  302.     }
  303. }
  304.  
  305. cr(){
  306.     outch('\r');
  307.     cursor.col = 0;
  308. }
  309.  
  310. clear(){
  311.     int i;
  312.  
  313.     if (CL){
  314.         putpad(CL);
  315.         cursor.col=cursor.line=0;
  316.     } else {
  317.         for(i=0; i<LINES; i++) {
  318.             putchar('\n');
  319.         }
  320.         cursor.line = LINES - 1;
  321.         home();
  322.     }
  323. }
  324.  
  325. home(){
  326.     struct point z;
  327.  
  328.     if(HO != 0){
  329.         putpad(HO);
  330.         cursor.col = cursor.line = 0;
  331.         return;
  332.     }
  333.     z.col = z.line = 0;
  334.     move(&z);
  335. }
  336.  
  337. ll(){
  338.     int j,l;
  339.     struct point z;
  340.  
  341.     l = lcnt + 2;
  342.     if(LL != NULL && LINES==l){
  343.         putpad(LL);
  344.         cursor.line = LINES-1;
  345.         cursor.col = 0;
  346.         return;
  347.     }
  348.     z.col = 0;
  349.     z.line = l-1;
  350.     move(&z);
  351. }
  352.  
  353. up(){
  354.     putpad(UP);
  355.     cursor.line--;
  356. }
  357.  
  358. down(){
  359.     putpad(DO);
  360.     cursor.line++;
  361.     if (cursor.line >= LINES)cursor.line=LINES-1;
  362. }
  363. bs(){
  364.     if (cursor.col > 0){
  365.         putpad(BS);
  366.         cursor.col--;
  367.     }
  368. }
  369.  
  370. nd(){
  371.     putpad(ND);
  372.     cursor.col++;
  373.     if (cursor.col == COLUMNS+1){
  374.         cursor.line++;
  375.         cursor.col = 0;
  376.         if (cursor.line >= LINES)cursor.line=LINES-1;
  377.     }
  378. }
  379.  
  380. pch(c)
  381. {
  382.     outch(c);
  383.     if(++cursor.col >= COLUMNS && AM) {
  384.         cursor.col = 0;
  385.         ++cursor.line;
  386.     }
  387. }
  388.  
  389. apr(ps, fmt)
  390.     struct point *ps;
  391.     char *fmt;
  392. {
  393.     struct point p;
  394.     va_list ap;
  395.  
  396.     p.line = ps->line+1; p.col = ps->col+1;
  397.     move(&p);
  398.     va_start(ap, fmt);
  399.     (void)vsprintf(str, fmt, ap);
  400.     va_end(ap);
  401.     pstring(str);
  402. }
  403.  
  404. pr(fmt)
  405.     char *fmt;
  406. {
  407.     va_list ap;
  408.  
  409.     va_start(ap, fmt);
  410.     (void)vsprintf(str, fmt, ap);
  411.     va_end(ap);
  412.     pstring(str);
  413. }
  414.  
  415. pstring(s)
  416. char *s;{
  417.     struct point z;
  418.     int stcol;
  419.  
  420.     stcol = cursor.col;
  421.     while (s[0] != '\0'){
  422.         switch (s[0]){
  423.         case '\n':
  424.             move(point(&z,0,cursor.line+1));
  425.             break;
  426.         case '\r':
  427.             move(point(&z,stcol,cursor.line+1));
  428.             break;
  429.         case '\t':
  430.             z.col = (((cursor.col + 8) >> 3) << 3);
  431.             z.line = cursor.line;
  432.             move(&z);
  433.             break;
  434.         case '\b':
  435.             bs();
  436.             break;
  437.         case CTRL('g'):
  438.             outch(CTRL('g'));
  439.             break;
  440.         default:
  441.             if (s[0] < ' ')break;
  442.             pch(s[0]);
  443.         }
  444.         s++;
  445.     }
  446. }
  447.  
  448. pchar(ps,ch)
  449. struct point *ps;
  450. char ch;{
  451.     struct point p;
  452.     p.col = ps->col + 1; p.line = ps->line + 1;
  453.     if (
  454.         (p.col >= 0) &&
  455.         (p.line >= 0) &&
  456.         (
  457.             (
  458.                 (p.line < LINES) &&
  459.                 (p.col < COLUMNS)
  460.             ) ||
  461.             (
  462.                     (p.col == COLUMNS) &&
  463.                 (p.line < LINES-1)
  464.             )
  465.           )
  466.     ){
  467.         move(&p);
  468.         pch(ch);
  469.     }
  470. }
  471.  
  472.             
  473. outch(c)
  474. {
  475.     putchar(c);
  476. }
  477.  
  478. putpad(str)
  479. char *str;
  480. {
  481.     if (str)
  482.         tputs(str, 1, outch);
  483. }
  484. baudrate()
  485. {
  486.  
  487.     switch (orig.sg_ospeed){
  488.     case B300:
  489.         return(300);
  490.     case B1200:
  491.         return(1200);
  492.     case B4800:
  493.         return(4800);
  494.     case B9600:
  495.         return(9600);
  496.     default:
  497.         return(0);
  498.     }
  499. }
  500. delay(t)
  501. int t;
  502. {
  503.     int k,j;
  504.  
  505.     k = baudrate() * t / 300;
  506.     for(j=0;j<k;j++){
  507.         putchar(PC);
  508.     }
  509. }
  510.  
  511. done()
  512. {
  513.     cook();
  514.     exit(0);
  515. }
  516.  
  517. cook()
  518. {
  519.     delay(1);
  520.     putpad(TE);
  521.     putpad(KE);
  522.     fflush(stdout);
  523.     stty(0, &orig);
  524. #ifdef TIOCSLTC
  525.     ioctl(0, TIOCSLTC, &olttyc);
  526. #endif
  527. }
  528.  
  529. raw()
  530. {
  531.     stty(0, &new);
  532. #ifdef TIOCSLTC
  533.     ioctl(0, TIOCSLTC, &nlttyc);
  534. #endif
  535. }
  536.  
  537. struct point *point(ps,x,y)
  538. struct point *ps;
  539. int x,y;
  540. {
  541.     ps->col=x;
  542.     ps->line=y;
  543.     return(ps);
  544. }
  545.  
  546. char *ap;
  547.  
  548. getcap()
  549. {
  550.     char *getenv();
  551.     char *term;
  552.     char *xPC;
  553.     struct point z;
  554.     void stop();
  555.  
  556.     term = getenv("TERM");
  557.     if (term==0) {
  558.         fprintf(stderr, "No TERM in environment\n");
  559.         exit(1);
  560.     }
  561.  
  562.     switch (tgetent(tbuf, term)) {
  563.     case -1:
  564.         fprintf(stderr, "Cannot open termcap file\n");
  565.         exit(2);
  566.     case 0:
  567.         fprintf(stderr, "%s: unknown terminal", term);
  568.         exit(3);
  569.     }
  570.  
  571.     ap = tcapbuf;
  572.  
  573.     LINES = tgetnum("li");
  574.     COLUMNS = tgetnum("co");
  575.     if (!lcnt)
  576.         lcnt = LINES - 2;
  577.     if (!ccnt)
  578.         ccnt = COLUMNS - 3;
  579.  
  580.     AM = tgetflag("am");
  581.     BW = tgetflag("bw");
  582.  
  583.     ND = tgetstr("nd", &ap);
  584.     UP = tgetstr("up", &ap);
  585.  
  586.     DO = tgetstr("do", &ap);
  587.     if (DO == 0)
  588.         DO = "\n";
  589.  
  590.     BS = tgetstr("bc", &ap);
  591.     if (BS == 0 && tgetflag("bs"))
  592.         BS = "\b";
  593.     if (BS)
  594.         xBC = *BS;
  595.  
  596.     TA = tgetstr("ta", &ap);
  597.     if (TA == 0 && tgetflag("pt"))
  598.         TA = "\t";
  599.  
  600.     HO = tgetstr("ho", &ap);
  601.     CL = tgetstr("cl", &ap);
  602.     CM = tgetstr("cm", &ap);
  603.     LL = tgetstr("ll", &ap);
  604.  
  605.     KL = tgetstr("kl", &ap);
  606.     KR = tgetstr("kr", &ap);
  607.     KU = tgetstr("ku", &ap);
  608.     KD = tgetstr("kd", &ap);
  609.     Klength = strlen(KL);
  610.         /*    NOTE:   If KL, KR, KU, and KD are not
  611.          *        all the same length, some problems
  612.          *        may arise, since tests are made on
  613.          *        all of them together.
  614.          */
  615.  
  616.     TI = tgetstr("ti", &ap);
  617.     TE = tgetstr("te", &ap);
  618.     KS = tgetstr("ks", &ap);
  619.     KE = tgetstr("ke", &ap);
  620.  
  621.     xPC = tgetstr("pc", &ap);
  622.     if (xPC)
  623.         PC = *xPC;
  624.  
  625.     NDlength = strlen(ND);
  626.     BSlength = strlen(BS);
  627.     if ((CM == 0) &&
  628.         (HO == 0 | UP==0 || BS==0 || ND==0)) {
  629.         fprintf(stderr, "Terminal must have addressible ");
  630.         fprintf(stderr, "cursor or home + 4 local motions\n");
  631.         exit(5);
  632.     }
  633.     if (tgetflag("os")) {
  634.         fprintf(stderr, "Terminal must not overstrike\n");
  635.         exit(5);
  636.     }
  637.     if (LINES <= 0 || COLUMNS <= 0) {
  638.         fprintf(stderr, "Must know the screen size\n");
  639.         exit(5);
  640.     }
  641.  
  642.     gtty(0, &orig);
  643.     new=orig;
  644.     new.sg_flags &= ~(ECHO|CRMOD|ALLDELAY|XTABS);
  645.     new.sg_flags |= CBREAK;
  646.     signal(SIGINT,stop);
  647.     ospeed = orig.sg_ospeed;
  648. #ifdef TIOCGLTC
  649.     ioctl(0, TIOCGLTC, &olttyc);
  650.     nlttyc = olttyc;
  651.     nlttyc.t_suspc = '\377';
  652.     nlttyc.t_dsuspc = '\377';
  653. #endif
  654.     raw();
  655.  
  656.     if ((orig.sg_flags & XTABS) == XTABS) TA=0;
  657.     putpad(KS);
  658.     putpad(TI);
  659.     point(&cursor,0,LINES-1);
  660. }
  661.