games@tekred.TEK.COM (06/08/88)
Submitted by: gmp@rayssd.RAY.COM (Gregory M. Paris) Comp.sources.games: Volume 4, Issue 32 Archive-name: cubes/Part01 [Warning to System V types: this game uses BSD sockets for its networking implementation. -br] #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 1 (of 3)." # Contents: README MANIFEST cubeserver.c screen.c # Wrapped by billr@saab on Tue Jun 7 16:36:05 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f README -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"README\" else echo shar: Extracting \"README\" \(5591 characters\) sed "s/^X//" >README <<'END_OF_README' XThe game of cubes is a computer implementation of a dice game played with five Xsix-sided dice. The goal of the game is to be the first player to score X10,000 points. Players take turns rolling the dice in the hopes of getting Xone or more of several scoring combinations. A player can continue rolling as Xlong as the previous roll produced a scoring combination. Failing that, any Xpoints accumulated during the turn are lost and the player's turn ends. XBefore that happens, the player may (prudently or cowardly) elect to quit Xrolling, at which time the points accumulated during the turn are added to the Xplayer's score. X XThese programs should compile and run without change on any 4.3BSD system. XExcept for missing the FD_ macros (faked in this distribution), it should work Xon 4.2BSD systems too. The program is based on a socket-based client/server Xmodel, so I'm afraid that you're going to have some problems if you want to Xrun it on something that doesn't have sockets. Of course, if you do port it Xto something like that, I'm interested in receiving the diffs... X XYou'll need to be root in order to install these programs. The main reason Xbeing that you must add the cube service to your /etc/services file. The Xline I've added on our systems is X Xcube 3840/tcp cubes # cube server X Xwhere the 3840 is the port number that I chose almost arbitrarily. You can Xpick anything you like, but since cubes doesn't need to use one of the Xprivileged ports, you'll probably want to pick something larger than 1024. If Xyou're not root and you want to run this program, you'll have to edit Xcubeserver.c and cubes.c to use a hard-coded port number where it now uses Xs_port. (Don't forget to convert the number to network byte order...) X XIf you want the server to start up when the system comes up, you'll have to Xput something in your /etc/rc or /etc/rc.local file. It is possible to modify Xcubes.c to start up a local server when necessary, but there was no reason Xhere to do that, so I didn't. X XAlso, root permissions will be helpful when installing the programs, unless Xyou edit the Makefile to put the programs somewhere other than /usr/games. XThe cubeserver is setuid to gdaemon, but that's only so it doesn't run as root Xand so the scorefile can be 644 mode. X XNote that both the server and the client do funny things with their Xarguments. The server tries to display its state by modifying argv[0] and the Xclients try to disguise themselves using a similar trick. This stuff might Xnot work on your system, but hopefully it won't keep the programs from Xrunning. Some may wish to take the argument-mangling stuff out even if it Xdoes work. If so, the execv stuff in cubeserver.c can be stripped out, since Xit's only there to provide a larger argv[0] for the status display. X XThe player interface, cubes, is pretty much locked-into a 24 x 80 screen, but Xworks OK with something larger. If you're on a graphics workstation, then Xyou'll find the whole thing pretty sorry. Well, if I had one on my desk, I'd Xdo something about that, but I don't, so I won't. If any industrious person Xwould like to write a player interface that takes advantage of a bit-mapped Xgraphics display, you're more than welcome to do so. Please send me whatever Xyou come up with so I can see to it that it gets added to the distribution. XNote that the game is playable via telnet (well, playable is an Xoverstatement), so you can use it to get an idea of what the server's doing if Xyou want to write the client from scratch. (That's how I did it for cubes.) X XSpeaking of graphics, I've made it so the cubes program can take advantage of Xan alternate graphics character set if your terminal has one. At my disposal XI had some vt100 clones and various Zenith terminals, so I made it handle Xthem. The dice do look somewhat better -- maybe too square -- though the XDEC-graphics dice look like the ace through six of diamonds. Additional Xgraphics sets will be added if anybody sends me the necessary diffs. Note Xthat to have graphics work, the terminal's termcap entry must use the "as" and X"ae" capabilities for entering and leaving graphics mode. X XThe biggest sore point I see with the game as it now stands is that it takes a Xbit of coordination to get everybody to start the game at the same time. XVerbal communication works, but when you're dialed-in from home, that method Xisn't available. If anybody comes up with a not-too-disruptive scheme to Xnotify people to begin a game, I'm interested. X XAnother likely change would be to make the player ranking system use some kind Xof moving average. As it is, once you get a large number of games in your Xrecord, you aren't able to effect much change in your ranking. X XAs far as the computer players go, it might be nice if you don't add or delete Xnames from the list, or add or delete any of the temperments or strategies. XNot that I want to stifle your creativity, but it might be interesting to see Xa composite ranking of all computer and human players net-wide. I must Xconfess that some of the computers are doing quite well here, tho' maybe we're Xjust a bad sample of humans. Hard to say without more data. X XFeel free to redistribute this program, but only for free. You can include it Xin a commercial distribution, but only if you don't charge extra for it. If Xyou make changes to it, I'd like to hear about them so I can decide whether or Xnot to include them in my version. Otherwise, as they say, enjoy... X XGreg Paris, June 2, 1988 Xgmp@rayssd.ray.com or gmp%rayssd.ray.com@a.cs.uiuc.edu X{att,decuac,gatech,necntc,sun,uiucdcs,ukma}!rayssd!gmp END_OF_README if test 5591 -ne `wc -c <README`; then echo shar: \"README\" unpacked with wrong size! fi # end of overwriting check fi if test -f MANIFEST -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"MANIFEST\" else echo shar: Extracting \"MANIFEST\" \(684 characters\) sed "s/^X//" >MANIFEST <<'END_OF_MANIFEST' X File Name Archive # Description X----------------------------------------------------------- X MANIFEST 1 This shipping list X Makefile 3 X README 1 X actions.c 2 X avg.c 2 X cuberank.tmplt 3 X cubes.6 2 X cubes.c 3 X cubes.h 3 X cubeserver.c 1 X dieopts.c 2 X history.c 3 X random.c 3 X risk.c 3 X screen.c 1 X strategies.c 3 X tactics.c 3 X tempers.c 3 X turn.c 2 END_OF_MANIFEST if test 684 -ne `wc -c <MANIFEST`; then echo shar: \"MANIFEST\" unpacked with wrong size! fi # end of overwriting check fi if test -f cubeserver.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"cubeserver.c\" else echo shar: Extracting \"cubeserver.c\" \(28971 characters\) sed "s/^X//" >cubeserver.c <<'END_OF_cubeserver.c' X/* vi:set sw=4 ts=4: */ X#ifndef lint Xstatic char sccsid[] = "@(#)cubeserver.c 1.1 6/2/88 Copyright 1988 Gregory M. Paris"; X#endif lint X X#include <stdio.h> X#include <ctype.h> X#include <strings.h> X#include <errno.h> X#include <signal.h> X#include <setjmp.h> X#include <sys/types.h> X#include <sys/time.h> X#include <sys/file.h> X#include <sys/ioctl.h> X#include <sys/socket.h> X#include <netinet/in.h> X#include <netdb.h> X#include "cubes.h" X X#ifndef FD_ZERO X/* XXXX: This system is missing the FD_ macros for select, so it's XXXX: probably a 4.2BSDish system. That means that the fd_set XXXX: type is probably just a single int, so just fake it here. X*/ X#define FD_ZERO(p) ((p)->fds_bits[0] = 0) X#define FD_SET(n,p) ((p)->fds_bits[0] |= 1L << (n)) X#endif FD_ZERO X X#define NOSEL ((fd_set *)0) X#define HANG ((struct timeval *)0) X Xextern int errno; Xextern int optind; Xextern int opterr; Xextern char *optarg; Xextern char *fgets(); Xextern char *gets(); Xextern boolean wantin(); Xextern boolean nameinuse(); Xextern boolean idinuse(); Xextern int plrcmp(); Xstatic int srvshutdown(); X Xint ssock = -1; /* server socket */ Xint active = 0; /* number of Active humans */ Xint waiting = 0; /* number of Waiting humans */ Xint turnnum = 0; /* current turn number */ Xunsigned neq = 0; /* number of equivalent hosts */ Xchar **equiv; /* equivalent hosts */ Xboolean inprogress = False; /* True when game in progress */ Xboolean firstgame = True; /* first game with set of players */ Xplayer plr[PLAYERS]; /* player/connection list */ Xstruct timeval poll = { 0L, 0L }; /* for select polling */ X X#define STATLEN 55 /* length of "status line" */ Xchar *statusline; /* really av[0] */ X Xmain(ac, av) Xchar *av[]; X{ X int c; X X /* X ** Make sure we have enough room to display our status. X */ X if(strlen(av[0]) < STATLEN) { X char *newav0; X char *malloc(); X X if((newav0 = malloc(STATLEN+1)) == 0) { X fprintf(stderr, "cubeserver: no memory for new argv zero\n"); X exit(1); X } X sprintf(newav0, "cubes %-*s.", STATLEN-7, "startup"); X av[0] = newav0; X execv(PATHNAME, av); X perror(PATHNAME); X exit(1); X } X X (void) setuid(geteuid()); X statusline = av[0]; X updstat(-1); X X opterr = 0; X while((c = getopt(ac, av, "")) >= 0) { X switch(c) { X default: X fprintf(stderr, "usage -- cubeserver\n"); X exit(1); X } X } X X /* X ** Close stdin and open server socket. X */ X (void) fclose(stdin); X if(openservsock() < 0) X exit(1); X X /* X ** Read history file. X */ X if(histread() < 0) X exit(1); X X /* X ** Ignore keybord signals. Catch TERM for controlled shutdown. X */ X (void) signal(SIGHUP, SIG_IGN); X (void) signal(SIGINT, SIG_IGN); X (void) signal(SIGQUIT, SIG_IGN); X (void) signal(SIGTSTP, SIG_IGN); X (void) signal(SIGTTIN, SIG_IGN); X (void) signal(SIGTTOU, SIG_IGN); X (void) signal(SIGTERM, srvshutdown); X X /* X ** Fork. X */ X switch(c = fork()) { X case -1: /* error */ X perror("cubeserver: fork"); X exit(1); X case 0: /* child */ X break; X default: /* parent */ X printf("%d\n", c); X exit(0); X } X X /* X ** Disconnect from controlling tty. X */ X if((c = open("/dev/tty", O_RDWR)) >= 0) { X (void) ioctl(c, TIOCNOTTY, (char *)0); X (void) close(c); X } X X /* X ** Reopen stdout and stderr as logfile. X */ X (void) close(2); X (void) open(LOGFILE, O_WRONLY|O_APPEND|O_CREAT, 0666); X (void) dup2(2, 1); X X /* X ** Initialize random number generator. X */ X irandom(); X X /* X ** Initialize player/connection list. X */ X active = 0; X waiting = 0; X for(c = 0;c < PLAYERS;++c) { X plr[c].p_stat = Inactive; X plr[c].p_fd = -1; X plr[c].p_score = 0; X plr[c].p_onboard = False; X plr[c].p_strategy = 0; X plr[c].p_temper = 0; X plr[c].p_name[0] = '\0'; X plr[c].p_id[0] = '\0'; X } X addcomp(); /* add COMP computer */ X X for(firstgame = True;;) { X inprogress = False; X newplayers(True); X begingame(); X while(active > 0 && winner() < 0) X gameturn(); X endgame(); X } X} X X/* X** openservsock: open, bind, and begin listening on server socket X*/ Xopenservsock() X{ X struct servent *ps; X struct sockaddr_in server; X X if((ssock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { X perror("cubeserver: socket"); X return (ssock = -1); X } X X if((ps = getservbyname("cube", "tcp")) == 0) { X fprintf(stderr, "cubeserver: no cube/tcp service listed\n"); X (void) close(ssock); X return (ssock = -1); X } X X server.sin_family = AF_INET; X server.sin_port = ps->s_port; X server.sin_addr.s_addr = INADDR_ANY; X if(bind(ssock, &server, sizeof server) < 0) { X perror("cubeserver: bind"); X (void) close(ssock); X return (ssock = -1); X } X X if(listen(ssock, 5) < 0) { X perror("cubeserver: listen"); X (void) close(ssock); X return (ssock = -1); X } X X return 0; X} X X/* X** wantin: return true if more players want in X*/ Xboolean Xwantin(hang) Xboolean hang; X{ X fd_set rdy; X X FD_ZERO(&rdy); X FD_SET(ssock, &rdy); X if(select(ssock+1, &rdy, NOSEL, NOSEL, hang==True ? HANG : &poll) > 0) X return True; X return False; X} X X/* X** newplayers: check for and add new players X*/ Xnewplayers(hang) Xboolean hang; X{ X register int c; X int csock; X int tries; X int len; X struct sockaddr_in client; X char msgbuf[BUFSIZ]; X int off = 0; X X /* X ** Is this a new batch of players? X */ X if(hang == True && active == 0) X firstgame = True; X X /* X ** If there are no active humans, just wait here in select. X */ X if(hang == True && active == 0 && waiting == 0) X while(wantin(True) == False) X ; X X /* X ** Keep looping until we run out of connection requests. X */ X for(;;) { X /* X ** If we are supposed to hang, then wait a while for X ** another connection request, elsewise, just return. X */ X#define MAXTRIES 5 X for(tries = 0;wantin(False) == False;++tries) { X if(hang == False || tries > MAXTRIES) X return; X sleep(1); X } X X /* X ** Accept a connection from a potential player. X */ X len = sizeof client; X if((csock = accept(ssock, &client, &len)) < 0) { X perror("cubeserver: accept"); X break; X } X (void) ioctl(csock, FIONBIO, (char *)&off); X X /* X ** Find an open slot. X */ X for(c = 0;c < PLAYERS;++c) X if(plr[c].p_stat == Inactive) X break; X if(c == PLAYERS) { X sprintf(msgbuf, "%d Sorry, full house.\r\n", M_ARGE); X (void) write(csock, msgbuf, strlen(msgbuf)); X sprintf(msgbuf, X "%d Server closing connection.\r\n", M_DOWN); X (void) write(csock, msgbuf, strlen(msgbuf)); X (void) close(csock); X continue; X } X X /* X ** Fill in player parameters. X */ X plr[c].p_fd = csock; X plr[c].p_name[0] = plr[c].p_id[0] = '\0'; X plr[c].p_stat = Waiting, ++waiting; X plr[c].p_score = 0, plr[c].p_onboard = False; X if(getplayername(c) < 0 || getplayerid(c) < 0) X continue; X sprintf(msgbuf, "%d %s, welcome to Cubes.\r\n", X M_INFO, plr[c].p_name); X if(message(c, msgbuf) < 0) X continue; X if(inprogress == True) X roster(c); /* roster for this player only */ X } X} X X/* X** oldplayer: remove a player from the game X*/ Xoldplayer(c) Xregister int c; X{ X /* X ** Close the socket if one is open. X */ X if(plr[c].p_fd != -1) { X (void) close(plr[c].p_fd); X plr[c].p_fd = -1; X } X X /* X ** Change the player's status. X */ X switch(plr[c].p_stat) { X case Computer: X if(inprogress == True && plr[c].p_onboard == True) X histpoints(c); X plr[c].p_stat = Inactive; X plr[c].p_score = 0; X plr[c].p_onboard = False; X plr[c].p_strategy = 0; X plr[c].p_temper = 0; X plr[c].p_name[0] = '\0'; X plr[c].p_id[0] = '\0'; X annfarewell(c); X break; X case Active: X /* X ** If game in progress and this player has some points, X ** then there's a chance that a computer proxy will be X ** assigned to take over. The proxy keeps the original X ** name so that other players are not made aware. The X ** id is also left unchanged so that a single player can't X ** flood the game with proxies. X */ X if(inprogress == True && plr[c].p_onboard == True && dieroll(5) > 2) { X plr[c].p_stat = Computer; X pickstrategy(c); /* also chooses temperment */ X } else { X if(inprogress == True && plr[c].p_onboard == True) X histpoints(c); X plr[c].p_stat = Inactive; X plr[c].p_score = 0; X plr[c].p_onboard = False; X plr[c].p_name[0] = '\0'; X plr[c].p_id[0] = '\0'; X annfarewell(c); X } X --active; X break; X case Waiting: X plr[c].p_stat = Inactive; X --waiting; X break; X } X if(active <= 0) { X /* X ** XXX: update computer points history here? X */ X inprogress = False; X active = 0; X } X} X X/* X** messagejmp, messagetimo: message timeout handler X*/ Xstatic jmp_buf messagejmp; Xstatic int Xmessagetimo() X{ X longjmp(messagejmp, 1); X} X X/* X** message: write a message on a channel X*/ Xmessage(c, mesg) Xint c; Xchar *mesg; X{ X int n, mesglen; X int (*oldalrm)(); X unsigned alarmv; X fd_set rdy; X X switch(plr[c].p_stat) { X case Inactive: X#ifdef notdef X fprintf(stderr, "message: to Inactive: %s", mesg); X#endif notdef X return -1; X case Computer: X fprintf(stderr, "message: to Computer: %s", mesg); X return -1; X } X X if((mesglen = strlen(mesg)) == 0) X return 0; X X oldalrm = signal(SIGALRM, SIG_IGN); X alarmv = alarm(0); X if(setjmp(messagejmp) != 0) { X fprintf(stderr, "message: timeout\n"); X oldplayer(c); X (void) signal(SIGALRM, oldalrm); X (void) alarm(alarmv); X return -1; X } X X (void) signal(SIGALRM, messagetimo); X (void) alarm(WRITETIMO); X FD_ZERO(&rdy); X FD_SET(plr[c].p_fd, &rdy); X (void) select(plr[c].p_fd+1, NOSEL, &rdy, NOSEL, &poll); X if((n = write(plr[c].p_fd, mesg, mesglen)) < 0) { X if(errno != EPIPE) X perror("message: write"); X (void) alarm(0); X oldplayer(c); X (void) signal(SIGALRM, oldalrm); X (void) alarm(alarmv); X return -1; X } X (void) alarm(0); X (void) signal(SIGALRM, oldalrm); X (void) alarm(alarmv); X return n; X} X X/* X** replyjmp, replytimo: reply timeout handler X*/ Xstatic jmp_buf replyjmp; Xstatic int Xreplytimo() X{ X longjmp(replyjmp, 1); X} X X/* X** reply: read a reply from a channel X*/ Xreply(c, mesg, mesglen) Xint c, mesglen; Xchar *mesg; X{ X int n, ntot; X int (*oldalrm)(); X unsigned alarmv; X fd_set rdy; X X switch(plr[c].p_stat) { X case Inactive: X fprintf(stderr, "reply: from Inactive\n"); X return -1; X case Computer: X fprintf(stderr, "reply: from Computer\n"); X return -1; X } X X /* X ** Handle read timeout. X */ X oldalrm = signal(SIGALRM, SIG_IGN); X alarmv = alarm(0); X if(setjmp(replyjmp) != 0) { X char timomsg[128]; X fprintf(stderr, "reply: timeout\n"); X sprintf(timomsg, X "%d Timed out waiting for your response!\r\n", M_INFO); X (void) message(c, timomsg); X (void) send(plr[c].p_fd, "\001", 1, MSG_OOB); X/* oldplayer(c); */ X (void) signal(SIGALRM, oldalrm); X (void) alarm(alarmv); X return -2; X } X X /* X ** Read until we get a newline. X */ X (void) signal(SIGALRM, replytimo); X (void) alarm(READTIMO); X ntot = 0, mesg[0] = '\0'; X while(index(mesg, '\n') == 0) { X FD_ZERO(&rdy); X FD_SET(plr[c].p_fd, &rdy); X (void) select(plr[c].p_fd+1, &rdy, NOSEL, NOSEL, HANG); X if((n = read(plr[c].p_fd, mesg+ntot, mesglen-ntot)) <= 0) { X (void) alarm(0); X#ifdef notdef X if(n < 0) X perror("reply: read"); X else X fprintf(stderr, "reply: read got zero bytes\n"); X#endif notdef X oldplayer(c); X (void) signal(SIGALRM, oldalrm); X (void) alarm(alarmv); X return -1; X } X ntot += n, mesg[ntot] = '\0'; X } X (void) alarm(0); X X /* X ** Strip trailing control characters and spaces. X ** Then get rid of control characters in the message. X */ X for(n = ntot - 1;n >= 0;--n) { X if(iscntrl(mesg[n]) || isspace(mesg[n])) X mesg[n] = '\0'; X else X break; X } X for(n = 0;mesg[n] != '\0';++n) X if(iscntrl(mesg[n])) X mesg[n] = '?'; X X (void) signal(SIGALRM, oldalrm); X (void) alarm(alarmv); X return n; X} X X/* X** compname: names for computer players X*/ Xchar *compname[] = { X/* 0*/ "CUBEX", /* the COMP player */ X/* 1*/ "UNIBLAB", X/* 2*/ "Rosie", X/* 3*/ "Brainiac", X/* 4*/ "Wotan", X/* 5*/ "K-2", X/* 6*/ "K-9", X/* 7*/ "M5", X/* 8*/ "NOMAD", X/* 9*/ "Landrew", X/*10*/ "Norman", X/*11*/ "Stella 500", X/*12*/ "Alice 3", X/*13*/ "The Old Man" /* in the Cave */, X/*14*/ "Agnes", X/*15*/ "Dr. Theopolis", X/*16*/ "Tweekie", X/*17*/ "Gort", X/*18*/ "Robbie", X/*19*/ "HAL9000", X/*20*/ "SAL9000", X/*21*/ "Mother", X/*22*/ "Ashe", X/*23*/ "Bishop", X/*24*/ "Woper", X/*25*/ "The Terminator", X/*26*/ "Number Five", X/*27*/ "Jenkins", X/*28*/ "R. Daneel Olivaw", X/*29*/ "GAX", X/*30*/ "TEX", X/*31*/ "MEX", X/*32*/ "BEX", X/*33*/ "DEX", X/*34*/ "LIBEX", X/*35*/ "Mr. Frostee", X/*36*/ "Ralph Numbers", X/*37*/ "Wagstaff", X/*38*/ "Berenice", X/*39*/ "Emul", X/*40*/ "Ulalume", X/*41*/ "Oozer", X/*42*/ "Kkandio", X}; Xint compnames = (sizeof compname / sizeof compname[0]); X X/* X** begingame: setup prior to a game X*/ Xbegingame() X{ X register int c, cc; X int ncomp; X X inprogress = False; X turnnum = 0; X updstat(-1); X X /* X ** Add waiting players to the game. X */ X for(c = 0;c < PLAYERS;++c) { X if(plr[c].p_stat == Waiting) { X plr[c].p_stat = Active; X plr[c].p_score = 0; X plr[c].p_onboard = False; X ++active, --waiting; X } X } X X /* X ** Count computer players. X */ X for(ncomp = c = 0;c < PLAYERS;++c) X if(plr[c].p_stat == Computer) X ++ncomp; X X /* X ** Add enough computer players to make at least two. X ** Add enough computer players to make four players total. X ** Add computer players randomly after that. X */ X while(ncomp < 2 || (active + ncomp < 4) || dieroll(7) > 5) { X for(c = 0;c < PLAYERS;++c) { X if(plr[c].p_stat == Inactive) { X cc = dieroll(compnames-1); /* zero reserved */ X if(nameinuse(c, compname[cc]) == False) { X plr[c].p_stat = Computer; X plr[c].p_fd = -1; X plr[c].p_score = 0; X plr[c].p_onboard = False; X strcpy(plr[c].p_name, compname[cc]); X plr[c].p_id[0] = '\0'; /* non-proxies are null */ X pickstrategy(c); /* also chooses temperment */ X ++ncomp; X } X break; X } X } X } X X updstat(-1); X X /* X ** If this is the first game with this set of players, X ** reorder them by wins/points ranking. Else, reorder by X ** points scored in last game. X */ X if(firstgame == True) X historder(); X else X qsort((char *)plr, PLAYERS, sizeof plr[0], plrcmp); X X /* X ** Zero scores and distribute new roster. X */ X for(c = 0;c < PLAYERS;++c) { X plr[c].p_score = 0; X plr[c].p_onboard = False; X } X roster(-1); X X inprogress = True; X updstat(-1); X} X X/* X** announce: send a message to all active and waiting players but one X*/ Xannounce(but, mesg) Xint but; Xchar *mesg; X{ X register int c; X X for(c = 0;c < PLAYERS;++c) if(c != but) { X switch(plr[c].p_stat) { X case Active: X case Waiting: X (void) message(c, mesg); X break; X } X } X} X X/* X** annscore: announce player score X** announces differently for affected player X*/ Xannscore(sc) Xint sc; X{ X char msgbuf[MESGLEN+64]; X X sprintf(msgbuf, "%d Player %d now has %d points.\r\n", X M_OSCO, sc, plr[sc].p_score); X announce(sc, msgbuf); X if(plr[sc].p_stat != Computer) { X sprintf(msgbuf, "%d You now have %d points.\r\n", X M_MSCO, plr[sc].p_score); X (void) message(sc, msgbuf); X } X} X X#ifdef notdef X/* X** annplayer: announce new player X** doesn't announce player to itself X*/ Xannplayer(newc) Xint newc; X{ X char msgbuf[MESGLEN+64]; X X sprintf(msgbuf, "%d player %d %s\r\n", M_PNUM, newc, plr[newc].p_name); X announce(newc, msgbuf); X} X#endif notdef X X/* X** annfarewell: bid farewell to player X** doesn't tell player about own leave X*/ Xannfarewell(oldc) Xint oldc; X{ X char msgbuf[MESGLEN+64]; X X sprintf(msgbuf, "%d farewell %d %s\r\n", X M_FARE, oldc, plr[oldc].p_name); X announce(oldc, msgbuf); X} X X/* X** gameturn: do a single turn for each active player X*/ Xgameturn() X{ X register int c, pts; X int about, wasabout; X char msgbuf[MESGLEN]; X X ++turnnum; X X updstat(-1); X X wasabout = -1; X for(c = 0;active > 0 && c < PLAYERS;++c) { X switch(plr[c].p_stat) { X case Computer: X case Active: X updstat(c); X if((pts = turn(c)) > 0) { X plr[c].p_score += pts; X plr[c].p_onboard = True; X } X annscore(c); X updstat(-1); X X /* X ** Tell about players about to win and players no longer X ** about to win. X */ X if((about = winner()) == c) { X sprintf(msgbuf, "%d %s is about to win...\r\n", X M_INFO, plr[c].p_name); X announce(c, msgbuf); X if(plr[c].p_stat == Active) { X sprintf(msgbuf, "%d You are about to win...\r\n", M_INFO); X (void) message(c, msgbuf); X } X sleep(2); /* a chance for everybody to see... */ X } else if(wasabout != about && wasabout >= 0) { X sprintf(msgbuf, "%d %s is no longer about to win.\r\n", X M_INFO, plr[wasabout].p_name); X announce(wasabout, msgbuf); X if(plr[wasabout].p_stat == Active) { X sprintf(msgbuf, "%d You're no longer about to win.\r\n", X M_INFO); X (void) message(wasabout, msgbuf); X } X sleep(2); /* a chance for everybody to see... */ X } X wasabout = about; X X /* X ** Accept new players to waiting status. X */ X if(inprogress == True && wantin(False) == True) { X newplayers(False); X updstat(-1); X } X sleep(2); X break; X } X } X updstat(-1); X X /* X ** Add any waiting players until the game is 9/10ths over. X */ X if(waiting > 0 && active > 0 && inprogress == True) X if(highscore(-1) < (9 * WINSCORE) / 10) X addwaiting(); X} X X/* X** endgame: cleanup after game finish X*/ Xendgame() X{ X register int c, highc; X char msgbuf[BUFSIZ]; X X inprogress = False; X firstgame = False; X/* turnnum = 0; /* don't zero; needed in histpoints */ X updstat(-1); X X /* X ** If there's a winner, update player score histories. X */ X if((highc = winner()) >= 0) { X for(c = 0;c < PLAYERS;++c) { X switch(plr[c].p_stat) { X case Computer: X case Active: X (void) histpoints(c); X break; X } X } X (void) histwins(highc); X } X X /* X ** Write history whether or not there was a winner. X */ X (void) histwrite(); X X /* X ** Tell everybody who won. X */ X if(highc < 0) X sprintf(msgbuf, "%d The game has concluded with no winner.\r\n", X M_NWIN); X else { X sprintf(msgbuf, "%d Player %d %s has won the game!\r\n", X M_OVER, highc, plr[highc].p_name); X } X for(c = 0;c < PLAYERS;++c) { X switch(plr[c].p_stat) { X case Active: X case Waiting: X (void) message(c, msgbuf); X break; X } X } X X /* X ** Ask human players to play again. X */ X for(c = 0;c < PLAYERS;++c) { X if(plr[c].p_stat != Active) X continue; X sprintf(msgbuf, "%d Play another game? [y]\r\n", M_ANOG); X if(message(c, msgbuf) < 0) X continue; X if(reply(c, msgbuf, sizeof msgbuf) < 0) X continue; X switch(msgbuf[0]) { X case 'n': case 'N': X case 'q': case 'Q': X sprintf(msgbuf, X "%d See you later %s...\r\n", M_DOWN, plr[c].p_name); X oldplayer(c); X break; X } X } X X /* X ** If there are no active players left, then get rid of any computers. X ** Reinstall the COMP computer. X */ X if(active == 0) { X for(c = 0;c < PLAYERS;++c) X if(plr[c].p_stat == Computer) X oldplayer(c); X addcomp(); X } X X updstat(-1); X} X X/* X** addcomp: add the COMP computer X*/ Xaddcomp() X{ X plr[COMP].p_stat = Computer; X strcpy(plr[COMP].p_name, compname[0]); X plr[COMP].p_fd = -1; X plr[COMP].p_id[0] = '\0'; X plr[COMP].p_score = 0; X plr[COMP].p_onboard = False; X pickstrategy(COMP); /* also chooses temperment */ X} X X/* X** plrcmp: player comparison function X*/ Xplrcmp(p1, p2) Xplayer *p1, *p2; X{ X int diff; X X /* X ** Put inactive players last. X */ X if(p1->p_stat == Inactive) X return (p2->p_stat == Inactive) ? 0 : 1; X if(p2->p_stat == Inactive) X return -1; X X /* X ** Sort in order of increasing score. X */ X if((diff = p1->p_score - p2->p_score) != 0) X return diff; X X /* X ** Put Computer players after humans. X */ X if(p1->p_stat != p2->p_stat) X return (p1->p_stat == Computer) ? 1 : -1; X X /* X ** Sort alphabetically. X */ X return strcmp(p1->p_name, p2->p_name); X} X X/* X** roster: broadcast the roster to all players X*/ Xroster(only) Xint only; X{ X register int c, cc; X char msgbuf[MESGLEN]; X X /* X ** Tell each player who he/she is then give a roster. X ** Tell Waiting players, but don't show them. X */ X for(c = 0;c < PLAYERS;++c) { X if(only != -1 && c != only) X continue; X switch(plr[c].p_stat) { X case Active: X case Waiting: X sprintf(msgbuf, "%d New player roster.\r\n", M_CPLR); X if(message(c, msgbuf) < 0) X continue; X if(plr[c].p_stat == Active) { X sprintf(msgbuf, "%d You are player %d (%s).\r\n", X M_UARE, c, plr[c].p_name); X if(message(c, msgbuf) < 0) X continue; X sprintf(msgbuf, "%d You now have %d points.\r\n", X M_MSCO, plr[c].p_score); X if(message(c, msgbuf) < 0) X continue; X } X for(cc = 0;cc < PLAYERS;++cc) if(cc != c) { X if(plr[cc].p_stat == Active || plr[cc].p_stat == Computer) { X sprintf(msgbuf, "%d player %d %s\r\n", X M_PNUM, cc, plr[cc].p_name); X if(message(c, msgbuf) < 0) X break; X sprintf(msgbuf, "%d Player %d now has %d points.\r\n", X M_OSCO, cc, plr[cc].p_score); X if(message(c, msgbuf) < 0) X break; X } X } X break; X } X } X} X X/* X** winner: return winner number or -1 if game in progress X*/ Xwinner() X{ X register int c; X register int high, next; X register int highc; X X /* X ** Find high score. If less than WINSCORE, no winner. X */ X for(high = c = 0;c < PLAYERS;++c) { X switch(plr[c].p_stat) { X case Computer: X case Active: X if(plr[c].p_score > high) X high = plr[(highc = c)].p_score; X break; X } X } X if(high < WINSCORE) X return -1; X X /* X ** Find next to highest score. If margin is less than X ** WINMARGIN, there's no winner yet. X */ X for(next = c = 0;c < PLAYERS;++c) { X if(c == highc) X continue; X switch(plr[c].p_stat) { X case Computer: X case Active: X if(plr[c].p_score > next) X next = plr[c].p_score; X break; X } X } X if(high - next < WINMARGIN) X return -1; X X /* X ** We have a winner! X */ X return highc; X} X X/* X** nameinuse: return True if name in use by other than numbered player X*/ Xboolean Xnameinuse(c, name) Xint c; Xchar *name; X{ X register int cc; X X for(cc = 0;cc < PLAYERS;++cc) X if(cc != c && plr[cc].p_stat != Inactive) X if(strncmp(plr[cc].p_name, name, NAMELEN-1) == 0) X return True; X X return False; X} X X X/* X** getequiv: determine equivalent hosts. X*/ Xgetequiv() X{ X register FILE *fp; X register int n; X char buf[512]; X X /* X ** Open the hosts.equiv file and count the entries. X ** Allocate memory for them and this host. X */ X neq = 1; X if((fp = fopen("/etc/hosts.equiv", "r")) != 0) { X while(fgets(buf, sizeof buf, fp) != 0) X ++neq; X clearerr(fp); X rewind(fp); X } X if((equiv = (char **)malloc(neq * sizeof *equiv)) == 0) { X fprintf(stderr, "malloc: no memory for equivalent hosts\n"); X exit(1); X } X X /* X ** This host is first in the list. X */ X (void) gethostname(buf, sizeof buf); X if((equiv[0] = malloc((unsigned)(strlen(buf) + 1))) == 0) { X fprintf(stderr, "malloc: no memory for this host\n"); X exit(1); X } X strcpy(equiv[0], buf); X X /* X ** Add the hosts from hosts.equiv. X */ X if(fp != 0) { X for(n = 1;n < neq;++n) { X if(gets(buf) == 0) { X neq = n; X break; X } X if((equiv[n] = malloc((unsigned)(strlen(buf) + 1))) == 0) { X fprintf(stderr, "malloc: no memory for an equivalent host\n"); X exit(1); X } X strcpy(equiv[n], buf); X } X (void) fclose(fp); X } X} X X/* X** equivalence: strip "@thishost" or "@equivhost" from an id X*/ Xequivalence(id) Xchar *id; X{ X register char *at; X register int n; X X if((at = index(id, '@')) == 0) X return; X if(neq == 0) X getequiv(); X for(n = 0;n < neq;++n) { X if(strcmp(at+1, equiv[n]) == 0) { X *at = '\0'; X return; X } X } X} X X/* X** idinuse: return True if id is in use by an Active or Waiting player X** or is in use by more than one Computer player X** side effect: converts user@thishost or user@equivhost to just user X*/ Xboolean Xidinuse(c, id) Xint c; Xchar *id; X{ X register int cc; X int humanuse; X int computeruse; X X equivalence(id); /* strip @equivhost */ X X humanuse = computeruse = 0; X for(cc = 0;cc < PLAYERS;++cc) if(cc != c) { X if(strncmp(plr[cc].p_id, id, IDLEN-1) == 0) { X switch(plr[cc].p_stat) { X case Waiting: X case Active: X ++humanuse; X break; X case Computer: X ++computeruse; X break; X default: X break; X } X } X } X X if(humanuse > 0 || computeruse > 1) X return True; X X return False; X} X X/* X** lowscore: give new player a low score X*/ Xlowscore(c) Xint c; X{ X register int cc, low; X X low = 2 * WINSCORE; X for(cc = 0;cc < PLAYERS;++cc) { X if(cc != c && plr[cc].p_score < low) { X switch(plr[cc].p_stat) { X case Active: X case Computer: X low = plr[cc].p_score; X break; X } X } X } X X /* X ** Set player score to 75% of lowest score. Score must be a multiple of X ** P_FIVE and must be greater than or equal to ONBOARD. X */ X low = (3 * low) / 4; X low = (low / P_FIVE) * P_FIVE; X if(low < ONBOARD) X low = 0; X plr[c].p_score = low; /* a putrid score, but... */ X plr[c].p_onboard = False; /* not on board yet */ X} X X/* X** updstat: update status line X*/ Xupdstat(cup) Xint cup; X{ X register int c, n, h; X char buf[2*STATLEN+NAMELEN]; X X if(active == 0) X strcpy(buf, "idle"); X else { X for(h = n = c = 0;c < PLAYERS;++c) { X if(plr[c].p_stat == Computer || plr[c].p_stat == Active) { X if(plr[c].p_score > h) X h = plr[c].p_score; X ++n; X } X } X if(inprogress == False) X sprintf(buf, "waiting pl%d", n); X else if(cup < 0) X sprintf(buf, "active pl%d hs%d tn%d", n, h, turnnum); X else X sprintf(buf, "active pl%d hs%d tn%d %s", X n, h, turnnum, plr[cup].p_name); X } X X sprintf(statusline, "cubes %-*s.", STATLEN-7, buf); X} X X/* X** srvshutdown: controlled shutdown on SIGTERM X*/ Xstatic int Xsrvshutdown() X{ X register int c; X char msgbuf[MESGLEN]; X X sprintf(msgbuf, "%s Server shutdown, closing connection.\r\n", M_DOWN); X for(c = 0;c < PLAYERS;++c) { X switch(plr[c].p_stat) { X case Active: X case Waiting: X (void) message(c, msgbuf); X break; X } X } X X sleep(3); X exit(0); X} X X/* X** Get the player's name. X*/ Xgetplayername(c) Xint c; X{ X char msgbuf[MESGLEN]; X X /* X ** Prompt for and read name. X */ X sprintf(msgbuf, X "%d Hello, I'm the Cube daemon. Who are you?\r\n", M_HELO); X if(message(c, msgbuf) < 0 || reply(c, msgbuf, sizeof msgbuf) < 0) X return -1; X X /* X ** Check it for (surface) validity. X */ X if(msgbuf[0] == '\0') { X sprintf(msgbuf, "%d Your moniker is really dumb.\r\n", M_ARGE); X if(message(c, msgbuf) < 0) X return -1; X sprintf(msgbuf, "%d Server closing connection.\r\n", M_DOWN); X if(message(c, msgbuf) < 0) X return -1; X plr[c].p_stat = Inactive; X plr[c].p_name[0] = '\0'; X plr[c].p_id[0] = '\0'; X (void) close(plr[c].p_fd); X plr[c].p_fd = -1; X return -1; X } X X /* X ** Check to see whether it's already in use. X */ X strncpy(plr[c].p_name, msgbuf, NAMELEN); X plr[c].p_name[NAMELEN-1] = '\0'; X if(nameinuse(c, plr[c].p_name) == True) { X sprintf(msgbuf, "%d Your moniker is already in use.\r\n", M_ARGE); X if(message(c, msgbuf) < 0) X return -1; X sprintf(msgbuf, "%d Server closing connection.\r\n", M_DOWN); X if(message(c, msgbuf) < 0) X return -1; X plr[c].p_stat = Inactive; X plr[c].p_name[0] = '\0'; X plr[c].p_id[0] = '\0'; X (void) close(plr[c].p_fd); X plr[c].p_fd = -1; X return -1; X } X X return 0; X} X X/* X** getplayerid: get player's unique id (user@host) X*/ Xgetplayerid(c) Xint c; X{ X char msgbuf[MESGLEN]; X X /* X ** Prompt for and read the id. X */ X sprintf(msgbuf, "%d Please supply a unique id.\r\n", M_RQID); X if(message(c, msgbuf) < 0 || reply(c, msgbuf, sizeof msgbuf) < 0) X return -1; X X /* X ** A null id is not valid. X */ X if(msgbuf[0] == '\0') { X sprintf(msgbuf, "%d Sorry, that's not unique.\r\n", M_ARGE); X if(message(c, msgbuf) < 0) X return -1; X sprintf(msgbuf, "%d Server closing connection.\r\n", M_DOWN); X if(message(c, msgbuf) < 0) X return -1; X plr[c].p_stat = Inactive; X plr[c].p_name[0] = '\0'; X plr[c].p_id[0] = '\0'; X (void) close(plr[c].p_fd); X plr[c].p_fd = -1; X return -1; X } X X /* X ** Check to see that the id is not already in use. X */ X strncpy(plr[c].p_id, msgbuf, IDLEN); X plr[c].p_id[IDLEN-1] = '\0'; X if(idinuse(c, plr[c].p_id) == True) { X sprintf(msgbuf, "%d You're already playing!\r\n", M_ARGE); X if(message(c, msgbuf) < 0) X return -1; X sprintf(msgbuf, "%d Server closing connection.\r\n", M_DOWN); X if(message(c, msgbuf) < 0) X return -1; X plr[c].p_stat = Inactive; X plr[c].p_name[0] = '\0'; X plr[c].p_id[0] = '\0'; X (void) close(plr[c].p_fd); X plr[c].p_fd = -1; X return -1; X } X X return 0; X} X X/* X** addwaiting: add waiting players to a game in progress. X*/ Xaddwaiting() X{ X int c, cc; X char msgbuf[MESGLEN]; X X if(waiting <= 0 || inprogress == False) X return; X X for(c = 0;c < PLAYERS;++c) { X if(plr[c].p_stat != Waiting) X continue; X plr[c].p_stat = Active; X ++active, --waiting; X X sprintf(msgbuf, "%d You are player %d (%s).\r\n", X M_UARE, c, plr[c].p_name); X if(message(c, msgbuf) < 0) X continue; X sprintf(msgbuf, "%d You have entered a game in progress.\r\n", M_INFO); X if(message(c, msgbuf) < 0) X continue; X X lowscore(c); X for(cc = 0;cc < PLAYERS;++cc) { X switch(plr[cc].p_stat) { X case Computer: X case Active: X case Waiting: X sprintf(msgbuf, "%d player %d %s\r\n", X M_PNUM, cc, plr[cc].p_name); X if(message(c, msgbuf) < 0) { X cc = PLAYERS; X continue; X } X sprintf(msgbuf, "%d Player %d now has %d points.\r\n", X M_OSCO, cc, plr[cc].p_score); X if(message(c, msgbuf) < 0) { X cc = PLAYERS; X continue; X } X break; X } X } X X sprintf(msgbuf, "%d player %d %s\r\n", M_PNUM, c, plr[c].p_name); X announce(c, msgbuf); X annscore(c); X } X} END_OF_cubeserver.c if test 28971 -ne `wc -c <cubeserver.c`; then echo shar: \"cubeserver.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f screen.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"screen.c\" else echo shar: Extracting \"screen.c\" \(16193 characters\) sed "s/^X//" >screen.c <<'END_OF_screen.c' X/* vi:set sw=4 ts=4: */ X#ifndef lint Xstatic char sccsid[] = "@(#)screen.c 1.1 6/2/88 Copyright 1988 Gregory M. Paris"; X#endif lint X X#include <stdio.h> X#include <curses.h> X#include <sys/ioctl.h> X#include <signal.h> X#include <setjmp.h> X#include <strings.h> X#include <ctype.h> X#include "cubes.h" X X#define DICEROW 0 /* top line of dice subwindow */ X#define DICECOL 0 /* first column of dice subwindow */ X#define DIELINES 7 /* height of a single die */ X#define DIEWID 10 /* width of a single die */ X#define DICELINES (DIELINES+5) /* height of dice subwindow */ X#define DICEWID (NDICE*DIEWID) /* width of dice subwindow */ XWINDOW *dicewin; /* dice subwindow */ XWINDOW *die[NDICE]; /* subwindow for each die */ X X#define INFOCOL 0 /* where status messages appear */ X#define INFOROW (DICELINES+1) /* where status messages appear */ X#define INFOLINES 1 /* lines in subwindow */ X#define INFOWID DICEWID /* same width as dice subwindow */ XWINDOW *infowin; /* informational subwindow */ X X#define PROMPTCOL 0 /* where prompt appears */ X#define PROMPTROW (INFOROW+1) /* where prompt appears */ X#define PROMPTLINES 1 /* one line of prompt */ X#define PROMPTWID DICEWID /* same width as dice subwindow */ XWINDOW *promptwin; /* prompt subwindow */ X X#define HELPROW (LINES-9) /* where help subwindow begins */ X#define HELPCOL 0 /* where help subwindow begins */ X#define HELPLINES 0 /* extends to edge of screen */ X#define HELPWID 0 /* extends to edge of screen */ XWINDOW *helpwin; /* help message subwindow */ X X#define SCOREROW 0 /* where score subwindow begins */ X#define SCORECOL (DICEWID+2) /* where score subwindow begins */ X#define SCORELINES HELPROW /* extends to help subwindow */ X#define SCOREWID 0 /* extends to edge of screen */ XWINDOW *scorewin; /* player scores subwindow */ X Xstruct ltchars tty_lt; /* local tty characters */ Xchar *AS, *AE; /* graphics... */ Xgraphtype graphics = Nographics; /* terminal has no graphics */ Xboolean quiet = False; /* in quiet mode */ X Xstatic int refdummy; X#define REFRESH() (refdummy = (quiet == False) ? refresh() : 0) X#define WREFRESH(win) (refdummy = (quiet == False) ? wrefresh(win) : 0) X Xextern int mypnum; Xextern int turnnum; Xextern boolean gotintr; Xextern player plr[]; Xextern diceset dice; Xstatic int beep(); Xstatic int outc(); Xstatic int suspend(); Xstatic char *combname(); X X/* X** interrupt: handle interrupt signal X*/ Xstatic int Xinterrupt() X{ X gotintr = True; X} X X/* X** reallyquit: ask player if they really want to quit X*/ Xreallyquit() X{ X char ans[128]; X X if(prompt("Do you really want to quit? [ny]", ans) >= 0) { X if(ans[0] != 'y' && ans[0] != 'Y') { X gotintr = False; X return; X } X } X X (void) infomesg("So long, quitter..."); X sleep(2); X cleanup(0); X} X X#define OWNgetcap X#ifdef OWNgetcap X#define getcap(x) mygetcap(x) X/* X** getcap: mimics functional curses getcap X*/ Xstatic char * Xmygetcap(cap) Xchar *cap; X{ X static char entbuf[1024]; X static char capbuf[1024]; X static char *acap = 0; X char *term; X extern char *getenv(); X extern char *tgetstr(); X X if(acap == 0) { X if((term = getenv("TERM")) == 0) X return (char *)0; X if(tgetent(entbuf, term) != 1) X return (char *)0; X acap = capbuf; X } X X return tgetstr(cap, &acap); X} X#endif OWNgetcap X X/* X** startup: initialize the screen X*/ Xstartup() X{ X register int d; X X initscr(); X (void) signal(SIGHUP, SIG_DFL); X gotintr = False; X if(signal(SIGINT, SIG_IGN) != SIG_IGN) X (void) signal(SIGINT, interrupt); X if(signal(SIGQUIT, SIG_IGN) != SIG_IGN) X (void) signal(SIGQUIT, interrupt); X if(signal(SIGTSTP, SIG_IGN) != SIG_IGN) X (void) signal(SIGTSTP, suspend); X X (void) ioctl(_tty_ch, TIOCGLTC, (char *)&tty_lt); X X scrollok(stdscr, FALSE); X crmode(); X noecho(); X REFRESH(); X X if(graphics != Nographics) { X AS = getcap("as"); X AE = getcap("ae"); X if(AS == 0 || AE == 0) X graphics = Nographics; X else X SO = AS, SE = AE; X } X X dicewin = subwin(stdscr, DICELINES, DICEWID, DICEROW, DICECOL); X if(dicewin == 0) { X fprintf(stderr, "cubes: can't create dicewin subwindow\n"); X cleanup(1); X } X X for(d = 0;d < NDICE;++d) { X die[d] = subwin(dicewin, DIELINES, DIEWID, 0, d*DIEWID); X if(die[d] == 0) { X fprintf(stderr, "cubes: can't create die[%d] subwindow\n", d); X cleanup(1); X } X } X X infowin = subwin(stdscr, INFOLINES, INFOWID, INFOROW, INFOCOL); X if(infowin == 0) { X fprintf(stderr, "cubes: can't create infowin subwindow\n"); X cleanup(1); X } X X promptwin = subwin(stdscr, PROMPTLINES, PROMPTWID, PROMPTROW, PROMPTCOL); X if(promptwin == 0) { X fprintf(stderr, "cubes: can't create promptwin subwindow\n"); X cleanup(1); X } X X scorewin = subwin(stdscr, SCORELINES, SCOREWID, SCOREROW, SCORECOL); X if(scorewin == 0) { X fprintf(stderr, "cubes: can't create scorewin subwindow\n"); X cleanup(1); X } X X helpwin = subwin(stdscr, HELPLINES, HELPWID, HELPROW, HELPCOL); X if(helpwin == 0) { X fprintf(stderr, "cubes: can't create helpwin subwindow\n"); X cleanup(1); X } X X helpmesg(); X} X X/* X** cleanup: cleanup the screen and exit X*/ Xcleanup(ex) Xint ex; X{ X if(quiet == False) { X endwin(); X if(ex == 0) X tputs(CL, LINES, outc); X } X exit(ex); X} X X/* X** infomesg: display an informational or status message X*/ Xinfomesg(mesg) Xchar *mesg; X{ X wclear(infowin); X waddstr(infowin, mesg); X WREFRESH(infowin); X if(quiet == True) { X printf("%s\n", mesg); X (void) fflush(stdout); X } X return 0; X} X X/* X** clearinfo: clear info message X*/ Xclearinfo() X{ X wclear(infowin); X WREFRESH(infowin); X return 0; X} X Xstatic char *hline[] = { X/* "1234567890123456789012345678901234567890123456789", */ X "+-----------------------------------------------+", X "| 5o'kind 300 * face (held dice count) |", X "| 4o'kind 200 * face (held dice don't count) |", X "| 3o'kind 100 * face (held dice don't count) |", X "| Straight 1500 (held dice don't count) +", X "| Small Str. 400 (held dice don't count) |", X "| One 100 (face for ones is ten) |", X "| Five 50 |", X "+-----------------------------------------------+", X (char *)0 X}; X Xstatic char *iline[] = { X/* "012345678901234567890123456789", */ X "-----------------------------+", X " ** Turn Point Thresholds ** |", X " To get on board 500 |", X " To go off board 500 |", X "-----------------------------+", X " ** Game Point Thresholds ** |", X " Total to win 10000 |", X " Margin to win by 250 |", X "-----------------------------+", X (char *)0 X}; X X/* X** helpmesg: display instructions X*/ Xhelpmesg() X{ X register int row; X X wmove(helpwin, 0, 0); X wclear(helpwin); X for(row = 0;hline[row] != 0;++row) { X wmove(helpwin, row, 0); X wclrtoeol(helpwin); X waddstr(helpwin, hline[row]); X waddstr(helpwin, iline[row]); X } X WREFRESH(helpwin); X} X X/* X** urgjmp, urgent: SIGURG handler X*/ Xstatic jmp_buf urgjmp; Xstatic int Xurgent() X{ X longjmp(urgjmp, 1); X} X X/* X** prompt: print a prompt message and read an answer X*/ Xprompt(mesg, answer) Xchar *mesg, *answer; X{ X register int c; X register char *s; X int (*sigurg)(); X int (*sigint)(); X long count; X char dbuf[64]; X X /* X ** Disallow interrupts for now. X */ X if((sigint = signal(SIGINT, SIG_IGN)) != SIG_IGN) X (void) signal(SIGINT, beep); X X /* X ** Flush any typeahead. X */ X while(ioctl(0, FIONREAD, (char *)&count) == 0 && count > 0) X (void) read(0, dbuf, sizeof dbuf); X rewind(stdin); X Xreprompt: X answer[0] = '\0'; X wmove(promptwin, 0, 0); X wclear(promptwin); X waddstr(promptwin, mesg); X waddch(promptwin, ' '); X WREFRESH(promptwin); X if(quiet == True) { X printf("%s ", mesg); X (void) fflush(stdout); X } X X /* X ** If server times out on us it sends out of band X ** data, which should cause us to receive a SIGURG. X */ X sigurg = signal(SIGURG, SIG_IGN); X if(setjmp(urgjmp) != 0) { X (void) signal(SIGINT, sigint); X (void) signal(SIGURG, sigurg); X wclear(promptwin); X (void) infomesg("The server timed out waiting for your response."); X return -2; /* timeout */ X } X X (void) signal(SIGURG, urgent); X for(s = answer;;) { X c = wgetch(promptwin); X if(c == EOF || c == '\r' || c == '\n') X break; X if(c == _tty.sg_erase) { X if(--s < answer) { X s = answer; X beep(); X continue; X } X waddch(promptwin, '\b'); X wdelch(promptwin); X WREFRESH(promptwin); X continue; X } X if(c == _tty.sg_kill || c == tty_lt.t_werasc) X goto reprompt; X if(c == tty_lt.t_rprntc || c == '\f') { X redraw(); X continue; X } X if(iscntrl(c)) { X beep(); X continue; X } X waddch(promptwin, c); X WREFRESH(promptwin); X *s++ = c; X } X *s = '\0'; X (void) signal(SIGURG, sigurg); X X wmove(promptwin, 0, 0); X wclear(promptwin); X WREFRESH(promptwin); X X wclear(infowin); X WREFRESH(infowin); X X (void) signal(SIGINT, sigint); X return 0; X} X X/* X** nowup: mark player number as being up X*/ Xnowup(num) Xint num; X{ X static int lastup = -1; X X (void) clearinfo(); X X wmove(scorewin, 0, 16); X wprintw(scorewin, "%5d", turnnum); X X if(lastup != -1) { X wmove(scorewin, lastup+2, 0); X waddstr(scorewin, " "); X } X wmove(scorewin, num+2, 0); X waddstr(scorewin, "=-> "); X lastup = num; X WREFRESH(scorewin); X X if(num == mypnum) X beep(); X X return 0; X} X X/* X** showplr: update player info X*/ Xshowplr(c) Xint c; X{ X wmove(scorewin, 0, 0); X wclrtoeol(scorewin); X wprintw(scorewin, X "%-3s %-11.11s %5d %5s", "Up", "Player", turnnum, "Score"); X wmove(scorewin, 1, 0); X wclrtoeol(scorewin); X wprintw(scorewin, "%3s %-17.17s %5s", "---", "-----------------", "-----"); X wmove(scorewin, c+2, 0); X wclrtoeol(scorewin); X if(plr[c].p_stat == Active || plr[c].p_stat == Computer) X wprintw(scorewin, " %-17.17s %5d", plr[c].p_name, plr[c].p_score); X WREFRESH(scorewin); X X return 0; X} X X/* X** clearplr: clear player info X*/ Xclearplr(c) Xint c; X{ X wmove(scorewin, c+2, 0); X wclrtoeol(scorewin); X WREFRESH(scorewin); X X return 0; X} X X/* X** showdice: show dice status and faces and scoring summary X*/ Xshowdice() X{ X int d; X int ndrawn; X boolean drawn[NDICE]; X char msgbuf[MESGLEN]; X X /* X ** Draw all the dice. First draw any held or free dice, X ** then draw the remaining dice in random order. Note that X ** the inefficient algorithm used might add a little suspense. X */ X ndrawn = 0; X for(d = 0;d < NDICE;++d) { X switch(dice.d_stat[d]) { X case Held: X case Free: X (void) drawdie(d); X drawn[d] = True; X ++ndrawn; X break; X default: X drawn[d] = False; X break; X } X } X while(ndrawn < NDICE) { X d = dieroll(NDICE) - 1; X if(drawn[d] == False) { X (void) drawdie(d); X drawn[d] = True; X ++ndrawn; X } X } X X /* X ** Show the combinations. X */ X wmove(dicewin, DICELINES-5, 0); X wclrtoeol(dicewin); X for(d = 0;d < NDICE;++d) { X wmove(dicewin, DICELINES-5, d * DIEWID); X if(dice.d_stat[d] != Free && dice.d_face[d] != BADFACE) X waddstr(dicewin, combname(dice.d_comb[d])); X } X WREFRESH(dicewin); X X wmove(dicewin, DICELINES-3, 0); X wclrtoeol(dicewin); X if(dice.d_mesg[0] != '\0') { X d = (DICEWID - strlen(dice.d_mesg)) / 2; X if(d < 0) d = 0; X wprintw(dicewin, "%*s%s", d, "", dice.d_mesg); X } X X wmove(dicewin, DICELINES-2, 0); X wclrtoeol(dicewin); X if(dice.d_pts_turn > 0 X && dice.d_mesg[0] != '\0' && strcmp(dice.d_mesg, "nothing") != 0) { X sprintf(msgbuf, "plus %d saved", dice.d_pts_turn); X d = (DICEWID - strlen(msgbuf)) / 2; X if(d < 0) d = 0; X wprintw(dicewin, "%*s%s", d, "", msgbuf); X } else if(dice.d_pts_roll < 0) { X sprintf(msgbuf, "threw away %d points", -dice.d_pts_roll); X d = (DICEWID - strlen(msgbuf)) / 2; X if(d < 0) d = 0; X wprintw(dicewin, "%*s%s", d, "", msgbuf); X } X X wmove(dicewin, DICELINES-1, 0); X wclrtoeol(dicewin); X for(d = 0;d < NDICE;++d) X if(dice.d_comb[d] == Nothing) X break; X if(d == NDICE) { X strcpy(msgbuf, "scored with all dice"); X d = (DICEWID - strlen(msgbuf)) / 2; X if(d < 0) d = 0; X wprintw(dicewin, "%*s%s", d, "", msgbuf); X } X X WREFRESH(dicewin); X X return 0; X} X X/* X** cdieface: die faces for each die formed by characters X*/ Xstatic char *cdieface[] = { X" in hand ",".-------,","| |","| |","| |","`-------'", X" one ",".-------,","| |","| * |","| |","`-------'", X" two ",".-------,","| * |","| |","| * |","`-------'", X" three ",".-------,","| * |","| * |","| * |","`-------'", X" four ",".-------,","| * * |","| |","| * * |","`-------'", X" five ",".-------,","| * * |","| * |","| * * |","`-------'", X" six ",".-------,","| * * |","| * * |","| * * |","`-------'", X}; X X/* X** ddieface: die faces for each die formed by DEC graphics characters X*/ Xstatic char *ddieface[] = { X" in hand ","lqqqqqqqk","x x","x x","x x","mqqqqqqqj", X" one ","lqqqqqqqk","x x","x ` x","x x","mqqqqqqqj", X" two ","lqqqqqqqk","x ` x","x x","x ` x","mqqqqqqqj", X" three ","lqqqqqqqk","x ` x","x ` x","x ` x","mqqqqqqqj", X" four ","lqqqqqqqk","x ` ` x","x x","x ` ` x","mqqqqqqqj", X" five ","lqqqqqqqk","x ` ` x","x ` x","x ` ` x","mqqqqqqqj", X" six ","lqqqqqqqk","x ` ` x","x ` ` x","x ` ` x","mqqqqqqqj", X}; X X/* X** zdieface: die faces for each die formed by Zenith graphics characters X*/ Xstatic char *zdieface[] = { X" in hand ","faaaaaaac","` `","` `","` `","eaaaaaaad", X" one ","faaaaaaac","` `","` ^ `","` `","eaaaaaaad", X" two ","faaaaaaac","` ^ `","` `","` ^ `","eaaaaaaad", X" three ","faaaaaaac","` ^ `","` ^ `","` ^ `","eaaaaaaad", X" four ","faaaaaaac","` ^ ^ `","` `","` ^ ^ `","eaaaaaaad", X" five ","faaaaaaac","` ^ ^ `","` ^ `","` ^ ^ `","eaaaaaaad", X" six ","faaaaaaac","` ^ ^ `","` ^ ^ `","` ^ ^ `","eaaaaaaad", X}; X X/* X** combname: return pointer to string describing combination X** all names are centered in nine spaces X*/ Xstatic char * Xcombname(comb) Xcombination comb; X{ X switch(comb) { X /* return "123456789"; */ X case Previous: return " + "; X case Nothing: return " "; X case Five: return " five "; X case Ace: return " one "; X case Three_of_a_kind: return " 3o'kind "; X case Small_straight: return " small "; X case Four_of_a_kind: return " 4o'kind "; X case Straight: return " straight"; X case All_of_a_kind: return " 5o'kind "; X default: return " ? "; X } X} X X/* X** drawdie: draw die number d X*/ Xdrawdie(d) Xint d; X{ X register int row, s; X register char **pix; X X wclear(die[d]); X X wmove(die[d], 0, 0); X wprintw(die[d], "%*d", (DIEWID+1)/2, d+1); X X if((s = dice.d_face[d]) == BADFACE) X s = 0; X X switch(graphics) { X case Digital: pix = &ddieface[s*(DIELINES-1)]; break; X case Zenith: pix = &zdieface[s*(DIELINES-1)]; break; X default: pix = &cdieface[s*(DIELINES-1)]; break; X } X X for(row = 0;row < DIELINES-1;++row) { X if(row > 0 && graphics != Nographics) X wstandout(die[d]); X wmove(die[d], row+1, 0); X waddstr(die[d], *(pix+row)); X if(row > 0 && graphics != Nographics) X wstandend(die[d]); X } X X WREFRESH(die[d]); X return 0; X} X X/* X** outc: write a single character X*/ Xstatic Xoutc(c) Xchar c; X{ X return write(_tty_ch, &c, 1); X} X X/* X** beep: send a beep X*/ Xstatic Xbeep() X{ X if(quiet == False) X (void) outc('\007'); X} X X/* X** neutral: return cursor to a neutral position X*/ Xneutral() X{ X move(PROMPTROW, PROMPTCOL); X REFRESH(); X} X X/* X** redraw: cause the screen to be redrawn X*/ Xredraw() X{ X tputs(TI, 0, outc); X tputs(VS, 0, outc); X WREFRESH(curscr); X} X X/* X** suspend: catch suspend signal X*/ Xstatic int Xsuspend() X{ X if(quiet == False) X beginquiet(); X else X endquiet(); X} X Xstatic int ttyflags; /* set in beginquiet, used in endquiet */ X X/* X** beginquiet: enter quiet mode X*/ Xstatic int Xbeginquiet() X{ X quiet = True; X ttyflags = _tty.sg_flags; /* store curses state */ X endwin(); X (void) fflush(stdout); X tputs(CL, LINES, outc); X printf("Hit <suspend> again to leave quiet mode.\n"); X (void) fflush(stdout); X} X/* X** endquiet: leave quiet mode X*/ Xstatic int Xendquiet() X{ X quiet = False; X savetty(); /* re-remember the virgin state */ X _tty.sg_flags = ttyflags; /* restore special curses state */ X (void) ioctl(_tty_ch, TIOCSETN, &_tty); X tputs(TI, 0, outc); X tputs(VS, 0, outc); X (void) WREFRESH(curscr); X} END_OF_screen.c if test 16193 -ne `wc -c <screen.c`; then echo shar: \"screen.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of archive 1 \(of 3\). cp /dev/null ark1isdone MISSING="" for I in 1 2 3 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 3 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0