summaryrefslogtreecommitdiffstats
path: root/hunt/hunt
diff options
context:
space:
mode:
authormrg <mrg@NetBSD.org>1997-10-04 09:00:13 +0000
committermrg <mrg@NetBSD.org>1997-10-04 09:00:13 +0000
commite9152f6d21d5a8b1e02922e0fc95b71fc21cbd92 (patch)
tree3e1b32f0c0c61414ebd853c92584cd9d95a99acc /hunt/hunt
parent6f367f8f8be268d527e585867c1c42ffbb07668c (diff)
downloadbsdgames-darwin-e9152f6d21d5a8b1e02922e0fc95b71fc21cbd92.tar.gz
bsdgames-darwin-e9152f6d21d5a8b1e02922e0fc95b71fc21cbd92.tar.zst
bsdgames-darwin-e9152f6d21d5a8b1e02922e0fc95b71fc21cbd92.zip
hunt version 1993-07-17
Diffstat (limited to 'hunt/hunt')
-rw-r--r--hunt/hunt/connect.c41
-rw-r--r--hunt/hunt/hunt.6378
-rw-r--r--hunt/hunt/hunt.c1072
-rw-r--r--hunt/hunt/otto.c585
-rw-r--r--hunt/hunt/playit.c628
5 files changed, 2704 insertions, 0 deletions
diff --git a/hunt/hunt/connect.c b/hunt/hunt/connect.c
new file mode 100644
index 00000000..587f8b40
--- /dev/null
+++ b/hunt/hunt/connect.c
@@ -0,0 +1,41 @@
+/*
+ * Hunt
+ * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
+ * San Francisco, California
+ */
+
+# include "hunt.h"
+# include <signal.h>
+
+do_connect(name, team, enter_status)
+char *name;
+char team;
+long enter_status;
+{
+ static long uid;
+ static long mode;
+ extern char *ttyname();
+
+ if (uid == 0)
+ uid = htonl(getuid());
+ (void) write(Socket, (char *) &uid, LONGLEN);
+ (void) write(Socket, name, NAMELEN);
+ (void) write(Socket, &team, 1);
+ enter_status = htonl(enter_status);
+ (void) write(Socket, (char *) &enter_status, LONGLEN);
+ (void) strcpy(Buf, ttyname(fileno(stderr)));
+ (void) write(Socket, Buf, NAMELEN);
+# ifdef INTERNET
+ if (Send_message != NULL)
+ mode = C_MESSAGE;
+ else
+# endif
+# ifdef MONITOR
+ if (Am_monitor)
+ mode = C_MONITOR;
+ else
+# endif
+ mode = C_PLAYER;
+ mode = htonl(mode);
+ (void) write(Socket, (char *) &mode, sizeof mode);
+}
diff --git a/hunt/hunt/hunt.6 b/hunt/hunt/hunt.6
new file mode 100644
index 00000000..5394e1ec
--- /dev/null
+++ b/hunt/hunt/hunt.6
@@ -0,0 +1,378 @@
+.\" hunt
+.\" Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
+.\" San Francisco, California
+.\"
+.\" Copyright (c) 1985 Regents of the University of California.
+.\" All rights reserved. The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.TH HUNT 6 "21 August 1986"
+.UC 4
+.SH NAME
+hunt \- a multi-player multi-terminal game
+.SH SYNOPSIS
+\fB/usr/games/hunt\fP [ \fB\-qmcsfbS\fP ] [ \fB\-n\fP name ] [ \fB\-t\fP team ] [ \fB\-p\fP port ] [ \fB\-w\fP message ] [ host ]
+.SH DESCRIPTION
+The object of the game
+.I hunt
+is to kill off the other players.
+There are no rooms, no treasures, and no monsters.
+Instead, you wander around a maze, find grenades, trip mines, and shoot down
+walls and players.
+The more players you kill before you die, the better your score is.
+If the
+.B \-m
+flag is given,
+you enter the game as a monitor
+(you can see the action but you cannot play).
+.PP
+.I Hunt
+normally looks for an active game on the local network;
+if none is found, it starts one up on the local host.
+The location of the game may be specified by giving the
+.I host
+argument.
+This presupposes that a hunt game is already running on that host, see
+.IR huntd (6)
+for details on how to setup a game on a specific host.
+If more than one game if found,
+you may pick which game to play in.
+.PP
+If the
+.B \-q
+flag is given,
+.I hunt
+queries the local network (or specific host)
+and reports on all active games found.
+This is useful for shell startup scripts, \fIe.g.\fP csh's .login.
+.PP
+The player name may be specified on the command line by using the
+.B \-n
+option.
+.PP
+The
+.BR \-c ,
+.BR \-s ,
+and
+.B \-f
+options are for entering the game cloaked, scanning, or flying respectively.
+.PP
+The
+.B \-b
+option turns off beeping when you reach the typeahead limit.
+.PP
+The
+.B \-t
+option aids team playing by making everyone else on one's team
+appear as the team name.
+A team name is a single digit to avoid conflicting with other characters
+used in the game.
+.PP
+The
+.B \-p
+.I port
+option allows the rendezvous port number to be set.
+This is a useful way for people playing on dialup lines to avoid playing
+with people on 9600 baud terminals.
+.PP
+The
+.B \-w
+.I message
+option is the only way to send a message to everyone else's screen when
+you start up.
+It is most often used to say ``eat slime death - NickD's coming in''.
+.PP
+When you die and are asked if you wish to re-enter the game,
+there are other answers than just yes or no.
+You can also reply with a
+.B w
+for write a message before continuing or
+.B o
+to change how you enter the game (cloaked, scanning, or flying).
+.PP
+To be notified automatically when a
+.I hunt
+starts up, add your login to the
+.I hunt-players
+mailing list (see
+.IR huntd (6)).
+.SH "PLAYING HINTS"
+.I Hunt
+only works on crt (vdt) terminals with at least 24 lines, 80 columns, and
+cursor addressing.
+The screen is divided in to 3 areas.
+On the right hand side is the status area.
+It shows damage sustained,
+charges remaining,
+who's in the game,
+who's scanning (the
+.B ``*''
+in front of the name),
+who's cloaked (the
+.B ``+''
+in front of the name),
+and other players' scores.
+The rest of the screen is taken up by your map of the maze.
+The 24th line
+is used for longer messages that don't fit in the status area.
+.PP
+.I Hunt
+uses the same keys to move as
+.IR vi (1)
+does,
+.IR i.e. ,
+.BR h ,
+.BR j ,
+.BR k ,
+and
+.B l
+for left, down, up, right respectively.
+To change which direction you're facing in the maze,
+use the upper case version of the movement key (\c
+.IR i.e. ,
+.BR HJKL ).
+You can only fire or throw things in the direction you're facing.
+.TP
+Other commands are:
+.sp
+.nf
+.ta
+.ta \w'>\|<\|^\|v\ \ 'u
+f or 1 \- Fire a bullet (Takes 1 charge)
+g or 2 \- Throw grenade (Takes 9 charges)
+F or 3 \- Throw satchel charge (Takes 25 charges)
+G or 4 \- Throw bomb (Takes 49 charges)
+5 \- Throw big bomb (Takes 81 charges)
+6 \- Throw even bigger bomb (Takes 121 charges)
+7 \- Throw even more big bomb (Takes 169 charges)
+8 \- Throw even more bigger bomb (Takes 225 charges)
+9 \- Throw very big bomb (Takes 289 charges)
+0 \- Throw very, very big bomb (Takes 361 charges)
+@ \- Throw biggest bomb (Takes 441 charges)
+o \- Throw small slime (Takes 15 charges)
+O \- Throw big slime (Takes 30 charges)
+p \- Throw bigger slime (Takes 45 charges)
+P \- Throw biggest slime (Takes 60 charges)
+s \- Scan (show where other players are) (Takes 1 charge)
+c \- Cloak (hide from scanners) (Takes 1 charge)
+
+^L \- Redraw screen
+q \- Quit
+.fi
+.TP
+The symbols on the screen are:
+.sp
+.nf
+.ta
+.ta \w'>\|<\|^\|v\ \ 'u
+\-\||\|+ \- walls
+/\|\\ \- diagonal (deflecting) walls
+# \- doors (dispersion walls)
+; \- small mine
+g \- large mine
+: \- bullet
+o \- grenade
+O \- satchel charge
+@ \- bomb
+s \- small slime
+$ \- big slime
+>\|<\|^\|v \- you facing right, left, up, or down
+}\|{\|i\|! \- other players facing right, left, up, or down
+\(** \- explosion
+.ne 3
+.cs R 24
+.cs I 24
+\fR\\|/\fP
+.cs R
+\fI\-\(**\-\fP \- grenade and large mine explosion
+.fl
+.cs R 24
+\fR/|\\\fP
+.cs R
+.cs I
+.fi
+.LP
+Other helpful hints:
+.sp
+.ie n .ds b []
+.el .ds b \(bu
+.ta
+.ta \w'\*b\ \|'u
+.nr In \n(.i
+.de MP
+.br
+.in \n(Inu+\w'\*b\ \|'u
+.ti \n(Inu
+\*b \c
+..
+.MP
+You can only fire in the direction you are facing.
+.MP
+You can only fire three shots in a row, then the gun must cool off.
+.MP
+Shots move 5 times faster than you do.
+.MP
+To stab someone,
+you face that player and move at them.
+.MP
+Stabbing does 2 points worth of damage and shooting does 5 points.
+.MP
+Slime does 5 points of damage each time it hits.
+.MP
+You start with 15 charges and get 5 more every time a player enters
+or re-enters.
+.MP
+Grenade explosions cover a 3 by 3 area, each larger bomb cover a
+correspondingly larger area (ranging from 5 by 5 to 21 by 21).
+All explosions are centered around the square the shot hits and
+do the most damage in the center.
+.MP
+Slime affects all squares it oozes over.
+The number of squares is equal to the number of charges used.
+.MP
+One small mine and one large mine is placed in the maze for every new player.
+A mine has a 2% probability of tripping when you walk forward on to it;
+50% when going sideways;
+95% when backing up.
+Tripping a mine costs you 5 points or 10 points respectively.
+Defusing a mine is worth 1 charge or 9 charges respectively.
+.MP
+You cannot see behind you.
+.MP
+Cloaking consumes 1 ammo charge per 20 of your moves.
+.MP
+Scanning consumes 1 ammo charge per (20 \(mu the number of players)
+of other player moves.
+.MP
+Turning on cloaking turns off scanning \(em turning on scanning turns off
+cloaking.
+.MP
+When you kill someone,
+you get 2 more damage capacity points and 2 damage points get taken away.
+.MP
+Maximum typeahead is 5 characters.
+.MP
+A shot destroys normal (\c
+.IR i.e.,
+non-diagonal, non-door) walls.
+.MP
+Diagonal walls deflect shots and change orientation.
+.MP
+Doors disperse shots in random directions (up, down, left, right).
+.MP
+Diagonal walls and doors cannot be destroyed by direct shots but may
+be destroyed by an adjacent grenade explosion.
+.MP
+Slime goes around walls, not through them.
+.MP
+Walls regenerate, reappearing in the order they were destroyed.
+One percent of the regenerated walls will be diagonal walls or doors.
+When a wall is generated directly beneath a player, he is thrown in
+a random direction for a random period of time. When he lands, he
+sustains damage (up to 20 percent of the amount of damage already
+sustained);
+.IR i.e. ,
+the less damage he had, the more nimble he is and
+therefore less likely to hurt himself on landing.
+.\"MP
+.\"There is a volcano close to the center of the maze which goes off
+.\"close to every 30 deaths.
+.MP
+Every 30 deaths or so, a
+.B ``?''
+will appear.
+It is a wandering bomb which will explode when it hits someone, or
+when it is slimed.
+.MP
+If no one moves, everything stands still.
+.MP
+The environment variable
+.B HUNT
+is checked to get the player name.
+If you don't have this variable set,
+.I hunt
+will ask you what name you want to play under.
+If you wish to set other options than just your name,
+you can enumerate the options as follows:
+.br
+.ti +1i
+setenv HUNT "name=Sneaky,team=1,cloak,mapkey=zoFfGg1f2g3F4G"
+.br
+sets the player name to Sneaky,
+sets the team to one,
+sets the enter game attribute to cloaked,
+and the maps \fBz\fP to \fBo\fP, \fBF\fP to \fBf\fP, \fBG\fP to \fBg\fP,
+\fB1\fP to \fBf\fP,
+\fB2\fP to \fBg\fP, \fB3\fP to \fBF\fP, and \fB4\fP to \fBG\fP.
+The \fImapkey\fP option must be last.
+Other options are: scan, fly, nobeep, port=string, host=string,
+and message=string \(em which correspond to the command line options.
+String options cannot contain commas since commas
+are used to separate options.
+.MP
+It's a boring game if you're the only one playing.
+.PP
+Your score is the decayed average of the ratio of number of kills to number
+of times you entered the game and is only kept for the duration
+of a single session of \fIhunt\fP.
+.PP
+.I Hunt
+normally drives up the load average to be approximately
+(number_of_players + 0.5) greater than it would be without a
+.I hunt
+game executing.
+.SH STATISTICS
+The
+.B \-S
+option fetches the current game statistics.
+The meaning of the column headings are as follows:
+.I score
+\(em the player's last score;
+.I ducked
+\(em
+how many shots a player ducked;
+.I absorb
+\(em how many shots a player absorbed;
+.I faced
+\(em how many shots were fired at player's face;
+.I shot
+\(em how many shots were fired at player;
+.I robbed
+\(em how many of player's shots were absorbed;
+.I missed
+\(em how many of player's shots were ducked;
+.I slimeK
+\(em how many slime kills player had;
+.I enemy
+\(em how many enemies were killed;
+.I friend
+\(em how many friends were killed (self and same team);
+.I deaths
+\(em how many times player died;
+.I still
+\(em how many times player died without typing in any commands;
+.I saved
+\(em how many times a shot/bomb would have killed player if he hadn't
+ducked or absorbed it.
+.SH FILES
+.nf
+.ta
+.ta \w'/usr/games/lib/huntd\ \ \ 'u
+/usr/games/lib/huntd game coordinator
+.DT
+.fi
+.SH "SEE ALSO"
+huntd(6)
+.SH AUTHORS
+Conrad Huang, Ken Arnold, and Greg Couch;
+.br
+University of California, San Francisco, Computer Graphics Lab
+.SH ACKNOWLEDGEMENTS
+We thank Don Kneller,
+John Thomason, Eric Pettersen, Mark Day,
+and Scott Weiner for providing
+endless hours of play-testing to improve the character of the game.
+We hope their significant others will forgive them;
+we certainly don't.
+.SH BUGS
+To keep up the pace, not everything is as realistic as possible.
diff --git a/hunt/hunt/hunt.c b/hunt/hunt/hunt.c
new file mode 100644
index 00000000..6599b87e
--- /dev/null
+++ b/hunt/hunt/hunt.c
@@ -0,0 +1,1072 @@
+/*
+ * Hunt
+ * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
+ * San Francisco, California
+ */
+
+# include <errno.h>
+# if !defined(USE_CURSES) && defined(BSD_RELEASE) && BSD_RELEASE >= 44
+# include <termios.h>
+static struct termios saved_tty;
+# endif
+# include <curses.h>
+# include <string.h>
+# include "hunt.h"
+# include <signal.h>
+# include <ctype.h>
+# include <sys/stat.h>
+# include <sys/time.h>
+
+/*
+ * Some old versions of curses don't have these defined
+ */
+# if !defined(cbreak) && (!defined(BSD_RELEASE) || BSD_RELEASE < 44)
+# define cbreak() crmode()
+# endif
+
+# if !defined(USE_CURSES) || !defined(TERMINFO)
+# define beep() (void) putchar(CTRL('G'))
+# endif
+# if !defined(USE_CURSES)
+# undef refresh
+# define refresh() (void) fflush(stdout);
+# endif
+# ifdef USE_CURSES
+# define clear_eol() clrtoeol()
+# define put_ch addch
+# define put_str addstr
+# endif
+
+#if !defined(BSD_RELEASE) || BSD_RELEASE < 44
+extern int _putchar();
+#endif
+
+FLAG Last_player = FALSE;
+# ifdef MONITOR
+FLAG Am_monitor = FALSE;
+# endif
+
+char Buf[BUFSIZ];
+
+int Socket;
+# ifdef INTERNET
+char *Sock_host;
+char *use_port;
+FLAG Query_driver = FALSE;
+char *Send_message = NULL;
+FLAG Show_scores = FALSE;
+# endif
+
+SOCKET Daemon;
+# ifdef INTERNET
+# define DAEMON_SIZE (sizeof Daemon)
+# else
+# define DAEMON_SIZE (sizeof Daemon - 1)
+# endif
+
+char map_key[256]; /* what to map keys to */
+FLAG no_beep;
+
+static char name[NAMELEN];
+static char team = ' ';
+
+static int in_visual;
+
+extern int cur_row, cur_col;
+extern char *tgoto();
+
+# ifdef INTERNET
+extern SOCKET *list_drivers();
+# endif
+
+/*
+ * main:
+ * Main program for local process
+ */
+main(ac, av)
+int ac;
+char **av;
+{
+ char *term;
+ int c;
+ extern int errno;
+ extern int Otto_mode;
+ extern int optind;
+ extern char *optarg;
+ long enter_status;
+ SIGNAL_TYPE intr(), sigterm(), sigemt(), tstp();
+ long env_init(), quit();
+
+ enter_status = env_init((long) Q_CLOAK);
+ while ((c = getopt(ac, av, "Sbcfh:l:mn:op:qst:w:")) != EOF) {
+ switch (c) {
+ case 'l': /* rsh compatibility */
+ case 'n':
+ (void) strncpy(name, optarg, NAMELEN);
+ break;
+ case 't':
+ team = *optarg;
+ if (!isdigit(team)) {
+ fprintf(stderr, "Team names must be numeric\n");
+ team = ' ';
+ }
+ break;
+ case 'o':
+# ifndef OTTO
+ fputs("The -o flag is reserved for future use.\n",
+ stderr);
+ goto usage;
+# else
+ Otto_mode = TRUE;
+ break;
+# endif
+ case 'm':
+# ifdef MONITOR
+ Am_monitor = TRUE;
+# else
+ fputs("The monitor was not compiled in.\n", stderr);
+# endif
+ break;
+# ifdef INTERNET
+ case 'S':
+ Show_scores = TRUE;
+ break;
+ case 'q': /* query whether hunt is running */
+ Query_driver = TRUE;
+ break;
+ case 'w':
+ Send_message = optarg;
+ break;
+ case 'h':
+ Sock_host = optarg;
+ break;
+ case 'p':
+ use_port = optarg;
+ Test_port = atoi(use_port);
+ break;
+# else
+ case 'S':
+ case 'q':
+ case 'w':
+ case 'h':
+ case 'p':
+ fputs("Need TCP/IP for S, q, w, h, and p options.\n",
+ stderr);
+ break;
+# endif
+ case 'c':
+ enter_status = Q_CLOAK;
+ break;
+ case 'f':
+# ifdef FLY
+ enter_status = Q_FLY;
+# else
+ fputs("The flying code was not compiled in.\n", stderr);
+# endif
+ break;
+ case 's':
+ enter_status = Q_SCAN;
+ break;
+ case 'b':
+ no_beep = !no_beep;
+ break;
+ default:
+ usage:
+ fputs(
+"usage:\thunt [-qmcsfS] [-n name] [-t team] [-p port] [-w message] [host]\n",
+ stderr);
+ exit(1);
+ }
+ }
+# ifdef INTERNET
+ if (optind + 1 < ac)
+ goto usage;
+ else if (optind + 1 == ac)
+ Sock_host = av[ac - 1];
+# else
+ if (optind > ac)
+ goto usage;
+# endif
+
+# ifdef INTERNET
+ if (Show_scores) {
+ SOCKET *hosts;
+
+ for (hosts = list_drivers(); hosts->sin_port != 0; hosts += 1)
+ dump_scores(*hosts);
+ exit(0);
+ }
+ if (Query_driver) {
+ SOCKET *hosts;
+
+ for (hosts = list_drivers(); hosts->sin_port != 0; hosts += 1) {
+ struct hostent *hp;
+ int num_players;
+
+ hp = gethostbyaddr((char *) &hosts->sin_addr,
+ sizeof hosts->sin_addr, AF_INET);
+ num_players = ntohs(hosts->sin_port);
+ printf("%d player%s hunting on %s!\n",
+ num_players, (num_players == 1) ? "" : "s",
+ hp != NULL ? hp->h_name :
+ inet_ntoa(hosts->sin_addr));
+ }
+ exit(0);
+ }
+# endif
+# ifdef OTTO
+ if (Otto_mode)
+ (void) strncpy(name, "otto", NAMELEN);
+ else
+# endif
+ fill_in_blanks();
+
+ (void) fflush(stdout);
+ if (!isatty(0) || (term = getenv("TERM")) == NULL) {
+ fprintf(stderr, "no terminal type\n");
+ exit(1);
+ }
+# ifdef USE_CURSES
+ initscr();
+ (void) noecho();
+ (void) cbreak();
+# else /* !USE_CURSES */
+# if !defined(BSD_RELEASE) || BSD_RELEASE < 44
+ _tty_ch = 0;
+# endif
+ gettmode();
+ (void) setterm(term);
+ (void) noecho();
+ (void) cbreak();
+# if defined(BSD_RELEASE) && BSD_RELEASE >= 44
+ tcgetattr(0, &saved_tty);
+# endif
+ _puts(TI);
+ _puts(VS);
+# endif /* !USE_CURSES */
+ in_visual = TRUE;
+ if (LINES < SCREEN_HEIGHT || COLS < SCREEN_WIDTH)
+ leave(1, "Need a larger window");
+ clear_the_screen();
+ (void) signal(SIGINT, intr);
+ (void) signal(SIGTERM, sigterm);
+ (void) signal(SIGEMT, sigemt);
+ (void) signal(SIGPIPE, SIG_IGN);
+#if !defined(USE_CURSES) && defined(SIGTSTP)
+ (void) signal(SIGTSTP, tstp);
+#endif
+
+ for (;;) {
+# ifdef INTERNET
+ find_driver(TRUE);
+
+ if (Daemon.sin_port == 0)
+ leave(1, "Game not found, try again");
+
+ jump_in:
+ do {
+ int option;
+
+ Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0);
+ if (Socket < 0) {
+ perror("socket");
+ exit(1);
+ }
+ option = 1;
+ if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK,
+ &option, sizeof option) < 0)
+ perror("setsockopt loopback");
+ errno = 0;
+ if (connect(Socket, (struct sockaddr *) &Daemon,
+ DAEMON_SIZE) < 0) {
+ if (errno != ECONNREFUSED) {
+ perror("connect");
+ leave(1, "connect");
+ }
+ }
+ else
+ break;
+ sleep(1);
+ } while (close(Socket) == 0);
+# else /* !INTERNET */
+ /*
+ * set up a socket
+ */
+
+ if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) {
+ perror("socket");
+ exit(1);
+ }
+
+ /*
+ * attempt to connect the socket to a name; if it fails that
+ * usually means that the driver isn't running, so we start
+ * up the driver.
+ */
+
+ Daemon.sun_family = SOCK_FAMILY;
+ (void) strcpy(Daemon.sun_path, Sock_name);
+ if (connect(Socket, &Daemon, DAEMON_SIZE) < 0) {
+ if (errno != ENOENT) {
+ perror("connect");
+ leave(1, "connect2");
+ }
+ start_driver();
+
+ do {
+ (void) close(Socket);
+ if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) {
+ perror("socket");
+ exit(1);
+ }
+ sleep(2);
+ } while (connect(Socket, &Daemon, DAEMON_SIZE) < 0);
+ }
+# endif
+
+ do_connect(name, team, enter_status);
+# ifdef INTERNET
+ if (Send_message != NULL) {
+ do_message();
+ if (enter_status == Q_MESSAGE)
+ break;
+ Send_message = NULL;
+ /* don't continue as that will call find_driver */
+ goto jump_in;
+ }
+# endif
+ playit();
+ if ((enter_status = quit(enter_status)) == Q_QUIT)
+ break;
+ }
+ leave(0, (char *) NULL);
+ /* NOTREACHED */
+}
+
+# ifdef INTERNET
+# ifdef BROADCAST
+broadcast_vec(s, vector)
+ int s; /* socket */
+ struct sockaddr **vector;
+{
+ char if_buf[BUFSIZ];
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ unsigned int n;
+ int vec_cnt;
+
+ *vector = NULL;
+ ifc.ifc_len = sizeof if_buf;
+ ifc.ifc_buf = if_buf;
+ if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
+ return 0;
+ vec_cnt = 0;
+ n = ifc.ifc_len / sizeof (struct ifreq);
+ *vector = (struct sockaddr *) malloc(n * sizeof (struct sockaddr));
+ for (ifr = ifc.ifc_req; n != 0; n--, ifr++)
+ if (ioctl(s, SIOCGIFBRDADDR, ifr) >= 0)
+ memcpy(&(*vector)[vec_cnt++], &ifr->ifr_addr,
+ sizeof (struct sockaddr));
+ return vec_cnt;
+}
+# endif
+
+SOCKET *
+list_drivers()
+{
+ int option;
+ u_short msg;
+ u_short port_num;
+ static SOCKET test;
+ int test_socket;
+ int namelen;
+ char local_name[256];
+ static initial = TRUE;
+ static struct in_addr local_address;
+ register struct hostent *hp;
+ extern int errno;
+# ifdef BROADCAST
+ static int brdc;
+ static SOCKET *brdv;
+# else
+ u_long local_net;
+# endif
+ int i;
+ static SOCKET *listv;
+ static unsigned int listmax;
+ unsigned int listc;
+ int mask;
+ struct timeval wait;
+
+ if (initial) { /* do one time initialization */
+# ifndef BROADCAST
+ sethostent(1); /* don't bother to close host file */
+# endif
+ if (gethostname(local_name, sizeof local_name) < 0) {
+ leave(1, "Sorry, I have no name.");
+ /* NOTREACHED */
+ }
+ if ((hp = gethostbyname(local_name)) == NULL) {
+ leave(1, "Can't find myself.");
+ /* NOTREACHED */
+ }
+ local_address = * ((struct in_addr *) hp->h_addr);
+
+ listmax = 20;
+ listv = (SOCKET *) malloc(listmax * sizeof (SOCKET));
+ } else if (Sock_host != NULL)
+ return listv; /* address already valid */
+
+ test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0);
+ if (test_socket < 0) {
+ perror("socket");
+ leave(1, "socket system call failed");
+ /* NOTREACHED */
+ }
+ test.sin_family = SOCK_FAMILY;
+ test.sin_port = htons(Test_port);
+ listc = 0;
+
+ if (Sock_host != NULL) { /* explicit host given */
+ if ((hp = gethostbyname(Sock_host)) == NULL) {
+ leave(1, "Unknown host");
+ /* NOTREACHED */
+ }
+ test.sin_addr = *((struct in_addr *) hp->h_addr);
+ goto test_one_host;
+ }
+
+ if (!initial) {
+ /* favor host of previous session by broadcasting to it first */
+ test.sin_addr = Daemon.sin_addr;
+ msg = htons(C_PLAYER); /* Must be playing! */
+ (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
+ (struct sockaddr *) &test, DAEMON_SIZE);
+ }
+
+# ifdef BROADCAST
+ if (initial)
+ brdc = broadcast_vec(test_socket, (struct sockaddr **) &brdv);
+
+ if (brdc <= 0) {
+ initial = FALSE;
+ test.sin_addr = local_address;
+ goto test_one_host;
+ }
+
+# ifdef SO_BROADCAST
+ /* Sun's will broadcast even though this option can't be set */
+ option = 1;
+ if (setsockopt(test_socket, SOL_SOCKET, SO_BROADCAST,
+ &option, sizeof option) < 0) {
+ perror("setsockopt broadcast");
+ leave(1, "setsockopt broadcast");
+ /* NOTREACHED */
+ }
+# endif
+
+ /* send broadcast packets on all interfaces */
+ msg = htons(C_TESTMSG());
+ for (i = 0; i < brdc; i++) {
+ test.sin_addr = brdv[i].sin_addr;
+ if (sendto(test_socket, (char *) &msg, sizeof msg, 0,
+ (struct sockaddr *) &test, DAEMON_SIZE) < 0) {
+ perror("sendto");
+ leave(1, "sendto");
+ /* NOTREACHED */
+ }
+ }
+# else /* !BROADCAST */
+ /* loop thru all hosts on local net and send msg to them. */
+ msg = htons(C_TESTMSG());
+ local_net = inet_netof(local_address);
+ sethostent(0); /* rewind host file */
+ while (hp = gethostent()) {
+ if (local_net == inet_netof(* ((struct in_addr *) hp->h_addr))){
+ test.sin_addr = * ((struct in_addr *) hp->h_addr);
+ (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
+ (struct sockaddr *) &test, DAEMON_SIZE);
+ }
+ }
+# endif
+
+get_response:
+ namelen = DAEMON_SIZE;
+ errno = 0;
+ wait.tv_sec = 1;
+ wait.tv_usec = 0;
+ for (;;) {
+ if (listc + 1 >= listmax) {
+ listmax += 20;
+ listv = (SOCKET *) realloc((char *) listv,
+ listmax * sizeof(SOCKET));
+ }
+
+ mask = 1 << test_socket;
+ if (select(test_socket + 1, &mask, NULL, NULL, &wait) == 1
+ && recvfrom(test_socket, (char *) &port_num, sizeof port_num,
+ 0, (struct sockaddr *) &listv[listc], &namelen) > 0) {
+ /*
+ * Note that we do *not* convert from network to host
+ * order since the port number *should* be in network
+ * order:
+ */
+ for (i = 0; i < listc; i += 1)
+ if (listv[listc].sin_addr.s_addr
+ == listv[i].sin_addr.s_addr)
+ break;
+ if (i == listc)
+ listv[listc++].sin_port = port_num;
+ continue;
+ }
+
+ if (errno != 0 && errno != EINTR) {
+ perror("select/recvfrom");
+ leave(1, "select/recvfrom");
+ /* NOTREACHED */
+ }
+
+ /* terminate list with local address */
+ listv[listc].sin_family = SOCK_FAMILY;
+ listv[listc].sin_addr = local_address;
+ listv[listc].sin_port = htons(0);
+
+ (void) close(test_socket);
+ initial = FALSE;
+ return listv;
+ }
+
+test_one_host:
+ msg = htons(C_TESTMSG());
+ (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
+ (struct sockaddr *) &test, DAEMON_SIZE);
+ goto get_response;
+}
+
+find_driver(do_startup)
+FLAG do_startup;
+{
+ SOCKET *hosts;
+
+ hosts = list_drivers();
+ if (hosts[0].sin_port != htons(0)) {
+ int i, c;
+
+ if (hosts[1].sin_port == htons(0)) {
+ Daemon = hosts[0];
+ return;
+ }
+ /* go thru list and return host that matches daemon */
+ clear_the_screen();
+# ifdef USE_CURSES
+ move(1, 0);
+# else
+ mvcur(cur_row, cur_col, 1, 0);
+ cur_row = 1;
+ cur_col = 0;
+# endif
+ put_str("Pick one:");
+ for (i = 0; i < HEIGHT - 4 && hosts[i].sin_port != htons(0);
+ i += 1) {
+ struct hostent *hp;
+ char buf[80];
+
+# ifdef USE_CURSES
+ move(3 + i, 0);
+# else
+ mvcur(cur_row, cur_col, 3 + i, 0);
+ cur_row = 3 + i;
+ cur_col = 0;
+# endif
+ hp = gethostbyaddr((char *) &hosts[i].sin_addr,
+ sizeof hosts[i].sin_addr, AF_INET);
+ (void) sprintf(buf, "%8c %.64s", 'a' + i,
+ hp != NULL ? hp->h_name
+ : inet_ntoa(hosts->sin_addr));
+ put_str(buf);
+ }
+# ifdef USE_CURSES
+ move(4 + i, 0);
+# else
+ mvcur(cur_row, cur_col, 4 + i, 0);
+ cur_row = 4 + i;
+ cur_col = 0;
+# endif
+ put_str("Enter letter: ");
+ refresh();
+ while (!islower(c = getchar()) || (c -= 'a') >= i) {
+ beep();
+ refresh();
+ }
+ Daemon = hosts[c];
+ clear_the_screen();
+ return;
+ }
+ if (!do_startup)
+ return;
+
+ start_driver();
+ sleep(2);
+ find_driver(FALSE);
+}
+
+dump_scores(host)
+ SOCKET host;
+{
+ struct hostent *hp;
+ int s;
+ char buf[BUFSIZ];
+ int cnt;
+
+ hp = gethostbyaddr((char *) &host.sin_addr, sizeof host.sin_addr,
+ AF_INET);
+ printf("\n%s:\n", hp != NULL ? hp->h_name : inet_ntoa(host.sin_addr));
+ fflush(stdout);
+
+ s = socket(SOCK_FAMILY, SOCK_STREAM, 0);
+ if (s < 0) {
+ perror("socket");
+ exit(1);
+ }
+ if (connect(s, (struct sockaddr *) &host, sizeof host) < 0) {
+ perror("connect");
+ exit(1);
+ }
+ while ((cnt = read(s, buf, BUFSIZ)) > 0)
+ write(fileno(stdout), buf, cnt);
+ (void) close(s);
+}
+
+# endif
+
+start_driver()
+{
+ register int procid;
+
+# ifdef MONITOR
+ if (Am_monitor) {
+ leave(1, "No one playing.");
+ /* NOTREACHED */
+ }
+# endif
+
+# ifdef INTERNET
+ if (Sock_host != NULL) {
+ sleep(3);
+ return;
+ }
+# endif
+
+# ifdef USE_CURSES
+ move(HEIGHT, 0);
+# else
+ mvcur(cur_row, cur_col, HEIGHT, 0);
+ cur_row = HEIGHT;
+ cur_col = 0;
+# endif
+ put_str("Starting...");
+ refresh();
+ procid = fork();
+ if (procid == -1) {
+ perror("fork");
+ leave(1, "fork failed.");
+ }
+ if (procid == 0) {
+ (void) signal(SIGINT, SIG_IGN);
+# ifndef INTERNET
+ (void) close(Socket);
+# else
+ if (use_port == NULL)
+# endif
+ execl(Driver, "HUNT", (char *) NULL);
+# ifdef INTERNET
+ else
+ execl(Driver, "HUNT", "-p", use_port, (char *) NULL);
+# endif
+ /* only get here if exec failed */
+ (void) kill(getppid(), SIGEMT); /* tell mom */
+ _exit(1);
+ }
+# ifdef USE_CURSES
+ move(HEIGHT, 0);
+# else
+ mvcur(cur_row, cur_col, HEIGHT, 0);
+ cur_row = HEIGHT;
+ cur_col = 0;
+# endif
+ put_str("Connecting...");
+ refresh();
+}
+
+/*
+ * bad_con:
+ * We had a bad connection. For the moment we assume that this
+ * means the game is full.
+ */
+bad_con()
+{
+ leave(1, "The game is full. Sorry.");
+ /* NOTREACHED */
+}
+
+/*
+ * bad_ver:
+ * version number mismatch.
+ */
+bad_ver()
+{
+ leave(1, "Version number mismatch. No go.");
+ /* NOTREACHED */
+}
+
+/*
+ * sigterm:
+ * Handle a terminate signal
+ */
+SIGNAL_TYPE
+sigterm()
+{
+ leave(0, (char *) NULL);
+ /* NOTREACHED */
+}
+
+
+/*
+ * sigemt:
+ * Handle a emt signal - shouldn't happen on vaxes(?)
+ */
+SIGNAL_TYPE
+sigemt()
+{
+ leave(1, "Unable to start driver. Try again.");
+ /* NOTREACHED */
+}
+
+# ifdef INTERNET
+/*
+ * sigalrm:
+ * Handle an alarm signal
+ */
+SIGNAL_TYPE
+sigalrm()
+{
+ return;
+}
+# endif
+
+/*
+ * rmnl:
+ * Remove a '\n' at the end of a string if there is one
+ */
+rmnl(s)
+char *s;
+{
+ register char *cp;
+
+ cp = strrchr(s, '\n');
+ if (cp != NULL)
+ *cp = '\0';
+}
+
+/*
+ * intr:
+ * Handle a interrupt signal
+ */
+SIGNAL_TYPE
+intr()
+{
+ register int ch;
+ register int explained;
+ register int y, x;
+
+ (void) signal(SIGINT, SIG_IGN);
+# ifdef USE_CURSES
+ getyx(stdscr, y, x);
+ move(HEIGHT, 0);
+# else
+ y = cur_row;
+ x = cur_col;
+ mvcur(cur_row, cur_col, HEIGHT, 0);
+ cur_row = HEIGHT;
+ cur_col = 0;
+# endif
+ put_str("Really quit? ");
+ clear_eol();
+ refresh();
+ explained = FALSE;
+ for (;;) {
+ ch = getchar();
+ if (isupper(ch))
+ ch = tolower(ch);
+ if (ch == 'y') {
+ if (Socket != 0) {
+ (void) write(Socket, "q", 1);
+ (void) close(Socket);
+ }
+ leave(0, (char *) NULL);
+ }
+ else if (ch == 'n') {
+ (void) signal(SIGINT, intr);
+# ifdef USE_CURSES
+ move(y, x);
+# else
+ mvcur(cur_row, cur_col, y, x);
+ cur_row = y;
+ cur_col = x;
+# endif
+ refresh();
+ return;
+ }
+ if (!explained) {
+ put_str("(Yes or No) ");
+ refresh();
+ explained = TRUE;
+ }
+ beep();
+ refresh();
+ }
+}
+
+/*
+ * leave:
+ * Leave the game somewhat gracefully, restoring all current
+ * tty stats.
+ */
+leave(eval, mesg)
+int eval;
+char *mesg;
+{
+ if (in_visual) {
+# ifdef USE_CURSES
+ move(HEIGHT, 0);
+ refresh();
+ endwin();
+# else /* !USE_CURSES */
+ mvcur(cur_row, cur_col, HEIGHT, 0);
+ (void) fflush(stdout); /* flush in case VE changes pages */
+# if defined(BSD_RELEASE) && BSD_RELEASE >= 44
+ tcsetattr(0, TCSADRAIN, &__orig_termios);
+# else
+ resetty();
+# endif
+ _puts(VE);
+ _puts(TE);
+# endif /* !USE_CURSES */
+ }
+ if (mesg != NULL)
+ puts(mesg);
+ exit(eval);
+}
+
+#if !defined(USE_CURSES) && defined(SIGTSTP)
+/*
+ * tstp:
+ * Handle stop and start signals
+ */
+SIGNAL_TYPE
+tstp()
+{
+# if BSD_RELEASE < 44
+ static struct sgttyb tty;
+# endif
+ int y, x;
+
+ y = cur_row;
+ x = cur_col;
+ mvcur(cur_row, cur_col, HEIGHT, 0);
+ cur_row = HEIGHT;
+ cur_col = 0;
+# if !defined(BSD_RELEASE) || BSD_RELEASE < 44
+ tty = _tty;
+# endif
+ _puts(VE);
+ _puts(TE);
+ (void) fflush(stdout);
+# if defined(BSD_RELEASE) && BSD_RELEASE >= 44
+ tcsetattr(0, TCSADRAIN, &__orig_termios);
+# else
+ resetty();
+# endif
+ (void) kill(getpid(), SIGSTOP);
+ (void) signal(SIGTSTP, tstp);
+# if defined(BSD_RELEASE) && BSD_RELEASE >= 44
+ tcsetattr(0, TCSADRAIN, &saved_tty);
+# else
+ _tty = tty;
+ ioctl(_tty_ch, TIOCSETP, &_tty);
+# endif
+ _puts(TI);
+ _puts(VS);
+ cur_row = y;
+ cur_col = x;
+ _puts(tgoto(CM, cur_row, cur_col));
+ redraw_screen();
+ (void) fflush(stdout);
+}
+#endif /* !defined(USE_CURSES) && defined(SIGTSTP) */
+
+# if defined(BSD_RELEASE) && BSD_RELEASE < 43
+char *
+strpbrk(s, brk)
+ register char *s, *brk;
+{
+ register char *p;
+ register c;
+
+ while (c = *s) {
+ for (p = brk; *p; p++)
+ if (c == *p)
+ return (s);
+ s++;
+ }
+ return (0);
+}
+# endif
+
+long
+env_init(enter_status)
+ long enter_status;
+{
+ register int i;
+ char *envp, *envname, *s;
+
+ for (i = 0; i < 256; i++)
+ map_key[i] = (char) i;
+
+ envname = NULL;
+ if ((envp = getenv("HUNT")) != NULL) {
+ while ((s = strpbrk(envp, "=,")) != NULL) {
+ if (strncmp(envp, "cloak,", s - envp + 1) == 0) {
+ enter_status = Q_CLOAK;
+ envp = s + 1;
+ }
+ else if (strncmp(envp, "scan,", s - envp + 1) == 0) {
+ enter_status = Q_SCAN;
+ envp = s + 1;
+ }
+ else if (strncmp(envp, "fly,", s - envp + 1) == 0) {
+ enter_status = Q_FLY;
+ envp = s + 1;
+ }
+ else if (strncmp(envp, "nobeep,", s - envp + 1) == 0) {
+ no_beep = TRUE;
+ envp = s + 1;
+ }
+ else if (strncmp(envp, "name=", s - envp + 1) == 0) {
+ envname = s + 1;
+ if ((s = strchr(envp, ',')) == NULL) {
+ *envp = '\0';
+ strncpy(name, envname, NAMELEN);
+ break;
+ }
+ *s = '\0';
+ strncpy(name, envname, NAMELEN);
+ envp = s + 1;
+ }
+# ifdef INTERNET
+ else if (strncmp(envp, "port=", s - envp + 1) == 0) {
+ use_port = s + 1;
+ Test_port = atoi(use_port);
+ if ((s = strchr(envp, ',')) == NULL) {
+ *envp = '\0';
+ break;
+ }
+ *s = '\0';
+ envp = s + 1;
+ }
+ else if (strncmp(envp, "host=", s - envp + 1) == 0) {
+ Sock_host = s + 1;
+ if ((s = strchr(envp, ',')) == NULL) {
+ *envp = '\0';
+ break;
+ }
+ *s = '\0';
+ envp = s + 1;
+ }
+ else if (strncmp(envp, "message=", s - envp + 1) == 0) {
+ Send_message = s + 1;
+ if ((s = strchr(envp, ',')) == NULL) {
+ *envp = '\0';
+ break;
+ }
+ *s = '\0';
+ envp = s + 1;
+ }
+# endif
+ else if (strncmp(envp, "team=", s - envp + 1) == 0) {
+ team = *(s + 1);
+ if (!isdigit(team))
+ team = ' ';
+ if ((s = strchr(envp, ',')) == NULL) {
+ *envp = '\0';
+ break;
+ }
+ *s = '\0';
+ envp = s + 1;
+ } /* must be last option */
+ else if (strncmp(envp, "mapkey=", s - envp + 1) == 0) {
+ for (s = s + 1; *s != '\0'; s += 2) {
+ map_key[(unsigned int) *s] = *(s + 1);
+ if (*(s + 1) == '\0') {
+ break;
+ }
+ }
+ *envp = '\0';
+ break;
+ } else {
+ *s = '\0';
+ printf("unknown option %s\n", envp);
+ if ((s = strchr(envp, ',')) == NULL) {
+ *envp = '\0';
+ break;
+ }
+ envp = s + 1;
+ }
+ }
+ if (*envp != '\0')
+ if (envname == NULL)
+ strncpy(name, envp, NAMELEN);
+ else
+ printf("unknown option %s\n", envp);
+ }
+ return enter_status;
+}
+
+fill_in_blanks()
+{
+ register int i;
+ register char *cp;
+
+again:
+ if (name[0] != '\0') {
+ printf("Entering as '%s'", name);
+ if (team != ' ')
+ printf(" on team %c.\n", team);
+ else
+ putchar('\n');
+ } else {
+ printf("Enter your code name: ");
+ if (fgets(name, NAMELEN, stdin) == NULL)
+ exit(1);
+ }
+ rmnl(name);
+ if (name[0] == '\0') {
+ name[0] = '\0';
+ printf("You have to have a code name!\n");
+ goto again;
+ }
+ for (cp = name; *cp != '\0'; cp++)
+ if (!isprint(*cp)) {
+ name[0] = '\0';
+ printf("Illegal character in your code name.\n");
+ goto again;
+ }
+ if (team == ' ') {
+ printf("Enter your team (0-9 or nothing): ");
+ i = getchar();
+ if (isdigit(i))
+ team = i;
+ while (i != '\n' && i != EOF)
+ i = getchar();
+ }
+}
diff --git a/hunt/hunt/otto.c b/hunt/hunt/otto.c
new file mode 100644
index 00000000..ab3b9029
--- /dev/null
+++ b/hunt/hunt/otto.c
@@ -0,0 +1,585 @@
+# ifdef OTTO
+/*
+ * otto - a hunt otto-matic player
+ *
+ * This guy is buggy, unfair, stupid, and not extensible.
+ * Future versions of hunt will have a subroutine library for
+ * automatic players to link to. If you write your own "otto"
+ * please let us know what subroutines you would expect in the
+ * subroutine library.
+ *
+ * $Id: otto.c,v 1.1.1.1 1997/10/04 09:00:14 mrg Exp $
+ */
+
+# include <curses.h>
+# include <ctype.h>
+# include "hunt.h"
+# include <sys/time.h>
+# include <signal.h>
+# undef WALL
+# undef NORTH
+# undef SOUTH
+# undef WEST
+# undef EAST
+# undef FRONT
+# undef LEFT
+# undef BACK
+# undef RIGHT
+
+# ifdef HPUX
+# define random rand
+# endif
+
+# ifndef USE_CURSES
+extern char screen[SCREEN_HEIGHT][SCREEN_WIDTH2];
+# define SCREEN(y, x) screen[y][x]
+# else
+# if defined(BSD_RELEASE) && BSD_RELEASE >= 44
+# define SCREEN(y, x) stdscr->lines[y]->line[x].ch
+# else
+# define SCREEN(y, x) stdscr->_y[y][x]
+# endif
+# endif
+
+# ifndef DEBUG
+# define STATIC static
+# else
+# define STATIC
+# endif
+
+# define OPPONENT "{}i!"
+# define PROPONENT "^v<>"
+# define WALL "+\\/#*-|"
+# define PUSHOVER " bg;*#&"
+# define SHOTS "$@Oo:"
+
+/* number of "directions" */
+# define NUMDIRECTIONS 4
+
+/* absolute directions (facings) - counterclockwise */
+# define NORTH 0
+# define WEST 1
+# define SOUTH 2
+# define EAST 3
+# define ALLDIRS 0xf
+
+/* relative directions - counterclockwise */
+# define FRONT 0
+# define LEFT 1
+# define BACK 2
+# define RIGHT 3
+
+# define ABSCHARS "NWSE"
+# define RELCHARS "FLBR"
+# define DIRKEYS "khjl"
+
+STATIC char command[BUFSIZ];
+STATIC int comlen;
+
+# ifdef DEBUG
+STATIC FILE *debug = NULL;
+# endif
+
+# define DEADEND 0x1
+# define ON_LEFT 0x2
+# define ON_RIGHT 0x4
+# define ON_SIDE (ON_LEFT|ON_RIGHT)
+# define BEEN 0x8
+# define BEEN_SAME 0x10
+
+struct item {
+ char what;
+ int distance;
+ int flags;
+};
+
+STATIC struct item flbr[NUMDIRECTIONS];
+
+# define fitem flbr[FRONT]
+# define litem flbr[LEFT]
+# define bitem flbr[BACK]
+# define ritem flbr[RIGHT]
+
+STATIC int facing;
+STATIC int row, col;
+STATIC int num_turns; /* for wandering */
+STATIC char been_there[HEIGHT][WIDTH2];
+STATIC struct itimerval pause_time = { { 0, 0 }, { 0, 55000 }};
+
+STATIC int stop_look();
+STATIC int look_around();
+STATIC int face_and_move_direction();
+STATIC int attack();
+STATIC int duck();
+STATIC int go_for_ammo();
+STATIC int wander();
+
+STATIC SIGNAL_TYPE
+nothing()
+{
+}
+
+otto(y, x, face)
+ int y, x;
+ char face;
+{
+ register int i;
+ extern int Otto_count;
+ int old_mask;
+
+# ifdef DEBUG
+ if (debug == NULL) {
+ debug = fopen("bug", "w");
+ setbuf(debug, NULL);
+ }
+ fprintf(debug, "\n%c(%d,%d)", face, y, x);
+# endif
+ (void) signal(SIGALRM, nothing);
+ old_mask = sigblock(sigmask(SIGALRM));
+ setitimer(ITIMER_REAL, &pause_time, NULL);
+ sigpause(old_mask);
+ sigsetmask(old_mask);
+
+ /* save away parameters so other functions may use/update info */
+ switch (face) {
+ case '^': facing = NORTH; break;
+ case '<': facing = WEST; break;
+ case 'v': facing = SOUTH; break;
+ case '>': facing = EAST; break;
+ default: abort();
+ }
+ row = y; col = x;
+ been_there[row][col] |= 1 << facing;
+
+ /* initially no commands to be sent */
+ comlen = 0;
+
+ /* find something to do */
+ look_around();
+ for (i = 0; i < NUMDIRECTIONS; i++) {
+ if (strchr(OPPONENT, flbr[i].what) != NULL) {
+ attack(i, &flbr[i]);
+ memset(been_there, 0, sizeof been_there);
+ goto done;
+ }
+ }
+
+ if (strchr(SHOTS, bitem.what) != NULL && !(bitem.what & ON_SIDE)) {
+ duck(BACK);
+ memset(been_there, 0, sizeof been_there);
+# ifdef BOOTS
+ } else if (go_for_ammo(BOOT_PAIR)) {
+ memset(been_there, 0, sizeof been_there);
+ } else if (go_for_ammo(BOOT)) {
+ memset(been_there, 0, sizeof been_there);
+# endif
+ } else if (go_for_ammo(GMINE))
+ memset(been_there, 0, sizeof been_there);
+ else if (go_for_ammo(MINE))
+ memset(been_there, 0, sizeof been_there);
+ else
+ wander();
+
+done:
+ (void) write(Socket, command, comlen);
+ Otto_count += comlen;
+# ifdef DEBUG
+ (void) fwrite(command, 1, comlen, debug);
+# endif
+}
+
+# define direction(abs,rel) (((abs) + (rel)) % NUMDIRECTIONS)
+
+STATIC
+stop_look(itemp, c, dist, side)
+ struct item *itemp;
+ char c;
+ int dist;
+ int side;
+{
+ switch (c) {
+
+ case SPACE:
+ if (side)
+ itemp->flags &= ~DEADEND;
+ return 0;
+
+ case MINE:
+ case GMINE:
+# ifdef BOOTS
+ case BOOT:
+ case BOOT_PAIR:
+# endif
+ if (itemp->distance == -1) {
+ itemp->distance = dist;
+ itemp->what = c;
+ if (side < 0)
+ itemp->flags |= ON_LEFT;
+ else if (side > 0)
+ itemp->flags |= ON_RIGHT;
+ }
+ return 0;
+
+ case SHOT:
+ case GRENADE:
+ case SATCHEL:
+ case BOMB:
+# ifdef OOZE
+ case SLIME:
+# endif
+ if (itemp->distance == -1 || (!side
+ && (itemp->flags & ON_SIDE
+ || itemp->what == GMINE || itemp->what == MINE))) {
+ itemp->distance = dist;
+ itemp->what = c;
+ itemp->flags &= ~ON_SIDE;
+ if (side < 0)
+ itemp->flags |= ON_LEFT;
+ else if (side > 0)
+ itemp->flags |= ON_RIGHT;
+ }
+ return 0;
+
+ case '{':
+ case '}':
+ case 'i':
+ case '!':
+ itemp->distance = dist;
+ itemp->what = c;
+ itemp->flags &= ~(ON_SIDE|DEADEND);
+ if (side < 0)
+ itemp->flags |= ON_LEFT;
+ else if (side > 0)
+ itemp->flags |= ON_RIGHT;
+ return 1;
+
+ default:
+ /* a wall or unknown object */
+ if (side)
+ return 0;
+ if (itemp->distance == -1) {
+ itemp->distance = dist;
+ itemp->what = c;
+ }
+ return 1;
+ }
+}
+
+look(rel_dir, itemp)
+ int rel_dir;
+ struct item *itemp;
+{
+ register int r, c;
+ register char ch;
+
+ itemp->what = 0;
+ itemp->distance = -1;
+ itemp->flags = DEADEND|BEEN; /* true until proven false */
+
+ switch (direction(facing, rel_dir)) {
+
+ case NORTH:
+ if (been_there[row - 1][col] & NORTH)
+ itemp->flags |= BEEN_SAME;
+ for (r = row - 1; r >= 0; r--)
+ for (c = col - 1; c < col + 2; c++) {
+ ch = SCREEN(r, c);
+ if (stop_look(itemp, ch, row - r, c - col))
+ goto cont_north;
+ if (c == col && !been_there[r][c])
+ itemp->flags &= ~BEEN;
+ }
+ cont_north:
+ if (itemp->flags & DEADEND) {
+ itemp->flags |= BEEN;
+ been_there[r][col] |= NORTH;
+ for (r = row - 1; r > row - itemp->distance; r--)
+ been_there[r][col] = ALLDIRS;
+ }
+ break;
+
+ case SOUTH:
+ if (been_there[row + 1][col] & SOUTH)
+ itemp->flags |= BEEN_SAME;
+ for (r = row + 1; r < HEIGHT; r++)
+ for (c = col - 1; c < col + 2; c++) {
+ ch = SCREEN(r, c);
+ if (stop_look(itemp, ch, r - row, col - c))
+ goto cont_south;
+ if (c == col && !been_there[r][c])
+ itemp->flags &= ~BEEN;
+ }
+ cont_south:
+ if (itemp->flags & DEADEND) {
+ itemp->flags |= BEEN;
+ been_there[r][col] |= SOUTH;
+ for (r = row + 1; r < row + itemp->distance; r++)
+ been_there[r][col] = ALLDIRS;
+ }
+ break;
+
+ case WEST:
+ if (been_there[row][col - 1] & WEST)
+ itemp->flags |= BEEN_SAME;
+ for (c = col - 1; c >= 0; c--)
+ for (r = row - 1; r < row + 2; r++) {
+ ch = SCREEN(r, c);
+ if (stop_look(itemp, ch, col - c, row - r))
+ goto cont_east;
+ if (r == row && !been_there[r][c])
+ itemp->flags &= ~BEEN;
+ }
+ cont_west:
+ if (itemp->flags & DEADEND) {
+ itemp->flags |= BEEN;
+ been_there[r][col] |= WEST;
+ for (c = col - 1; c > col - itemp->distance; c--)
+ been_there[row][c] = ALLDIRS;
+ }
+ break;
+
+ case EAST:
+ if (been_there[row][col + 1] & EAST)
+ itemp->flags |= BEEN_SAME;
+ for (c = col + 1; c < WIDTH; c++)
+ for (r = row - 1; r < row + 2; r++) {
+ ch = SCREEN(r, c);
+ if (stop_look(itemp, ch, c - col, r - row))
+ goto cont_east;
+ if (r == row && !been_there[r][c])
+ itemp->flags &= ~BEEN;
+ }
+ cont_east:
+ if (itemp->flags & DEADEND) {
+ itemp->flags |= BEEN;
+ been_there[r][col] |= EAST;
+ for (c = col + 1; c < col + itemp->distance; c++)
+ been_there[row][c] = ALLDIRS;
+ }
+ break;
+
+ default:
+ abort();
+ }
+}
+
+STATIC
+look_around()
+{
+ register int i;
+
+ for (i = 0; i < NUMDIRECTIONS; i++) {
+ look(i, &flbr[i]);
+# ifdef DEBUG
+ fprintf(debug, " look(%c)=%c(%d)(0x%x)",
+ RELCHARS[i], flbr[i].what, flbr[i].distance, flbr[i].flags);
+# endif
+ }
+}
+
+/*
+ * as a side effect modifies facing and location (row, col)
+ */
+
+STATIC
+face_and_move_direction(rel_dir, distance)
+ int rel_dir, distance;
+{
+ register int old_facing;
+ register char cmd;
+
+ old_facing = facing;
+ cmd = DIRKEYS[facing = direction(facing, rel_dir)];
+
+ if (rel_dir != FRONT) {
+ register int i;
+ struct item items[NUMDIRECTIONS];
+
+ command[comlen++] = toupper(cmd);
+ if (distance == 0) {
+ /* rotate look's to be in right position */
+ for (i = 0; i < NUMDIRECTIONS; i++)
+ items[i] =
+ flbr[(i + old_facing) % NUMDIRECTIONS];
+ memcpy(flbr, items, sizeof flbr);
+ }
+ }
+ while (distance--) {
+ command[comlen++] = cmd;
+ switch (facing) {
+
+ case NORTH: row--; break;
+ case WEST: col--; break;
+ case SOUTH: row++; break;
+ case EAST: col++; break;
+ }
+ if (distance == 0)
+ look_around();
+ }
+}
+
+STATIC
+attack(rel_dir, itemp)
+ int rel_dir;
+ struct item *itemp;
+{
+ if (!(itemp->flags & ON_SIDE)) {
+ face_and_move_direction(rel_dir, 0);
+ command[comlen++] = 'o';
+ command[comlen++] = 'o';
+ duck(FRONT);
+ command[comlen++] = ' ';
+ } else if (itemp->distance > 1) {
+ face_and_move_direction(rel_dir, 2);
+ duck(FRONT);
+ } else {
+ face_and_move_direction(rel_dir, 1);
+ if (itemp->flags & ON_LEFT)
+ rel_dir = LEFT;
+ else
+ rel_dir = RIGHT;
+ (void) face_and_move_direction(rel_dir, 0);
+ command[comlen++] = 'f';
+ command[comlen++] = 'f';
+ duck(FRONT);
+ command[comlen++] = ' ';
+ }
+}
+
+STATIC
+duck(rel_dir)
+ int rel_dir;
+{
+ int dir;
+
+ switch (dir = direction(facing, rel_dir)) {
+
+ case NORTH:
+ case SOUTH:
+ if (strchr(PUSHOVER, SCREEN(row, col - 1)) != NULL)
+ command[comlen++] = 'h';
+ else if (strchr(PUSHOVER, SCREEN(row, col + 1)) != NULL)
+ command[comlen++] = 'l';
+ else if (dir == NORTH
+ && strchr(PUSHOVER, SCREEN(row + 1, col)) != NULL)
+ command[comlen++] = 'j';
+ else if (dir == SOUTH
+ && strchr(PUSHOVER, SCREEN(row - 1, col)) != NULL)
+ command[comlen++] = 'k';
+ else if (dir == NORTH)
+ command[comlen++] = 'k';
+ else
+ command[comlen++] = 'j';
+ break;
+
+ case WEST:
+ case EAST:
+ if (strchr(PUSHOVER, SCREEN(row - 1, col)) != NULL)
+ command[comlen++] = 'k';
+ else if (strchr(PUSHOVER, SCREEN(row + 1, col)) != NULL)
+ command[comlen++] = 'j';
+ else if (dir == WEST
+ && strchr(PUSHOVER, SCREEN(row, col + 1)) != NULL)
+ command[comlen++] = 'l';
+ else if (dir == EAST
+ && strchr(PUSHOVER, SCREEN(row, col - 1)) != NULL)
+ command[comlen++] = 'h';
+ else if (dir == WEST)
+ command[comlen++] = 'h';
+ else
+ command[comlen++] = 'l';
+ break;
+ }
+}
+
+/*
+ * go for the closest mine if possible
+ */
+
+STATIC
+go_for_ammo(mine)
+ char mine;
+{
+ register int i, rel_dir, dist;
+
+ rel_dir = -1;
+ dist = WIDTH;
+ for (i = 0; i < NUMDIRECTIONS; i++) {
+ if (flbr[i].what == mine && flbr[i].distance < dist) {
+ rel_dir = i;
+ dist = flbr[i].distance;
+ }
+ }
+ if (rel_dir == -1)
+ return FALSE;
+
+ if (!(flbr[rel_dir].flags & ON_SIDE)
+ || flbr[rel_dir].distance > 1) {
+ if (dist > 4)
+ dist = 4;
+ face_and_move_direction(rel_dir, dist);
+ } else
+ return FALSE; /* until it's done right */
+ return TRUE;
+}
+
+STATIC
+wander()
+{
+ register int i, j, rel_dir, dir_mask, dir_count;
+
+ for (i = 0; i < NUMDIRECTIONS; i++)
+ if (!(flbr[i].flags & BEEN) || flbr[i].distance <= 1)
+ break;
+ if (i == NUMDIRECTIONS)
+ memset(been_there, 0, sizeof been_there);
+ dir_mask = dir_count = 0;
+ for (i = 0; i < NUMDIRECTIONS; i++) {
+ j = (RIGHT + i) % NUMDIRECTIONS;
+ if (flbr[j].distance <= 1 || flbr[j].flags & DEADEND)
+ continue;
+ if (!(flbr[j].flags & BEEN_SAME)) {
+ dir_mask = 1 << j;
+ dir_count = 1;
+ break;
+ }
+ if (j == FRONT
+ && num_turns > 4 + (random() %
+ ((flbr[FRONT].flags & BEEN) ? 7 : HEIGHT)))
+ continue;
+ dir_mask |= 1 << j;
+# ifdef notdef
+ dir_count++;
+# else
+ dir_count = 1;
+ break;
+# endif
+ }
+ if (dir_count == 0) {
+ duck(random() % NUMDIRECTIONS);
+ num_turns = 0;
+ return;
+ } else if (dir_count == 1)
+ rel_dir = ffs(dir_mask) - 1;
+ else {
+ rel_dir = ffs(dir_mask) - 1;
+ dir_mask &= ~(1 << rel_dir);
+ while (dir_mask != 0) {
+ i = ffs(dir_mask) - 1;
+ if (random() % 5 == 0)
+ rel_dir = i;
+ dir_mask &= ~(1 << i);
+ }
+ }
+ if (rel_dir == FRONT)
+ num_turns++;
+ else
+ num_turns = 0;
+
+# ifdef DEBUG
+ fprintf(debug, " w(%c)", RELCHARS[rel_dir]);
+# endif
+ face_and_move_direction(rel_dir, 1);
+}
+
+# endif /* OTTO */
diff --git a/hunt/hunt/playit.c b/hunt/hunt/playit.c
new file mode 100644
index 00000000..4a6046c9
--- /dev/null
+++ b/hunt/hunt/playit.c
@@ -0,0 +1,628 @@
+/*
+ * Hunt
+ * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
+ * San Francisco, California
+ */
+
+# if defined(HPUX) || (defined(BSD_RELEASE) && BSD_RELEASE >= 44)
+# include <termios.h>
+# endif
+# include <curses.h>
+# include <ctype.h>
+# include <signal.h>
+# include <errno.h>
+# include "hunt.h"
+# include <sys/file.h>
+
+# ifndef FREAD
+# define FREAD 1
+# endif
+
+# if !defined(USE_CURSES) || !defined(TERMINFO)
+# define beep() (void) putchar(CTRL('G'))
+# endif
+# if !defined(USE_CURSES)
+# undef refresh
+# define refresh() (void) fflush(stdout);
+# endif
+# ifdef USE_CURSES
+# define clear_eol() clrtoeol()
+# define put_ch addch
+# define put_str addstr
+# endif
+
+int input();
+static int nchar_send;
+static int in = FREAD;
+# ifndef USE_CURSES
+char screen[SCREEN_HEIGHT][SCREEN_WIDTH2], blanks[SCREEN_WIDTH];
+int cur_row, cur_col;
+# endif
+# ifdef OTTO
+int Otto_count;
+int Otto_mode;
+static int otto_y, otto_x;
+static char otto_face;
+# endif
+
+# define MAX_SEND 5
+# define STDIN 0
+
+/*
+ * ibuf is the input buffer used for the stream from the driver.
+ * It is small because we do not check for user input when there
+ * are characters in the input buffer.
+ */
+static int icnt = 0;
+static unsigned char ibuf[256], *iptr = ibuf;
+static unsigned char getchr();
+
+#define GETCHR() (--icnt < 0 ? getchr() : *iptr++)
+
+#if !defined(BSD_RELEASE) || BSD_RELEASE < 44
+extern int _putchar();
+#endif
+
+/*
+ * playit:
+ * Play a given game, handling all the curses commands from
+ * the driver.
+ */
+playit()
+{
+ register int ch;
+ register int y, x;
+ extern int errno;
+ long version;
+
+ if (read(Socket, (char *) &version, LONGLEN) != LONGLEN) {
+ bad_con();
+ /* NOTREACHED */
+ }
+ if (ntohl(version) != HUNT_VERSION) {
+ bad_ver();
+ /* NOTREACHED */
+ }
+ errno = 0;
+# ifdef OTTO
+ Otto_count = 0;
+# endif
+ nchar_send = MAX_SEND;
+ while ((ch = GETCHR()) != EOF) {
+# ifdef DEBUG
+ fputc(ch, stderr);
+# endif
+ switch (ch & 0377) {
+ case MOVE:
+ y = GETCHR();
+ x = GETCHR();
+# ifdef USE_CURSES
+ move(y, x);
+# else
+ mvcur(cur_row, cur_col, y, x);
+ cur_row = y;
+ cur_col = x;
+# endif
+ break;
+ case ADDCH:
+ ch = GETCHR();
+# ifdef OTTO
+ switch (ch) {
+
+ case '<':
+ case '>':
+ case '^':
+ case 'v':
+ otto_face = ch;
+# ifdef USE_CURSES
+ getyx(stdscr, otto_y, otto_x);
+# else
+ otto_y = cur_row;
+ otto_x = cur_col;
+# endif
+ break;
+ }
+# endif
+ put_ch(ch);
+ break;
+ case CLRTOEOL:
+ clear_eol();
+ break;
+ case CLEAR:
+ clear_the_screen();
+ break;
+ case REFRESH:
+ refresh();
+ break;
+ case REDRAW:
+ redraw_screen();
+ refresh();
+ break;
+ case ENDWIN:
+ refresh();
+ if ((ch = GETCHR()) == LAST_PLAYER)
+ Last_player = TRUE;
+ ch = EOF;
+ goto out;
+ case BELL:
+ beep();
+ break;
+ case READY:
+ refresh();
+ if (nchar_send < 0)
+# if defined(HPUX) || (defined(BSD_RELEASE) && BSD_RELEASE >= 44)
+ tcflush(STDIN, TCIFLUSH);
+# else
+# ifndef TCFLSH
+ (void) ioctl(STDIN, TIOCFLUSH, &in);
+# else
+ (void) ioctl(STDIN, TCFLSH, 0);
+# endif
+# endif
+ nchar_send = MAX_SEND;
+# ifndef OTTO
+ (void) GETCHR();
+# else
+ Otto_count -= (GETCHR() & 0xff);
+ if (!Am_monitor) {
+# ifdef DEBUG
+ fputc('0' + Otto_count, stderr);
+# endif
+ if (Otto_count == 0 && Otto_mode)
+ otto(otto_y, otto_x, otto_face);
+ }
+# endif
+ break;
+ default:
+# ifdef OTTO
+ switch (ch) {
+
+ case '<':
+ case '>':
+ case '^':
+ case 'v':
+ otto_face = ch;
+# ifdef USE_CURSES
+ getyx(stdscr, otto_y, otto_x);
+# else
+ otto_y = cur_row;
+ otto_x = cur_col;
+# endif
+ break;
+ }
+# endif
+ put_ch(ch);
+ break;
+ }
+ }
+out:
+ (void) close(Socket);
+}
+
+/*
+ * getchr:
+ * Grab input and pass it along to the driver
+ * Return any characters from the driver
+ * When this routine is called by GETCHR, we already know there are
+ * no characters in the input buffer.
+ */
+static
+unsigned char
+getchr()
+{
+ long readfds, s_readfds;
+ int driver_mask, stdin_mask;
+ int nfds, s_nfds;
+
+ driver_mask = 1L << Socket;
+ stdin_mask = 1L << STDIN;
+ s_readfds = driver_mask | stdin_mask;
+ s_nfds = (Socket > STDIN) ? Socket : STDIN;
+ s_nfds++;
+
+one_more_time:
+ do {
+ errno = 0;
+ readfds = s_readfds;
+ nfds = s_nfds;
+ nfds = select(nfds, &readfds, NULL, NULL, NULL);
+ } while (nfds <= 0 && errno == EINTR);
+
+ if (readfds & stdin_mask)
+ send_stuff();
+ if ((readfds & driver_mask) == 0)
+ goto one_more_time;
+ icnt = read(Socket, ibuf, sizeof ibuf);
+ if (icnt < 0) {
+ bad_con();
+ /* NOTREACHED */
+ }
+ if (icnt == 0)
+ goto one_more_time;
+ iptr = ibuf;
+ icnt--;
+ return *iptr++;
+}
+
+/*
+ * send_stuff:
+ * Send standard input characters to the driver
+ */
+send_stuff()
+{
+ register int count;
+ register char *sp, *nsp;
+ static char inp[sizeof Buf];
+
+ count = read(STDIN, Buf, sizeof Buf);
+ if (count <= 0)
+ return;
+ if (nchar_send <= 0 && !no_beep) {
+ (void) write(1, "\7", 1); /* CTRL('G') */
+ return;
+ }
+
+ /*
+ * look for 'q'uit commands; if we find one,
+ * confirm it. If it is not confirmed, strip
+ * it out of the input
+ */
+ Buf[count] = '\0';
+ nsp = inp;
+ for (sp = Buf; *sp != '\0'; sp++)
+ if ((*nsp = map_key[*sp]) == 'q')
+ intr();
+ else
+ nsp++;
+ count = nsp - inp;
+ if (count) {
+# ifdef OTTO
+ Otto_count += count;
+# endif
+ nchar_send -= count;
+ if (nchar_send < 0)
+ count += nchar_send;
+ (void) write(Socket, inp, count);
+ }
+}
+
+/*
+ * quit:
+ * Handle the end of the game when the player dies
+ */
+long
+quit(old_status)
+long old_status;
+{
+ register int explain, ch;
+
+ if (Last_player)
+ return Q_QUIT;
+# ifdef OTTO
+ if (Otto_mode)
+ return Q_CLOAK;
+# endif
+# ifdef USE_CURSES
+ move(HEIGHT, 0);
+# else
+ mvcur(cur_row, cur_col, HEIGHT, 0);
+ cur_row = HEIGHT;
+ cur_col = 0;
+# endif
+ put_str("Re-enter game [ynwo]? ");
+ clear_eol();
+ explain = FALSE;
+ for (;;) {
+ refresh();
+ if (isupper(ch = getchar()))
+ ch = tolower(ch);
+ if (ch == 'y')
+ return old_status;
+ else if (ch == 'o')
+ break;
+ else if (ch == 'n') {
+# ifndef INTERNET
+ return Q_QUIT;
+# else
+# ifdef USE_CURSES
+ move(HEIGHT, 0);
+# else
+ mvcur(cur_row, cur_col, HEIGHT, 0);
+ cur_row = HEIGHT;
+ cur_col = 0;
+# endif
+ put_str("Write a parting message [yn]? ");
+ clear_eol();
+ refresh();
+ for (;;) {
+ if (isupper(ch = getchar()))
+ ch = tolower(ch);
+ if (ch == 'y')
+ goto get_message;
+ if (ch == 'n')
+ return Q_QUIT;
+ }
+# endif
+ }
+# ifdef INTERNET
+ else if (ch == 'w') {
+ static char buf[WIDTH + WIDTH % 2];
+ char *cp, c;
+
+get_message:
+ c = ch; /* save how we got here */
+# ifdef USE_CURSES
+ move(HEIGHT, 0);
+# else
+ mvcur(cur_row, cur_col, HEIGHT, 0);
+ cur_row = HEIGHT;
+ cur_col = 0;
+# endif
+ put_str("Message: ");
+ clear_eol();
+ refresh();
+ cp = buf;
+ for (;;) {
+ refresh();
+ if ((ch = getchar()) == '\n' || ch == '\r')
+ break;
+# if defined(TERMINFO) || BSD_RELEASE >= 44
+ if (ch == erasechar())
+# else
+ if (ch == _tty.sg_erase)
+# endif
+ {
+ if (cp > buf) {
+# ifdef USE_CURSES
+ int y, x;
+ getyx(stdscr, y, x);
+ move(y, x - 1);
+# else
+ mvcur(cur_row, cur_col, cur_row,
+ cur_col - 1);
+ cur_col -= 1;
+# endif
+ cp -= 1;
+ clear_eol();
+ }
+ continue;
+ }
+# if defined(TERMINFO) || BSD_RELEASE >= 44
+ else if (ch == killchar())
+# else
+ else if (ch == _tty.sg_kill)
+# endif
+ {
+# ifdef USE_CURSES
+ int y, x;
+ getyx(stdscr, y, x);
+ move(y, x - (cp - buf));
+# else
+ mvcur(cur_row, cur_col, cur_row,
+ cur_col - (cp - buf));
+ cur_col -= cp - buf;
+# endif
+ cp = buf;
+ clear_eol();
+ continue;
+ } else if (!isprint(ch)) {
+ beep();
+ continue;
+ }
+ put_ch(ch);
+ *cp++ = ch;
+ if (cp + 1 >= buf + sizeof buf)
+ break;
+ }
+ *cp = '\0';
+ Send_message = buf;
+ return (c == 'w') ? old_status : Q_MESSAGE;
+ }
+# endif
+ beep();
+ if (!explain) {
+ put_str("(Yes, No, Write message, or Options) ");
+ explain = TRUE;
+ }
+ }
+
+# ifdef USE_CURSES
+ move(HEIGHT, 0);
+# else
+ mvcur(cur_row, cur_col, HEIGHT, 0);
+ cur_row = HEIGHT;
+ cur_col = 0;
+# endif
+# ifdef FLY
+ put_str("Scan, Cloak, Flying, or Quit? ");
+# else
+ put_str("Scan, Cloak, or Quit? ");
+# endif
+ clear_eol();
+ refresh();
+ explain = FALSE;
+ for (;;) {
+ if (isupper(ch = getchar()))
+ ch = tolower(ch);
+ if (ch == 's')
+ return Q_SCAN;
+ else if (ch == 'c')
+ return Q_CLOAK;
+# ifdef FLY
+ else if (ch == 'f')
+ return Q_FLY;
+# endif
+ else if (ch == 'q')
+ return Q_QUIT;
+ beep();
+ if (!explain) {
+# ifdef FLY
+ put_str("[SCFQ] ");
+# else
+ put_str("[SCQ] ");
+# endif
+ explain = TRUE;
+ }
+ refresh();
+ }
+}
+
+# ifndef USE_CURSES
+put_ch(ch)
+ char ch;
+{
+ if (!isprint(ch)) {
+ fprintf(stderr, "r,c,ch: %d,%d,%d", cur_row, cur_col, ch);
+ return;
+ }
+ screen[cur_row][cur_col] = ch;
+ putchar(ch);
+ if (++cur_col >= COLS) {
+ if (!AM || XN)
+ putchar('\n');
+ cur_col = 0;
+ if (++cur_row >= LINES)
+ cur_row = LINES;
+ }
+}
+
+put_str(s)
+ char *s;
+{
+ while (*s)
+ put_ch(*s++);
+}
+# endif
+
+clear_the_screen()
+{
+# ifdef USE_CURSES
+ clear();
+ move(0, 0);
+ refresh();
+# else
+ register int i;
+
+ if (blanks[0] == '\0')
+ for (i = 0; i < SCREEN_WIDTH; i++)
+ blanks[i] = ' ';
+
+ if (CL != NULL) {
+#if !defined(BSD_RELEASE) || BSD_RELEASE < 44
+ tputs(CL, LINES, _putchar);
+#else
+ tputs(CL, LINES, __cputchar);
+#endif
+ for (i = 0; i < SCREEN_HEIGHT; i++)
+ memcpy(screen[i], blanks, SCREEN_WIDTH);
+ } else {
+ for (i = 0; i < SCREEN_HEIGHT; i++) {
+ mvcur(cur_row, cur_col, i, 0);
+ cur_row = i;
+ cur_col = 0;
+ clear_eol();
+ }
+ mvcur(cur_row, cur_col, 0, 0);
+ }
+ cur_row = cur_col = 0;
+#endif
+}
+
+#ifndef USE_CURSES
+clear_eol()
+{
+ if (CE != NULL)
+#if !defined(BSD_RELEASE) || BSD_RELEASE < 44
+ tputs(CE, 1, _putchar);
+#else
+ tputs(CE, 1, __cputchar);
+#endif
+ else {
+ fwrite(blanks, sizeof (char), SCREEN_WIDTH - cur_col, stdout);
+ if (COLS != SCREEN_WIDTH)
+ mvcur(cur_row, SCREEN_WIDTH, cur_row, cur_col);
+ else if (AM)
+ mvcur(cur_row + 1, 0, cur_row, cur_col);
+ else
+ mvcur(cur_row, SCREEN_WIDTH - 1, cur_row, cur_col);
+ }
+ memcpy(&screen[cur_row][cur_col], blanks, SCREEN_WIDTH - cur_col);
+}
+# endif
+
+redraw_screen()
+{
+# ifdef USE_CURSES
+ clearok(stdscr, TRUE);
+ touchwin(stdscr);
+# else
+ register int i;
+# ifndef NOCURSES
+ static int first = 1;
+
+ if (first) {
+ curscr = newwin(SCREEN_HEIGHT, SCREEN_WIDTH, 0, 0);
+ if (curscr == NULL) {
+ fprintf(stderr, "Can't create curscr\n");
+ exit(1);
+ }
+# if !defined(BSD_RELEASE) || BSD_RELEASE < 44
+ for (i = 0; i < SCREEN_HEIGHT; i++)
+ curscr->_y[i] = screen[i];
+# endif
+ first = 0;
+ }
+# if defined(BSD_RELEASE) && BSD_RELEASE >= 44
+ for (i = 0; i < SCREEN_HEIGHT; i++) {
+ register int j;
+ for (j = 0; j < SCREEN_WIDTH; j++)
+ curscr->lines[i]->line[j].ch = screen[i][j];
+ }
+ curscr->cury = cur_row;
+ curscr->curx = cur_col;
+# else
+ curscr->_cury = cur_row;
+ curscr->_curx = cur_col;
+# endif
+ clearok(curscr, TRUE);
+ touchwin(curscr);
+ wrefresh(curscr);
+#else
+ mvcur(cur_row, cur_col, 0, 0);
+ for (i = 0; i < SCREEN_HEIGHT - 1; i++) {
+ fwrite(screen[i], sizeof (char), SCREEN_WIDTH, stdout);
+ if (COLS > SCREEN_WIDTH || (COLS == SCREEN_WIDTH && !AM))
+ putchar('\n');
+ }
+ fwrite(screen[SCREEN_HEIGHT - 1], sizeof (char), SCREEN_WIDTH - 1,
+ stdout);
+ mvcur(SCREEN_HEIGHT - 1, SCREEN_WIDTH - 1, cur_row, cur_col);
+#endif
+#endif
+}
+
+/*
+ * do_message:
+ * Send a message to the driver and return
+ */
+do_message()
+{
+ extern int errno;
+ long version;
+
+ if (read(Socket, (char *) &version, LONGLEN) != LONGLEN) {
+ bad_con();
+ /* NOTREACHED */
+ }
+ if (ntohl(version) != HUNT_VERSION) {
+ bad_ver();
+ /* NOTREACHED */
+ }
+# ifdef INTERNET
+ if (write(Socket, Send_message, strlen(Send_message)) < 0) {
+ bad_con();
+ /* NOTREACHED */
+ }
+# endif
+ (void) close(Socket);
+}