DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T a

⟦7e08637b9⟧ TextFile

    Length: 15195 (0x3b5b)
    Types: TextFile
    Names: »actions.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/General/Cubes/actions.c« 

TextFile

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