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 */
- if ( (g->state == ST_GAMEOVER) && (g->flags & F_DISPLAYED) )
- return(0); /* game is in "keepold" wait, no need to display */
- 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.pfile);
- rc.gbackup = NULL; /* only backup old file once */
- }
- for (i = 0; i < 4; i++) /* draw my new roll */
- FeDrawMove(g,WHO_ME,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;
- }
- 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;
- char pm = '\0';
- int gv;
- static char *m[]={"Roll","Double","Board","Next Game","Concede","Quit",NULL};
-
- FeDrawMenu(m); /* display the menu */
- GameState = STATE_MYTURN;
- while (1) {
- c = FeMenu(m,0,0,"\n\r ",pm); /* get a menu choice */
- pm = c;
- switch (c) {
- case '\n':
- case '\r':
- case ' ':
- FeOnMenuItem(m,'R'); /* highlight Roll item */
- pm = 'R'; /* remember to unhighlight it later */
- /* fall through */
- case 'R': /* roll them dice */
- 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.pfile);
- 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 */
- }
- if (g->flags & F_CRGAME) {
- FeMessage("Double not allowed (Crawford rule)");
- break;
- }
- if (FeGetComment(g) < 0) { /* get message */
- FeMessage("Double aborted.");
- break; /* changed his mind */
- }
- g->state = ST_OPACCEPT; /* we are waiting for accept/decline */
- sendpkt(g,OFRDBL); /* send the double packet */
- return(0); /* this game is done for now */
- case 'C': /* I'm wimping out */
- if ( (check_concede(g) == 0) || (FeGetComment(g) < 0) ) {
- FeMessage("Concede aborted.");
- break;
- }
- ilose(g,T_ICONCEDE,0); /* this game is over */
- 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};
- char pm = '\0';
- int lastpt = 99; /* point last move started from */
- int lastd = 99; /* point last move ended at */
-
- FeDrawMenu(m);
- GameState = STATE_MYMOVE;
- while (1) {
- c = FeMenu(m,g->mvs[0].roll,g->mvs[1].roll,"\n\r ",pm);
- pm = c;
- switch (c) {
- case 'S': /* send moves */
- if (checkused(g)) /* didn't use all our moves */
- break;
- if (FeGetComment(g) < 0) { /* get our comment */
- FeMessage("Send aborted.");
- break;
- }
- if (g->board[OFFPT(g->mydir)].qty == 15) /* I win */
- iwin(g,T_IWIN,0);
- else
- g->state = ST_OPTURN;
- sendpkt(g,MOVE); /* send our move */
- return(g->state == ST_GAMEOVER);/* need to call gameover() */
- 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 */
- for (i = 0; i < 4; i++) {
- g->mvs[i].pt = -1;
- FeDrawMove(g,WHO_ME,i);
- }
- copyboard(g->mybd,g->board);
- FeDrawBoard(g->board,NULL,g->mydir,0,g->flags & F_INVERT);
- FeLabelBoard(g);
- FeDrawPip(g->board,g);
- 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 */
- if ( (check_concede(g) == 0) || (FeGetComment(g) < 0) ) {
- FeMessage("Concede aborted.");
- break;
- }
- ilose(g,T_ICONCEDE,0);
- 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(g);
- }
- 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,WHO_ME,i,A_REDRAW,&lastd);
- if (n < 0) { /* move rejected */
- g->mvs[i].pt = -1;
- FeMessage(rejlcl[-n]);
- lastd = 99;
- }
- else
- lastpt = g->mvs[i].pt;
- FeDrawMove(g,WHO_ME,i);
- FeCheckContact(g);
- 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(g);
- }
- 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,WHO_ME,i,A_REDRAW,&lastd);
- if (n < 0) { /* move rejected */
- g->mvs[i].pt = -1;
- FeMessage(rejlcl[-n]);
- lastpt = 99;
- }
- FeDrawMove(g,WHO_ME,i);
- FeCheckContact(g);
- 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(g);
- }
- 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,WHO_ME,i,A_REDRAW,&lastd);
- if (n < 0) { /* move rejected */
- g->mvs[i].pt = -1;
- FeMessage(rejlcl[-n]);
- }
- FeDrawMove(g,WHO_ME,i);
- FeCheckContact(g);
- 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(g);
- }
- 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,WHO_ME,i,A_REDRAW,&lastd);
- if (n < 0) { /* move rejected */
- g->mvs[i].pt = -1;
- FeMessage(rejlcl[-n]);
- }
- FeDrawMove(g,WHO_ME,i);
- FeCheckContact(g);
- 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(g);
- }
- 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,WHO_ME,0);
- FeDrawMove(g,WHO_ME,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,WHO_ME,i);
- break;
- }
- g->mvs[i].pt = n;
- n = apply(g,WHO_ME,i,A_REDRAW,&lastd);
- if (n < 0) { /* move rejected */
- g->mvs[i].pt = -1;
- FeMessage(rejlcl[-n]);
- }
- else
- lastpt = g->mvs[i].pt;
- }
- FeDrawMove(g,WHO_ME,i);
- FeCheckContact(g);
- 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;
- char pm = '\0';
- int gv;
- static char *m[] = {"Accept","Decline","Board","Next Game","Quit",NULL};
-
- FeDrawMenu(m);
- GameState = STATE_MYACPT;
- while (1) {
- c = FeMenu(m,0,0,"",pm);
- pm = c;
- switch (c) {
- case 'A': /* I accepted */
- if (FeGetComment(g) < 0) { /* get message */
- FeMessage("Accept aborted.");
- break;
- }
- g->gameval *= 2; /* the game value is doubled */
- g->state = ST_OPTURN; /* it's opponent's turn */
- sendpkt(g,ACPTDBL); /* send accept packet */
- return(0); /* done w/ this game for now */
- case 'D': /* I declined */
- if (FeGetComment(g) < 0) { /* get message */
- FeMessage("Decline aborted.");
- break;
- }
- ilose(g,T_IDECLINE,0);
- 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, c1, c2;
- char pm = '\0';
- int i;
- static char *m[] = {"Board","Next Game","Quit",NULL};
-
- if (g->flags & F_DISPLAYED) /* this game already displayed */
- return(0);
- FeDrawMenu(m);
- GameState = STATE_GAMEOVER;
- while (1) {
- c = FeMenu(m,0,0,"\n\r ",pm);
- pm = c;
- 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 ' ':
- case '\r':
- case '\n':
- FeOnMenuItem(m,'N'); /* highlight Next Game item */
- pm = 'N'; /* remember to unhighlight */
- /* fall through */
- case 'N': /* delete game & go to next */
- if ( (g->mcurrent[WHO_ME] < g->mtotal) &&
- (g->mcurrent[WHO_OPP] < g->mtotal) ) {
- g->state = ST_OPSTART;
- if ( (g->term == T_ILOSE) || (g->term == T_OPCONCEDE)
- || (g->term == T_OPDECLINE) ) {
- g->gameval = 1; /* reset for next game */
- g->adcnt = 0;
- g->flags &= ~F_IDOUBLED;
- g->term = 0;
- clearmvs(g->mvs);
- clearmvs(g->opmvs);
- if (g->mydir > 0) {
- c1 = g->mycolor;
- c2 = g->opcolor;
- }
- else {
- c1 = g->opcolor;
- c2 = g->mycolor;
- }
- newboard(g->opbd,c1,c2);
- newboard(g->mybd,c1,c2);
- newboard(g->board,c1,c2);
- for (i = 0; i < 6; i++) {
- g->rolls[i] = 0;
- g->doubles[i] = 0;
- g->oprolls[i] = 0;
- g->opdoubles[i] = 0;
- }
- crawford_check(g);
- g->mvs[0].roll = Rolldie();
- sendpkt(g,MSTART);
- }
- }
- else {
- g->flags |= F_DISPLAYED;/* done looking at this game */
- if (g->mtotal > 0) { /* finished match */
- if (g->term <= T_ILOSE)
- g->ppl->score[SC_MLOST]++;
- else
- g->ppl->score[SC_MWON]++;
- }
- }
- return(0); /* I'm done looking at this game */
- case 'Q': /* delete game & quit */
- return(-1);
- default:
- FeMessage("Invalid command.");
- break;
- }
- }
- }
-
-
- check_concede(g)
- struct game *g;
- {
- int gv, bg;
- char *msg;
-
- g->term = T_ICONCEDE;
- bg = gvalue(g,&gv);
- switch (bg) {
- case 1:
- msg = "This will score as a gammon. Are you sure? [yn]";
- break;
- case 2:
- msg = "This will score as a backgammon. Are you sure? [yn]";
- break;
- default:
- msg = "Are you sure? [yn]";
- break;
- }
- return(FeYesNo(msg));
- }
-