|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T a
Length: 15195 (0x3b5b) Types: TextFile Names: »actions.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Cubes/actions.c«
/* vi:set sw=4 ts=4: */ #ifndef lint static char sccsid[] = "@(#)actions.c 5.1 (G.M. Paris) 89/01/22"; #endif lint /* ** ** cubes 5.1 Copyright 1989 Gregory M. Paris ** Permission granted to redistribute on a no charge basis. ** All other rights are reserved. ** */ #include <stdio.h> #include <signal.h> #include <strings.h> #include <ctype.h> #include <sys/types.h> #include <sys/time.h> #include <sys/file.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netdb.h> #include <netinet/in.h> #include <pwd.h> #include "cubes.h" player plr[PLAYERS]; /* player status */ diceset dice; /* the status of the dice */ cstat mystat = Inactive; /* our playing status */ boolean jokermode= False; /* jokers on the dice */ boolean inprogress= False; /* game in progress */ int winscore= 0; /* game win score */ int mypnum = -1; /* my player number */ int turnnum = 0; /* current turn number */ int nobs = 0; /* number of observers */ int beats = 0; /* number of heartbeats */ extern boolean quiet; /* in background */ extern enterlate watch; /* what to do about late entry */ extern enterlate spider; /* what to do about waiting */ extern winpref preference; /* gametype/winscore preference */ extern char *cubename; /* player name */ extern char *cubehist; /* personal ranking history file */ extern int ssock; /* server socket */ extern int errno; extern char *sys_errlist[]; extern boolean active; /* True while active */ extern char *index(); extern char *getenv(); struct passwd *getpwuid(); /* ** respond: send a reply to the server adding "\r\n" */ respond(reply) char *reply; { char repbuf[BUFSIZ]; strcpy(repbuf, reply); strcat(repbuf, "\r\n"); return write(ssock, repbuf, strlen(repbuf)) < 0 ? -1 : 0; } /* ** dispact: display an informative message to the player */ /*ARGSUSED*/ dispact(t,m) char *m; { return infomesg(m+4); } /* ** heloact: respond to the M_HELO message by giving player name. */ /*ARGSUSED*/ heloact(t,m) char *m; { return respond(cubename); } /* ** rqidact: respond to the M_RQID message by giving player identity ** and gametype preference. */ /*ARGSUSED*/ rqidact(t,m) char *m; { char idbuf[IDLEN]; char host[256]; int uid; struct passwd *pw; char pchar; (void) gethostname(host, sizeof host); switch(preference) { case Standard: pchar = 's'; break; case Fstand: pchar = 'S'; break; case Blitz: pchar = 'b'; break; case Fblitz: pchar = 'B'; break; default: pchar = 'n'; break; } /* ** Look up login name in the password file. If it's not there, ** just use the user id number. */ uid = getuid(); if((pw = getpwuid(uid)) == 0) sprintf(idbuf, "%c;%d@%.*s", pchar, uid, IDLEN-12, host); else sprintf(idbuf, "%c;%s@%.*s", pchar, pw->pw_name, IDLEN-12, host); return respond(idbuf); } /* ** worpact: respond to the M_WORP message by saying play or watch */ worpact(t,m) char *m; { switch(watch) { case Watch: return respond("watch"); case Play: return respond("play"); default: return rfstact(t,m); } } /* ** sorpact: respond to the M_SORP message by saying wait or play */ sorpact(t,m) char *m; { switch(spider) { case Wait: return respond("wait"); /* be a spider */ case Play: return respond("play"); default: return rfstact(t,m); } } /* ** actvact: respond to the M_ACTV message by alerting the player */ /*ARGSUSED*/ actvact(t,m) char *m; { cstat oldstat; oldstat = mystat; mystat = Active, beats = 0; if(quiet == True) mybeep(2); switch(oldstat) { case Computer: (void) infomesg("You've regained control of the dice."); break; case Watching: if(turnnum > 1) (void) infomesg("You've joined the game in progress."); break; default: /* (void) infomesg(m+4); /* don't need this chatter */ break; } return 0; } /* ** autoact: respond to the M_AUTO message by alerting the player */ /*ARGSUSED*/ autoact(t,m) char *m; { mystat = Computer, beats = 0; (void) infomesg(m+4); return 0; } /* ** waitact: respond to the M_WAIT message by notifying the player */ /*ARGSUSED*/ waitact(t,m) char *m; { if(mystat == Spider || mystat == Watching) (void) infomesg(m+4); mystat = Waiting, beats = 0; return 0; } /* ** voyract: respond to the M_VOYR message by notifying the player */ /*ARGSUSED*/ voyract(t,m) char *m; { mystat = Watching, beats = 0; return infomesg(m+4); } /* ** spdract: respond to the M_SPDR message by entering spider mode ** We could suspend here, but that makes this mode ** unusable in shells without job control. */ /*ARGSUSED*/ spdract(t,m) char *m; { mystat = Spider, beats = 0; (void) infomesg(m+4); #ifdef notdef sleep(2); (void) kill(0, SIGTSTP); /* suspend process group */ #endif notdef return 0; } /* ** noopact: no operation (really heartbeat action) ** Assumes that heartbeats come one per minute. */ /*ARGSUSED*/ noopact(t,m) char *m; { char msgbuf[MESGLEN]; ++beats; sprintf(msgbuf, "You've been a spider for %d minute%s...", beats, beats == 1 ? "" : "s"); return infomesg(msgbuf); } /* ** infoact: display an informational message */ /*ARGSUSED*/ infoact(t,m) char *m; { return infomesg(m+4); } /* ** helpact: display a help message */ /*ARGSUSED*/ helpact(t,m) char *m; { return helpmesg(m+4); } /* ** playact: display a play-by-play message (not used) */ /*ARGSUSED*/ playact(t,m) char *m; { return 0; } /* ** rfstact: respond to "roll first?" message */ /*ARGSUSED*/ rfstact(t,m) char *m; { char answer[BUFSIZ]; switch(prompt(m+4, answer, False)) { case -2: /* timeout */ return 0; case -1: /* error */ return -1; } if(respond(answer) < 0) return -1; return 0; } /* ** keepact: respond to "%d points:" message */ keepact(t,m) char *m; { return rfstact(t,m); } /* ** anogact: respond to "another game?" message */ anogact(t,m) char *m; { return rfstact(t,m); } /* ** downact: print the shutdown message and exit gracefully */ /*ARGSUSED*/ downact(t,m) char *m; { for(m += 4;*m == ' ';++m) ; if(*m == '\0') m = "Server said goodbye (no reason given)."; (void) infomesg(m); sleep(2); cleanup(0, ""); return -1; } /* ** turnact: cause turn indicator to advance */ /*ARGSUSED*/ turnact(t,m) char *m; { int pnum; if(sscanf(m+4, "Turn %d: player %d", &turnnum, &pnum) != 2) return -1; --pnum; return nowup(pnum); } /* ** cplract: clear player roster */ /*ARGSUSED*/ cplract(t,m) char *m; { register int c; mypnum = -1; for(c = 0;c < PLAYERS;++c) { plr[c].p_stat = Inactive; plr[c].p_name[0] = '\0'; plr[c].p_score = plr[c].p_squander = 0; } return clearscores(); } /* ** uareact: setup this player */ /*ARGSUSED*/ uareact(t,m) char *m; { int pnum; char *s; if(sscanf(m+4, "You are player %d", &pnum) < 1) return -1; --pnum; mypnum = pnum; plr[pnum].p_score = plr[pnum].p_squander = 0; plr[pnum].p_stat = Active; plr[pnum].p_name[0] = '\0'; if((s = index(m+20, ' ')) == 0) /* mmm You are player n */ return -1; strncat(plr[pnum].p_name, s+1, sizeof plr[pnum].p_name); return showplr(pnum); } /* ** pnumact: setup another player */ /*ARGSUSED*/ pnumact(t,m) char *m; { int pnum; char *s; if(sscanf(m+4, "player %d", &pnum) < 1) return -1; --pnum; plr[pnum].p_score = plr[pnum].p_squander = 0; plr[pnum].p_stat = Active; plr[pnum].p_name[0] = '\0'; if((s = index(m+12, ' ')) == 0) /* mmm player n */ return -1; strncat(plr[pnum].p_name, s+1, sizeof plr[pnum].p_name); return showplr(pnum); } /* ** fareact: clean up when a player leaves */ /*ARGSUSED*/ fareact(t,m) char *m; { static struct timeval halfsec = { 0L, 500000L }; int pnum; char msgbuf[MESGLEN]; char name[NAMELEN]; if(sscanf(m+4, "farewell %d %[^\r\n]", &pnum, name) < 2) return -1; --pnum; sprintf(msgbuf, "%s has left the game.", name); plr[pnum].p_score = plr[pnum].p_squander = 0; plr[pnum].p_stat = Inactive; plr[pnum].p_name[0] = '\0'; (void) clearplr(pnum); (void) infomesg(msgbuf); (void) select(32, NOSEL, NOSEL, NOSEL, &halfsec); return 0; } /* ** nobsact: update number of observers */ /*ARGSUSED*/ nobsact(t,m) char *m; { if(sscanf(m+4, "%d", &nobs) < 1) return -1; return 0; } /* ** mscoact: update my score */ /*ARGSUSED*/ mscoact(t,m) char *m; { int score, squander; if(sscanf(m+4, "You now have %d points (squandered %d).", &score, &squander) < 2) return -1; if(mypnum < 0) return -1; plr[mypnum].p_score = score, plr[mypnum].p_squander = squander; return showplr(mypnum); } /* ** oscoact: update other player score */ /*ARGSUSED*/ oscoact(t,m) char *m; { int pnum, score, squander; if(sscanf(m+4, "Player %d now has %d points (squandered %d).", &pnum, &score, &squander) < 3) return -1; --pnum; plr[pnum].p_score = score, plr[pnum].p_squander = squander; return showplr(pnum); } /* ** nwin: no winner message */ /*ARGSUSED*/ nwinact(t,m) char *m; { inprogress = False; (void) infomesg(m+4); return cleardice(); } /* ** overact: game over with winner */ /*ARGSUSED*/ overact(t,m) char *m; { inprogress = False; (void) infomesg(m+4); return cleardice(); } /* ** rankact: save ranking info */ /*ARGSUSED*/ rankact(t,m) char *m; { static FILE *frec = 0; int omask; /* ** If cubehist is null then we aren't recording history. */ if(cubehist == 0 || *cubehist == '\0') return 0; /* ** Open the cubehist file for append. */ if(frec == 0) { omask = umask(022); (void) umask(omask|022); /* ensure write protection */ if((frec = fopen(cubehist, "a")) == 0) { char err[MESGLEN]; sprintf(err, "Can't open %s: %s.", cubehist, sys_errlist[errno]); (void) umask(omask); return infomesg(err); } (void) umask(omask); } /* ** Write the info supplied by the server. */ fprintf(frec, "%s\n", m+4); (void) fflush(frec); return 0; } /* ** diceact: parse the dice status message and redisplay the dice */ /*ARGSUSED*/ diceact(t,m) char *m; { register int d; char stats[NDICE+1]; char faces[NDICE+1]; char combs[NDICE+1]; int c; dice.d_mesg[0] = '\0'; if(sscanf(m+4, "%d %s %s %s %d %d %d %d%*1c%[^\n]", &c, stats, faces, combs, &dice.d_pts_roll, &dice.d_pts_dice, &dice.d_pts_turn, &dice.d_pts_max, dice.d_mesg) < 8) { fprintf(stderr, "dieact: couldn't parse dice status\n"); return -1; } for(d = 0;d < NDICE;++d) { switch(stats[d]) { case 'f': dice.d_stat[d] = Free; break; case 'h': dice.d_stat[d] = Held; break; case 't': dice.d_stat[d] = Taken; break; case 'r': dice.d_stat[d] = Rolled; break; default: dice.d_stat[d] = Free; break; } dice.d_face[d] = isdigit(faces[d]) ? (faces[d] - '0') : BADFACE; switch(combs[d]) { case 'p': dice.d_comb[d] = Previous; break; case 'n': dice.d_comb[d] = Nothing; break; case 'j': dice.d_comb[d] = Joker; break; case '5': dice.d_comb[d] = Five; break; case '1': dice.d_comb[d] = Ace; break; case 't': dice.d_comb[d] = Three_of_a_kind; break; case 'l': dice.d_comb[d] = Small_straight; break; case 'f': dice.d_comb[d] = Four_of_a_kind; break; case 'b': dice.d_comb[d] = Asm_straight; break; case 's': dice.d_comb[d] = Straight; break; case 'a': dice.d_comb[d] = All_of_a_kind; break; default: dice.d_comb[d] = Nothing; break; } } return drawdice(); } /* ** parmact: read game parameters winscore and jokermode */ /*ARGSUSED*/ parmact(t,m) char *m; { int n; char word[64]; if((n = sscanf(m+4, "This is a %d point game with %s", &winscore, word)) < 1) return -1; /* ** This message happens at game startup. If we're suspended ** we want to alert the player, so send a bunch of beeps. */ if(quiet == True) mybeep(3); inprogress = True; jokermode = (n == 2 && word[0] == 'j') ? True : False; (void) infomesg(m+4); (void) defhelpmesg(); return drawdice(); } /* ** argeact: argument error, display error message */ /*ARGSUSED*/ argeact(t,m) char *m; { if(quiet != True) mybeep(1); (void) infomesg(m+4); sleep(2); return 0; } /* ** badmact: alert player to bad message */ badmact(t,m) char *m; { return (dispact(t,"Bad message follows:") < 0 || dispact(t,m) < 0) ? -1 : 0; } /* ** unktact: alert player to unknown type message */ unktact(t,m) char *m; { return (dispact(t,"Unknown message follows:") < 0 || dispact(t,m) < 0) ? -1 : 0; } /* ** actmap: relates message types to actions */ typedef struct { m_num a_type; /* message type M_???? */ int (*a_action)(); /* action to take */ } actmap; /* ** atable: action table */ static actmap atable[] = { { M_NOOP, noopact }, /* no operation (usually heartbeat) */ { M_INFO, infoact }, /* informational or status messages */ { M_HELP, helpact }, /* help messages */ { M_DICE, diceact }, /* dice status */ { M_PARM, parmact }, /* game parameters */ { M_PLAY, playact }, /* play-by-play on other players */ { M_KEEP, keepact }, /* %d points: */ { M_HELO, heloact }, /* hello message (and name query) */ { M_DOWN, downact }, /* shutdown message */ { M_RQID, rqidact }, /* id request */ { M_WORP, worpact }, /* play or watch? */ { M_SORP, sorpact }, /* wait (spider) or play? */ { M_ACTV, actvact }, /* you are now an active player */ { M_AUTO, autoact }, /* you are on autopilot */ { M_WAIT, waitact }, /* you are waiting to be added */ { M_VOYR, voyract }, /* you are now a voyeur */ { M_SPDR, spdract }, /* you are now a spider */ { M_TURN, turnact }, /* Player %d, ... up with %d points. */ { M_NWIN, nwinact }, /* game over, no winner */ { M_OVER, overact }, /* Player %d has won the game! */ { M_RANK, rankact }, /* player ranking info after game */ { M_CPLR, cplract }, /* clear player roster */ { M_UARE, uareact }, /* you are player %d */ { M_PNUM, pnumact }, /* player %d %s */ { M_FARE, fareact }, /* farewell %d %s */ { M_NOBS, nobsact }, /* %d observer%s */ { M_MSCO, mscoact }, /* You now have %d points. */ { M_OSCO, oscoact }, /* Player %d now has %d points. */ { M_ANOG, anogact }, /* play another game? */ { M_RFST, rfstact }, /* 0 points, roll first? */ { M_ARGE, argeact }, /* argument error, try again */ { M_BADM, badmact }, /* bad message */ }; static int nactions = (sizeof atable / sizeof atable[0]); /* ** actlist: array of pointers to actions */ static int (**actlist)() = 0; /* ** initactions: build an array of actions from atable */ initactions() { register int m; unsigned size; char *malloc(); /* ** Just in case we're called more than once. */ if(actlist != 0) { free((char *)actlist); actlist = 0; } /* ** Get memory for action list. Initialize each pointer. */ size = (unsigned)(M_LAST - M_BASE + 1); if((actlist = (int (**)())malloc(size * sizeof *actlist)) == 0) cleanup(1, "no memory for action list"); for(m = 0;m < size;++m) *(actlist+m) = unktact; /* un-mapped action */ /* ** Install the values mapped in atable. */ for(m = 0;m < nactions;++m) actlist[(int)atable[m].a_type-M_BASE] = atable[m].a_action; } /* ** action: a dispatching function */ action(type, mesg) int type; char *mesg; { int r; if(type < M_BASE || type > M_LAST) r = badmact(type, mesg); else r = (*actlist[type-M_BASE])(type, mesg); neutral(); return r; }