home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume36 / ldb / part04 / process.c < prev   
Encoding:
C/C++ Source or Header  |  1993-04-11  |  15.8 KB  |  585 lines

  1. /*    process.c        8/8/91
  2.  *
  3.  * Copyright 1991  Perry R. Ross
  4.  *
  5.  * Permission to use, copy, modify, and distribute this software and its
  6.  * documentation without fee is hereby granted, subject to the restrictions
  7.  * detailed in the README file, which is included here by reference.
  8.  * Any other use requires written permission from the author.  This software
  9.  * is distributed "as is" without any warranty, including any implied
  10.  * warranties of merchantability or fitness for a particular purpose.
  11.  * The author shall not be liable for any damages resulting from the
  12.  * use of this software.  By using this software, the user agrees
  13.  * to these terms.
  14.  */
  15.  
  16. #include "ldb.h"
  17.  
  18. /*===========================================================================
  19.  * This file contains the code to process user input.
  20.  *===========================================================================
  21.  */
  22.  
  23.  
  24.  
  25. /*----------------------------------------------------------------------
  26.  *    process -- process a game while it needs local input
  27.  *
  28.  * This function calls the appropriate handler, according to what
  29.  * state the game is in, to prompt the user for input.  If a game
  30.  * does not need local input, it is skipped.  Process() returns 1
  31.  * if the game still needs local input, in which case the main program
  32.  * will re-call process with the same game.  When the game no longer
  33.  * needs local input, process will return 0, telling the main program
  34.  * to proceed to the next game.
  35.  *----------------------------------------------------------------------
  36.  */
  37.  
  38. process(g)
  39. struct game *g;
  40. {
  41. int i;
  42.  
  43. if (g->state < OPSTATES)    /* this game is waiting for the opponent */
  44.     return(0);        /* skip it for now */
  45. if ( (g->state == ST_GAMEOVER) && (g->flags & F_DISPLAYED) )
  46.     return(0);    /* game is in "keepold" wait, no need to display */
  47. FeDrawGame(g);            /* draw the game */
  48. switch (g->state) {
  49. case ST_MYTURN:            /* my turn, I haven't rolled yet */
  50.     if ( ((g->flags & F_IDOUBLED) == 0) || (*rc.autoroll == 'n') ) {
  51.         i = myturn(g);    /* I didn't double last */
  52.         break;
  53.         }
  54.     rolldice(g);        /* if I doubled last, go ahead and roll */
  55.     g->state = ST_MYMOVE;    /* skip this state completely */
  56.     if (*rc.chkpt == 'y') {    /* checkpoint games */
  57.         writegames(rc.gfile,rc.gbackup,rc.pfile);
  58.         rc.gbackup = NULL;    /* only backup old file once */
  59.         }
  60.     for (i = 0; i < 4; i++)        /* draw my new roll */
  61.         FeDrawMove(g,WHO_ME,i);
  62.     /**** fall through ****/
  63. case ST_MYMOVE:            /* my turn, I have rolled */
  64.     i = mymove(g);        /* user has rolled, must move */
  65.     break;
  66. case ST_MYACCEPT:
  67.     i = myacpt(g);    /* user must accept or decline double */
  68.     break;
  69. case ST_GAMEOVER:
  70.     i = gameover(g);        /* tell him the game is over */
  71.     break;
  72.     }
  73. return(i);
  74. }
  75.  
  76.  
  77. /*----------------------------------------------------------------------
  78.  *    myturn -- allow user to roll or double
  79.  *
  80.  * This function is called to allow the user to choose between
  81.  * rolling the dice and doubling.  It also allows the user to cycle
  82.  * through the three board displays, to concede, and to go to the next game.
  83.  *----------------------------------------------------------------------
  84.  */
  85.  
  86. myturn(g)
  87. struct game *g;
  88. {
  89. char c;
  90. char pm = '\0';
  91. int gv;
  92. static char *m[]={"Roll","Double","Board","Next Game","Concede","Quit",NULL};
  93.  
  94. FeDrawMenu(m);            /* display the menu */
  95. GameState = STATE_MYTURN;
  96. while (1) {
  97.     c = FeMenu(m,0,0,"\n\r ",pm);    /* get a menu choice */
  98.     pm = c;
  99.     switch (c) {
  100.     case '\n':
  101.     case '\r':
  102.     case ' ':
  103.         FeOnMenuItem(m,'R');    /* highlight Roll item */
  104.         pm = 'R';        /* remember to unhighlight it later */
  105.         /* fall through */
  106.     case 'R':            /* roll them dice */
  107.         g->curbd = BD_CUR;    /* bring up current board */
  108.         rolldice(g);
  109.         g->state = ST_MYMOVE;    /* I just entered a new state */
  110.         if (*rc.chkpt == 'y') {    /* checkpoint games */
  111.             writegames(rc.gfile,rc.gbackup,rc.pfile);
  112.             rc.gbackup = NULL;    /* only backup old file once */
  113.             }
  114.         return(1);        /* make sure process gets re-called */
  115.     case 'D':            /* I want to double */
  116.         if (g->flags & F_IDOUBLED) {    /* I doubled last */
  117.             FeMessage("You doubled last.");
  118.             break;        /* so I can't double now */
  119.             }
  120.         if (g->flags & F_CRGAME) {
  121.             FeMessage("Double not allowed (Crawford rule)");
  122.             break;
  123.             }
  124.         if (FeGetComment(g) < 0) {    /* get message */
  125.             FeMessage("Double aborted.");
  126.             break;        /* changed his mind */
  127.             }
  128.         g->state = ST_OPACCEPT;    /* we are waiting for accept/decline */
  129.         sendpkt(g,OFRDBL);    /* send the double packet */
  130.         return(0);        /* this game is done for now */
  131.     case 'C':            /* I'm wimping out */
  132.         if ( (check_concede(g) == 0) || (FeGetComment(g) < 0) ) {
  133.             FeMessage("Concede aborted.");
  134.             break;
  135.             }
  136.         ilose(g,T_ICONCEDE,0);    /* this game is over */
  137.         sendpkt(g,CONCEDE);    /* send the packet */
  138.         return(1);        /* display the gameover screen */
  139.     case 'B':            /* display different board */
  140.         if (g->curbd++ >= BD_CUR)    /* go to next board */
  141.             g->curbd = BD_BEFOP;    /* wrap around */
  142.         return(1);        /* redraw & call us again */
  143.     case 'N':            /* I don't want to decide right now */
  144.         return(0);
  145.     case 'Q':            /* I want to quit ldb */
  146.         return(-1);
  147.         }
  148.     }
  149. }
  150.  
  151.  
  152. /*----------------------------------------------------------------------
  153.  *    mymove -- allow user to move
  154.  *
  155.  * This function is called to allow the user to use his roll.
  156.  * It also allows the user to cycle through the three board displays,
  157.  * to concede, and to go to the next game.
  158.  * Since the user has already rolled, doubling is not allowed here.
  159.  *----------------------------------------------------------------------
  160.  */
  161.  
  162. mymove(g)
  163. struct game *g;
  164. {
  165. char c;
  166. int i, n;
  167. static char used[] = "That move is already used -- use Reset to start over";
  168. struct mv tmp;
  169. static char *m[] = {"Reset","Send","Board","Next Game","Concede",
  170.             "Point","Off","Quit",NULL};
  171. char pm = '\0';
  172. int lastpt = 99;        /* point last move started from */
  173. int lastd = 99;            /* point last move ended at */
  174.  
  175. FeDrawMenu(m);
  176. GameState = STATE_MYMOVE;
  177. while (1) {
  178.     c = FeMenu(m,g->mvs[0].roll,g->mvs[1].roll,"\n\r ",pm);
  179.     pm = c;
  180.     switch (c) {
  181.     case 'S':            /* send moves */
  182.         if (checkused(g))    /* didn't use all our moves */
  183.             break;
  184.         if (FeGetComment(g) < 0) {    /* get our comment */
  185.             FeMessage("Send aborted.");
  186.             break;
  187.             }
  188.         if (g->board[OFFPT(g->mydir)].qty == 15)    /* I win */
  189.             iwin(g,T_IWIN,0);
  190.         else
  191.             g->state = ST_OPTURN;
  192.         sendpkt(g,MOVE);        /* send our move */
  193.         return(g->state == ST_GAMEOVER);/* need to call gameover() */
  194.     case 'R':            /* reset -- erase moves & start over */
  195.         if (g->curbd != BD_CUR)        /* if we are not looking at */
  196.             g->curbd = BD_CUR;    /* current board, switch */
  197.         for (i = 0; i < 4; i++) {
  198.             g->mvs[i].pt = -1;
  199.             FeDrawMove(g,WHO_ME,i);
  200.             }
  201.         copyboard(g->mybd,g->board);
  202.         FeDrawBoard(g->board,NULL,g->mydir,0,g->flags & F_INVERT);
  203.         FeLabelBoard(g);
  204.         FeDrawPip(g->board,g);
  205.         break;
  206.     case 'B':                /* display different board */
  207.         if (g->curbd++ >= BD_CUR)    /* go to next board */
  208.             g->curbd = BD_BEFOP;    /* wrap around */
  209.         return(1);        /* redraw & call us again */
  210.     case 'C':            /* I'm wimping out */
  211.         if ( (check_concede(g) == 0) || (FeGetComment(g) < 0) ) {
  212.             FeMessage("Concede aborted.");
  213.             break;
  214.             }
  215.         ilose(g,T_ICONCEDE,0);
  216.         sendpkt(g,CONCEDE);    /* send the packet */
  217.         return(1);        /* display the gameover screen */
  218.     case 'N':            /* I don't want to decide right now */
  219.         return(0);
  220.     case 'Q':            /* I want to quit ldb */
  221.         return(-1);
  222.     case ' ':            /* continue last move */
  223.         if (g->curbd != BD_CUR) {
  224.             g->curbd = BD_CUR;
  225.             FeDrawBoard(g->board,NULL,g->mydir,0,
  226.                 g->flags & F_INVERT);
  227.             FeLabelBoard(g);
  228.             }
  229.         n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
  230.         for (i = 0; i < n; i++)        /* search for an unused move */
  231.             if (g->mvs[i].pt < 0)
  232.                 break;
  233.         if (i >= n) {
  234.             FeMessage("You don't have any moves left.");
  235.             break;
  236.             }
  237.         if ( (lastd < 1) || (lastd > 24) ) {
  238.             FeMessage(
  239.                "No move to continue -- please select a roll.");
  240.             break;
  241.             }
  242.         g->mvs[i].pt = lastd;
  243.         n = apply(g,WHO_ME,i,A_REDRAW,&lastd);
  244.         if (n < 0) {    /* move rejected */
  245.             g->mvs[i].pt = -1;
  246.             FeMessage(rejlcl[-n]);
  247.             lastd = 99;
  248.             }
  249.         else
  250.             lastpt = g->mvs[i].pt;
  251.         FeDrawMove(g,WHO_ME,i);
  252.         FeCheckContact(g);
  253.         break;
  254.     case '\n':            /* repeat last move */
  255.     case '\r':
  256.         if (g->curbd != BD_CUR) {
  257.             g->curbd = BD_CUR;
  258.             FeDrawBoard(g->board,NULL,g->mydir,0,
  259.                 g->flags & F_INVERT);
  260.             FeLabelBoard(g);
  261.             }
  262.         n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
  263.         for (i = 0; i < n; i++)        /* search for an unused move */
  264.             if (g->mvs[i].pt < 0)
  265.                 break;
  266.         if (i >= n) {
  267.             FeMessage("You don't have any moves left.");
  268.             break;
  269.             }
  270.         if ( (lastpt < 0) || (lastpt > 25) ) {
  271.             FeMessage("No move to repeat -- please select a roll.");
  272.             break;
  273.             }
  274.         g->mvs[i].pt = lastpt;
  275.         n = apply(g,WHO_ME,i,A_REDRAW,&lastd);
  276.         if (n < 0) {    /* move rejected */
  277.             g->mvs[i].pt = -1;
  278.             FeMessage(rejlcl[-n]);
  279.             lastpt = 99;
  280.             }
  281.         FeDrawMove(g,WHO_ME,i);
  282.         FeCheckContact(g);
  283.         break;
  284.     case 'P':                /* make point from last move */
  285.         if (g->curbd != BD_CUR) {
  286.             g->curbd = BD_CUR;
  287.             FeDrawBoard(g->board,NULL,g->mydir,0,
  288.                 g->flags & F_INVERT);
  289.             FeLabelBoard(g);
  290.             }
  291.         n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
  292.         for (i = 0; i < n; i++)        /* search for an unused move */
  293.             if (g->mvs[i].pt < 0)
  294.                 break;
  295.         if (i >= n) {
  296.             FeMessage("You don't have any moves left.");
  297.             break;
  298.             }
  299.         if ( (lastpt < 0) || (lastpt > 25) ) {
  300.             FeMessage("No point to make -- please select a roll.");
  301.             break;
  302.             }
  303.         g->mvs[i].pt = lastd - g->mydir*g->mvs[i].roll;
  304.         n = apply(g,WHO_ME,i,A_REDRAW,&lastd);
  305.         if (n < 0) {    /* move rejected */
  306.             g->mvs[i].pt = -1;
  307.             FeMessage(rejlcl[-n]);
  308.             }
  309.         FeDrawMove(g,WHO_ME,i);
  310.         FeCheckContact(g);
  311.         break;
  312.     case 'O':                /* bear off with next roll */
  313.         if (g->curbd != BD_CUR) {
  314.             g->curbd = BD_CUR;
  315.             FeDrawBoard(g->board,NULL,g->mydir,0,
  316.                 g->flags & F_INVERT);
  317.             FeLabelBoard(g);
  318.             }
  319.         n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
  320.         for (i = 0; i < n; i++)        /* search for an unused move */
  321.             if (g->mvs[i].pt < 0)
  322.                 break;
  323.         if (i >= n) {
  324.             FeMessage("You don't have any moves left.");
  325.             break;
  326.             }
  327.         n = ( (g->mydir > 0) ? 25 : 0 ) - g->mydir*g->mvs[i].roll;
  328.         while ( (n > 0) && (n < 25) && ( (g->board[n].qty <= 0) ||
  329.            (g->board[n].color != g->mycolor) )  )
  330.             n += g->mydir;        /* search for occupied point */
  331.         if ( (n < 1) || (n > 24) ) {
  332.             FeMessage("You cannot bear off with that roll.");
  333.             break;
  334.             }
  335.         g->mvs[i].pt = n;
  336.         n = apply(g,WHO_ME,i,A_REDRAW,&lastd);
  337.         if (n < 0) {    /* move rejected */
  338.             g->mvs[i].pt = -1;
  339.             FeMessage(rejlcl[-n]);
  340.             }
  341.         FeDrawMove(g,WHO_ME,i);
  342.         FeCheckContact(g);
  343.         break;
  344.     case '1':
  345.     case '2':
  346.     case '3':
  347.     case '4':
  348.     case '5':
  349.     case '6':
  350.         if (g->curbd != BD_CUR) {
  351.             g->curbd = BD_CUR;
  352.             FeDrawBoard(g->board,NULL,g->mydir,0,
  353.                 g->flags & F_INVERT);
  354.             FeLabelBoard(g);
  355.             }
  356.         c -= '0';
  357.         if ( (c == g->mvs[0].roll) && (c == g->mvs[1].roll) ) {
  358.             for (i = 0; i < 4; i++)        /* doubles */
  359.                 if (g->mvs[i].pt < 0)
  360.                     break;
  361.             if (i == 4) {
  362.                 FeMessage(used);
  363.                 break;
  364.                 }
  365.             }
  366.         else if (c == g->mvs[0].roll) {        /* used 1st move */
  367.             if (g->mvs[0].pt >= 0) {
  368.                 FeMessage(used);
  369.                 break;
  370.                 }
  371.             i = 0;
  372.             }
  373.         else {
  374.             if (g->mvs[0].pt < 0) {    /* used 2nd move 1st */
  375.                 tmp = g->mvs[0];    /* swap moves */
  376.                 g->mvs[0] = g->mvs[1];
  377.                 g->mvs[1] = tmp;
  378.                 FeDrawMove(g,WHO_ME,0);
  379.                 FeDrawMove(g,WHO_ME,1);
  380.                 i = 0;
  381.                 }
  382.             else if (g->mvs[1].pt >= 0) {    /* this move used? */
  383.                 FeMessage(used);
  384.                 break;
  385.                 }
  386.             else
  387.                 i = 1;
  388.             }
  389.         n = FeGetPoint(g,i,lastpt,lastd);
  390.         if (n >= 0) {
  391.             if (n > 25) {
  392.                 FeMessage("Invalid point number");
  393.                 FeDrawMove(g,WHO_ME,i);
  394.                 break;
  395.                 }
  396.             g->mvs[i].pt = n;
  397.             n = apply(g,WHO_ME,i,A_REDRAW,&lastd);
  398.             if (n < 0) {    /* move rejected */
  399.                 g->mvs[i].pt = -1;
  400.                 FeMessage(rejlcl[-n]);
  401.                 }
  402.             else
  403.                 lastpt = g->mvs[i].pt;
  404.             }
  405.         FeDrawMove(g,WHO_ME,i);
  406.         FeCheckContact(g);
  407.         break;
  408.     default:
  409.         FeMessage("Invalid command.");
  410.         break;
  411.         }
  412.     }
  413. }
  414.  
  415.  
  416. /*----------------------------------------------------------------------
  417.  *    myacpt -- allow user to accept or decline double.
  418.  *
  419.  * This function allows the user to decide whether he
  420.  * wants to accept or decline his opponent's double.
  421.  * It also allows the user to cycle through the three board displays,
  422.  * to concede, and to go to the next game.
  423.  * Rolling and doubling are not allowed here.
  424.  *----------------------------------------------------------------------
  425.  */
  426.  
  427. myacpt(g)
  428. struct game *g;
  429. {
  430. char c;
  431. char pm = '\0';
  432. int gv;
  433. static char *m[] = {"Accept","Decline","Board","Next Game","Quit",NULL};
  434.  
  435. FeDrawMenu(m);
  436. GameState = STATE_MYACPT;
  437. while (1) {
  438.     c = FeMenu(m,0,0,"",pm);
  439.     pm = c;
  440.     switch (c) {
  441.     case 'A':                /* I accepted */
  442.         if (FeGetComment(g) < 0) {        /* get message */
  443.             FeMessage("Accept aborted.");
  444.             break;
  445.             }
  446.         g->gameval *= 2;        /* the game value is doubled */
  447.         g->state = ST_OPTURN;        /* it's opponent's turn */
  448.         sendpkt(g,ACPTDBL);        /* send accept packet */
  449.         return(0);            /* done w/ this game for now */
  450.     case 'D':                /* I declined */
  451.         if (FeGetComment(g) < 0) {        /* get message */
  452.             FeMessage("Decline aborted.");
  453.             break;
  454.             }
  455.         ilose(g,T_IDECLINE,0);
  456.         sendpkt(g,DECDBL);        /* tell the opponent */
  457.         return(1);            /* call gameover() */
  458.     case 'B':                /* display different board */
  459.         if (g->curbd++ >= BD_CUR)    /* go to next board */
  460.             g->curbd = BD_BEFOP;    /* wrap around */
  461.         return(1);        /* redraw & call us again */
  462.     case 'N':
  463.         return(0);        /* I'm done with this game for now */
  464.     case 'Q':            /* I want to quit ldb */
  465.         return(-1);
  466.     default:
  467.         FeMessage("Invalid command.");
  468.         break;
  469.         }
  470.     }
  471. }
  472.  
  473.  
  474. /*----------------------------------------------------------------------
  475.  *    gameover -- show game to user before it is deleted.
  476.  *
  477.  * This function displays a game that has just terminated.
  478.  * It displays the final board, the reason the game ended, and the
  479.  * number of points won or lost.  The game will be deleted by
  480.  * writegames() when ldb exits.
  481.  *----------------------------------------------------------------------
  482.  */
  483.  
  484. gameover(g)
  485. struct game *g;
  486. {
  487. char c, c1, c2;
  488. char pm = '\0';
  489. int i;
  490. static char *m[] = {"Board","Next Game","Quit",NULL};
  491.  
  492. if (g->flags & F_DISPLAYED)        /* this game already displayed */
  493.     return(0);
  494. FeDrawMenu(m);
  495. GameState = STATE_GAMEOVER;
  496. while (1) {
  497.     c = FeMenu(m,0,0,"\n\r ",pm);
  498.     pm = c;
  499.     switch (c) {
  500.     case 'B':                /* display different board */
  501.         if (g->curbd++ >= BD_CUR)    /* go to next board */
  502.             g->curbd = BD_BEFOP;    /* wrap around */
  503.         return(1);        /* redraw & call us again */
  504.     case ' ':
  505.     case '\r':
  506.     case '\n':
  507.         FeOnMenuItem(m,'N');    /* highlight Next Game item */
  508.         pm = 'N';        /* remember to unhighlight */
  509.         /* fall through */
  510.     case 'N':            /* delete game & go to next */
  511.         if ( (g->mcurrent[WHO_ME] < g->mtotal) &&
  512.              (g->mcurrent[WHO_OPP] < g->mtotal) ) {
  513.             g->state = ST_OPSTART;
  514.             if ( (g->term == T_ILOSE) || (g->term == T_OPCONCEDE)
  515.                  || (g->term == T_OPDECLINE) ) {
  516.                 g->gameval = 1;    /* reset for next game */
  517.                 g->adcnt = 0;
  518.                 g->flags &= ~F_IDOUBLED;
  519.                 g->term = 0;
  520.                 clearmvs(g->mvs);
  521.                 clearmvs(g->opmvs);
  522.                 if (g->mydir > 0) {
  523.                     c1 = g->mycolor;
  524.                     c2 = g->opcolor;
  525.                     }
  526.                 else {
  527.                     c1 = g->opcolor;
  528.                     c2 = g->mycolor;
  529.                     }
  530.                 newboard(g->opbd,c1,c2);
  531.                 newboard(g->mybd,c1,c2);
  532.                 newboard(g->board,c1,c2);
  533.                 for (i = 0; i < 6; i++) {
  534.                     g->rolls[i] = 0;
  535.                     g->doubles[i] = 0;
  536.                     g->oprolls[i] = 0;
  537.                     g->opdoubles[i] = 0;
  538.                     }
  539.                 crawford_check(g);
  540.                 g->mvs[0].roll = Rolldie();
  541.                 sendpkt(g,MSTART);
  542.                 }
  543.             }
  544.         else {
  545.             g->flags |= F_DISPLAYED;/* done looking at this game */
  546.             if (g->mtotal > 0) {    /* finished match */
  547.                 if (g->term <= T_ILOSE)
  548.                     g->ppl->score[SC_MLOST]++;
  549.                 else
  550.                     g->ppl->score[SC_MWON]++;
  551.                 }
  552.             }
  553.         return(0);        /* I'm done looking at this game */
  554.     case 'Q':            /* delete game & quit */
  555.         return(-1);
  556.     default:
  557.         FeMessage("Invalid command.");
  558.         break;
  559.         }
  560.     }
  561. }
  562.  
  563.  
  564. check_concede(g)
  565. struct game *g;
  566. {
  567. int gv, bg;
  568. char *msg;
  569.  
  570. g->term = T_ICONCEDE;
  571. bg = gvalue(g,&gv);
  572. switch (bg) {
  573. case 1:
  574.     msg = "This will score as a gammon.  Are you sure? [yn]";
  575.     break;
  576. case 2:
  577.     msg = "This will score as a backgammon.  Are you sure? [yn]";
  578.     break;
  579. default:
  580.     msg = "Are you sure? [yn]";
  581.     break;
  582.     }
  583. return(FeYesNo(msg));
  584. }
  585.