home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume36 / ldb / part10 < prev    next >
Encoding:
Text File  |  1993-04-10  |  43.7 KB  |  1,436 lines

  1. Newsgroups: comp.sources.misc
  2. From: ross@teserv.den.mmc.com (Perry R. Ross)
  3. Subject: v36i107:  ldb - Play backgammon by e-mail, v1.3, Part10/12
  4. Message-ID: <1993Apr11.233218.18742@sparky.imd.sterling.com>
  5. X-Md4-Signature: d277b24b5b00d91c7093c66e5eafc4cd
  6. Date: Sun, 11 Apr 1993 23:32:18 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: ross@teserv.den.mmc.com (Perry R. Ross)
  10. Posting-number: Volume 36, Issue 107
  11. Archive-name: ldb/part10
  12. Environment: UNIX, C, VMS, VAXC, CURSES, 32BIT
  13. Supersedes: ldb: Volume 28, Issue 93-97
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 10 (of 12)."
  22. # Contents:  fe_curses.c
  23. # Wrapped by ross@teserv.den.mmc.com on Tue Apr  6 14:52:24 1993
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'fe_curses.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'fe_curses.c'\"
  27. else
  28. echo shar: Extracting \"'fe_curses.c'\" \(41435 characters\)
  29. sed "s/^X//" >'fe_curses.c' <<'END_OF_FILE'
  30. X/*    fe_curses.c        9/5/91
  31. X *
  32. X * Copyright 1991  Perry R. Ross
  33. X *
  34. X * Permission to use, copy, modify, and distribute this software and its
  35. X * documentation without fee is hereby granted, subject to the restrictions
  36. X * detailed in the README file, which is included here by reference.
  37. X * Any other use requires written permission from the author.  This software
  38. X * is distributed "as is" without any warranty, including any implied
  39. X * warranties of merchantability or fitness for a particular purpose.
  40. X * The author shall not be liable for any damages resulting from the
  41. X * use of this software.  By using this software, the user agrees
  42. X * to these terms.
  43. X */
  44. X
  45. X#include "ldb.h"
  46. X
  47. X/*======================================================================
  48. X * This file is the "curses" front-end for ldb.  It performs all
  49. X * display output and keyboard input in a way that will (hopefully)
  50. X * allow other front-ends to be added later.  These could include
  51. X * MAC's (blech), IBM PC's (double blech), and X, although it must
  52. X * be stated that, as of this writing, ldb is not organized in an
  53. X * event-driven manner, so it will take more work to port to X than
  54. X * just writing fe_motif.c or what have you.  But I'm working on it.
  55. X *
  56. X * All publicly-accessible functions in the front-end begin with Fe.
  57. X * These are the functions that must be written to implement a new
  58. X * front-end.  There are a few private functions in this file, which
  59. X * begin with P.  These are used internally by fe_curses.c and need not
  60. X * be implemented in other front-ends.
  61. X *
  62. X * The front-end is activated by calling FeInitialize.  In addition to
  63. X * performing any required initialization, it is mandatory for FeInitialize
  64. X * to set FeIsActive to non-zero.  The front-end is closed down by
  65. X * calling FeFinishSession, which must set FeIsActive to 0.  No calls
  66. X * to any Fe functions may be made while FeIsActive is 0.
  67. X *======================================================================
  68. X */
  69. X
  70. XPRIVATE char PGetChr();
  71. XPRIVATE PGetString();
  72. XPRIVATE PDrawComment();
  73. XPRIVATE PReverseText();
  74. XPRIVATE PEndReverse();
  75. X
  76. XPRIVATE struct game *Current_Game = NULL;
  77. X
  78. X
  79. X/* VAX C doesn't have tgetstr, but if you're using vax-c,    */
  80. X/* you're probably using a DEC terminal anyway.            */
  81. X#ifdef vaxc
  82. X#define PClearScreen() fputs("\33[H\33[2J",stdout);fflush(stdout)
  83. X#else
  84. XPRIVATE PClearScreen();
  85. X#endif
  86. X
  87. X
  88. X/*----------------------------------------------------------------------
  89. X *    FeInitialize -- initialize the front end
  90. X *
  91. X * This function initializes the curses package, turns off echo,
  92. X * turns on cbreak mode (to allow reading one character at a time),
  93. X * turns off mapping return to newline, and sets the FeIsActive flag.
  94. X * If FeWaitInit is set, the user is prompted to press <return> before
  95. X * the screen is cleared.  FeWaitInit is set by message() to indicate
  96. X * that there are messages on the screen that the user will want to
  97. X * read before the screen is cleared.
  98. X *----------------------------------------------------------------------
  99. X */
  100. X
  101. XFeInitialize()
  102. X{
  103. Xchar buf[80];
  104. X
  105. Xif (FeIsActive)
  106. X    return;
  107. Xif (FeWaitInit) {
  108. X    fprintf(stderr,"Press <return> to continue...");
  109. X    fflush(stdout);
  110. X    fflush(stderr);
  111. X    fgets(buf,sizeof(buf),stdin);
  112. X    FeWaitInit = 0;
  113. X    }
  114. Xinitscr();
  115. Xnoecho();
  116. Xcbreak();
  117. Xnonl();
  118. XFeIsActive = 1;
  119. XCurrent_Game = NULL;
  120. X}
  121. X
  122. X
  123. X/*----------------------------------------------------------------------
  124. X *    FeFinishSession -- shut down the front end
  125. X *
  126. X * This function clears the screen, closes down the curses package,
  127. X * and clears the FeIsActive flag.
  128. X *----------------------------------------------------------------------
  129. X */
  130. X
  131. XFeFinishSession()
  132. X{
  133. X
  134. Xif (FeIsActive) {
  135. X    clear();
  136. X    refresh();
  137. X    endwin();
  138. X    FeIsActive = 0;
  139. X    Current_Game = NULL;
  140. X    }
  141. X}
  142. X
  143. X
  144. X/*----------------------------------------------------------------------
  145. X *    FeDrawScreen -- draw the constant parts of the screen
  146. X *
  147. X * This function draws the parts of the screen that don't change for
  148. X * each game.  This includes the board outline and a few other
  149. X * miscellaneous things.
  150. X *----------------------------------------------------------------------
  151. X */
  152. X
  153. XFeDrawScreen()
  154. X{
  155. Xstatic char horz[] = "_____________________________________________________";
  156. Xint i;
  157. X
  158. Xclear();
  159. Xmvaddstr(2,5,horz);
  160. Xmvaddstr(17,5,horz);
  161. Xfor (i = 3; i < 18; i++) {
  162. X    mvaddch(i,5,'|');
  163. X    mvaddch(i,29,'|');
  164. X    mvaddch(i,33,'|');
  165. X    mvaddch(i,57,'|');
  166. X    }
  167. Xmvaddstr(3,61,"----------------");
  168. Xmvaddstr(4,63,"Roll  Move");
  169. Xmvaddstr(12,61,"----------------");
  170. Xmvaddstr(13,63,"Roll  Move");
  171. Xmvaddstr(18,62,"------[ ]------");
  172. Xfor (i = 19; i < 24; i++)
  173. X    mvaddch(i,62,'|');
  174. Xmvaddstr(18,0,"Messages:");
  175. Xmvaddstr(19,0,"Sent:");
  176. Xmvaddstr(21,0,"Rcvd:");
  177. Xrefresh();
  178. X}
  179. X
  180. X
  181. X
  182. X/*----------------------------------------------------------------------
  183. X *    FeDrawGame -- draw all items associated with a game
  184. X *
  185. X * This function displays all information related to a specific game.
  186. X * This includes the point labels, move blocks, cube; shoot, just
  187. X * about everything you can think of.
  188. X *----------------------------------------------------------------------
  189. X */
  190. X
  191. XFeDrawGame(g)
  192. Xstruct game *g;
  193. X{
  194. Xint i, p, r1, r2;
  195. Xchar blots[12], tmp[60], *n;
  196. Xchar addr[68];        /* all of e-mail address that will fit on top line */
  197. Xint bgflag;        /* 1 = gammon, 2 = backgammon, 0 = neither */
  198. Xint gval;        /* game value (when game is over) */
  199. Xstatic char pts1[] = " 1   2   3   4   5   6 |   | 7   8   9  10  11  12";
  200. Xstatic char pts2[] = "24  23  22  21  20  19 |   |18  17  16  15  14  13";
  201. Xstatic char *events[] = { "", "Gammon!  ", "Backgammon!  " };
  202. X
  203. XCurrent_Game = g;
  204. Xmove(0,0);
  205. Xclrtoeol();
  206. Xmove(0,0);
  207. Xn = (g->opname != NULL) ? g->opname : PPL_ANON;
  208. Xi = sizeof(addr) - strlen(n) - 1;  /* longest e-mail addr we can display */
  209. Xif (strlen(g->opaddr) > i) {    /* too long, truncate */
  210. X    strncpy(addr,g->opaddr,i-3);    /* leave space for ... */
  211. X    strcpy(&addr[i-3],"...");    /* add ellipsis & null terminate */
  212. X    }
  213. Xelse
  214. X    strcpy(addr,g->opaddr);
  215. Xprintw("Playing: %s (%s)",n,addr);        /* who am I playing? */
  216. Xif (g->flags & F_INVERT) {        /* board is inverted?  */
  217. X    mvaddstr(16,6,pts2);        /* draw inverted point labels */
  218. X    mvaddstr(4,6,pts1);
  219. X    r1 = 11;            /* remember which move block to use */
  220. X    r2 = 2;
  221. X    p = 1;
  222. X    }
  223. Xelse {
  224. X    mvaddstr(4,6,pts2);        /* draw normal point labels */
  225. X    mvaddstr(16,6,pts1);
  226. X    r1 = 2;                /* remember which move block to use */
  227. X    r2 = 11;
  228. X    p = 0;
  229. X    }
  230. Xif (g->mydir > 0) {        /* I'm playing up, switch move blocks */
  231. X    i = r1;
  232. X    r1 = r2;
  233. X    r2 = i;
  234. X    p = 1 - p;
  235. X    }
  236. Xmove(r1,63);
  237. Xprintw("Opponent  (%c)",g->opcolor);
  238. Xmove(r2,63);
  239. Xprintw("You       (%c)",g->mycolor);
  240. X
  241. Xswitch (g->curbd) {            /* which board should I draw? */
  242. Xcase BD_BEFOP:
  243. X    FeDrawBoard(g->opbd,g->opmvs,g->opdir,0,g->flags & F_INVERT);
  244. X    FeDrawPip(g->opbd,g);
  245. X    break;
  246. Xcase BD_AFTOP:
  247. X    FeDrawBoard(g->mybd,g->opmvs,g->opdir,1,g->flags & F_INVERT);
  248. X    FeDrawPip(g->mybd,g);
  249. X    break;
  250. Xcase BD_CUR:
  251. X    FeDrawBoard(g->board,NULL,g->mydir,0,g->flags & F_INVERT);
  252. X    FeDrawPip(g->board,g);
  253. X    break;
  254. X    }
  255. XFeLabelBoard(g);
  256. Xmvaddch(5,59,'|');            /* draw those little arrows */
  257. Xmvaddch(4,59,'-');
  258. Xmvaddch(14,59,'|');            /* that tell us which direction */
  259. Xmvaddch(15,59,'|');            /* we are going */
  260. Xmvaddch(16,59,'-');
  261. Xif (p == 0) {
  262. X    mvaddstr(4,1,"-->");
  263. X    mvaddch(4,58,'-');
  264. X    mvaddch(6,59,'V');
  265. X    mvaddch(16,58,'<');
  266. X    mvaddstr(16,1,"<--");
  267. X    mvaddstr(13,58,"   ");
  268. X    mvaddch(12,59,' ');
  269. X    mvaddstr(4,30,"-->");
  270. X    mvaddstr(16,30,"<--");
  271. X    }
  272. Xelse {
  273. X    mvaddstr(4,1,"<--");
  274. X    mvaddch(4,58,'<');
  275. X    mvaddch(6,59,'|');
  276. X    mvaddch(16,58,'-');
  277. X    mvaddstr(16,1,"-->");
  278. X    mvaddstr(13,58,"/|\\");
  279. X    mvaddch(12,59,'.');
  280. X    mvaddstr(16,30,"-->");
  281. X    mvaddstr(4,30,"<--");
  282. X    }
  283. X*blots = '\0';                /* did any of our blots get hit? */
  284. Xfor (i = 0, p = 0; i < 4; i++) {
  285. X    FeDrawMove(g,WHO_ME,i);        /* draw my moves */
  286. X    FeDrawMove(g,WHO_OPP,i);    /* draw opponent's moves */
  287. X    if (g->blot[i] > 0) {
  288. X        strcat(blots," ");    /* add a blot to the list */
  289. X        sprintf(tmp,"%d",g->blot[i]);
  290. X        strcat(blots,tmp);
  291. X        p++;
  292. X        }
  293. X    }
  294. XFeDrawCube(g);        /* draw the current game value */
  295. XPDrawComment(WHO_ME, g);    /* draw my old comment */
  296. XPDrawComment(WHO_OPP, g);    /* draw opponent's comment */
  297. Xif (g->state == ST_MYACCEPT)
  298. X    strcpy(tmp,"Opponent has doubled.");
  299. Xelse if (g->state == ST_GAMEOVER) {    /* game is over, find out why */
  300. X    bgflag = gvalue(g,&gval);        /* calculate game value */
  301. X    switch (g->term) {
  302. X    case T_IWIN:        /* I won, check for gammon/backgammon */
  303. X        sprintf(tmp,"%sYou win %d point%s.",events[bgflag],
  304. X            gval,(gval == 1) ? "" : "s");
  305. X        break;
  306. X    case T_ILOSE:        /* I lost, check for gammon/backgammon */
  307. X        sprintf(tmp,"%sYou lose %d point%s.",events[bgflag],
  308. X            gval,(gval == 1) ? "" : "s");
  309. X        break;
  310. X    case T_ICONCEDE:            /* I wimped out */
  311. X        sprintf(tmp,"You conceded.  You lose %d point%s.",
  312. X            gval,(gval == 1) ? "" : "s");
  313. X        break;
  314. X    case T_OPCONCEDE:            /* Opponent wimped out */
  315. X        sprintf(tmp,"Opponent conceded.  You win %d point%s.",
  316. X            gval,(gval == 1) ? "" : "s");
  317. X        break;
  318. X    case T_IDECLINE:            /* I declined the double */
  319. X        sprintf(tmp,"Double declined.  You lose %d point%s.",
  320. X            gval,(gval == 1) ? "" : "s");
  321. X        break;
  322. X    case T_OPDECLINE:        /* Opponent declined my double */
  323. X        sprintf(tmp,"Double declined.  You win %d point%s.",
  324. X            gval,(gval == 1) ? "" : "s");
  325. X        break;
  326. X        }
  327. X    }
  328. Xelse if (*blots)
  329. X    sprintf(tmp,"Blot%s hit:%s",(p == 1) ? "" : "s",blots);
  330. Xelse
  331. X    *tmp = '\0';
  332. XFeStatusLine(tmp);
  333. XFeMessage(g->dispmsg);        /* put message (if any) on message line */
  334. Xif (g->dispmsg != NULL) {    /* if there was a message, it has been */
  335. X    free(g->dispmsg);    /* displayed, so it can thrown away */
  336. X    g->dispmsg = NULL;
  337. X    }
  338. Xrefresh();
  339. X}
  340. X
  341. X
  342. X/*----------------------------------------------------------------------
  343. X *    FeDrawPip -- display the PIP count
  344. X *
  345. X * This function displays the current pip count.
  346. X *----------------------------------------------------------------------
  347. X */
  348. X
  349. XFeDrawPip(b,g)
  350. Xboard b;            /* the current board array */
  351. Xstruct game *g;            /* the current game structure */
  352. X{
  353. Xint mypip, oppip;
  354. X
  355. Xpipcount(b,g,&mypip,&oppip);
  356. Xmove(1,29);
  357. Xclrtoeol();
  358. Xmove(1,29);
  359. Xprintw("You: %3d  Op: %3d  ", mypip, oppip);
  360. Xif (mypip > oppip)
  361. X    printw("(%d behind)", mypip - oppip);
  362. Xelse if (oppip > mypip)
  363. X    printw("(%d ahead)", oppip - mypip);
  364. Xelse
  365. X    printw("(even)");
  366. X}
  367. X
  368. X
  369. X/*----------------------------------------------------------------------
  370. X *    FeDrawPoint -- draw all pieces on a point
  371. X *
  372. X * This function redraws all 15 slots on a point.  It is passed a
  373. X * board image and the index of the point to draw, from which it
  374. X * extracts the number of pieces on that point and the character used
  375. X * to represent pieces.  It will draw as many of these pieces as
  376. X * exist on the point, and will draw blanks over the remaining slots
  377. X * to erase any pieces that may have existed before.
  378. X * If the nh argument is greater than 0, it specifies how many of
  379. X * the pieces drawn should be highlighted.  This is used to highlight
  380. X * pieces moved by the opponent.
  381. X *----------------------------------------------------------------------
  382. X */
  383. X
  384. XFeDrawPoint(b,pt,nh,inv)
  385. Xboard b;        /* the board array */
  386. Xint pt;            /* which point are we to draw */
  387. Xint nh;            /* how many pieces should be highlighted */
  388. Xint inv;        /* is the board inverted? */
  389. X{
  390. Xstatic int cols[BOARDSIZE] = {  31,7,11,15,19,23,27,35,39,43,47,51,55,
  391. X                55,51,47,43,39,35,27,23,19,15,11,7,31,2,2};
  392. Xint sr, r;        /* the row we are at */
  393. Xint c;        /* the column we are at */
  394. Xint d;        /* which direction does the column grow 1/-1 */
  395. Xint i;        /* counter */
  396. Xchar x;        /* char to draw piece with */
  397. Xint nn;        /* number of normal pieces */
  398. X
  399. Xif ( (pt > 12) && (pt != DOWNOFF)) {
  400. X    sr = inv ? 15 : 5;    /* starting row is 5 (unless inverted) */
  401. X    d = inv ? -1 : 1;    /* direction is down (unless inverted) */
  402. X    }
  403. Xelse {
  404. X    sr = inv ? 5 : 15;    /* starting row is 15 (unless inverted) */
  405. X    d = inv ? 1 : -1;    /* direction is up (unless inverted) */
  406. X    }
  407. Xc = cols[pt];
  408. Xx = b[pt].color;        /* char to draw piece with */
  409. Xif (nh < 0)
  410. X    nh = 0;
  411. Xelse if (nh > b[pt].qty)
  412. X    nh = b[pt].qty;
  413. Xnn = b[pt].qty - nh;        /* how many normal pcs */
  414. Xr = sr;
  415. Xfor (i = 0; i < 15; i++) {        /* draw all 15 slots on this point */
  416. X    if (nn <= 0) {        /* no more normal pieces */
  417. X        if (nh <= 0)    /* and no highlighted pieces */
  418. X            x = ' ';    /* so draw blanks */
  419. X        else {
  420. X            PReverseText();
  421. X            nh--;
  422. X            }
  423. X        }
  424. X    else
  425. X        nn--;
  426. X    mvaddch(r,c,x);            /* draw this piece */
  427. X    PEndReverse();
  428. X    if (i == 4) {
  429. X        r = sr;            /* reset row */
  430. X        c--;            /* use col to left of first row */
  431. X        }
  432. X    else if (i == 9) {
  433. X        r = sr;            /* reset row */
  434. X        c += 2;            /* use col to right of first row */
  435. X        }
  436. X    else
  437. X        r += d;            /* bump row number */
  438. X    }
  439. X}
  440. X
  441. X
  442. X/*----------------------------------------------------------------------
  443. X *    FeDrawMove -- draw a line in a move block
  444. X *
  445. X * This function draws one line in a move block.  This consists of the
  446. X * value of the roll, the starting and ending position of the piece
  447. X * moved, and an asterisk if the move was from the opponent and hit
  448. X * one of our blots.
  449. X *----------------------------------------------------------------------
  450. X */
  451. X
  452. XFeDrawMove(g,who,mn)
  453. Xstruct game *g;            /* the game structure */
  454. Xint who;            /* WHO_ME or WHO_OPP */
  455. Xint mn;                /* which move to draw */
  456. X{
  457. Xint p, r, d;
  458. Xstruct mv *m;
  459. X
  460. Xd = (who == WHO_ME) ? g->mydir : g->opdir;/* this move upbound or downbound? */
  461. Xp = (d > 0);                /* upper or lower block? */
  462. Xif (g->flags & F_INVERT)        /* inverted board */
  463. X    p = !p;                /* switch move blocks */
  464. Xr = mn + (p ? 5 : 14);            /* figure out the row number */
  465. Xm = (who == WHO_ME) ? &g->mvs[mn] : &g->opmvs[mn];/* find the move structure */
  466. Xmove(r,64);
  467. Xclrtoeol();                /* clear the old move */
  468. Xif (m->roll > 0) {
  469. X    move(r,64);
  470. X    printw("%d",m->roll);        /* draw the roll */
  471. X    move(r,69);
  472. X    if (m->pt < 0) {        /* if it is unused, say so */
  473. X        addstr("UNUSED");
  474. X        return;
  475. X        }
  476. X    if ( ( (p = m->pt) == UPBAR) || (m->pt == DOWNBAR) ) {
  477. X        p = BARPT(d);        /* if coming off bar, say so */
  478. X        printw("BAR-");
  479. X        }
  480. X    else
  481. X        printw("%d-",m->pt);    /* draw starting point */
  482. X    if ( ( (p += d*m->roll) <= 0) || (p >= 25) )
  483. X        printw("OFF");        /* if bearing off, say so */
  484. X    else
  485. X        printw("%d",p);        /* draw ending point */
  486. X    if ( (who == WHO_OPP) && g->blot[mn])    /* if op move hit a blot */
  487. X        mvaddch(r,76,'*');    /* mark it */
  488. X    }
  489. X}
  490. X
  491. X
  492. X/*----------------------------------------------------------------------
  493. X *    FeDrawBoard -- draw all points on a board
  494. X *
  495. X * This is a convenience function that calls FeDrawPoint for all
  496. X * points on a board.  It takes as an argument an array of moves,
  497. X * as well as an argument that determines whether DrawPoint should be
  498. X * instructed to highlight the source of those moves, the destination,
  499. X * or nothing.
  500. X *----------------------------------------------------------------------
  501. X */
  502. X
  503. XFeDrawBoard(b,mvs,dir,sd,inv)
  504. Xboard b;            /* board image */
  505. Xstruct mv mvs[4];        /* moves to highlight (NULL = none) */
  506. Xint dir;            /* direction */
  507. Xint sd;                /* 0=highlight source, 1=dest */
  508. Xint inv;            /* is the board inverted? */
  509. X{
  510. Xint i, s, e;
  511. Xstatic char hcnt[BOARDSIZE];    /* number of pieces to highlight */
  512. X
  513. Xfor (i = 0; i < BOARDSIZE; i++)
  514. X    hcnt[i] = 0;        /* init to no highlight */
  515. Xif (mvs != NULL) {    /* find all points that should be highlighted */
  516. X    for (i = 0; i < 4; i++) {
  517. X        if ( (mvs[i].roll <= 0) || ( (s = mvs[i].pt) < 0) )
  518. X            continue;    /* this move is unused */
  519. X        if ( (s < 1) || (s > 24) )    /* if coming off bar */
  520. X            s = BARPT(dir);        /* use correct bar point */
  521. X        e = s + dir*mvs[i].roll;    /* add in the roll used */
  522. X        if ( (e < 1) || (e > 24) )    /* off the board */
  523. X            e = OFFPT(dir);    /* use correct off point */
  524. X        if (sd > 0) {            /* we are showing dest */
  525. X            hcnt[e]++;        /* inc destination count */
  526. X            hcnt[s]--;        /* handle continued moves */
  527. X            }
  528. X        else {                /* we are showing start */
  529. X            hcnt[s]++;        /* inc start count */
  530. X            hcnt[e]--;        /* handle continued moves */
  531. X            }
  532. X        }
  533. X    }
  534. Xfor (i = 0; i < BOARDSIZE; i++)        /* draw each point */
  535. X    FeDrawPoint(b,i,hcnt[i],inv);
  536. X}
  537. X
  538. X
  539. X/*----------------------------------------------------------------------
  540. X *    FeLabelBoard -- draw board info
  541. X *
  542. X * This function displays information about the board currently
  543. X * being displayed.  This includes its label, any special rule flags,
  544. X * and the current match score.
  545. X *----------------------------------------------------------------------
  546. X */
  547. X
  548. XFeLabelBoard(g)
  549. Xstruct game *g;
  550. X{
  551. Xint i;
  552. Xstatic char *bdlbl[] = {"Bef", "Aft", "Cur"};
  553. X
  554. Xmvaddstr(1,5,BLANKS(24));        /* clear old stuff */
  555. Xmvaddstr(1,5,bdlbl[g->curbd]);        /* draw the board label */
  556. Xif (g->flags & F_JACOBY)        /* label special rules flags */
  557. X    mvaddch(1,10,'J');
  558. Xif (g->flags & F_CRAWFORD) {
  559. X    if (g->flags & F_CRGAME)    /* if this is crawford rule game */
  560. X        PReverseText();        /* highlight the C indicator */
  561. X    mvaddch(1,11,'C');
  562. X    if (g->flags & F_CRGAME)
  563. X        PEndReverse();
  564. X    }
  565. Xif (g->flags & F_EUROPE)
  566. X    mvaddch(1,12,'E');
  567. Xif (g->flags & F_PERM)
  568. X    mvaddch(1,13,'P');
  569. Xif (g->mtotal > 0) {            /* if this is a match */
  570. X    move(1,16);            /* draw the match score */
  571. X    printw("%02d:%02d to %2d",
  572. X        g->mcurrent[WHO_ME], g->mcurrent[WHO_OPP], g->mtotal);
  573. X    }
  574. XFeCheckContact(g);
  575. X}
  576. X
  577. X
  578. X
  579. X
  580. X/*----------------------------------------------------------------------
  581. X *    FeCheckContact -- check for contact after a move is made.
  582. X *
  583. X * This routine keeps the BAR indicator up to date as moves are made.
  584. X * The BAR indicator changes to "---" when no further contact is
  585. X * possible for a game.  Note that the BAR indicator only reflects
  586. X * the value of the current board, and is not affected by which
  587. X * board is being displayed.
  588. X *----------------------------------------------------------------------
  589. X */
  590. X
  591. XFeCheckContact(g)
  592. Xstruct game *g;
  593. X{
  594. X
  595. Xif (iscontact(g))            /* if contact is possible */
  596. X    mvaddstr(10,30,"BAR");        /* draw BAR label */
  597. Xelse                    /* change BAR indicator to */
  598. X    mvaddstr(10,30,"---");        /* no contact indicator */
  599. X}
  600. X
  601. X
  602. X/*----------------------------------------------------------------------
  603. X *    FeGetPoint -- read a point number from the user
  604. X *
  605. X * This function prompts the user for a point number.  The user types
  606. X * the input on the line of the move block corresponding to the
  607. X * roll being used.  Normally, the input is a number between 1 and 24.  
  608. X * Point numbers are two digits unless:
  609. X *    - The first digit is 3 .. 9.
  610. X * OR    - The first digit is 1 and there is no point in 10 .. 19
  611. X *      that could use the selected roll.
  612. X * OR    - The first digit is 2 and there is no point in 20 .. 24
  613. X *      that could use the selected roll.
  614. X * Otherwise, there must be a non-digit entered to finish a 1-digit
  615. X * point number.  Alternatively, the user may enter them
  616. X * with a leading 0.  There are a number of special characters that
  617. X * are also recognized:
  618. X *    char            return value
  619. X *    ---------------------------------------------------------------
  620. X *    space            the "spdflt" argument.
  621. X *    return/linefeed        the "crdflt" argument.
  622. X *    DEL/ESC/BS        cancel move.
  623. X *    p/P            the point from which a piece would have
  624. X *                to be moved to land on spdflt.
  625. X *    o/O            The point from which the selected roll
  626. X *                could be used to bear off.  If that point
  627. X *                is unoccupied, the next lower occupied
  628. X *                point is returned.
  629. X * If there are pieces on the bar, the bar point is returned immediately,
  630. X * since there could be no other possible choice the user would make.
  631. X *----------------------------------------------------------------------
  632. X */
  633. X
  634. XFeGetPoint(g,r,crdflt,spdflt)
  635. Xstruct game *g;                /* game structure */
  636. Xint r;                    /* which row in move block */
  637. Xint crdflt;                /* what to return for cr/nl */
  638. Xint spdflt;                /* what to return for space */
  639. X{
  640. Xint n, row;
  641. Xchar buf[4];
  642. X
  643. X
  644. Xif (g->board[BARPT(g->mydir)].qty > 0)    /* pieces on the bar */
  645. X    return(BARPT(g->mydir));    /* no need to even ask */
  646. Xrow = r;
  647. Xif (g->flags & F_INVERT)        /* which move block do I use? */
  648. X    row += (g->mydir < 0) ? 5 : 14;    /* inverted board */
  649. Xelse
  650. X    row += (g->mydir > 0) ? 5 : 14;    /* normal board */
  651. Xmove(row,69);
  652. Xclrtoeol();
  653. Xmove(row,69);
  654. Xrefresh();
  655. X*buf = PGetChr(0,1);
  656. Xif ( (*buf == '\n') || (*buf == '\r') )    /* return means repeat move */
  657. X    return(crdflt);
  658. Xif (*buf == ' ')            /* space means continue move */
  659. X    return(spdflt);
  660. Xif ( (*buf == '\177') || (*buf == '\033') || (*buf == '\b') )
  661. X    return(-1);            /* DEL/ESC/BS means cancel move */
  662. Xif ( (*buf == 'b') || (*buf == 'B') )    /* bar */
  663. X    return(BARPT(g->mydir));
  664. Xif ( (*buf == 'p') || (*buf == 'P') ) {    /* P means spdflt - roll*dir */
  665. X    n = spdflt - g->mvs[r].roll*g->mydir;    /* make point */
  666. X    if ( (n < 1) || (n > 24) )        /* not on board */
  667. X        n = 99;                /* force invalid point */
  668. X    return(n);
  669. X    }
  670. Xif ( (*buf == 'o') || (*buf == 'O') ) {    /* O means bear a piece off */
  671. X    n = ( (g->mydir > 0) ? 25 : 0 ) - g->mydir*g->mvs[r].roll;
  672. X    while ( (n > 0) && (n <= 24) &&
  673. X       ( (g->board[n].qty <= 0) || (g->board[n].color != g->mycolor)) )
  674. X        n += g->mydir;
  675. X    if ( (n < 1) || (n > 24) )    /* no piece found */
  676. X        n = 99;            /* force invalid point */
  677. X    return(n);
  678. X    }
  679. Xif ( ! isdigit(*buf))
  680. X    return(99);            /* force invalid point message */
  681. Xif ( (*buf >= '3') && (*buf <= '9') )    /* 3 .. 9 */
  682. X    return(*buf - '0');        /* don't bother with 2nd digit */
  683. Xif (*buf == '1') {            /* look for valid move in 10 .. 19 */
  684. X    if (canmove(g,r,10,19) == 0)    /* no valid move */
  685. X        return(1);        /* don't bother with second digit */
  686. X    }
  687. Xelse if (*buf == '2') {            /* look for valid move in 20 .. 24 */
  688. X    if (canmove(g,r,20,24) == 0)    /* no valid move */
  689. X        return(2);        /* don't bother with second digit */
  690. X    }
  691. Xaddch(*buf);                /* echo the char */
  692. Xrefresh();
  693. Xbuf[1] = PGetChr(0,1);
  694. Xbuf[2] = '\0';                /* null terminate */
  695. Xif ( ((n = atoi(buf)) == UPBAR) || (n == DOWNBAR) )
  696. X    return(BARPT(g->mydir));
  697. Xreturn(n);
  698. X}
  699. X
  700. X
  701. X/*----------------------------------------------------------------------
  702. X *    PGetChr -- get a single character
  703. X *
  704. X * This function gets one character from the user and returns it.
  705. X * If the "e" argument is non-zero, the character is echoed at the
  706. X * current cursor position.  If the "h" argument is non-zero, the
  707. X * online help is displayed by pressing "H", "h", or "?".  The ^L and ^R
  708. X * characters are intercepted and cause the screen to be redrawn without
  709. X * returning from PGetChr.  Null characters are discarded.
  710. X *----------------------------------------------------------------------
  711. X */
  712. X
  713. XPRIVATE char PGetChr(e,h)
  714. Xint e, h;
  715. X{
  716. Xchar c;
  717. Xint y, x;
  718. X
  719. X#ifdef VMS
  720. Xchar Prompt[4] = "_$ ";
  721. Xstruct dsc$descriptor_s *cmd = 0, *prmpt=0;
  722. X$DESCRIPTOR(cm_dsc,rc.supercmd);
  723. X$DESCRIPTOR(prmpt_dsc,Prompt);
  724. X#endif
  725. X
  726. Xloop:
  727. Xif ( (c = getch() & 0x7f) == '\0')
  728. X    goto loop;
  729. Xif ( (c == 0x0c) || (c == 0x12) ) {    /* ^L or ^R? */
  730. X    clearok(curscr, TRUE);
  731. X    wrefresh(curscr);    /* repaint current screen */
  732. X    goto loop;        /* and get another char */
  733. X    }
  734. Xif (c == rc.superkey) {            /* uh oh, we're busted */
  735. X    getyx(stdscr,y,x);        /* save old cursor postition */
  736. X    PClearScreen();            /* get the screen cleared fast */
  737. X    nl();                /* set tty back to normal */
  738. X    nocbreak();
  739. X    echo();
  740. X#ifdef VMS
  741. X    cm_dsc.dsc$w_length = strlen(rc.supercmd);    /* length of cmd */
  742. X    cmd = &cm_dsc;            /* set up the command argument */
  743. X    prmpt_dsc.dsc$w_length = strlen(Prompt);
  744. X    prmpt = &prmpt_dsc;            /* set up the command argument */
  745. X    lib$spawn(cmd,0,0,0,0,0,0,0,0,0,prmpt,0);    /* spawn a subprocess */
  746. X#else
  747. X    system(rc.supercmd);        /* run the supervisor command */
  748. X#endif
  749. X    noecho();
  750. X    cbreak();
  751. X    nonl();                /* ok, we're safe again */
  752. X    PClearScreen();            /* clear old junk */
  753. X    clearok(curscr, TRUE);
  754. X    wrefresh(curscr);        /* repaint current screen */
  755. X    move(y,x);            /* put cursor back where it was */
  756. X    refresh();
  757. X    goto loop;            /* and get another character */
  758. X    }
  759. Xif (h && (c == '?' || c == 'h' || c == 'H')) {    /* user needs help */
  760. X    dohelp();            /* give it to 'em */
  761. X    touchwin(stdscr);        /* Make sure the screen gets updated */
  762. X    wrefresh(stdscr);        /* Now refresh it */
  763. X    goto loop;            /* and get another character */
  764. X    }
  765. Xif (h && (c == '%' || c == '#')) {    /* user wants stats */
  766. X    dostats(Current_Game);        /* give it to 'em */
  767. X    touchwin(stdscr);        /* Make sure the screen gets updated */
  768. X    wrefresh(stdscr);        /* Now refresh it */
  769. X    goto loop;            /* and get another character */
  770. X    }
  771. Xif (e && isprint(c)) {        /* echo char? */
  772. X    addch(c);        /* yup */
  773. X    refresh();
  774. X    }
  775. Xreturn(c);
  776. X}
  777. X
  778. X
  779. X/*----------------------------------------------------------------------
  780. X *    PClearScreen -- clear the screen somehow
  781. X *
  782. X * This function clears the physical display without affecting what
  783. X * the curses package thinks is there.  If the "cl" (clear screen)
  784. X * capability is defined, it uses that.  If that fails, it tries
  785. X * to move to 0,0 and use the "cd" (clear to end of display).
  786. X * Failing that, it goes to the bottom of the screen and scrolls
  787. X * it 24 times.
  788. X *----------------------------------------------------------------------
  789. X */
  790. X
  791. X#ifndef vaxc
  792. XPRIVATE PClearScreen()
  793. X{
  794. Xchar *s, *x, buf[80];
  795. X
  796. Xx = buf;
  797. Xif ( (s = tgetstr("cl",&x)) == NULL) {        /* no clear screen */
  798. X    if ( (s = tgetstr("cd",&x)) != NULL) {    /* do we have clr to end? */
  799. X        move(0,0);        /* yup, use it */
  800. X        refresh();
  801. X        fputs(s,stdout);
  802. X        }
  803. X    else {            /* well, do it the hard way */
  804. X        move(23,0);
  805. X        refresh();
  806. X        printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
  807. X        }
  808. X    }
  809. Xelse
  810. X    fputs(s,stdout);    /* send clear screen */
  811. Xfflush(stdout);            /* git along, li'l characters */
  812. X}
  813. X#endif
  814. X
  815. X
  816. X/*----------------------------------------------------------------------
  817. X *    FeGetComment -- prompt for a comment to send along with a move
  818. X *
  819. X * This function allows the user to enter a 2-line comment.  If the
  820. X * user types a non-empty string, it is stored in the mycmt/mycmt2
  821. X * fields of the game structure passed as an argument.  The previous comment,
  822. X * if any, is discarded.  The number of lines read is returned,
  823. X * or -1 if PGetString was terminated by ESC.  This has the effect of
  824. X * aborting the Send command.
  825. X *----------------------------------------------------------------------
  826. X */
  827. X
  828. XFeGetComment(g)
  829. Xstruct game *g;
  830. X{
  831. Xchar buf[120];
  832. Xchar *lptrs[2];
  833. Xint n;
  834. X
  835. Xn = PGetString(buf,56,lptrs,2,19,6);    /* get new comment */
  836. Xif (n < 0) {            /* user hit escape, back out of send */
  837. X    PDrawComment(WHO_ME, g);        /* put my old comment back */
  838. X    return(-1);            /* return "escape" code */
  839. X    }
  840. Xif (g->mycmt != NULL)        /* throw away old comment */
  841. X    free(g->mycmt);
  842. Xif (g->mycmt2 != NULL)
  843. X    free(g->mycmt2);
  844. Xif (n > 0)
  845. X    g->mycmt = save(lptrs[0]);    /* save first line */
  846. Xelse
  847. X    g->mycmt = NULL;    /* mark comment as empty */
  848. Xif (n > 1)
  849. X    g->mycmt2 = save(lptrs[1]);    /* save second line */
  850. Xelse
  851. X    g->mycmt2 = NULL;
  852. Xreturn(n);
  853. X}
  854. X
  855. X
  856. X
  857. X/*----------------------------------------------------------------------
  858. X *    PGetString -- read a multi-line string from the user
  859. X *
  860. X * This function allows the user to enter multiple lines of a fixed maximum
  861. X * length.  The normal line editing characters are recognized and
  862. X * processed.  These include:
  863. X *    DEL/BS        The character before the cursor is deleted.
  864. X *    ^X/^U        The entire line is erased.
  865. X *    ^L/^R        The screen is redrawn.
  866. X *    ^W/^B        The word before the cursor is erased.
  867. X * Typing past the end of a line automatically causes a word-
  868. X * wrap to the next line.  Words are delimited by spaces.  Typing
  869. X * a carriage return or line feed on the last line, or on an empty
  870. X * line, terminates PGetString; otherwise, it moves to the next line.
  871. X * ESC terminates PGetString regardless of the cursor position.
  872. X * Backspacing from the beginning of one line to the end of the previous
  873. X * is allowed.  PGetString returns the number of lines entered,
  874. X * or -1 if it was terminated by an ESC.
  875. X *----------------------------------------------------------------------
  876. X */
  877. X
  878. XPRIVATE PGetString(buf,len,lines,nls,y,x)
  879. Xchar *buf, *lines[];
  880. Xint len, nls, y, x;
  881. X{
  882. Xchar c, *bp, *p;
  883. Xint cl, l;
  884. X
  885. Xfor (cl = 0; cl < nls; cl++) {
  886. X    lines[cl] = NULL;        /* clear line pointers */
  887. X    mvaddstr(y+cl,x,BLANKS(len));    /* clear line */
  888. X    }
  889. Xcl = 0;                    /* current line = 0 */
  890. Xl = 0;                /* length of current line */
  891. Xmove(y,x);            /* go to first location in field */
  892. Xbp = buf;            /* ptr to next storage location */
  893. Xlines[0] = buf;            /* init first line pointer */
  894. Xrefresh();
  895. Xwhile (1) {
  896. X    switch (c = PGetChr(0,0)) {
  897. X    case '\177':        /* DEL */
  898. X    case '\b':        /* BS */
  899. X        if (l <= 0) {    /* at beginning of line */
  900. X            if (cl <= 0)    /* on first line */
  901. X                break;        /* nothing to delete */
  902. X            cl--;        /* back up one line */
  903. X            *--bp = '\0';    /* back up buffer pointer */
  904. X            l = strlen(lines[cl]);    /* load line length */
  905. X            move(y+cl,x+l);    /* move cursor to end of prev line */
  906. X            }
  907. X        else {
  908. X            bp--;        /* back up buffer pointer */
  909. X            l--;        /* decrement length */
  910. X            move(y+cl,x+l);
  911. X            addch(' ');    /* erase the char from the screen */
  912. X            move(y+cl,x+l);
  913. X            }
  914. X        refresh();
  915. X        break;
  916. X    case '\2':        /* ^B -- erase previous character */
  917. X    case '\27':        /* ^W */
  918. X        if (l <= 0) {        /* beginning of line */
  919. X            if (cl <= 0)    /* on first line */
  920. X                break;        /* nothing to delete */
  921. X            cl--;        /* back up one line */
  922. X            *--bp = '\0';    /* back up buffer pointer */
  923. X            l = strlen(lines[cl]);    /* load line length */
  924. X            }
  925. X        while (l > 0) {        /* skip leading spaces, if any */
  926. X            if (*--bp != ' ') {
  927. X                bp++;
  928. X                break;
  929. X                }
  930. X            l--;
  931. X            *bp = '\0';
  932. X            }
  933. X        while (l > 0) {        /* delete to last space */
  934. X            if (*--bp == ' ') {
  935. X                bp++;
  936. X                break;
  937. X                }
  938. X            *bp = '\0';
  939. X            l--;
  940. X            mvaddch(y+cl,x+l,' ');
  941. X            }
  942. X        move(y+cl,x+l);
  943. X        refresh();
  944. X        break;
  945. X    case '\33':        /* ESC */
  946. X        *bp++ = '\0';        /* terminate the string */
  947. X        return(-1);        /* return abort code */
  948. X    case '\r':        /* CR */
  949. X    case '\n':        /* NL */
  950. X        *bp++ = '\0';    /* terminate the string */
  951. X        if (l <= 0)        /* empty line */
  952. X            return(cl);    /* don't include it in #lines */
  953. X        if (cl >= nls-1)        /* last line */
  954. X            return(cl+1);    /* return number of lines */
  955. X        lines[++cl] = bp;    /* go to next line */
  956. X        l = 0;
  957. X        move(y+cl,x);
  958. X        refresh();
  959. X        break;
  960. X    case '\30':        /* ^X -- erase entire line & goto prev line */
  961. X    case '\25':        /* ^U */
  962. X        mvaddstr(y+cl,x,BLANKS(len));
  963. X        if (cl > 0) {    /* back up one line */
  964. X            bp = lines[cl--] - 1;
  965. X            l = strlen(lines[cl]);
  966. X            }
  967. X        else {        /* already on top line, go to beginning */
  968. X            bp = buf;
  969. X            l = 0;
  970. X            }
  971. X        move(y+cl,x+l);
  972. X        refresh();
  973. X        break;
  974. X    case '\t':            /* convert tab to a space */
  975. X        c = ' ';
  976. X        /* fall through */
  977. X    default:
  978. X        if (iscntrl(c)){        /* bad char */
  979. X            fputc('\7',stderr);    /* beep */
  980. X            fflush(stderr);
  981. X            break;            /* & ignore character */
  982. X            }
  983. X        if (l >= len) {        /* typed up to end of line */
  984. X            if (cl >= nls-1) {    /* last line, can't go on */
  985. X                fputc('\7',stderr);    /* beep */
  986. X                fflush(stderr);
  987. X                break;        /* & ignore character */
  988. X                }
  989. X            *bp++ = c;        /* store rcvd char */
  990. X            for (p = bp-1; (l > 0) && (! isspace(*p)); p--, l--);
  991. X            if ( (p <= buf) || (*p == '\0') ) {
  992. X                *bp++ = '\0';
  993. X                lines[++cl] = bp;    /* didn't find word */
  994. X                l = 0;
  995. X                }
  996. X            else {
  997. X                *p++ = '\0';    /* terminate previous line */
  998. X                mvaddstr(y+cl,x,BLANKS(len));    /* redraw */
  999. X                mvaddstr(y+cl,x,lines[cl]);    /* w/o word */
  1000. X                lines[++cl] = p;    /* start new line */
  1001. X                *bp = '\0';        /* terminate word */
  1002. X                l = strlen(p);        /* set line len */
  1003. X                mvaddstr(y+cl,x,p);    /* draw word */
  1004. X                }
  1005. X            move(y+cl,x+l);
  1006. X            }
  1007. X        else {
  1008. X            *bp++ = c;        /* put char in string */
  1009. X            l++;            /* bump length */
  1010. X            addch(c);        /* echo char to screen */
  1011. X            }
  1012. X        refresh();
  1013. X        break;
  1014. X        }
  1015. X    }
  1016. X}
  1017. X
  1018. X
  1019. X/*----------------------------------------------------------------------
  1020. X *    FeDrawMenu -- draw menu choices in menu box
  1021. X *
  1022. X * This function takes an array of strings, terminated by a NULL
  1023. X * pointer, and writes each string into successive lines of the
  1024. X * menu box in the bottom right corner of the screen.  If there are
  1025. X * more strings than will fit in the box, the extra strings are
  1026. X * ignored.  If NULL is passed as the menu array, the menu box
  1027. X * is cleared.
  1028. X *----------------------------------------------------------------------
  1029. X */
  1030. X
  1031. XFeDrawMenu(m)
  1032. Xchar *m[];
  1033. X{
  1034. Xint i;
  1035. X
  1036. Xfor (i = 0; i < 5; i++) {        /* clear all lines in menu box */
  1037. X    move(19+i,63);
  1038. X    clrtoeol();
  1039. X    }
  1040. Xif (m == NULL)                /* no menu to display */
  1041. X    return;
  1042. Xfor (i = 0; (m[i] != NULL) && (i < 5); i++) {
  1043. X    if (strlen(m[i]) > 15)        /* menu string is too long */
  1044. X        m[15] = '\0';        /* so shorten it */
  1045. X    mvaddstr(19+i,64,m[i]);        /* put string in menu area */
  1046. X    }
  1047. Xrefresh();
  1048. X}
  1049. X
  1050. X
  1051. X/*----------------------------------------------------------------------
  1052. X *    FeMenu -- get menu choice from user
  1053. X *
  1054. X * This function accepts a menu choice from the user.  The menu choices
  1055. X * are passed as an array of strings, terminated by a NULL pointer.
  1056. X * Users select one of these strings by typing the first letter of the
  1057. X * string, thus the first letter of the strings must be unique.
  1058. X *
  1059. X * FeMenu also handles two special cases:
  1060. X *    1. The user types a number between 1 and 6 (a roll)
  1061. X *    2. The user types some character that the caller wishes
  1062. X *       to handle directly.
  1063. X * If a roll entry is valid, the caller may pass up to two different
  1064. X * rolls that are valid in the r1 and r2 arguments.  Any characters
  1065. X * the caller wishes to handle are passed as a string in the
  1066. X * "extra" argument.  These typically include space and newline.
  1067. X *
  1068. X * When a menu item is selected, it is highlighted before FeMenu
  1069. X * returns.  If the caller calls FeMenu again without posting a
  1070. X * new menu (via FeDrawMenu), the character returned by FeMenu
  1071. X * on the first call should be passed in the "prev" argument so
  1072. X * that choice can be un-highlighted.  If there is no previous
  1073. X * choice to unhighlight, prev can be '\0'.
  1074. X *----------------------------------------------------------------------
  1075. X */
  1076. X
  1077. Xchar FeMenu(m,r1,r2,extra,prev)
  1078. Xchar *m[];            /* array of menu choices */
  1079. Xint r1, r2;            /* rolls (pass 0 if no roll valid) */
  1080. Xchar *extra;            /* chars that caller wants to handle */
  1081. Xchar prev;            /* previous choice we should un-highlight */
  1082. X{
  1083. Xint i;
  1084. Xchar c, x;
  1085. X
  1086. XFeOffMenuItem(m,prev);
  1087. Xwhile (1) {
  1088. X    mvaddch(18,69,' ');
  1089. X    move(18,69);            /* put cursor in its little box */
  1090. X    refresh();
  1091. X    c = PGetChr(1,1);        /* get a character */
  1092. X    FeMessage(NULL);        /* clear message line */
  1093. X    if ( (extra != NULL) && (strchr(extra,c) != NULL) )
  1094. X        return(c);        /* these chars are handled by caller */
  1095. X    if ( (c >= '1') && (c <= '6') ) {    /* handle digits differently */
  1096. X        if (r1 <= 0) {
  1097. X            FeMessage("Roll not valid here.");
  1098. X            continue;
  1099. X            }
  1100. X        x = c - '0';        /* convert to number */
  1101. X        if ( (x == r1) || (x == r2) )    /* is it a valid roll? */
  1102. X            return(c);        /* yup, return it */
  1103. X        FeMessage("No such roll.");
  1104. X        continue;
  1105. X        }
  1106. X    if (islower(c))            /* ignore case */
  1107. X        c = toupper(c);
  1108. X    for (i = 0; m[i] != NULL; i++) {    /* search menu strings */
  1109. X        x = *m[i];
  1110. X        if (islower(x))            /* ignore case */
  1111. X            x = toupper(x);
  1112. X        if (c != x)            /* this isn't it */
  1113. X            continue;        /* keep looking */
  1114. X        FeOnMenuItem(m,c);        /* highlight selection */
  1115. X        return(c);
  1116. X        }
  1117. X    FeMessage("Invalid command.");
  1118. X    }
  1119. X}
  1120. X
  1121. X
  1122. X/*----------------------------------------------------------------------
  1123. X *    FeMessage -- print a highlighted message on bottom line
  1124. X *
  1125. X * This function prints a string in reverse video on line 23.
  1126. X * The message length is restricted to 62 characters to avoid
  1127. X * running into the menu box.  If NULL is passed as a message,
  1128. X * the message line is cleared.
  1129. X *----------------------------------------------------------------------
  1130. X */
  1131. X
  1132. XFeMessage(s)
  1133. Xchar *s;
  1134. X{
  1135. Xchar c = 0;
  1136. X
  1137. Xmvaddstr(23,0,BLANKS(62));        /* clear message line */
  1138. Xif (s != NULL) {        /* if we have a message to print */
  1139. X    if (strlen(s) > 62) {    /* check that it's not too long */
  1140. X        c = s[62];    /* save char at this position */
  1141. X        s[62] = '\0';    /* and end the string */
  1142. X        }
  1143. X    move(23,0);
  1144. X    PReverseText();
  1145. X    addstr(s);        /* print the message */
  1146. X    PEndReverse();
  1147. X    if (c != '\0')        /* if we shortened it, restore it */
  1148. X        s[62] = c;
  1149. X    }
  1150. Xrefresh();
  1151. X}
  1152. X
  1153. X
  1154. X/*----------------------------------------------------------------------
  1155. X *    FeStatusLine -- draw string on status line
  1156. X *
  1157. X * This function puts a string on line 18 in reverse video.  It is
  1158. X * used to display blots hit, double offers, etc.
  1159. X *----------------------------------------------------------------------
  1160. X */
  1161. X
  1162. XFeStatusLine(s)
  1163. Xchar *s;
  1164. X{
  1165. Xchar c = 0;
  1166. Xint l;
  1167. X
  1168. Xmvaddstr(18,10,BLANKS(50));    /* clear status line */
  1169. Xif (s != NULL) {        /* if we have a message to print */
  1170. X    if ( (l = strlen(s)) > 50) {    /* check that it's not too long */
  1171. X        c = s[50];    /* save char at this position */
  1172. X        s[50] = '\0';    /* and end the string */
  1173. X        l = 50;
  1174. X        }
  1175. X    move(18,(50 - l)/2 + 10);
  1176. X    PReverseText();
  1177. X    addstr(s);        /* print the message */
  1178. X    PEndReverse();
  1179. X    if (c != '\0')        /* if we shortened it, restore it */
  1180. X        s[50] = c;
  1181. X    }
  1182. Xrefresh();
  1183. X}
  1184. X
  1185. X
  1186. X/*----------------------------------------------------------------------
  1187. X *    FeDrawCube -- draw doubling cube
  1188. X *
  1189. X * This function draws the doubling cube.  The cube is displayed beside
  1190. X * the inner table of the player who owns it (i.e. the one who didn't
  1191. X * double last).  If neither player has doubled, the cube is drawn
  1192. X * in the middle of the board.
  1193. X *----------------------------------------------------------------------
  1194. X */
  1195. X
  1196. XFeDrawCube(g)
  1197. Xstruct game *g;
  1198. X{
  1199. Xint r, c;
  1200. Xchar buf[8];
  1201. X
  1202. Xmvaddstr(3,0,"    ");        /* clear all cube locations */
  1203. Xmvaddstr(10,0,"    ");
  1204. Xmvaddstr(17,0,"    ");
  1205. Xif (g->gameval == (1 << g->adcnt))    /* nobody has doubled */
  1206. X    r = 10;            /* cube is in the middle of the board */
  1207. Xelse {            /* assume I didn't double last, mydir is up, */
  1208. X    r = 0;        /* and board is not inverted */
  1209. X    if (g->flags & F_IDOUBLED)    /* if I did double last */
  1210. X        r = 1 - r;        /* switch rows */
  1211. X    if (g->mydir < 0)        /* if my direction is down */
  1212. X        r = 1 - r;        /* switch rows */
  1213. X    if (g->flags & F_INVERT)    /* if board is inverted */
  1214. X        r = 1 - r;        /* switch rows */
  1215. X    r = r ? 17 : 3;            /* which row am I left with? */
  1216. X    }
  1217. X
  1218. Xsprintf(buf,"%d",g->gameval);        /* generate the game value */
  1219. Xif ( (c = 4 - strlen(buf)) < 0) {    /* doubled past 4 digits? */
  1220. X    strcpy(buf,"****");        /* we are out of columns */
  1221. X    c = 0;
  1222. X    }
  1223. Xmove(r,c);
  1224. XPReverseText();
  1225. Xmvaddstr(r,c,buf);        /* go there and draw game value */
  1226. XPEndReverse();
  1227. X}
  1228. X
  1229. X
  1230. X/*----------------------------------------------------------------------
  1231. X *    PDrawComment -- print a comment stored in a game
  1232. X *
  1233. X * This function takes a pointer to a game and draws the comment
  1234. X * strings to the screen.  If "who" is WHO_ME, the "mycmt" strings
  1235. X * are drawn on lines 19 and 20.  Otherwise, the "opcmt" strings
  1236. X * are drawn on lines 21 and 22.  Any unused space on these lines
  1237. X * is cleared.
  1238. X *----------------------------------------------------------------------
  1239. X */
  1240. X
  1241. XPRIVATE PDrawComment(who,g)
  1242. Xint who;
  1243. Xstruct game *g;
  1244. X{
  1245. Xint line;
  1246. Xchar *s1, *s2;
  1247. X
  1248. Xline = (who == WHO_OPP) ? 21 : 19;
  1249. Xs1 = (who == WHO_OPP) ? g->opcmt : g->mycmt;
  1250. Xs2 = (who == WHO_OPP) ? g->opcmt2 : g->mycmt2;
  1251. Xmvaddstr(line,6,BLANKS(56));
  1252. Xmvaddstr(line+1,6,BLANKS(56));
  1253. Xif (s1 != NULL) {
  1254. X    if (strlen(s1) > 56)
  1255. X        s1[56] = '\0';
  1256. X    mvaddstr(line,6,s1);
  1257. X    }
  1258. Xif (s2 != NULL) {
  1259. X    if (strlen(s2) > 56)
  1260. X        s2[56] = '\0';
  1261. X    mvaddstr(line+1,6,s2);
  1262. X    }
  1263. X}
  1264. X
  1265. X
  1266. X/*----------------------------------------------------------------------
  1267. X *    PReverseText -- go into reverse video mode
  1268. X *
  1269. X * This function goes into what is hopefully reverse video.  It
  1270. X * uses the standout() call from curses, which actually only
  1271. X * does whatever :so is set to in termcap (or the equivalent
  1272. X * in terminfo).  This is not necessarily reverse, but the
  1273. X * only way to be sure of getting reverse (setattr) is not
  1274. X * portable.  For VMS, the standout call uses bold rather than
  1275. X * reverse, so we use setattr.
  1276. X *----------------------------------------------------------------------
  1277. X */
  1278. X
  1279. XPRIVATE PReverseText()
  1280. X{
  1281. X
  1282. X#ifdef VMS
  1283. Xsetattr(_REVERSE);
  1284. X#else
  1285. Xstandout();
  1286. X#endif
  1287. X}
  1288. X
  1289. X
  1290. X/*----------------------------------------------------------------------
  1291. X *    PEndReverse -- go back to normal text
  1292. X *
  1293. X * This function reverses PReverseText, going back to unhighlighted text.
  1294. X *----------------------------------------------------------------------
  1295. X */
  1296. X
  1297. XPRIVATE PEndReverse()
  1298. X{
  1299. X
  1300. X#ifdef VMS
  1301. Xclrattr(_REVERSE);
  1302. X#else
  1303. Xstandend();
  1304. X#endif
  1305. X}
  1306. X
  1307. X
  1308. X/*----------------------------------------------------------------------
  1309. X *    FeOnMenuItem -- highlight a menu item
  1310. X *
  1311. X * This function highlights a menu item.  This is used to show the menu
  1312. X * selection that was picked.  It stays highlighted until FeOffMenuItem
  1313. X * is called or a new menu is displayed.
  1314. X *----------------------------------------------------------------------
  1315. X */
  1316. X
  1317. XFeOnMenuItem(m,p)
  1318. Xchar *m[];
  1319. Xchar p;
  1320. X{
  1321. Xint i;
  1322. X
  1323. Xfor (i = 0; m[i] && (i < 5); i++) {
  1324. X    if (*m[i] == p) {
  1325. X        move(19+i,63);
  1326. X        clrtoeol();
  1327. X        move(19+i,64);
  1328. X        PReverseText();
  1329. X        addstr(m[i]);
  1330. X        PEndReverse();
  1331. X        }
  1332. X    }
  1333. Xrefresh();
  1334. X}
  1335. X
  1336. X
  1337. X/*----------------------------------------------------------------------
  1338. X *    FeOffMenuItem -- unhighlight a menu item
  1339. X *
  1340. X * This function un-highlights a menu item.  This is used when another
  1341. X * pick is going to be made from the same menu.
  1342. X *----------------------------------------------------------------------
  1343. X */
  1344. X
  1345. XFeOffMenuItem(m,p)
  1346. Xchar *m[];
  1347. Xchar p;
  1348. X{
  1349. Xint i;
  1350. X
  1351. Xfor (i = 0; m[i] && (i < 5); i++) {
  1352. X    if (*m[i] == p) {
  1353. X        move(19+i,63);
  1354. X        clrtoeol();
  1355. X        move(19+i,64);
  1356. X        addstr(m[i]);
  1357. X        }
  1358. X    }
  1359. Xrefresh();
  1360. X}
  1361. X
  1362. X
  1363. X/*----------------------------------------------------------------------
  1364. X *    FeDumpScreen -- copy screen image to a file
  1365. X *
  1366. X * This function reads all characters off the screen and copies
  1367. X * them to a file.  It uses the inch() function from the curses
  1368. X * library to read the screen.  It returns 1 for success, 0 for failure.
  1369. X *----------------------------------------------------------------------
  1370. X */
  1371. X
  1372. XFeDumpScreen(fn)
  1373. Xchar *fn;
  1374. X{
  1375. XFILE *fp;
  1376. Xint x, y;
  1377. X
  1378. Xif ( (fp = fopen(fn,"w")) == NULL)
  1379. X    return(0);
  1380. Xfor (y = 0; y < 24; y++) {
  1381. X    for (x = 0; x < 80; x++) {
  1382. X        move(y,x);
  1383. X        putc(inch(),fp);
  1384. X        }
  1385. X    putc('\n',fp);
  1386. X    }
  1387. Xfclose(fp);
  1388. X}
  1389. X
  1390. X
  1391. X/*----------------------------------------------------------------------
  1392. X *    FeYesNo -- see if user knows what he's doing
  1393. X *
  1394. X * This function displays a message and waits for a single character
  1395. X * from the user.  If it is Y or y, 1 is returned, otherwise
  1396. X * 0 is returned.
  1397. X *----------------------------------------------------------------------
  1398. X */
  1399. XFeYesNo(msg)
  1400. Xchar *msg;
  1401. X{
  1402. Xchar c;
  1403. X
  1404. Xif (msg == NULL)
  1405. X    msg = "Are you sure? [yn]";
  1406. XFeMessage(msg);
  1407. Xc = PGetChr(0,0);
  1408. XFeMessage(NULL);
  1409. Xreturn( (c == 'y') || (c == 'Y') );
  1410. X}
  1411. END_OF_FILE
  1412. if test 41435 -ne `wc -c <'fe_curses.c'`; then
  1413.     echo shar: \"'fe_curses.c'\" unpacked with wrong size!
  1414. fi
  1415. # end of 'fe_curses.c'
  1416. fi
  1417. echo shar: End of archive 10 \(of 12\).
  1418. cp /dev/null ark10isdone
  1419. MISSING=""
  1420. for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
  1421.     if test ! -f ark${I}isdone ; then
  1422.     MISSING="${MISSING} ${I}"
  1423.     fi
  1424. done
  1425. if test "${MISSING}" = "" ; then
  1426.     echo You have unpacked all 12 archives.
  1427.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1428. else
  1429.     echo You still need to unpack the following archives:
  1430.     echo "        " ${MISSING}
  1431. fi
  1432. ##  End of shell archive.
  1433. exit 0
  1434.  
  1435. exit 0 # Just in case...
  1436.