home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume28 / ldb / part03 / process.c next >
Encoding:
C/C++ Source or Header  |  1992-03-15  |  13.7 KB  |  481 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. FeDrawGame(g);            /* draw the game */
  46. switch (g->state) {
  47. case ST_MYTURN:            /* my turn, I haven't rolled yet */
  48.     if ( ((g->flags & F_IDOUBLED) == 0) || (*rc.autoroll == 'n') ) {
  49.         i = myturn(g);    /* I didn't double last */
  50.         break;
  51.         }
  52.     rolldice(g);        /* if I doubled last, go ahead and roll */
  53.     g->state = ST_MYMOVE;    /* skip this state completely */
  54.     if (*rc.chkpt == 'y') {    /* checkpoint games */
  55.         writegames(rc.gfile,rc.gbackup);
  56.         rc.gbackup = NULL;    /* only backup old file once */
  57.         }
  58.     for (i = 0; i < 4; i++)        /* draw my new roll */
  59.         FeDrawMove(g,1,i);
  60.     /**** fall through ****/
  61. case ST_MYMOVE:            /* my turn, I have rolled */
  62.     i = mymove(g);        /* user has rolled, must move */
  63.     break;
  64. case ST_MYACCEPT:
  65.     i = myacpt(g);    /* user must accept or decline double */
  66.     break;
  67. case ST_GAMEOVER:
  68.     i = gameover(g);        /* tell him the game is over */
  69.     break;
  70.     }
  71. if ( (i == 0) && (*rc.chkpt == 'y') ) {
  72.     writegames(rc.gfile,rc.gbackup);
  73.     rc.gbackup = NULL;    /* only backup old file once */
  74.     }
  75. return(i);
  76. }
  77.  
  78.  
  79. /*----------------------------------------------------------------------
  80.  *    myturn -- allow user to roll or double
  81.  *
  82.  * This function is called to allow the user to choose between
  83.  * rolling the dice and doubling.  It also allows the user to cycle
  84.  * through the three board displays, to concede, and to go to the next game.
  85.  *----------------------------------------------------------------------
  86.  */
  87.  
  88. myturn(g)
  89. struct game *g;
  90. {
  91. char c;
  92. static char *m[]={"Roll","Double","Board","Next Game","Concede","Quit",NULL};
  93.  
  94. FeDrawMenu(m);            /* display the menu */
  95. while (1) {
  96.     c = FeMenu(m,0,0,"\n\r ");    /* get a menu choice */
  97.     switch (c) {
  98.     case 'R':            /* roll them dice */
  99.     case '\n':
  100.     case '\r':
  101.     case ' ':
  102.         g->curbd = BD_CUR;    /* bring up current board */
  103.         rolldice(g);
  104.         g->state = ST_MYMOVE;    /* I just entered a new state */
  105.         if (*rc.chkpt == 'y') {    /* checkpoint games */
  106.             writegames(rc.gfile,rc.gbackup);
  107.             rc.gbackup = NULL;    /* only backup old file once */
  108.             }
  109.         return(1);        /* make sure process gets re-called */
  110.     case 'D':            /* I want to double */
  111.         if (g->flags & F_IDOUBLED) {    /* I doubled last */
  112.             FeMessage("You doubled last.");
  113.             break;        /* so I can't double now */
  114.             }
  115.         g->state = ST_OPACCEPT;    /* we are waiting for accept/decline */
  116.         FeGetComment(g);    /* get message */
  117.         sendpkt(g,OFRDBL);    /* send the double packet */
  118.         return(0);        /* this game is done for now */
  119.     case 'C':            /* I'm wimping out */
  120.         g->state = ST_GAMEOVER;    /* this game is over */
  121.         g->term = T_ICONCEDE;    /* this is why */
  122.         FeGetComment(g);    /* get message */
  123.         sendpkt(g,CONCEDE);    /* send the packet */
  124.         return(1);        /* display the gameover screen */
  125.     case 'B':            /* display different board */
  126.         if (g->curbd++ >= BD_CUR)    /* go to next board */
  127.             g->curbd = BD_BEFOP;    /* wrap around */
  128.         return(1);        /* redraw & call us again */
  129.     case 'N':            /* I don't want to decide right now */
  130.         return(0);
  131.     case 'Q':            /* I want to quit ldb */
  132.         return(-1);
  133.         }
  134.     }
  135. }
  136.  
  137.  
  138. /*----------------------------------------------------------------------
  139.  *    mymove -- allow user to move
  140.  *
  141.  * This function is called to allow the user to use his roll.
  142.  * It also allows the user to cycle through the three board displays,
  143.  * to concede, and to go to the next game.
  144.  * Since the user has already rolled, doubling is not allowed here.
  145.  *----------------------------------------------------------------------
  146.  */
  147.  
  148. mymove(g)
  149. struct game *g;
  150. {
  151. char c;
  152. int i, n;
  153. static char used[] = "That move is already used -- use Reset to start over";
  154. struct mv tmp;
  155. static char *m[] = {"Reset","Send","Board","Next Game","Concede",
  156.             "Point","Off","Quit",NULL};
  157. int lastpt = 99;        /* point last move started from */
  158. int lastd = 99;            /* point last move ended at */
  159.  
  160. FeDrawMenu(m);
  161. while (1) {
  162.     c = FeMenu(m,g->mvs[0].roll,g->mvs[1].roll,"\n\r ");
  163.     switch (c) {
  164.     case 'S':            /* send moves */
  165.         if (checkused(g))    /* didn't use all our moves */
  166.             break;
  167.         FeGetComment(g);    /* see if we're sending a comment */
  168.         sendpkt(g,MOVE);        /* send our move */
  169.         if (g->board[OFFPT(g->mydir)].qty == 15) {    /* I win */
  170.             g->state = ST_GAMEOVER;
  171.             g->term = T_IWIN;    /* now return 1 so that */
  172.             return(1);        /* gameover() gets called */
  173.             }
  174.         else {
  175.             g->state = ST_OPTURN;
  176.             return(0);
  177.             }
  178.     case 'R':            /* reset -- erase moves & start over */
  179.         if (g->curbd != BD_CUR)    {    /* if we are not looking at */
  180.             g->curbd = BD_CUR;    /* current board, switch */
  181.             FeLabelBoard(bdlabels[BD_CUR]);
  182.             }
  183.         for (i = 0; i < 4; i++) {
  184.             g->mvs[i].pt = -1;
  185.             FeDrawMove(g,1,i);
  186.             }
  187.         copyboard(g->mybd,g->board);
  188.         FeDrawBoard(g->board,NULL,g->mydir,0,g->flags & F_INVERT);
  189.         break;
  190.     case 'B':                /* display different board */
  191.         if (g->curbd++ >= BD_CUR)    /* go to next board */
  192.             g->curbd = BD_BEFOP;    /* wrap around */
  193.         return(1);        /* redraw & call us again */
  194.     case 'C':            /* I'm wimping out */
  195.         g->state = ST_GAMEOVER;    /* this game is over */
  196.         g->term = T_ICONCEDE;    /* this is why */
  197.         FeGetComment(g);    /* get message */
  198.         sendpkt(g,CONCEDE);    /* send the packet */
  199.         return(1);        /* display the gameover screen */
  200.     case 'N':            /* I don't want to decide right now */
  201.         return(0);
  202.     case 'Q':            /* I want to quit ldb */
  203.         return(-1);
  204.     case ' ':            /* continue last move */
  205.         if (g->curbd != BD_CUR) {
  206.             g->curbd = BD_CUR;
  207.             FeDrawBoard(g->board,NULL,g->mydir,0,
  208.                 g->flags & F_INVERT);
  209.             FeLabelBoard(bdlabels[BD_CUR]);
  210.             }
  211.         n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
  212.         for (i = 0; i < n; i++)        /* search for an unused move */
  213.             if (g->mvs[i].pt < 0)
  214.                 break;
  215.         if (i >= n) {
  216.             FeMessage("You don't have any moves left.");
  217.             break;
  218.             }
  219.         if ( (lastd < 1) || (lastd > 24) ) {
  220.             FeMessage(
  221.                "No move to continue -- please select a roll.");
  222.             break;
  223.             }
  224.         g->mvs[i].pt = lastd;
  225.         n = apply(g,1,i,A_REDRAW,&lastd);
  226.         if (n < 0) {    /* move rejected */
  227.             g->mvs[i].pt = -1;
  228.             FeMessage(rejmsg[-n]);
  229.             lastd = 99;
  230.             }
  231.         else
  232.             lastpt = g->mvs[i].pt;
  233.         FeDrawMove(g,1,i);
  234.         break;
  235.     case '\n':            /* repeat last move */
  236.     case '\r':
  237.         if (g->curbd != BD_CUR) {
  238.             g->curbd = BD_CUR;
  239.             FeDrawBoard(g->board,NULL,g->mydir,0,
  240.                 g->flags & F_INVERT);
  241.             FeLabelBoard(bdlabels[BD_CUR]);
  242.             }
  243.         n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
  244.         for (i = 0; i < n; i++)        /* search for an unused move */
  245.             if (g->mvs[i].pt < 0)
  246.                 break;
  247.         if (i >= n) {
  248.             FeMessage("You don't have any moves left.");
  249.             break;
  250.             }
  251.         if ( (lastpt < 0) || (lastpt > 25) ) {
  252.             FeMessage("No move to repeat -- please select a roll.");
  253.             break;
  254.             }
  255.         g->mvs[i].pt = lastpt;
  256.         n = apply(g,1,i,A_REDRAW,&lastd);
  257.         if (n < 0) {    /* move rejected */
  258.             g->mvs[i].pt = -1;
  259.             FeMessage(rejmsg[-n]);
  260.             lastpt = 99;
  261.             }
  262.         FeDrawMove(g,1,i);
  263.         break;
  264.     case 'P':                /* make point from last move */
  265.         if (g->curbd != BD_CUR) {
  266.             g->curbd = BD_CUR;
  267.             FeDrawBoard(g->board,NULL,g->mydir,0,
  268.                 g->flags & F_INVERT);
  269.             FeLabelBoard(bdlabels[BD_CUR]);
  270.             }
  271.         n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
  272.         for (i = 0; i < n; i++)        /* search for an unused move */
  273.             if (g->mvs[i].pt < 0)
  274.                 break;
  275.         if (i >= n) {
  276.             FeMessage("You don't have any moves left.");
  277.             break;
  278.             }
  279.         if ( (lastpt < 0) || (lastpt > 25) ) {
  280.             FeMessage("No point to make -- please select a roll.");
  281.             break;
  282.             }
  283.         g->mvs[i].pt = lastd - g->mydir*g->mvs[i].roll;
  284.         n = apply(g,1,i,A_REDRAW,&lastd);
  285.         if (n < 0) {    /* move rejected */
  286.             g->mvs[i].pt = -1;
  287.             FeMessage(rejmsg[-n]);
  288.             }
  289.         FeDrawMove(g,1,i);
  290.         break;
  291.     case 'O':                /* bear off with next roll */
  292.         if (g->curbd != BD_CUR) {
  293.             g->curbd = BD_CUR;
  294.             FeDrawBoard(g->board,NULL,g->mydir,0,
  295.                 g->flags & F_INVERT);
  296.             FeLabelBoard(bdlabels[BD_CUR]);
  297.             }
  298.         n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
  299.         for (i = 0; i < n; i++)        /* search for an unused move */
  300.             if (g->mvs[i].pt < 0)
  301.                 break;
  302.         if (i >= n) {
  303.             FeMessage("You don't have any moves left.");
  304.             break;
  305.             }
  306.         n = ( (g->mydir > 0) ? 25 : 0 ) - g->mydir*g->mvs[i].roll;
  307.         while ( (n > 0) && (n < 25) && ( (g->board[n].qty <= 0) ||
  308.            (g->board[n].color != g->mycolor) )  )
  309.             n += g->mydir;        /* search for occupied point */
  310.         if ( (n < 1) || (n > 24) ) {
  311.             FeMessage("You cannot bear off with that roll.");
  312.             break;
  313.             }
  314.         g->mvs[i].pt = n;
  315.         n = apply(g,1,i,A_REDRAW,&lastd);
  316.         if (n < 0) {    /* move rejected */
  317.             g->mvs[i].pt = -1;
  318.             FeMessage(rejmsg[-n]);
  319.             }
  320.         FeDrawMove(g,1,i);
  321.         break;
  322.     case '1':
  323.     case '2':
  324.     case '3':
  325.     case '4':
  326.     case '5':
  327.     case '6':
  328.         if (g->curbd != BD_CUR) {
  329.             g->curbd = BD_CUR;
  330.             FeDrawBoard(g->board,NULL,g->mydir,0,
  331.                 g->flags & F_INVERT);
  332.             FeLabelBoard(bdlabels[BD_CUR]);
  333.             }
  334.         c -= '0';
  335.         if ( (c == g->mvs[0].roll) && (c == g->mvs[1].roll) ) {
  336.             for (i = 0; i < 4; i++)        /* doubles */
  337.                 if (g->mvs[i].pt < 0)
  338.                     break;
  339.             if (i == 4) {
  340.                 FeMessage(used);
  341.                 break;
  342.                 }
  343.             }
  344.         else if (c == g->mvs[0].roll) {        /* used 1st move */
  345.             if (g->mvs[0].pt >= 0) {
  346.                 FeMessage(used);
  347.                 break;
  348.                 }
  349.             i = 0;
  350.             }
  351.         else {
  352.             if (g->mvs[0].pt < 0) {    /* used 2nd move 1st */
  353.                 tmp = g->mvs[0];    /* swap moves */
  354.                 g->mvs[0] = g->mvs[1];
  355.                 g->mvs[1] = tmp;
  356.                 FeDrawMove(g,1,0);
  357.                 FeDrawMove(g,1,1);
  358.                 i = 0;
  359.                 }
  360.             else if (g->mvs[1].pt >= 0) {    /* this move used? */
  361.                 FeMessage(used);
  362.                 break;
  363.                 }
  364.             else
  365.                 i = 1;
  366.             }
  367.         n = FeGetPoint(g,i,lastpt,lastd);
  368.         if (n >= 0) {
  369.             if (n > 25) {
  370.                 FeMessage("Invalid point number");
  371.                 FeDrawMove(g,1,i);
  372.                 break;
  373.                 }
  374.             g->mvs[i].pt = n;
  375.             n = apply(g,1,i,A_REDRAW,&lastd);
  376.             if (n < 0) {    /* move rejected */
  377.                 g->mvs[i].pt = -1;
  378.                 FeMessage(rejmsg[-n]);
  379.                 }
  380.             else
  381.                 lastpt = g->mvs[i].pt;
  382.             }
  383.         FeDrawMove(g,1,i);
  384.         break;
  385.     default:
  386.         FeMessage("Invalid command.");
  387.         break;
  388.         }
  389.     }
  390. }
  391.  
  392.  
  393. /*----------------------------------------------------------------------
  394.  *    myacpt -- allow user to accept or decline double.
  395.  *
  396.  * This function allows the user to decide whether he
  397.  * wants to accept or decline his opponent's double.
  398.  * It also allows the user to cycle through the three board displays,
  399.  * to concede, and to go to the next game.
  400.  * Rolling and doubling are not allowed here.
  401.  *----------------------------------------------------------------------
  402.  */
  403.  
  404. myacpt(g)
  405. struct game *g;
  406. {
  407. char c;
  408. static char *m[] = {"Accept","Decline","Board","Next Game","Quit",NULL};
  409.  
  410. FeDrawMenu(m);
  411. while (1) {
  412.     c = FeMenu(m,0,0,"");
  413.     switch (c) {
  414.     case 'A':                /* I accepted */
  415.         g->gameval *= 2;        /* the game value is doubled */
  416.         FeGetComment(g);        /* get message */
  417.         sendpkt(g,ACPTDBL);        /* send accept packet */
  418.         g->state = ST_OPTURN;        /* it's opponent's turn */
  419.         return(0);            /* done w/ this game for now */
  420.     case 'D':                /* I declined */
  421.         g->state = ST_GAMEOVER;        /* game is dead */
  422.         g->term = T_IDECLINE;        /* store the reason */
  423.         FeGetComment(g);        /* get message */
  424.         sendpkt(g,DECDBL);        /* tell the opponent */
  425.         return(1);            /* call gameover() */
  426.     case 'B':                /* display different board */
  427.         if (g->curbd++ >= BD_CUR)    /* go to next board */
  428.             g->curbd = BD_BEFOP;    /* wrap around */
  429.         return(1);        /* redraw & call us again */
  430.     case 'N':
  431.         return(0);        /* I'm done with this game for now */
  432.     case 'Q':            /* I want to quit ldb */
  433.         return(-1);
  434.     default:
  435.         FeMessage("Invalid command.");
  436.         break;
  437.         }
  438.     }
  439. }
  440.  
  441.  
  442. /*----------------------------------------------------------------------
  443.  *    gameover -- show game to user before it is deleted.
  444.  *
  445.  * This function displays a game that has just terminated.
  446.  * It displays the final board, the reason the game ended, and the
  447.  * number of points won or lost.  The game will be deleted by
  448.  * writegames() when ldb exits.
  449.  *----------------------------------------------------------------------
  450.  */
  451.  
  452. gameover(g)
  453. struct game *g;
  454. {
  455. char c;
  456. static char *m[] = {"Board","Next Game","Quit",NULL};
  457.  
  458. FeDrawMenu(m);
  459. while (1) {
  460.     c = FeMenu(m,0,0,"\n\r ");
  461.     switch (c) {
  462.     case 'B':                /* display different board */
  463.         if (g->curbd++ >= BD_CUR)    /* go to next board */
  464.             g->curbd = BD_BEFOP;    /* wrap around */
  465.         return(1);        /* redraw & call us again */
  466.     case 'N':            /* delete game & go to next */
  467.     case ' ':
  468.     case '\r':
  469.     case '\n':
  470.         g->flags |= F_DELETE;    /* tell writegames to delete game */
  471.         return(0);        /* I'm done looking at this game */
  472.     case 'Q':            /* delete game & quit */
  473.         g->flags |= F_DELETE;    /* tell writegames to delete game */
  474.         return(-1);
  475.     default:
  476.         FeMessage("Invalid command.");
  477.         break;
  478.         }
  479.     }
  480. }
  481.