|
|
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;
}