home *** CD-ROM | disk | FTP | other *** search
- /* process.c 8/8/91
- *
- * Copyright 1991 Perry R. Ross
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation without fee is hereby granted, subject to the restrictions
- * detailed in the README file, which is included here by reference.
- * Any other use requires written permission from the author. This software
- * is distributed "as is" without any warranty, including any implied
- * warranties of merchantability or fitness for a particular purpose.
- * The author shall not be liable for any damages resulting from the
- * use of this software. By using this software, the user agrees
- * to these terms.
- */
-
- #include "ldb.h"
-
- /*===========================================================================
- * This file contains the code to process user input.
- *===========================================================================
- */
-
-
-
- /*----------------------------------------------------------------------
- * process -- process a game while it needs local input
- *
- * This function calls the appropriate handler, according to what
- * state the game is in, to prompt the user for input. If a game
- * does not need local input, it is skipped. Process() returns 1
- * if the game still needs local input, in which case the main program
- * will re-call process with the same game. When the game no longer
- * needs local input, process will return 0, telling the main program
- * to proceed to the next game.
- *----------------------------------------------------------------------
- */
-
- process(g)
- struct game *g;
- {
- int i;
-
- if (g->state < OPSTATES) /* this game is waiting for the opponent */
- return(0); /* skip it for now */
- FeDrawGame(g); /* draw the game */
- switch (g->state) {
- case ST_MYTURN: /* my turn, I haven't rolled yet */
- if ( ((g->flags & F_IDOUBLED) == 0) || (*rc.autoroll == 'n') ) {
- i = myturn(g); /* I didn't double last */
- break;
- }
- rolldice(g); /* if I doubled last, go ahead and roll */
- g->state = ST_MYMOVE; /* skip this state completely */
- if (*rc.chkpt == 'y') { /* checkpoint games */
- writegames(rc.gfile,rc.gbackup);
- rc.gbackup = NULL; /* only backup old file once */
- }
- for (i = 0; i < 4; i++) /* draw my new roll */
- FeDrawMove(g,1,i);
- /**** fall through ****/
- case ST_MYMOVE: /* my turn, I have rolled */
- i = mymove(g); /* user has rolled, must move */
- break;
- case ST_MYACCEPT:
- i = myacpt(g); /* user must accept or decline double */
- break;
- case ST_GAMEOVER:
- i = gameover(g); /* tell him the game is over */
- break;
- }
- if ( (i == 0) && (*rc.chkpt == 'y') ) {
- writegames(rc.gfile,rc.gbackup);
- rc.gbackup = NULL; /* only backup old file once */
- }
- return(i);
- }
-
-
- /*----------------------------------------------------------------------
- * myturn -- allow user to roll or double
- *
- * This function is called to allow the user to choose between
- * rolling the dice and doubling. It also allows the user to cycle
- * through the three board displays, to concede, and to go to the next game.
- *----------------------------------------------------------------------
- */
-
- myturn(g)
- struct game *g;
- {
- char c;
- static char *m[]={"Roll","Double","Board","Next Game","Concede","Quit",NULL};
-
- FeDrawMenu(m); /* display the menu */
- while (1) {
- c = FeMenu(m,0,0,"\n\r "); /* get a menu choice */
- switch (c) {
- case 'R': /* roll them dice */
- case '\n':
- case '\r':
- case ' ':
- g->curbd = BD_CUR; /* bring up current board */
- rolldice(g);
- g->state = ST_MYMOVE; /* I just entered a new state */
- if (*rc.chkpt == 'y') { /* checkpoint games */
- writegames(rc.gfile,rc.gbackup);
- rc.gbackup = NULL; /* only backup old file once */
- }
- return(1); /* make sure process gets re-called */
- case 'D': /* I want to double */
- if (g->flags & F_IDOUBLED) { /* I doubled last */
- FeMessage("You doubled last.");
- break; /* so I can't double now */
- }
- g->state = ST_OPACCEPT; /* we are waiting for accept/decline */
- FeGetComment(g); /* get message */
- sendpkt(g,OFRDBL); /* send the double packet */
- return(0); /* this game is done for now */
- case 'C': /* I'm wimping out */
- g->state = ST_GAMEOVER; /* this game is over */
- g->term = T_ICONCEDE; /* this is why */
- FeGetComment(g); /* get message */
- sendpkt(g,CONCEDE); /* send the packet */
- return(1); /* display the gameover screen */
- case 'B': /* display different board */
- if (g->curbd++ >= BD_CUR) /* go to next board */
- g->curbd = BD_BEFOP; /* wrap around */
- return(1); /* redraw & call us again */
- case 'N': /* I don't want to decide right now */
- return(0);
- case 'Q': /* I want to quit ldb */
- return(-1);
- }
- }
- }
-
-
- /*----------------------------------------------------------------------
- * mymove -- allow user to move
- *
- * This function is called to allow the user to use his roll.
- * It also allows the user to cycle through the three board displays,
- * to concede, and to go to the next game.
- * Since the user has already rolled, doubling is not allowed here.
- *----------------------------------------------------------------------
- */
-
- mymove(g)
- struct game *g;
- {
- char c;
- int i, n;
- static char used[] = "That move is already used -- use Reset to start over";
- struct mv tmp;
- static char *m[] = {"Reset","Send","Board","Next Game","Concede",
- "Point","Off","Quit",NULL};
- int lastpt = 99; /* point last move started from */
- int lastd = 99; /* point last move ended at */
-
- FeDrawMenu(m);
- while (1) {
- c = FeMenu(m,g->mvs[0].roll,g->mvs[1].roll,"\n\r ");
- switch (c) {
- case 'S': /* send moves */
- if (checkused(g)) /* didn't use all our moves */
- break;
- FeGetComment(g); /* see if we're sending a comment */
- sendpkt(g,MOVE); /* send our move */
- if (g->board[OFFPT(g->mydir)].qty == 15) { /* I win */
- g->state = ST_GAMEOVER;
- g->term = T_IWIN; /* now return 1 so that */
- return(1); /* gameover() gets called */
- }
- else {
- g->state = ST_OPTURN;
- return(0);
- }
- case 'R': /* reset -- erase moves & start over */
- if (g->curbd != BD_CUR) { /* if we are not looking at */
- g->curbd = BD_CUR; /* current board, switch */
- FeLabelBoard(bdlabels[BD_CUR]);
- }
- for (i = 0; i < 4; i++) {
- g->mvs[i].pt = -1;
- FeDrawMove(g,1,i);
- }
- copyboard(g->mybd,g->board);
- FeDrawBoard(g->board,NULL,g->mydir,0,g->flags & F_INVERT);
- break;
- case 'B': /* display different board */
- if (g->curbd++ >= BD_CUR) /* go to next board */
- g->curbd = BD_BEFOP; /* wrap around */
- return(1); /* redraw & call us again */
- case 'C': /* I'm wimping out */
- g->state = ST_GAMEOVER; /* this game is over */
- g->term = T_ICONCEDE; /* this is why */
- FeGetComment(g); /* get message */
- sendpkt(g,CONCEDE); /* send the packet */
- return(1); /* display the gameover screen */
- case 'N': /* I don't want to decide right now */
- return(0);
- case 'Q': /* I want to quit ldb */
- return(-1);
- case ' ': /* continue last move */
- if (g->curbd != BD_CUR) {
- g->curbd = BD_CUR;
- FeDrawBoard(g->board,NULL,g->mydir,0,
- g->flags & F_INVERT);
- FeLabelBoard(bdlabels[BD_CUR]);
- }
- n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
- for (i = 0; i < n; i++) /* search for an unused move */
- if (g->mvs[i].pt < 0)
- break;
- if (i >= n) {
- FeMessage("You don't have any moves left.");
- break;
- }
- if ( (lastd < 1) || (lastd > 24) ) {
- FeMessage(
- "No move to continue -- please select a roll.");
- break;
- }
- g->mvs[i].pt = lastd;
- n = apply(g,1,i,A_REDRAW,&lastd);
- if (n < 0) { /* move rejected */
- g->mvs[i].pt = -1;
- FeMessage(rejmsg[-n]);
- lastd = 99;
- }
- else
- lastpt = g->mvs[i].pt;
- FeDrawMove(g,1,i);
- break;
- case '\n': /* repeat last move */
- case '\r':
- if (g->curbd != BD_CUR) {
- g->curbd = BD_CUR;
- FeDrawBoard(g->board,NULL,g->mydir,0,
- g->flags & F_INVERT);
- FeLabelBoard(bdlabels[BD_CUR]);
- }
- n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
- for (i = 0; i < n; i++) /* search for an unused move */
- if (g->mvs[i].pt < 0)
- break;
- if (i >= n) {
- FeMessage("You don't have any moves left.");
- break;
- }
- if ( (lastpt < 0) || (lastpt > 25) ) {
- FeMessage("No move to repeat -- please select a roll.");
- break;
- }
- g->mvs[i].pt = lastpt;
- n = apply(g,1,i,A_REDRAW,&lastd);
- if (n < 0) { /* move rejected */
- g->mvs[i].pt = -1;
- FeMessage(rejmsg[-n]);
- lastpt = 99;
- }
- FeDrawMove(g,1,i);
- break;
- case 'P': /* make point from last move */
- if (g->curbd != BD_CUR) {
- g->curbd = BD_CUR;
- FeDrawBoard(g->board,NULL,g->mydir,0,
- g->flags & F_INVERT);
- FeLabelBoard(bdlabels[BD_CUR]);
- }
- n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
- for (i = 0; i < n; i++) /* search for an unused move */
- if (g->mvs[i].pt < 0)
- break;
- if (i >= n) {
- FeMessage("You don't have any moves left.");
- break;
- }
- if ( (lastpt < 0) || (lastpt > 25) ) {
- FeMessage("No point to make -- please select a roll.");
- break;
- }
- g->mvs[i].pt = lastd - g->mydir*g->mvs[i].roll;
- n = apply(g,1,i,A_REDRAW,&lastd);
- if (n < 0) { /* move rejected */
- g->mvs[i].pt = -1;
- FeMessage(rejmsg[-n]);
- }
- FeDrawMove(g,1,i);
- break;
- case 'O': /* bear off with next roll */
- if (g->curbd != BD_CUR) {
- g->curbd = BD_CUR;
- FeDrawBoard(g->board,NULL,g->mydir,0,
- g->flags & F_INVERT);
- FeLabelBoard(bdlabels[BD_CUR]);
- }
- n = (g->mvs[0].roll == g->mvs[1].roll) ? 4 : 2;
- for (i = 0; i < n; i++) /* search for an unused move */
- if (g->mvs[i].pt < 0)
- break;
- if (i >= n) {
- FeMessage("You don't have any moves left.");
- break;
- }
- n = ( (g->mydir > 0) ? 25 : 0 ) - g->mydir*g->mvs[i].roll;
- while ( (n > 0) && (n < 25) && ( (g->board[n].qty <= 0) ||
- (g->board[n].color != g->mycolor) ) )
- n += g->mydir; /* search for occupied point */
- if ( (n < 1) || (n > 24) ) {
- FeMessage("You cannot bear off with that roll.");
- break;
- }
- g->mvs[i].pt = n;
- n = apply(g,1,i,A_REDRAW,&lastd);
- if (n < 0) { /* move rejected */
- g->mvs[i].pt = -1;
- FeMessage(rejmsg[-n]);
- }
- FeDrawMove(g,1,i);
- break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- if (g->curbd != BD_CUR) {
- g->curbd = BD_CUR;
- FeDrawBoard(g->board,NULL,g->mydir,0,
- g->flags & F_INVERT);
- FeLabelBoard(bdlabels[BD_CUR]);
- }
- c -= '0';
- if ( (c == g->mvs[0].roll) && (c == g->mvs[1].roll) ) {
- for (i = 0; i < 4; i++) /* doubles */
- if (g->mvs[i].pt < 0)
- break;
- if (i == 4) {
- FeMessage(used);
- break;
- }
- }
- else if (c == g->mvs[0].roll) { /* used 1st move */
- if (g->mvs[0].pt >= 0) {
- FeMessage(used);
- break;
- }
- i = 0;
- }
- else {
- if (g->mvs[0].pt < 0) { /* used 2nd move 1st */
- tmp = g->mvs[0]; /* swap moves */
- g->mvs[0] = g->mvs[1];
- g->mvs[1] = tmp;
- FeDrawMove(g,1,0);
- FeDrawMove(g,1,1);
- i = 0;
- }
- else if (g->mvs[1].pt >= 0) { /* this move used? */
- FeMessage(used);
- break;
- }
- else
- i = 1;
- }
- n = FeGetPoint(g,i,lastpt,lastd);
- if (n >= 0) {
- if (n > 25) {
- FeMessage("Invalid point number");
- FeDrawMove(g,1,i);
- break;
- }
- g->mvs[i].pt = n;
- n = apply(g,1,i,A_REDRAW,&lastd);
- if (n < 0) { /* move rejected */
- g->mvs[i].pt = -1;
- FeMessage(rejmsg[-n]);
- }
- else
- lastpt = g->mvs[i].pt;
- }
- FeDrawMove(g,1,i);
- break;
- default:
- FeMessage("Invalid command.");
- break;
- }
- }
- }
-
-
- /*----------------------------------------------------------------------
- * myacpt -- allow user to accept or decline double.
- *
- * This function allows the user to decide whether he
- * wants to accept or decline his opponent's double.
- * It also allows the user to cycle through the three board displays,
- * to concede, and to go to the next game.
- * Rolling and doubling are not allowed here.
- *----------------------------------------------------------------------
- */
-
- myacpt(g)
- struct game *g;
- {
- char c;
- static char *m[] = {"Accept","Decline","Board","Next Game","Quit",NULL};
-
- FeDrawMenu(m);
- while (1) {
- c = FeMenu(m,0,0,"");
- switch (c) {
- case 'A': /* I accepted */
- g->gameval *= 2; /* the game value is doubled */
- FeGetComment(g); /* get message */
- sendpkt(g,ACPTDBL); /* send accept packet */
- g->state = ST_OPTURN; /* it's opponent's turn */
- return(0); /* done w/ this game for now */
- case 'D': /* I declined */
- g->state = ST_GAMEOVER; /* game is dead */
- g->term = T_IDECLINE; /* store the reason */
- FeGetComment(g); /* get message */
- sendpkt(g,DECDBL); /* tell the opponent */
- return(1); /* call gameover() */
- case 'B': /* display different board */
- if (g->curbd++ >= BD_CUR) /* go to next board */
- g->curbd = BD_BEFOP; /* wrap around */
- return(1); /* redraw & call us again */
- case 'N':
- return(0); /* I'm done with this game for now */
- case 'Q': /* I want to quit ldb */
- return(-1);
- default:
- FeMessage("Invalid command.");
- break;
- }
- }
- }
-
-
- /*----------------------------------------------------------------------
- * gameover -- show game to user before it is deleted.
- *
- * This function displays a game that has just terminated.
- * It displays the final board, the reason the game ended, and the
- * number of points won or lost. The game will be deleted by
- * writegames() when ldb exits.
- *----------------------------------------------------------------------
- */
-
- gameover(g)
- struct game *g;
- {
- char c;
- static char *m[] = {"Board","Next Game","Quit",NULL};
-
- FeDrawMenu(m);
- while (1) {
- c = FeMenu(m,0,0,"\n\r ");
- switch (c) {
- case 'B': /* display different board */
- if (g->curbd++ >= BD_CUR) /* go to next board */
- g->curbd = BD_BEFOP; /* wrap around */
- return(1); /* redraw & call us again */
- case 'N': /* delete game & go to next */
- case ' ':
- case '\r':
- case '\n':
- g->flags |= F_DELETE; /* tell writegames to delete game */
- return(0); /* I'm done looking at this game */
- case 'Q': /* delete game & quit */
- g->flags |= F_DELETE; /* tell writegames to delete game */
- return(-1);
- default:
- FeMessage("Invalid command.");
- break;
- }
- }
- }
-