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

  1. Newsgroups: comp.sources.misc
  2. From: ross@teserv.den.mmc.com (Perry R. Ross)
  3. Subject: v36i101:  ldb - Play backgammon by e-mail, v1.3, Part04/12
  4. Message-ID: <1993Apr11.232955.18017@sparky.imd.sterling.com>
  5. X-Md4-Signature: 8219d1518a7e679a4b18b57fc6e3cbc0
  6. Date: Sun, 11 Apr 1993 23:29:55 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 101
  11. Archive-name: ldb/part04
  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 4 (of 12)."
  22. # Contents:  game.c ldb.h process.c
  23. # Wrapped by ross@teserv.den.mmc.com on Tue Apr  6 14:52:19 1993
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'game.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'game.c'\"
  27. else
  28. echo shar: Extracting \"'game.c'\" \(16695 characters\)
  29. sed "s/^X//" >'game.c' <<'END_OF_FILE'
  30. X/*    game.c        8/3/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 *    startgame -- start a game
  49. X *
  50. X * This function is called in response to the -start command line
  51. X * option to start a game with another user.  It allocates a game
  52. X * record and fills it in, then sends a START packet to the opponent.
  53. X * The arguments are:
  54. X *    The email address of the opponent
  55. X *    The direction I want to play
  56. X *    The color I want to play
  57. X *    The color I want the opponent to play
  58. X *    The F_JACOBY/F_CRAWFORD/F_EUROPE/F_INVERT/F_PERM flags, if desired.
  59. X *    The match value (number of points to play to)
  60. X *    The time to use as the start time of the game (0 = current time)
  61. X *----------------------------------------------------------------------
  62. X */
  63. X
  64. Xstruct game *startgame(addr,d,mc,oc,flgs,mch,stime)
  65. Xchar *addr;            /* path to opponent */
  66. Xint d;                /* my direction */
  67. Xchar mc, oc;            /* my color, opponent's color */
  68. Xint flgs;            /* flags (F_*) */
  69. Xint mch;            /* match score */
  70. Xlong stime;            /* start time (0 = current time) */
  71. X{
  72. Xstruct game *g;
  73. Xchar c1, c2, *newid;
  74. Xstruct people *ppl;
  75. X
  76. Xnewid = makeid();        /* give it a unique id */
  77. Xg = addgame();            /* allocate new game */
  78. Xg->gameid = newid;        /* store new id */
  79. Xif (rc.debug & DB_GSTART) {
  80. X    message("DB-startgame:\tstarted game %s\n",newid);
  81. X    message("\t\twith %s flags=%04x match=%d\n",addr,flgs,mch);
  82. X    }
  83. Xif ( (ppl = findppl(addr,P_ADDR|P_ALIAS)) != NULL) {    /* we know this guy */
  84. X    g->opaddr = save(ppl->addr);    /* copy out people info */
  85. X    g->opname = save(ppl->name);
  86. X    g->myaddr = save(ppl->myaddr);
  87. X    g->ppl = ppl;
  88. X    }
  89. Xelse {                    /* new opponent */
  90. X    g->opaddr = save(addr);        /* save his address */
  91. X    g->opname = save(PPL_ANON);    /* don't know his name yet */
  92. X    g->myaddr = save(rc.myaddr);    /* store my return address */
  93. X    newppl(g);            /* make up a people record */
  94. X    }
  95. Xg->mycolor = mc;        /* set starting colors */
  96. Xg->opcolor = oc;
  97. Xg->mydir = d;            /* set starting directions */
  98. Xg->opdir = REV(d);
  99. Xg->gameval = 1;            /* no doubles yet */
  100. Xg->adcnt = 0;            /* no autodoubles yet */
  101. Xg->admax = rc.autodouble;    /* max allowed autodoubles */
  102. Xg->flags = flgs & (F_JACOBY|F_CRAWFORD|F_PERM|F_EUROPE|F_INVERT);
  103. Xg->state = ST_OPSTART;        /* need to send first roll */
  104. Xg->seq = 1;            /* start with sequence number = 1 */
  105. Xg->notify = notify;        /* copy notify address (if any) */
  106. Xg->curbd = boardnums[*rc.initboard - 'a'];    /* display initial board */
  107. Xif (d > 0) {
  108. X    c1 = mc;    /* upbound color is mine */
  109. X    c2 = oc;    /* downbound color is opponent's */
  110. X    }
  111. Xelse {
  112. X    c1 = oc;    /* upbound color is opponent's */
  113. X    c2 = mc;    /* downbound color is mine */
  114. X    }
  115. Xclearmvs(g->mvs);
  116. Xclearmvs(g->opmvs);
  117. Xnewboard(g->opbd,c1,c2);    /* set up boards for new game */
  118. Xnewboard(g->mybd,c1,c2);
  119. Xnewboard(g->board,c1,c2);
  120. Xg->mtotal = mch;
  121. Xg->mvs[0].roll = Rolldie();    /* roll an initial die */
  122. Xif (stime == 0L)
  123. X    g->starttime = time( (long *) 0);
  124. Xelse
  125. X    g->starttime = stime;    /* hack to detect duplicate remotestart pkts */
  126. Xg->lastacc = g->starttime;
  127. Xsendpkt(g,START);        /* send the start message */
  128. Xreturn(g);            /* and return pointer to new game */
  129. X}
  130. X
  131. X
  132. X/*----------------------------------------------------------------------
  133. X *    makeid -- create a unique game identifier.
  134. X *
  135. X * This function creates a string that is guaranteed unique among all
  136. X * ldb games worldwide, provided that email addresses are unique.
  137. X * This should be a good assumption, since if there is a duplicate,
  138. X * the users with the duplicate id's will have a great deal of difficulty
  139. X * getting mail delivered, and therefore won't be able to play ldb anyway.
  140. X * To make id's created by the same user unique, the time is
  141. X * appended to the mail address; to make sure the time is unique when
  142. X * the user creates more than 1 game per second, the games list is searched
  143. X * for a new id before it is returned and, if it is found, we sleep for
  144. X * 1 second and try again.
  145. X *----------------------------------------------------------------------
  146. X */
  147. X
  148. Xchar *makeid()
  149. X{
  150. Xchar *n;
  151. X
  152. Xif ( (n = calloc(strlen(rc.myaddr)+10,1)) == NULL)
  153. X    fatal("ERROR: Out of memory!");
  154. Xdo {
  155. X    sprintf(n,"%s|%08x",rc.myaddr,time((long *)0));
  156. X    if (findgame(n) == NULL)
  157. X        return(n);
  158. X    sleep(1);
  159. X    } while (1);
  160. X}
  161. X
  162. X
  163. X/*---------------------------------------------------------------------------
  164. X *    addgame -- allocate a game struct and link it into the game list
  165. X *
  166. X * This function allocates a game structure and links it into the
  167. X * doubly-linked game list.  The head of this list is ghead, and the
  168. X * tail is gtail.
  169. X *
  170. X * NOTE: the memory-zeroing feature of calloc is depended on to
  171. X *     initialize the allocated game struct.
  172. X *---------------------------------------------------------------------------
  173. X */
  174. X
  175. Xstruct game *addgame()
  176. X{
  177. Xstruct game *g;
  178. X
  179. Xif ( (g = (struct game *)calloc(sizeof(struct game),1)) == NULL)
  180. X    fatal("Out of memory!");
  181. Xg->next = NULL;
  182. Xif (gtail == NULL) {        /* this is the first game in the list */
  183. X    ghead = g;
  184. X    gtail = g;
  185. X    g->prev = NULL;
  186. X    }
  187. Xelse {
  188. X    g->prev = gtail;    /* link onto end of list */
  189. X    gtail->next = g;
  190. X    gtail = g;
  191. X    }
  192. Xreturn(g);
  193. X}
  194. X
  195. X
  196. X/*----------------------------------------------------------------------
  197. X *    deletegame -- delete a game from the game list
  198. X *
  199. X * This function removes a game from the game list by linking around
  200. X * it, then frees the memory associated with the game structure.
  201. X *----------------------------------------------------------------------
  202. X */
  203. X
  204. Xdeletegame(g)
  205. Xstruct game *g;
  206. X{
  207. X
  208. Xif (g == ghead) {        /* deleting first game in list */
  209. X    ghead = g->next;    /* move head pointer to next game */
  210. X    if (ghead == NULL)    /* we just deleted the last game */
  211. X        gtail = NULL;    /* set both ptrs to NULL */
  212. X    else
  213. X        ghead->prev = NULL;    /* first in list has no prev */
  214. X    }
  215. Xelse if (g == gtail) {        /* deleting last game in list */
  216. X    gtail = g->prev;    /* move tail pointer back */
  217. X    gtail->next = NULL;    /* last game has no next */
  218. X    }
  219. Xelse {
  220. X    g->next->prev = g->prev;    /* link back link around g */
  221. X    g->prev->next = g->next;    /* and forward link too */
  222. X    }
  223. Xif (g->gameid != NULL)
  224. X    free(g->gameid);        /* free string space */
  225. Xif (g->opname != NULL)
  226. X    free(g->opname);
  227. Xif (g->opaddr != NULL)
  228. X    free(g->opaddr);
  229. Xif (g->mycmt != NULL)
  230. X    free(g->mycmt);
  231. Xif (g->mycmt2 != NULL)
  232. X    free(g->mycmt2);
  233. Xif (g->opcmt != NULL)
  234. X    free(g->opcmt);
  235. Xif (g->opcmt2 != NULL)
  236. X    free(g->opcmt2);
  237. Xif (g->dispmsg != NULL)
  238. X    free(g->dispmsg);
  239. Xfree(g);            /* free the memory */
  240. X}
  241. X
  242. X
  243. X/*----------------------------------------------------------------------
  244. X *    findgame -- find a game based on its game id
  245. X *
  246. X * This function performs a linear search through the game list
  247. X * for a game id.  It returns a pointer to the game, or NULL if
  248. X * the game does not exist.
  249. X *----------------------------------------------------------------------
  250. X */
  251. X
  252. Xstruct game *findgame(gid)
  253. Xchar *gid;
  254. X{
  255. Xstruct game *g;
  256. X
  257. Xfor (g = ghead; g != NULL; g = g->next)
  258. X    if (strcmp(gid,g->gameid) == 0)        /* is this it? */
  259. X        return(g);            /* return it */
  260. Xreturn(NULL);                    /* no such game */
  261. X}
  262. X
  263. X
  264. X/*---------------------------------------------------------------------------
  265. X *    addppl -- allocate a people struct and link it into the list
  266. X *
  267. X * This function allocates a people structure and links it into the
  268. X * people list.  The head of this list is phead.
  269. X *
  270. X * NOTE: the memory-zeroing feature of calloc is depended on to
  271. X *     initialize the allocated people struct.
  272. X *---------------------------------------------------------------------------
  273. X */
  274. X
  275. Xstruct people *addppl()
  276. X{
  277. Xstruct people *p, *t;
  278. X
  279. Xfor (t = NULL, p = phead; p != NULL; t = p, p = p->next); /* t = end of list */
  280. Xif ( (p = (struct people *)calloc(sizeof(struct people),1)) == NULL)
  281. X    fatal("Out of memory!");
  282. Xif (t == NULL)
  283. X    phead = p;
  284. Xelse
  285. X    t->next = p;
  286. Xp->next = NULL;
  287. Xreturn(p);
  288. X}
  289. X
  290. X
  291. X/*----------------------------------------------------------------------
  292. X *    findppl -- find a people struct by address or alias
  293. X *
  294. X * This function performs a linear search through the people list
  295. X * searching for an address (if flag & P_ADDR) or an alias (if flag & P_ALIAS).
  296. X * It returns a pointer to the struct, or NULL if the address does not exist.
  297. X *----------------------------------------------------------------------
  298. X */
  299. X
  300. Xstruct people *findppl(a,flag)
  301. Xchar *a;
  302. Xint flag;
  303. X{
  304. Xint i, lcnt;
  305. Xstruct people *p;
  306. X
  307. Xif (a == NULL)
  308. X    fatal("NULL address in findppl");
  309. Xlcnt = 0;        /* counter to detect infinite loop */
  310. X
  311. Xrescan:
  312. X
  313. Xif (lcnt++ > 100)
  314. X    fatal("Infinite loop in findppl.");
  315. X
  316. Xfor (p = phead; p != NULL; p = p->next) {
  317. X    if ( (flag & P_ADDR) && (strcmp(a,p->addr) == 0) ) {   /* check addr */
  318. X        if (p->equiv != NULL) {        /* if equiv record, */
  319. X            a = p->equiv;        /* go look for base record */
  320. X            goto rescan;
  321. X            }
  322. X        return(p);            /* return it */
  323. X        }
  324. X    if (p->equiv != NULL)        /* equiv records don't have aliases */
  325. X        continue;
  326. X    if ( (flag & P_ALIAS) && (strcmp(a,p->alias) == 0) ) /* check alias */
  327. X        return(p);
  328. X    }
  329. Xreturn(NULL);                    /* no such record */
  330. X}
  331. X
  332. X
  333. X/*----------------------------------------------------------------------
  334. X *    newppl -- create a new people struct for a game
  335. X *
  336. X * This function creates a new people record for a new opponent.  It takes
  337. X * a game structure, extracts the necessary information, and inserts
  338. X * the new record into the people list, as well as storing a pointer
  339. X * to the new people struct into the game's ppl pointer.
  340. X *
  341. X * The alias field is initialized to the first word of g->opname
  342. X * with all upper case converted to lower.
  343. X *
  344. X * To handle people with more than one e-mail address, the people list
  345. X * is scanned for identical name fields.  If one is found, the
  346. X * user is asked if these people are the same.  If he answers yes,
  347. X * the "equiv" field is set to the name of the existing people
  348. X * record, and the rest of the record is zeroed out.
  349. X *----------------------------------------------------------------------
  350. X */
  351. X
  352. Xstruct people *newppl(g)
  353. Xstruct game *g;
  354. X{
  355. Xchar *a;
  356. Xregister struct people *p, *q;
  357. Xchar buf[80];
  358. X
  359. X    /* if this is a new game, and we don't have the opponent's    */
  360. X    /* personal information yet, just create a temporary people    */
  361. X    /* record, and don't link it into the people list.        */
  362. Xif ( (g->opname == NULL) || (strcmp(g->opname,PPL_ANON) == 0) ) {
  363. X    if ( (p = (struct people *) calloc(sizeof(struct people),1)) == NULL)
  364. X        fatal("Out of memory!");
  365. X    p->addr = save(g->opaddr); /* this will keep everyone happy until */
  366. X    p->myaddr = save(rc.myaddr);
  367. X    p->name = save(PPL_ANON);    /* we find out what his name is */
  368. X    p->alias = save(PPL_ANON);
  369. X    p->opver = 100;
  370. X    p->score[0] = -1;        /* this identifies temp records */
  371. X    g->ppl = p;
  372. X    return(p);
  373. X    }
  374. Xif (g->ppl != NULL) {    /* hey, there's already a people struct! */
  375. X    if (g->ppl->score[0] < 0) {    /* it's a temp */
  376. X        free(g->ppl->addr);    /* just get rid of it */
  377. X        free(g->ppl->myaddr);
  378. X        free(g->ppl->name);
  379. X        free(g->ppl->alias);
  380. X        free(g->ppl);
  381. X        g->ppl = NULL;
  382. X        }
  383. X    else        /* we got trouble */
  384. X        fatal("newppl: ppl rec already exists!");
  385. X    }
  386. Xp = addppl();                /* create new people struct */
  387. Xp->addr = save(g->opaddr);        /* copy opponent's address */
  388. Xfor (q = phead; q != NULL; q = q->next) {
  389. X    if ( (q->name != NULL) && (strcmp(q->name,g->opname) == 0) ) {
  390. X        printf("The following e-mail addresses:\n\n\t%s\n\t%s\n\n",
  391. X            q->addr,g->opaddr);
  392. X        printf("have the same name. [%s]\n",g->opname);
  393. X        printf("Do they refer to the same person? [default=yes]  ");
  394. X        fgets(buf,sizeof(buf),stdin);
  395. X        if ( (*buf == 'n') || (*buf == 'N') )
  396. X            break;
  397. X        p->equiv = save(q->addr);    /* if so, make an equiv rec */
  398. X        g->ppl = q;
  399. X        return(q);
  400. X        }
  401. X    }
  402. Xp->equiv = NULL;
  403. Xp->name = save(g->opname);        /* copy opponent's name */
  404. Xif ( (a = strchr(g->opname,' ')) != NULL)    /* create default alias */
  405. X    *a = '\0';
  406. Xp->alias = save(g->opname);        /* first word of opponent's name */
  407. Xif (a != NULL)
  408. X    *a = ' ';
  409. Xfor (a = p->alias; *a; a++)        /* converted to lower case */
  410. X    if (isupper(*a))
  411. X        *a = tolower(*a);
  412. Xp->myaddr = save(g->myaddr);        /* copy out my address */
  413. Xif (g->opver >= 100)
  414. X    p->opver = g->opver;        /* copy out opponent's ldb version */
  415. Xelse
  416. X    p->opver = 100;            /* default to version 1.0 */
  417. Xp->fence = 0L;                /* no fence time yet */
  418. Xg->ppl = p;                /* side pointer from game struct */
  419. Xreturn(p);
  420. X}
  421. X
  422. X
  423. X/*----------------------------------------------------------------------
  424. X *    printscore -- print the cumulative score for each opponent
  425. X *
  426. X * This function scans the people file printing the contents of the
  427. X * score field for each opponent.  It also prints the total over
  428. X * all opponents at the end.  For the following:
  429. X *    points
  430. X *    games
  431. X *    matches
  432. X *    gammons
  433. X *    backgammons
  434. X * the number won/lost/net is printed.  Games in progress are not counted,
  435. X * but games that have been completed are, even if they are part of
  436. X * a match that has not completed.
  437. X *----------------------------------------------------------------------
  438. X */
  439. X
  440. Xprintscore()
  441. X{
  442. Xregister struct people *p;
  443. Xregister int i;
  444. Xint total[10];            /* to store the total for all opponent's */
  445. X
  446. Xif (phead == NULL)        /* nothing to print */
  447. X    return;
  448. Xprintf("opponent                   points     games      gammons  backgammons  matches\n");
  449. Xprintf("------------------------------------------------------------------------------\n");
  450. Xfor (i = 0; i < 10; i++)
  451. X    total[i] = 0;
  452. Xfor (p = phead; p != NULL; p = p->next) {
  453. X    if (p->equiv != NULL)
  454. X        continue;        /* skip equiv records */
  455. X    pscore(p->name,p->score);    /* print this opponent */
  456. X    for (i = 0; i < 10; i++)    /* keep running total */
  457. X        total[i] += p->score[i];
  458. X    }
  459. Xpscore("total",total);            /* print the total */
  460. X}
  461. X
  462. X
  463. X/*----------------------------------------------------------------------
  464. X *    pscore -- print the score for one opponent
  465. X *
  466. X * This function is called by printscore to print each opponent.
  467. X * The opponent name is in "name", and the score table is in "score".
  468. X *----------------------------------------------------------------------
  469. X */
  470. X
  471. Xpscore(name,score)
  472. Xchar *name;
  473. Xint score[10];
  474. X{
  475. Xstatic int sc_idx[] = { 2, 0, 4, 6, 8 };    /* order to print p->score[] */
  476. Xregister int i, diff;
  477. Xchar buf[30];
  478. Xchar c;
  479. X
  480. Xif (strlen(name) > 25) {    /* truncate name to 25 chars */
  481. X    c = name[25];
  482. X    name[25] = '\0';
  483. X    }
  484. Xelse
  485. X    c = '\0';
  486. Xprintf("%-25s",name);
  487. Xif (c != '\0')
  488. X    name[25] = c;        /* restore name */
  489. Xfor (i = 0; i < 5; i++) {
  490. X    sprintf(buf,"%d/%d",score[sc_idx[i]],score[sc_idx[i]+1]);
  491. X    buf[9] = '\0';        /* truncate to 9 chars */
  492. X    if (strcmp(buf,"0/0") == 0)    /* none won or lost */
  493. X        *buf = '\0';        /* just leave it blank */
  494. X    printf("  %-9s",buf);    /* print with field width of 9 */
  495. X    }
  496. Xprintf("\n%21s","");
  497. Xfor (i = 0; i < 5; i++) {
  498. X    diff = score[sc_idx[i]] - score[sc_idx[i]+1];
  499. X    if (diff == 0) {
  500. X        if ( (score[sc_idx[i]] == 0) && (score[sc_idx[i]+1] == 0) )
  501. X            printf("           ");
  502. X        else
  503. X            printf("      even ");
  504. X        }
  505. X    else
  506. X        printf("      %+-5d", diff);
  507. X    }
  508. Xprintf("\n\n");
  509. X}
  510. X
  511. X
  512. Xilose(g,term,rsflag)
  513. Xstruct game *g;
  514. Xint term;            /* T_* */
  515. Xint rsflag;            /* 1 = restart game if necessary */
  516. X{
  517. Xint bg, gv;
  518. X
  519. Xg->state = ST_GAMEOVER;
  520. Xg->term = term;
  521. Xbg = gvalue(g,&gv);
  522. Xg->mcurrent[WHO_OPP] += gv;        /* bump match count */
  523. Xg->ppl->score[SC_GAMESLOST]++;        /* inc games lost */
  524. Xg->ppl->score[SC_PTSLOST] += gv;
  525. Xif (bg == 1)            /* gammon */
  526. X    g->ppl->score[SC_GMNLOST]++;
  527. Xelse if (bg == 2)
  528. X    g->ppl->score[SC_BGLOST]++;
  529. Xendgame(g,rsflag);
  530. X}
  531. X
  532. X
  533. Xiwin(g,term,rsflag)
  534. Xstruct game *g;
  535. Xint term;            /* T_* */
  536. Xint rsflag;            /* 1 = restart game if necessary */
  537. X{
  538. Xint bg, gv;
  539. X
  540. Xg->state = ST_GAMEOVER;
  541. Xg->term = term;
  542. Xbg = gvalue(g,&gv);
  543. Xg->mcurrent[WHO_ME] += gv;        /* bump match count */
  544. Xg->ppl->score[SC_GAMESWON]++;        /* inc games lost */
  545. Xg->ppl->score[SC_PTSWON] += gv;
  546. Xif (bg == 1)            /* gammon */
  547. X    g->ppl->score[SC_GMNWON]++;
  548. Xelse if (bg == 2)
  549. X    g->ppl->score[SC_BGWON]++;
  550. Xendgame(g,rsflag);
  551. X}
  552. X
  553. X
  554. Xendgame(g,rsflag)
  555. Xstruct game *g;
  556. Xint rsflag;                /* 1 = restart game if necessary */
  557. X{
  558. X
  559. Xif (g->ppl->fence < g->starttime)   /* if newer than fence */
  560. X    g->ppl->fence = g->starttime;    /* move up fence */
  561. Xif (rsflag && (g->flags & F_PERM) && (g->mcurrent[WHO_OPP] >= g->mtotal) ) {
  562. X    message("Restarted game with %s (%s).\n",g->opname,g->opaddr);
  563. X    notify = NULL;
  564. X    startgame(g->opaddr,g->mydir,g->mycolor,g->opcolor,
  565. X       g->flags & (F_JACOBY|F_CRAWFORD|F_PERM|F_EUROPE|F_INVERT),
  566. X       g->mtotal,0);
  567. X    }
  568. Xif ( (g->notify != NULL) && (g->mcurrent[WHO_OPP] >= g->mtotal) )
  569. X    sendpkt(g,NOTIFY);
  570. X}
  571. END_OF_FILE
  572. if test 16695 -ne `wc -c <'game.c'`; then
  573.     echo shar: \"'game.c'\" unpacked with wrong size!
  574. fi
  575. # end of 'game.c'
  576. fi
  577. if test -f 'ldb.h' -a "${1}" != "-c" ; then 
  578.   echo shar: Will not clobber existing file \"'ldb.h'\"
  579. else
  580. echo shar: Extracting \"'ldb.h'\" \(18491 characters\)
  581. sed "s/^X//" >'ldb.h' <<'END_OF_FILE'
  582. X/*    ldb.h        8/3/91
  583. X *
  584. X * Copyright 1991  Perry R. Ross
  585. X *
  586. X * Permission to use, copy, modify, and distribute this software and its
  587. X * documentation without fee is hereby granted, subject to the restrictions
  588. X * detailed in the README file, which is included here by reference.
  589. X * Any other use requires written permission from the author.  This software
  590. X * is distributed "as is" without any warranty, including any implied
  591. X * warranties of merchantability or fitness for a particular purpose.
  592. X * The author shall not be liable for any damages resulting from the
  593. X * use of this software.  By using this software, the user agrees
  594. X * to these terms.
  595. X */
  596. X
  597. X#include "patchlevel.h"
  598. X
  599. X    /* LDB_VER breaks if REVISION or PATCHLEVEL > 9, see patchlevel.h */
  600. X#define LDB_VER    ((VERSION*100)+(REVISION*10)+PATCHLEVEL)  /* used in sendpkt */
  601. X
  602. X#include <stdio.h>
  603. X#include <ctype.h>
  604. X#include <curses.h>
  605. X#include <signal.h>
  606. X
  607. X#ifdef VMS
  608. X
  609. X#include <types.h>
  610. X#include <time.h>
  611. X#include <unixio.h>
  612. X#include <file.h>
  613. X#include <descrip.h>
  614. X#include <processes.h>
  615. X#include <ssdef.h>
  616. X#include <rms.h>
  617. X#include <stat.h>
  618. X#define STAT_NORM SS$_NORMAL
  619. X#define STAT_ABORT SS$_ABORT
  620. X#define SYS_GOOD 1        /* success return from system() */
  621. X
  622. X#else
  623. X
  624. X#include <sys/types.h>
  625. X#include <sys/dir.h>
  626. X#include <sys/stat.h>
  627. X#include <time.h>
  628. X#include <fcntl.h>
  629. X#define STAT_NORM 0
  630. X#define STAT_ABORT 1
  631. X#define SYS_GOOD 0        /* success return from system() */
  632. X
  633. X#endif
  634. X
  635. X#ifdef NEED_READDIR        /* defined by Makefile */
  636. Xextern struct direct dirbuf;    /* simulate Berkeley directory routines */
  637. X#define DIR FILE
  638. X#define opendir(X) fopen((X),"r")
  639. X#define readdir(X) (fread(&dirbuf,sizeof(dirbuf),1,(X))?&dirbuf:NULL)
  640. X#define closedir(X) fclose(X)
  641. X#endif
  642. X
  643. X#ifdef vaxc
  644. X#define OLD_CURSES 1
  645. X#define unlink(X) delete(X)
  646. X#endif
  647. X
  648. X#ifdef sequent
  649. X#define OLD_CURSES 1
  650. X#endif
  651. X
  652. X#ifdef OLD_CURSES        /* defined above or in Makefile */
  653. X#define cbreak() crmode()    /* from ancient curses */
  654. X#define nocbreak() nocrmode()
  655. X#endif
  656. X
  657. X#ifdef USE_INDEX        /* defined in Makefile */
  658. X#define strchr index        /* $%!@^&#$ pick a name and stick with it */
  659. X#define strrchr rindex
  660. X#endif
  661. X
  662. X#define release_lock(X) unlink(X)    /* delete lock file */
  663. X
  664. X    /* swiped from X toolkit */
  665. X#define Offset(T,F) ((int)(((char *)(&(((T)NULL)->F)))-((char *)NULL)))
  666. X
  667. X#define PRIVATE static        /* for private functions */
  668. X
  669. X#define INTGFILE "interrupt.ldbdata"    /* file to save games to on ^C */
  670. X#define INTPFILE "interrupt.ldbpeople"    /* file to save people to on ^C */
  671. X
  672. X#define BLANKS(X) (&blk76[76-(X)])    /* blank string of specified length */
  673. X
  674. X        /* locations in board typedef */
  675. X#define UPBAR        0        /* BAR point for up-bound player */
  676. X#define DOWNBAR        25        /* BAR point for down-bound player */
  677. X#define UPOFF        26        /* off point for up-bound player */
  678. X#define DOWNOFF        27        /* off point for down-bound player */
  679. X#define BOARDSIZE    28        /* number of points in board */
  680. X
  681. X    /* BARPT takes a direction (-1 or 1) and returns the    */
  682. X    /* point in the board typedef that represents that    */
  683. X    /* players bar.  OFFPT does the same thing for the    */
  684. X    /* point that pieces go to when they are thrown off.    */
  685. X    /* REV(direction) returns the opposite direction.    */
  686. X#define BARPT(D)    (((D)>0)?UPBAR:DOWNBAR)
  687. X#define OFFPT(D)    (((D)>0)?UPOFF:DOWNOFF)
  688. X#define REV(D)        (-(D))
  689. X
  690. X        /* states we can be in */
  691. X#define ST_OPSTART    0        /* we have sent a START (or rcvd one)*/
  692. X#define ST_OPTURN    1        /* Its the opponent's turn */
  693. X#define ST_OPACCEPT    2        /* I have offered to double */
  694. X
  695. X#define OPSTATES    3        /* < OPSTATES needs remote input */
  696. X
  697. X#define ST_MYTURN    3        /* My turn, I haven't rolled yet */
  698. X#define ST_MYMOVE    4        /* I've rolled, but I haven't moved */
  699. X#define ST_MYACCEPT    5        /* Opponent has offered to double */
  700. X#define ST_GAMEOVER    6        /* game is dead, see T_* for reason */
  701. X#define NSTATE        7        /* number of possible states */
  702. X
  703. X        /* operations to send or receive */
  704. X#define START        0        /* start a game */
  705. X#define USTART        1        /* if rcvd, we won the initial roll */
  706. X#define TIE        2        /* tie on initial roll, restart */
  707. X#define MOVE        3        /* send a move */
  708. X#define OFRDBL        4        /* offer to double */
  709. X#define ACPTDBL        5        /* double accepted */
  710. X#define DECDBL        6        /* double declined, game over */
  711. X#define CONCEDE        7        /* we give up */
  712. X#define RSTART        8        /* remote start packet */
  713. X#define RESTART        9        /* repeat initial roll */
  714. X#define MSTART        10        /* start next game of match */
  715. X#define RESEND        11        /* resend request from opponent */
  716. X#define NOTIFY        12        /* tell game starter when game ends */
  717. X#define NOP        13        /* number of possible operations */
  718. X
  719. X        /* termination codes for state ST_GAMEOVER */
  720. X#define T_ICONCEDE    1        /* I gave up */
  721. X#define T_IDECLINE    2        /* I declined double */
  722. X#define T_ILOSE        3        /* opponent moved all pieces off */
  723. X#define T_OPCONCEDE    4        /* opponent gave up */
  724. X#define T_OPDECLINE    5        /* opponent declined double */
  725. X#define T_IWIN        6        /* I moved all pieces off */
  726. X
  727. X        /* flags passed to apply */
  728. X#define A_REDRAW    1    /* redraw the pieces moved */
  729. X#define A_CHKONLY    2    /* check move but don't move pieces */
  730. X
  731. X        /* codes returned by apply */
  732. X#define MVOK        0    /* move was accepted by apply() */
  733. X#define RJ_NOROLL    -1    /* move does not contain valid roll */
  734. X#define RJ_NOOFF    -2    /* all pcs not in inner tbl, can't throw off */
  735. X#define RJ_NOPIECE    -3    /* no piece at specified point */
  736. X#define RJ_OCC        -4    /* destination occupied */
  737. X#define RJ_ONBAR    -5    /* can't move, pieces are on bar */
  738. X#define RJ_NOTYOURS    -6    /* wrong color, dummy */
  739. X#define RJ_EXACT    -7    /* must use exact roll except for outer pc */
  740. X
  741. X        /* bits for flags field of game struct */
  742. X#define F_IDOUBLED    1    /* I doubled last */
  743. X#define F_SENTNAME    2    /* I've sent my name */
  744. X#define F_INVERT    4    /* I want my board upside down */
  745. X#define F_DELETE    8    /* this game is deleted */
  746. X#define F_JACOBY    16    /* jacoby rule in effect for this game */
  747. X#define F_CRAWFORD    32    /* crawford rule in effect for this game */
  748. X#define F_PERM        64    /* permanent game */
  749. X#define F_EUROPE    128    /* european rule (backgammons count double) */
  750. X#define F_DISPLAYED    256    /* Game over, keeping in case need resend */
  751. X#define F_CRGAME    512    /* This game is the crawford rule game */
  752. X#define F_CRDONE    1024    /* The crawford rule game has been played */
  753. X
  754. X        /* field types for reading name/value files */
  755. X#define FT_CHAR        1    /* store a single character */
  756. X#define FT_INT        2    /* store a single integer */
  757. X#define FT_STRING    3    /* store a char * (use save()) */
  758. X#define FT_MOVE        4    /* a struct mv */
  759. X#define FT_BOARD    5    /* a board image */
  760. X#define FT_STRLKUP    6    /* lookup string in table & store index */
  761. X#define FT_TIME        7    /* a timestamp */
  762. X#define FT_INTARRAY    8    /* array of integers */
  763. X#define FT_END        99    /* end of structure */
  764. X
  765. X        /* which board is currently displayed (g->curbd) */
  766. X#define BD_BEFOP    0    /* before op's move (after my previous) */
  767. X#define BD_AFTOP    1    /* after op's move (before my next) */
  768. X#define BD_CUR        2    /* current (with any moves I've made so far) */
  769. X
  770. X        /* these are the command line options */
  771. X#define OPT_START    1    /* start a game */
  772. X#define OPT_READ    2    /* read incoming mail */
  773. X#define OPT_PLAY    3    /* play any games that are waiting for me */
  774. X#define OPT_COLOR    4    /* set the color for created games */
  775. X#define OPT_DIRECTION    5    /* set the direction for created games */
  776. X#define OPT_RSTART    6    /* remote start a game */
  777. X#define OPT_HELP    7    /* print long help */
  778. X#define OPT_CONTROL    8    /* go into control mode */
  779. X#define OPT_MYADDR    9    /* set my e-mail address (override .ldbrc) */
  780. X#define OPT_BCAST    10    /* send a mail message to all opponents */
  781. X#define OPT_JACOBY    11    /* enable the jacoby rule */
  782. X#define OPT_CRAWFORD    12    /* enable the crawford rule */
  783. X#define OPT_PERM    13    /* make game permanent */
  784. X#define OPT_MATCH    14    /* set number of points in match */
  785. X#define OPT_EUROPE    15    /* enable european rule */
  786. X#define OPT_RECONS    16    /* reconstruct a game from opponent's data */
  787. X#define OPT_SCORE    17    /* print cumulative scores */
  788. X#define OPT_NOTIFY    18    /* set notify address */
  789. X#define OPT_NEWADDR    19    /* tell people my mail address changed */
  790. X
  791. X        /* these are the different game states for the help call */
  792. X#define STATE_CONTROL    1    /* Invoked with the control option */
  793. X#define STATE_MYTURN    2    /* Waiting for user to move */
  794. X#define STATE_MYMOVE    3    /* User has rolled but needs to move */
  795. X#define STATE_MYACPT    4    /* Accept or decline the double */
  796. X#define STATE_GAMEOVER    5    /* The game is over */
  797. X
  798. X#define WHO_ME        0    /* used to mean local player */
  799. X#define WHO_OPP        1    /* used to mean opponent */
  800. X
  801. X    /* these bits are passed to findppl to specify whether    */
  802. X    /* we want to look up an address, an alias, or both    */
  803. X#define P_ADDR        1    /* look for a address */
  804. X#define P_ALIAS        2    /* look for an alias */
  805. X
  806. X    /* this string is put in the name field of a temporary    */
  807. X    /* people struct.  Temporary people structs are created    */
  808. X    /* when a game is started with a new opponent, and we    */
  809. X    /* don't know any of his personal information yet.    */
  810. X    /* PPL_ANON is used as the opponent's name and alias    */
  811. X    /* until we know his real name.                */
  812. X#define PPL_ANON    "*** UNKNOWN ***"
  813. X
  814. X    /* these are the bits to set in rc.debug to enable    */
  815. X    /* debug messages for various functions.        */
  816. X#define DB_READFILE    1    /* print mail files scanned */
  817. X#define DB_RWGAMES    2    /* print games read/written */
  818. X#define DB_GSTART    4    /* print games started */
  819. X#define DB_RSTART    8    /* trace remote start packets */
  820. X
  821. X    /* these refer to the elements of struct people->score */
  822. X#define SC_GAMESWON    0    /* number of games won against this guy */
  823. X#define SC_GAMESLOST    1    /* number of games lost to this guy */
  824. X#define SC_PTSWON    2    /* number of points won against this guy */
  825. X#define SC_PTSLOST    3    /* number of points lost to this guy */
  826. X#define SC_GMNWON    4    /* number of gammons won */
  827. X#define SC_GMNLOST    5    /* number of gammons lost */
  828. X#define SC_BGWON    6    /* number of backgammons won */
  829. X#define SC_BGLOST    7    /* number of backgammons lost */
  830. X#define SC_MWON        8    /* number of matches won */
  831. X#define SC_MLOST    9    /* number of matches lost */
  832. X
  833. X    /* These codes are for the newaddr field of the people    */
  834. X    /* structure.  They are used to notify opponents that    */
  835. X    /* the local user's address has changed.        */
  836. X#define NA_NONE        0    /* address has not changed */
  837. X#define NA_PEND        1    /* address has changed, op not notified */
  838. X#define NA_SENT        2    /* op has been notified, waiting for ack */
  839. X
  840. Xstruct opt {            /* used to make list of command line options */
  841. X    char    *name;        /* name of option (as used on command line) */
  842. X    int    index;        /* OPT_* */
  843. X    char    *args;        /* arguments the option takes, if any */
  844. X    char    *help;        /* 1-line help string for option */
  845. X    };
  846. X
  847. Xstruct ldbrc {        /* struct where all fields from .ldbrc are stored */
  848. X    char    *myaddr;    /* my e-mail address */
  849. X    char    *myname;    /* my name */
  850. X    char    *pfile;        /* people file */
  851. X    char    *gfile;        /* games file */
  852. X    char    *gbackup;    /* where to save old game file */
  853. X    char    *mfile;        /* mail file */
  854. X    char    *delmail;    /* should we delete mail files after reading?*/
  855. X    char    *lockfile;    /* ldb mutex lock file */
  856. X    char    *sendcmd;    /* mail send command */
  857. X    char    *tempfile;    /* temp file for sendpkt */
  858. X    char    *defclrs;    /* default colors (2 from [rwb]) */
  859. X    char    *defdir;    /* default direction (up/down) */
  860. X    char    *initboard;    /* init. brd display (before/after/current) */
  861. X    char    *autoroll;    /* enable autoroll? (yes/no) */
  862. X    char    *automove;    /* enable automove? (yes/no) */
  863. X    int    autodouble;    /* autodouble count, 0 to disable */
  864. X    char    *supercmd;    /* command to run to fool supervisor */
  865. X    char    superkey;    /* key to activate supercmd */
  866. X    char    *chkpt;        /* keep games up to date? */
  867. X    int    acctime;    /* number of days until auto resend */
  868. X    int    keepold;    /* number of days to keep finished games */
  869. X    int    debug;        /* debug level, 0 = none */
  870. X    };
  871. X
  872. X        /* the following structure is used to save/load */
  873. X        /* the games file, the .ldbrc, and to send    */
  874. X        /* packets between the players.  It stores a    */
  875. X        /* name, the type (see FT_* above), and the    */
  876. X        /* offset into a structure.  A pointer to the    */
  877. X        /* structure is provided at runtime.        */
  878. Xstruct namevalue {
  879. X       char *name;        /* name of the field */
  880. X       char type;        /* type of the field (T_*) */
  881. X       int offset;        /* where to store value */
  882. X       int dflt;        /* default value */
  883. X       };
  884. X
  885. Xunion nvtypes {            /* convert char* to/from FT_* */
  886. X    char    *nvchar;    /* FT_CHAR */
  887. X    int    *nvint;        /* FT_INT */
  888. X    long    *nvtime;    /* FT_TIME */
  889. X    char    **nvstring;    /* FT_STRING */
  890. X    struct mv *nvmove;    /* FT_MOVE */
  891. X    struct point *nvboard;    /* FT_BOARD */
  892. X    };
  893. X
  894. Xstruct flist {            /* list returned by filelist() */
  895. X    char    *name;        /* file name */
  896. X    struct flist *next;    /* forward link */
  897. X    };
  898. X
  899. Xstruct mv {
  900. X    char    roll;            /* # on 1 die, 0 = DOUBLE, -1=empty */
  901. X    char    pt;            /* point move is from, -1=UNUSED */
  902. X    };
  903. X
  904. Xstruct point {
  905. X    char    qty;            /* number of pieces on this point */
  906. X    char    color;            /* color of pieces on this point */
  907. X    };
  908. X
  909. Xtypedef struct point board[BOARDSIZE];    /* board is array of points */
  910. X
  911. Xstruct game {                /* all info about a game in progress */
  912. X    char    *gameid;        /* unique game id */
  913. X    char    *opaddr;        /* email path to opponent */
  914. X    char    *opname;        /* full name of opponent */
  915. X    char    *myaddr;        /* my address for this user */
  916. X    char    mycolor;        /* char to represent my pieces */
  917. X    char    opcolor;        /* opponent's pieces */
  918. X    char    mydir;            /* 1/-1 direction I am moving */
  919. X    char    opdir;            /* 1/-1 direction opponent is moving */
  920. X    int    gameval;        /* current value of game */
  921. X    int    adcnt;            /* current number of autodoubles */
  922. X    int    admax;            /* max autodoubles allowed */
  923. X    int    flags;            /* various flags (F_*) */
  924. X    int    opver;            /* opponent's ldb version */
  925. X    char    state;            /* my current state (ST_*) */
  926. X    char    term;            /* if game over, why (T_*) */
  927. X    int    seq;            /* sequence number of next pkt */
  928. X    int    lastop;            /* last opcode sent (for resends) */
  929. X    char    *mycmt;            /* comment I sent with last move */
  930. X    char    *mycmt2;        /* second line of mycmt */
  931. X    char    *opcmt;            /* comment I received with last move */
  932. X    char    *opcmt2;        /* second line of opcmt */
  933. X    char    *dispmsg;        /* msg to display when game drawn */
  934. X    struct mv opmvs[4];        /* opponent's last move */
  935. X    char    blot[4];        /* my blots that were hit */
  936. X    struct mv mvs[4];        /* my move, holds roll until I move */
  937. X    int    maxused;        /* # of rolls in mvs that can be used*/
  938. X    int    hiused;            /* highest roll that can be used */
  939. X    board    opbd;            /* board image before opmvs applied */
  940. X    board    mybd;            /* board before mvs (for Reset) */
  941. X    board    board;            /* current board image */
  942. X    char    curbd;            /* which brd is currently displayed */
  943. X    int    rolls[6];        /* how many of each roll we get */
  944. X    int    doubles[6];        /* how many of each double we get */
  945. X    int    oprolls[6];        /* how many of each roll op gets */
  946. X    int    opdoubles[6];        /* how many of each double op gets */
  947. X    long    starttime;        /* time START packet was sent */
  948. X    long    lastacc;        /* last time game was accessed */
  949. X    int    mcurrent[2];        /* current match scores for me & op */
  950. X    int    mtotal;            /* match score we are playing to */
  951. X    char    *notify;        /* address to mail to when game over */
  952. X    struct people *ppl;        /* side pointer to people record */
  953. X    struct game *prev;        /* back link in game list */
  954. X    struct game *next;        /* forward link in game list */
  955. X    };
  956. X
  957. Xstruct packet {
  958. X    int    version;        /* ldb version */
  959. X    long    timestamp;        /* time packet was sent */
  960. X    char    *gameid;        /* the gameid string */
  961. X    int    opcode;            /* operation being performed */
  962. X    char    *name;            /* name */
  963. X    char    *addr;            /* mail address */
  964. X    char    *comment;        /* comment received */
  965. X    char    *comment2;        /* second line of comment */
  966. X    int    seq;            /* sequence number */
  967. X    char    *colors;        /* colors of new game */
  968. X    char    *dir;            /* direction of game starter */
  969. X    char    *autodbl;        /* autodouble count (sprintf'ed) */
  970. X    struct mv mvs[4];        /* moves (if opcode == MOVE) */
  971. X    char    *jacoby;        /* yes=jacoby rule in effect */
  972. X    char    *crawford;        /* yes=crawford rule in effect */
  973. X    char    *european;        /* yes=european rule in effect */
  974. X    char    *perm;            /* yes=permanent game */
  975. X    char    *match;            /* number of points in match */
  976. X    char    *notify;        /* address to notify when game ends */
  977. X    struct game *gameptr;        /* not a pkt field, set by getpkt() */
  978. X    };
  979. X
  980. Xstruct people {                /* people we play with */
  981. X    char    *name;            /* person's name */
  982. X    char    *addr;            /* person's mail address */
  983. X    char    *alias;            /* person's nickname */
  984. X    char    *myaddr;        /* my addr for this person */
  985. X    int    newaddr;        /* new address to send?  see NA_* */
  986. X    char    *equiv;            /* equiv name for ppl w/ mult addr */
  987. X    int    opver;            /* opponent's ldb version */
  988. X    long    fence;            /* start time of newest finished game*/
  989. X    int    score[10];        /* won/lost record, see SC_* */
  990. X    struct people *next;        /* forward link */
  991. X    };
  992. X
  993. Xstruct legal {                /* list of legal moves */
  994. X    int nmove;            /* number of moves in this entry */
  995. X    int himove;            /* highest roll used in this entry */
  996. X    struct mv mvs[4];        /* the rolls and moves */
  997. X    struct legal *prev;        /* pointer to the previous entry */
  998. X    struct legal *next;        /* pointer to the previous entry */
  999. X    };
  1000. X
  1001. Xextern int Pflag;            /* should I process local input? */
  1002. Xextern int Rflag;            /* should I look for mail? */
  1003. Xextern struct game *ghead;        /* head of linked list of games */
  1004. Xextern struct game *gtail;        /* tail of linked list of games */
  1005. Xextern struct legal *lhead;        /* head of list of legal moves */
  1006. Xextern struct legal *ltail;        /* tail of list of legal moves */
  1007. Xextern int (*func[OPSTATES][NOP])();    /* receive state machine */
  1008. Xstruct ldbrc rc;            /* stuff from .ldbrc */
  1009. Xextern struct opt options[];        /* command line options */
  1010. Xextern char *rejlcl[];            /* error messages for local player */
  1011. Xextern char *rejmsg[];            /* error messages for received moves */
  1012. Xextern char *opcodes[];
  1013. Xextern char blk76[];            /* 76 blanks */
  1014. Xextern struct packet P;            /* last packet read */
  1015. Xextern char cr_mycolor;            /* my color when game is created */
  1016. Xextern char cr_opcolor;            /* opponent's color for new games */
  1017. Xextern char cr_mydir;            /* my direction for new games */
  1018. Xextern char *notify;            /* address to notify when game ends */
  1019. Xextern char *states[];            /* description of the states */
  1020. X
  1021. Xextern char FeIsActive;            /* front-end been initialized? */
  1022. Xextern char FeWaitInit;            /* non-0 if message() called */
  1023. Xextern int GameState;            /* Current game state for help */
  1024. Xextern int boardnums[3];        /* board name -> board number */
  1025. X
  1026. Xextern struct people *phead;        /* head pointer of people list */
  1027. X
  1028. Xextern struct namevalue nv_rcfile[], nv_gfile[], nv_packet[], nv_pfile[];
  1029. Xextern struct namevalue nv_pequiv[];
  1030. X
  1031. Xchar *tgetstr();
  1032. Xchar *save(), *makeid(), *calloc();
  1033. Xchar *nvscan(), *strchr(), *boardstr();
  1034. Xchar *strchr(), *strrchr();
  1035. Xstruct game *startgame(), *addgame(), *findgame();
  1036. X
  1037. Xstruct people *addppl(), *findppl(), *newppl();
  1038. X
  1039. Xint start(), istart(), tie(), restart(), mstart();
  1040. Xint opmove(), opofr(), opconc(), opacpt(), opdec();
  1041. Xint smerr();
  1042. X
  1043. Xlong rnd_ri();
  1044. X
  1045. Xchar FeMenu();
  1046. X
  1047. Xstruct flist *filelist();
  1048. END_OF_FILE
  1049. if test 18491 -ne `wc -c <'ldb.h'`; then
  1050.     echo shar: \"'ldb.h'\" unpacked with wrong size!
  1051. fi
  1052. # end of 'ldb.h'
  1053. fi
  1054. if test -f 'process.c' -a "${1}" != "-c" ; then 
  1055.   echo shar: Will not clobber existing file \"'process.c'\"
  1056. else
  1057. echo shar: Extracting \"'process.c'\" \(16183 characters\)
  1058. sed "s/^X//" >'process.c' <<'END_OF_FILE'
  1059. X/*    process.c        8/8/91
  1060. X *
  1061. X * Copyright 1991  Perry R. Ross
  1062. X *
  1063. X * Permission to use, copy, modify, and distribute this software and its
  1064. X * documentation without fee is hereby granted, subject to the restrictions
  1065. X * detailed in the README file, which is included here by reference.
  1066. X * Any other use requires written permission from the author.  This software
  1067. X * is distributed "as is" without any warranty, including any implied
  1068. X * warranties of merchantability or fitness for a particular purpose.
  1069. X * The author shall not be liable for any damages resulting from the
  1070. X * use of this software.  By using this software, the user agrees
  1071. X * to these terms.
  1072. X */
  1073. X
  1074. X#include "ldb.h"
  1075. X
  1076. X/*===========================================================================
  1077. X * This file contains the code to process user input.
  1078. X *===========================================================================
  1079. X */
  1080. X
  1081. X
  1082. X
  1083. X/*----------------------------------------------------------------------
  1084. X *    process -- process a game while it needs local input
  1085. X *
  1086. X * This function calls the appropriate handler, according to what
  1087. X * state the game is in, to prompt the user for input.  If a game
  1088. X * does not need local input, it is skipped.  Process() returns 1
  1089. X * if the game still needs local input, in which case the main program
  1090. X * will re-call process with the same game.  When the game no longer
  1091. X * needs local input, process will return 0, telling the main program
  1092. X * to proceed to the next game.
  1093. X *----------------------------------------------------------------------
  1094. X */
  1095. X
  1096. Xprocess(g)
  1097. Xstruct game *g;
  1098. X{
  1099. Xint i;
  1100. X
  1101. Xif (g->state < OPSTATES)    /* this game is waiting for the opponent */
  1102. X    return(0);        /* skip it for now */
  1103. Xif ( (g->state == ST_GAMEOVER) && (g->flags & F_DISPLAYED) )
  1104. X    return(0);    /* game is in "keepold" wait, no need to display */
  1105. XFeDrawGame(g);            /* draw the game */
  1106. Xswitch (g->state) {
  1107. Xcase ST_MYTURN:            /* my turn, I haven't rolled yet */
  1108. X    if ( ((g->flags & F_IDOUBLED) == 0) || (*rc.autoroll == 'n') ) {
  1109. X        i = myturn(g);    /* I didn't double last */
  1110. X        break;
  1111. X        }
  1112. X    rolldice(g);        /* if I doubled last, go ahead and roll */
  1113. X    g->state = ST_MYMOVE;    /* skip this state completely */
  1114. X    if (*rc.chkpt == 'y') {    /* checkpoint games */
  1115. X        writegames(rc.gfile,rc.gbackup,rc.pfile);
  1116. X        rc.gbackup = NULL;    /* only backup old file once */
  1117. X        }
  1118. X    for (i = 0; i < 4; i++)        /* draw my new roll */
  1119. X        FeDrawMove(g,WHO_ME,i);
  1120. X    /**** fall through ****/
  1121. Xcase ST_MYMOVE:            /* my turn, I have rolled */
  1122. X    i = mymove(g);        /* user has rolled, must move */
  1123. X    break;
  1124. Xcase ST_MYACCEPT:
  1125. X    i = myacpt(g);    /* user must accept or decline double */
  1126. X    break;
  1127. Xcase ST_GAMEOVER:
  1128. X    i = gameover(g);        /* tell him the game is over */
  1129. X    break;
  1130. X    }
  1131. Xreturn(i);
  1132. X}
  1133. X
  1134. X
  1135. X/*----------------------------------------------------------------------
  1136. X *    myturn -- allow user to roll or double
  1137. X *
  1138. X * This function is called to allow the user to choose between
  1139. X * rolling the dice and doubling.  It also allows the user to cycle
  1140. X * through the three board displays, to concede, and to go to the next game.
  1141. X *----------------------------------------------------------------------
  1142. X */
  1143. X
  1144. Xmyturn(g)
  1145. Xstruct game *g;
  1146. X{
  1147. Xchar c;
  1148. Xchar pm = '\0';
  1149. Xint gv;
  1150. Xstatic char *m[]={"Roll","Double","Board","Next Game","Concede","Quit",NULL};
  1151. X
  1152. XFeDrawMenu(m);            /* display the menu */
  1153. XGameState = STATE_MYTURN;
  1154. Xwhile (1) {
  1155. X    c = FeMenu(m,0,0,"\n\r ",pm);    /* get a menu choice */
  1156. X    pm = c;
  1157. X    switch (c) {
  1158. X    case '\n':
  1159. X    case '\r':
  1160. X    case ' ':
  1161. X        FeOnMenuItem(m,'R');    /* highlight Roll item */
  1162. X        pm = 'R';        /* remember to unhighlight it later */
  1163. X        /* fall through */
  1164. X    case 'R':            /* roll them dice */
  1165. X        g->curbd = BD_CUR;    /* bring up current board */
  1166. X        rolldice(g);
  1167. X        g->state = ST_MYMOVE;    /* I just entered a new state */
  1168. X        if (*rc.chkpt == 'y') {    /* checkpoint games */
  1169. X            writegames(rc.gfile,rc.gbackup,rc.pfile);
  1170. X            rc.gbackup = NULL;    /* only backup old file once */
  1171. X            }
  1172. X        return(1);        /* make sure process gets re-called */
  1173. X    case 'D':            /* I want to double */
  1174. X        if (g->flags & F_IDOUBLED) {    /* I doubled last */
  1175. X            FeMessage("You doubled last.");
  1176. X            break;        /* so I can't double now */
  1177. X            }
  1178. X        if (g->flags & F_CRGAME) {
  1179. X            FeMessage("Double not allowed (Crawford rule)");
  1180. X            break;
  1181. X            }
  1182. X        if (FeGetComment(g) < 0) {    /* get message */
  1183. X            FeMessage("Double aborted.");
  1184. X            break;        /* changed his mind */
  1185. X            }
  1186. X        g->state = ST_OPACCEPT;    /* we are waiting for accept/decline */
  1187. X        sendpkt(g,OFRDBL);    /* send the double packet */
  1188. X        return(0);        /* this game is done for now */
  1189. X    case 'C':            /* I'm wimping out */
  1190. X        if ( (check_concede(g) == 0) || (FeGetComment(g) < 0) ) {
  1191. X            FeMessage("Concede aborted.");
  1192. X            break;
  1193. X            }
  1194. X        ilose(g,T_ICONCEDE,0);    /* this game is over */
  1195. X        sendpkt(g,CONCEDE);    /* send the packet */
  1196. X        return(1);        /* display the gameover screen */
  1197. X    case 'B':            /* display different board */
  1198. X        if (g->curbd++ >= BD_CUR)    /* go to next board */
  1199. X            g->curbd = BD_BEFOP;    /* wrap around */
  1200. X        return(1);        /* redraw & call us again */
  1201. X    case 'N':            /* I don't want to decide right now */
  1202. X        return(0);
  1203. X    case 'Q':            /* I want to quit ldb */
  1204. X        return(-1);
  1205. X        }
  1206. X    }
  1207. X}
  1208. X
  1209. X
  1210. X/*----------------------------------------------------------------------
  1211. X *    mymove -- allow user to move
  1212. X *
  1213. X * This function is called to allow the user to use his roll.
  1214. X * It also allows the user to cycle through the three board displays,
  1215. X * to concede, and to go to the next game.
  1216. X * Since the user has already rolled, doubling is not allowed here.
  1217. X *----------------------------------------------------------------------
  1218. X */
  1219. X
  1220. Xmymove(g)
  1221. Xstruct game *g;
  1222. X{
  1223. Xchar c;
  1224. Xint i, n;
  1225. Xstatic char used[] = "That move is already used -- use Reset to start over";
  1226. Xstruct mv tmp;
  1227. Xstatic char *m[] = {"Reset","Send","Board","Next Game","Concede",
  1228. X            "Point","Off","Quit",NULL};
  1229. Xchar pm = '\0';
  1230. Xint lastpt = 99;        /* point last move started from */
  1231. Xint lastd = 99;            /* point last move ended at */
  1232. X
  1233. XFeDrawMenu(m);
  1234. XGameState = STATE_MYMOVE;
  1235. Xwhile (1) {
  1236. X    c = FeMenu(m,g->mvs[0].roll,g->mvs[1].roll,"\n\r ",pm);
  1237. X    pm = c;
  1238. X    switch (c) {
  1239. X    case 'S':            /* send moves */
  1240. X        if (checkused(g))    /* didn't use all our moves */
  1241. X            break;
  1242. X        if (FeGetComment(g) < 0) {    /* get our comment */
  1243. X            FeMessage("Send aborted.");
  1244. X            break;
  1245. X            }
  1246. X        if (g->board[OFFPT(g->mydir)].qty == 15)    /* I win */
  1247. X            iwin(g,T_IWIN,0);
  1248. X        else
  1249. X            g->state = ST_OPTURN;
  1250. X        sendpkt(g,MOVE);        /* send our move */
  1251. X        return(g->state == ST_GAMEOVER);/* need to call gameover() */
  1252. X    case 'R':            /* reset -- erase moves & start over */
  1253. X        if (g->curbd != BD_CUR)        /* if we are not looking at */
  1254. X            g->curbd = BD_CUR;    /* current board, switch */
  1255. X        for (i = 0; i < 4; i++) {
  1256. X            g->mvs[i].pt = -1;
  1257. X            FeDrawMove(g,WHO_ME,i);
  1258. X            }
  1259. X        copyboard(g->mybd,g->board);
  1260. X        FeDrawBoard(g->board,NULL,g->mydir,0,g->flags & F_INVERT);
  1261. X        FeLabelBoard(g);
  1262. X        FeDrawPip(g->board,g);
  1263. X        break;
  1264. X    case 'B':                /* display different board */
  1265. X        if (g->curbd++ >= BD_CUR)    /* go to next board */
  1266. X            g->curbd = BD_BEFOP;    /* wrap around */
  1267. X        return(1);        /* redraw & call us again */
  1268. X    case 'C':            /* I'm wimping out */
  1269. X        if ( (check_concede(g) == 0) || (FeGetComment(g) < 0) ) {
  1270. X            FeMessage("Concede aborted.");
  1271. X            break;
  1272. X            }
  1273. X        ilose(g,T_ICONCEDE,0);
  1274. X        sendpkt(g,CONCEDE);    /* send the packet */
  1275. X        return(1);        /* display the gameover screen */
  1276. X    case 'N':            /* I don't want to decide right now */
  1277. X        return(0);
  1278. X    case 'Q':            /* I want to quit ldb */
  1279. X        return(-1);
  1280. X    case ' ':            /* continue last move */
  1281. X        if (g->curbd != BD_CUR) {
  1282. X            g->curbd = BD_CUR;
  1283. X            FeDrawBoard(g->board,NULL,g->mydir,0,
  1284. X                g->flags & F_INVERT);
  1285. X            FeLabelBoard(g);
  1286. X            }
  1287. X        n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
  1288. X        for (i = 0; i < n; i++)        /* search for an unused move */
  1289. X            if (g->mvs[i].pt < 0)
  1290. X                break;
  1291. X        if (i >= n) {
  1292. X            FeMessage("You don't have any moves left.");
  1293. X            break;
  1294. X            }
  1295. X        if ( (lastd < 1) || (lastd > 24) ) {
  1296. X            FeMessage(
  1297. X               "No move to continue -- please select a roll.");
  1298. X            break;
  1299. X            }
  1300. X        g->mvs[i].pt = lastd;
  1301. X        n = apply(g,WHO_ME,i,A_REDRAW,&lastd);
  1302. X        if (n < 0) {    /* move rejected */
  1303. X            g->mvs[i].pt = -1;
  1304. X            FeMessage(rejlcl[-n]);
  1305. X            lastd = 99;
  1306. X            }
  1307. X        else
  1308. X            lastpt = g->mvs[i].pt;
  1309. X        FeDrawMove(g,WHO_ME,i);
  1310. X        FeCheckContact(g);
  1311. X        break;
  1312. X    case '\n':            /* repeat last move */
  1313. X    case '\r':
  1314. X        if (g->curbd != BD_CUR) {
  1315. X            g->curbd = BD_CUR;
  1316. X            FeDrawBoard(g->board,NULL,g->mydir,0,
  1317. X                g->flags & F_INVERT);
  1318. X            FeLabelBoard(g);
  1319. X            }
  1320. X        n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
  1321. X        for (i = 0; i < n; i++)        /* search for an unused move */
  1322. X            if (g->mvs[i].pt < 0)
  1323. X                break;
  1324. X        if (i >= n) {
  1325. X            FeMessage("You don't have any moves left.");
  1326. X            break;
  1327. X            }
  1328. X        if ( (lastpt < 0) || (lastpt > 25) ) {
  1329. X            FeMessage("No move to repeat -- please select a roll.");
  1330. X            break;
  1331. X            }
  1332. X        g->mvs[i].pt = lastpt;
  1333. X        n = apply(g,WHO_ME,i,A_REDRAW,&lastd);
  1334. X        if (n < 0) {    /* move rejected */
  1335. X            g->mvs[i].pt = -1;
  1336. X            FeMessage(rejlcl[-n]);
  1337. X            lastpt = 99;
  1338. X            }
  1339. X        FeDrawMove(g,WHO_ME,i);
  1340. X        FeCheckContact(g);
  1341. X        break;
  1342. X    case 'P':                /* make point from last move */
  1343. X        if (g->curbd != BD_CUR) {
  1344. X            g->curbd = BD_CUR;
  1345. X            FeDrawBoard(g->board,NULL,g->mydir,0,
  1346. X                g->flags & F_INVERT);
  1347. X            FeLabelBoard(g);
  1348. X            }
  1349. X        n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
  1350. X        for (i = 0; i < n; i++)        /* search for an unused move */
  1351. X            if (g->mvs[i].pt < 0)
  1352. X                break;
  1353. X        if (i >= n) {
  1354. X            FeMessage("You don't have any moves left.");
  1355. X            break;
  1356. X            }
  1357. X        if ( (lastpt < 0) || (lastpt > 25) ) {
  1358. X            FeMessage("No point to make -- please select a roll.");
  1359. X            break;
  1360. X            }
  1361. X        g->mvs[i].pt = lastd - g->mydir*g->mvs[i].roll;
  1362. X        n = apply(g,WHO_ME,i,A_REDRAW,&lastd);
  1363. X        if (n < 0) {    /* move rejected */
  1364. X            g->mvs[i].pt = -1;
  1365. X            FeMessage(rejlcl[-n]);
  1366. X            }
  1367. X        FeDrawMove(g,WHO_ME,i);
  1368. X        FeCheckContact(g);
  1369. X        break;
  1370. X    case 'O':                /* bear off with next roll */
  1371. X        if (g->curbd != BD_CUR) {
  1372. X            g->curbd = BD_CUR;
  1373. X            FeDrawBoard(g->board,NULL,g->mydir,0,
  1374. X                g->flags & F_INVERT);
  1375. X            FeLabelBoard(g);
  1376. X            }
  1377. X        n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
  1378. X        for (i = 0; i < n; i++)        /* search for an unused move */
  1379. X            if (g->mvs[i].pt < 0)
  1380. X                break;
  1381. X        if (i >= n) {
  1382. X            FeMessage("You don't have any moves left.");
  1383. X            break;
  1384. X            }
  1385. X        n = ( (g->mydir > 0) ? 25 : 0 ) - g->mydir*g->mvs[i].roll;
  1386. X        while ( (n > 0) && (n < 25) && ( (g->board[n].qty <= 0) ||
  1387. X           (g->board[n].color != g->mycolor) )  )
  1388. X            n += g->mydir;        /* search for occupied point */
  1389. X        if ( (n < 1) || (n > 24) ) {
  1390. X            FeMessage("You cannot bear off with that roll.");
  1391. X            break;
  1392. X            }
  1393. X        g->mvs[i].pt = n;
  1394. X        n = apply(g,WHO_ME,i,A_REDRAW,&lastd);
  1395. X        if (n < 0) {    /* move rejected */
  1396. X            g->mvs[i].pt = -1;
  1397. X            FeMessage(rejlcl[-n]);
  1398. X            }
  1399. X        FeDrawMove(g,WHO_ME,i);
  1400. X        FeCheckContact(g);
  1401. X        break;
  1402. X    case '1':
  1403. X    case '2':
  1404. X    case '3':
  1405. X    case '4':
  1406. X    case '5':
  1407. X    case '6':
  1408. X        if (g->curbd != BD_CUR) {
  1409. X            g->curbd = BD_CUR;
  1410. X            FeDrawBoard(g->board,NULL,g->mydir,0,
  1411. X                g->flags & F_INVERT);
  1412. X            FeLabelBoard(g);
  1413. X            }
  1414. X        c -= '0';
  1415. X        if ( (c == g->mvs[0].roll) && (c == g->mvs[1].roll) ) {
  1416. X            for (i = 0; i < 4; i++)        /* doubles */
  1417. X                if (g->mvs[i].pt < 0)
  1418. X                    break;
  1419. X            if (i == 4) {
  1420. X                FeMessage(used);
  1421. X                break;
  1422. X                }
  1423. X            }
  1424. X        else if (c == g->mvs[0].roll) {        /* used 1st move */
  1425. X            if (g->mvs[0].pt >= 0) {
  1426. X                FeMessage(used);
  1427. X                break;
  1428. X                }
  1429. X            i = 0;
  1430. X            }
  1431. X        else {
  1432. X            if (g->mvs[0].pt < 0) {    /* used 2nd move 1st */
  1433. X                tmp = g->mvs[0];    /* swap moves */
  1434. X                g->mvs[0] = g->mvs[1];
  1435. X                g->mvs[1] = tmp;
  1436. X                FeDrawMove(g,WHO_ME,0);
  1437. X                FeDrawMove(g,WHO_ME,1);
  1438. X                i = 0;
  1439. X                }
  1440. X            else if (g->mvs[1].pt >= 0) {    /* this move used? */
  1441. X                FeMessage(used);
  1442. X                break;
  1443. X                }
  1444. X            else
  1445. X                i = 1;
  1446. X            }
  1447. X        n = FeGetPoint(g,i,lastpt,lastd);
  1448. X        if (n >= 0) {
  1449. X            if (n > 25) {
  1450. X                FeMessage("Invalid point number");
  1451. X                FeDrawMove(g,WHO_ME,i);
  1452. X                break;
  1453. X                }
  1454. X            g->mvs[i].pt = n;
  1455. X            n = apply(g,WHO_ME,i,A_REDRAW,&lastd);
  1456. X            if (n < 0) {    /* move rejected */
  1457. X                g->mvs[i].pt = -1;
  1458. X                FeMessage(rejlcl[-n]);
  1459. X                }
  1460. X            else
  1461. X                lastpt = g->mvs[i].pt;
  1462. X            }
  1463. X        FeDrawMove(g,WHO_ME,i);
  1464. X        FeCheckContact(g);
  1465. X        break;
  1466. X    default:
  1467. X        FeMessage("Invalid command.");
  1468. X        break;
  1469. X        }
  1470. X    }
  1471. X}
  1472. X
  1473. X
  1474. X/*----------------------------------------------------------------------
  1475. X *    myacpt -- allow user to accept or decline double.
  1476. X *
  1477. X * This function allows the user to decide whether he
  1478. X * wants to accept or decline his opponent's double.
  1479. X * It also allows the user to cycle through the three board displays,
  1480. X * to concede, and to go to the next game.
  1481. X * Rolling and doubling are not allowed here.
  1482. X *----------------------------------------------------------------------
  1483. X */
  1484. X
  1485. Xmyacpt(g)
  1486. Xstruct game *g;
  1487. X{
  1488. Xchar c;
  1489. Xchar pm = '\0';
  1490. Xint gv;
  1491. Xstatic char *m[] = {"Accept","Decline","Board","Next Game","Quit",NULL};
  1492. X
  1493. XFeDrawMenu(m);
  1494. XGameState = STATE_MYACPT;
  1495. Xwhile (1) {
  1496. X    c = FeMenu(m,0,0,"",pm);
  1497. X    pm = c;
  1498. X    switch (c) {
  1499. X    case 'A':                /* I accepted */
  1500. X        if (FeGetComment(g) < 0) {        /* get message */
  1501. X            FeMessage("Accept aborted.");
  1502. X            break;
  1503. X            }
  1504. X        g->gameval *= 2;        /* the game value is doubled */
  1505. X        g->state = ST_OPTURN;        /* it's opponent's turn */
  1506. X        sendpkt(g,ACPTDBL);        /* send accept packet */
  1507. X        return(0);            /* done w/ this game for now */
  1508. X    case 'D':                /* I declined */
  1509. X        if (FeGetComment(g) < 0) {        /* get message */
  1510. X            FeMessage("Decline aborted.");
  1511. X            break;
  1512. X            }
  1513. X        ilose(g,T_IDECLINE,0);
  1514. X        sendpkt(g,DECDBL);        /* tell the opponent */
  1515. X        return(1);            /* call gameover() */
  1516. X    case 'B':                /* display different board */
  1517. X        if (g->curbd++ >= BD_CUR)    /* go to next board */
  1518. X            g->curbd = BD_BEFOP;    /* wrap around */
  1519. X        return(1);        /* redraw & call us again */
  1520. X    case 'N':
  1521. X        return(0);        /* I'm done with this game for now */
  1522. X    case 'Q':            /* I want to quit ldb */
  1523. X        return(-1);
  1524. X    default:
  1525. X        FeMessage("Invalid command.");
  1526. X        break;
  1527. X        }
  1528. X    }
  1529. X}
  1530. X
  1531. X
  1532. X/*----------------------------------------------------------------------
  1533. X *    gameover -- show game to user before it is deleted.
  1534. X *
  1535. X * This function displays a game that has just terminated.
  1536. X * It displays the final board, the reason the game ended, and the
  1537. X * number of points won or lost.  The game will be deleted by
  1538. X * writegames() when ldb exits.
  1539. X *----------------------------------------------------------------------
  1540. X */
  1541. X
  1542. Xgameover(g)
  1543. Xstruct game *g;
  1544. X{
  1545. Xchar c, c1, c2;
  1546. Xchar pm = '\0';
  1547. Xint i;
  1548. Xstatic char *m[] = {"Board","Next Game","Quit",NULL};
  1549. X
  1550. Xif (g->flags & F_DISPLAYED)        /* this game already displayed */
  1551. X    return(0);
  1552. XFeDrawMenu(m);
  1553. XGameState = STATE_GAMEOVER;
  1554. Xwhile (1) {
  1555. X    c = FeMenu(m,0,0,"\n\r ",pm);
  1556. X    pm = c;
  1557. X    switch (c) {
  1558. X    case 'B':                /* display different board */
  1559. X        if (g->curbd++ >= BD_CUR)    /* go to next board */
  1560. X            g->curbd = BD_BEFOP;    /* wrap around */
  1561. X        return(1);        /* redraw & call us again */
  1562. X    case ' ':
  1563. X    case '\r':
  1564. X    case '\n':
  1565. X        FeOnMenuItem(m,'N');    /* highlight Next Game item */
  1566. X        pm = 'N';        /* remember to unhighlight */
  1567. X        /* fall through */
  1568. X    case 'N':            /* delete game & go to next */
  1569. X        if ( (g->mcurrent[WHO_ME] < g->mtotal) &&
  1570. X             (g->mcurrent[WHO_OPP] < g->mtotal) ) {
  1571. X            g->state = ST_OPSTART;
  1572. X            if ( (g->term == T_ILOSE) || (g->term == T_OPCONCEDE)
  1573. X                 || (g->term == T_OPDECLINE) ) {
  1574. X                g->gameval = 1;    /* reset for next game */
  1575. X                g->adcnt = 0;
  1576. X                g->flags &= ~F_IDOUBLED;
  1577. X                g->term = 0;
  1578. X                clearmvs(g->mvs);
  1579. X                clearmvs(g->opmvs);
  1580. X                if (g->mydir > 0) {
  1581. X                    c1 = g->mycolor;
  1582. X                    c2 = g->opcolor;
  1583. X                    }
  1584. X                else {
  1585. X                    c1 = g->opcolor;
  1586. X                    c2 = g->mycolor;
  1587. X                    }
  1588. X                newboard(g->opbd,c1,c2);
  1589. X                newboard(g->mybd,c1,c2);
  1590. X                newboard(g->board,c1,c2);
  1591. X                for (i = 0; i < 6; i++) {
  1592. X                    g->rolls[i] = 0;
  1593. X                    g->doubles[i] = 0;
  1594. X                    g->oprolls[i] = 0;
  1595. X                    g->opdoubles[i] = 0;
  1596. X                    }
  1597. X                crawford_check(g);
  1598. X                g->mvs[0].roll = Rolldie();
  1599. X                sendpkt(g,MSTART);
  1600. X                }
  1601. X            }
  1602. X        else {
  1603. X            g->flags |= F_DISPLAYED;/* done looking at this game */
  1604. X            if (g->mtotal > 0) {    /* finished match */
  1605. X                if (g->term <= T_ILOSE)
  1606. X                    g->ppl->score[SC_MLOST]++;
  1607. X                else
  1608. X                    g->ppl->score[SC_MWON]++;
  1609. X                }
  1610. X            }
  1611. X        return(0);        /* I'm done looking at this game */
  1612. X    case 'Q':            /* delete game & quit */
  1613. X        return(-1);
  1614. X    default:
  1615. X        FeMessage("Invalid command.");
  1616. X        break;
  1617. X        }
  1618. X    }
  1619. X}
  1620. X
  1621. X
  1622. Xcheck_concede(g)
  1623. Xstruct game *g;
  1624. X{
  1625. Xint gv, bg;
  1626. Xchar *msg;
  1627. X
  1628. Xg->term = T_ICONCEDE;
  1629. Xbg = gvalue(g,&gv);
  1630. Xswitch (bg) {
  1631. Xcase 1:
  1632. X    msg = "This will score as a gammon.  Are you sure? [yn]";
  1633. X    break;
  1634. Xcase 2:
  1635. X    msg = "This will score as a backgammon.  Are you sure? [yn]";
  1636. X    break;
  1637. Xdefault:
  1638. X    msg = "Are you sure? [yn]";
  1639. X    break;
  1640. X    }
  1641. Xreturn(FeYesNo(msg));
  1642. X}
  1643. END_OF_FILE
  1644. if test 16183 -ne `wc -c <'process.c'`; then
  1645.     echo shar: \"'process.c'\" unpacked with wrong size!
  1646. fi
  1647. # end of 'process.c'
  1648. fi
  1649. echo shar: End of archive 4 \(of 12\).
  1650. cp /dev/null ark4isdone
  1651. MISSING=""
  1652. for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
  1653.     if test ! -f ark${I}isdone ; then
  1654.     MISSING="${MISSING} ${I}"
  1655.     fi
  1656. done
  1657. if test "${MISSING}" = "" ; then
  1658.     echo You have unpacked all 12 archives.
  1659.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1660. else
  1661.     echo You still need to unpack the following archives:
  1662.     echo "        " ${MISSING}
  1663. fi
  1664. ##  End of shell archive.
  1665. exit 0
  1666.  
  1667. exit 0 # Just in case...
  1668.