Initial revision

git-svn-id: file:///srv/svn/joey/bsdgames-trunk@5086 a4a2c43b-8ac3-0310-8836-e0e880c912e2
This commit is contained in:
joey
1999-09-08 23:56:51 +00:00
commit 03272d67da
623 changed files with 243457 additions and 0 deletions

14
hunt/hunt/Makefile.bsd Normal file
View File

@@ -0,0 +1,14 @@
# $NetBSD: Makefile,v 1.5 1998/02/18 22:37:31 jtc Exp $
PROG= hunt
SRCS= connect.c hunt.c otto.c playit.c pathname.c
MAN= hunt.6
LDADD= -lcurses
DPADD= ${LIBTERMCAP}
HIDEGAME=hidegame
CPPFLAGS+=-I${.CURDIR}/../huntd
.PATH: ${.CURDIR}/../huntd
.include <bsd.prog.mk>

14
hunt/hunt/Makefrag Normal file
View File

@@ -0,0 +1,14 @@
# Makefrag - makefile fragment for hunt/hunt
include hunt/Makeconfig
hunt_hunt_DEFS := $(hunt_DEFS)
hunt_hunt_DIRS := $(GAMESDIR) $(MAN6DIR)
hunt_hunt_INCS := -Ihunt/huntd
hunt_hunt_all: hunt/hunt/hunt hunt/hunt/hunt.6
hunt_hunt_install: hunt_hunt_all
$(INSTALL_BINARY) hunt/hunt/hunt $(INSTALL_PREFIX)$(GAMESDIR)/hunt
$(HIDE_GAME) hunt
$(INSTALL_MANUAL) hunt/hunt/hunt.6

48
hunt/hunt/connect.c Normal file
View File

@@ -0,0 +1,48 @@
/* $NetBSD: connect.c,v 1.3 1997/10/11 08:13:40 lukem Exp $ */
/*
* Hunt
* Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
* San Francisco, California
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: connect.c,v 1.3 1997/10/11 08:13:40 lukem Exp $");
#endif /* not lint */
# include "hunt.h"
# include <signal.h>
# include <unistd.h>
void
do_connect(name, team, enter_status)
const char *name;
char team;
long enter_status;
{
static long uid;
static long mode;
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);
}

380
hunt/hunt/hunt.6.in Normal file
View File

@@ -0,0 +1,380 @@
.\" $NetBSD: hunt.6,v 1.3 1997/10/10 16:32:30 lukem Exp $
.\"
.\" 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@gamesdir@/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'@sbindir@/huntd\ \ \ 'u
@sbindir@/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.

1104
hunt/hunt/hunt.c Normal file

File diff suppressed because it is too large Load Diff

602
hunt/hunt/otto.c Normal file
View File

@@ -0,0 +1,602 @@
/* $NetBSD: otto.c,v 1.2 1997/10/10 16:32:39 lukem Exp $ */
# 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.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: otto.c,v 1.2 1997/10/10 16:32:39 lukem Exp $");
#endif /* not lint */
# include <sys/time.h>
# include <curses.h>
# include <ctype.h>
# include <signal.h>
# include <stdlib.h>
# include <unistd.h>
# include "hunt.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
#ifndef NCURSES_VERSION
# define SCREEN(y, x) stdscr->lines[y]->line[x].ch
#else
#define SCREEN(y, x) stdscr->_line[y].text[x]
#endif
# 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 void attack __P((int, struct item *));
STATIC void duck __P((int));
STATIC void face_and_move_direction __P((int, int));
STATIC int go_for_ammo __P((char));
STATIC void ottolook __P((int, struct item *));
STATIC void look_around __P((void));
STATIC SIGNAL_TYPE nothing __P((int));
STATIC int stop_look __P((struct item *, char, int, int));
STATIC void wander __P((void));
STATIC SIGNAL_TYPE
nothing(dummy)
int dummy __attribute__((unused));
{
}
void
otto(y, x, face)
int y, x;
char face;
{
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 int
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;
}
}
STATIC void
ottolook(rel_dir, itemp)
int rel_dir;
struct item *itemp;
{
int r, c;
char ch;
r = 0;
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_west;
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 void
look_around()
{
int i;
for (i = 0; i < NUMDIRECTIONS; i++) {
ottolook(i, &flbr[i]);
# ifdef DEBUG
fprintf(debug, " ottolook(%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 void
face_and_move_direction(rel_dir, distance)
int rel_dir, distance;
{
int old_facing;
char cmd;
old_facing = facing;
cmd = DIRKEYS[facing = direction(facing, rel_dir)];
if (rel_dir != FRONT) {
int i;
struct item items[NUMDIRECTIONS];
command[comlen++] = toupper(cmd);
if (distance == 0) {
/* rotate ottolook'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 void
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 void
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 int
go_for_ammo(mine)
char mine;
{
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 void
wander()
{
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 */

640
hunt/hunt/playit.c Normal file
View File

@@ -0,0 +1,640 @@
/* $NetBSD: playit.c,v 1.4 1997/10/20 00:37:15 lukem Exp $ */
/*
* Hunt
* Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
* San Francisco, California
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: playit.c,v 1.4 1997/10/20 00:37:15 lukem Exp $");
#endif /* not lint */
# include <sys/file.h>
# include <err.h>
# include <errno.h>
# include <curses.h>
# include <ctype.h>
# include <signal.h>
# include <sys/time.h>
# if defined(HPUX) || (defined(BSD_RELEASE) && BSD_RELEASE >= 44)
# include <termios.h>
# include <unistd.h>
# endif
# include "hunt.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
static int nchar_send;
# 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;
#define GETCHR() (--icnt < 0 ? getchr() : *iptr++)
#if !defined(BSD_RELEASE) || BSD_RELEASE < 44
extern int _putchar();
#endif
static unsigned char getchr __P((void));
static void send_stuff __P((void));
/*
* playit:
* Play a given game, handling all the curses commands from
* the driver.
*/
void
playit()
{
int ch;
int y, x;
long version;
if (read(Socket, (char *) &version, LONGLEN) != LONGLEN) {
bad_con();
/* NOTREACHED */
}
if (ntohl(version) != (unsigned long)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()
{
fd_set readfds, s_readfds;
int nfds, s_nfds;
FD_ZERO(&s_readfds);
FD_SET(Socket, &s_readfds);
FD_SET(STDIN, &s_readfds);
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 (FD_ISSET(STDIN, &readfds))
send_stuff();
if (! FD_ISSET(Socket, &readfds))
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
*/
static void
send_stuff()
{
int count;
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[(int)*sp]) == 'q')
intr(0);
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
*/
int
quit(old_status)
int old_status;
{
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
void
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;
}
}
void
put_str(s)
const char *s;
{
while (*s)
put_ch(*s++);
}
# endif
void
clear_the_screen()
{
# ifdef USE_CURSES
clear();
move(0, 0);
refresh();
# else
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
void
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
void
redraw_screen()
{
# ifdef USE_CURSES
clearok(stdscr, TRUE);
touchwin(stdscr);
# else
int i;
# ifndef NOCURSES
static int first = 1;
if (first) {
curscr = newwin(SCREEN_HEIGHT, SCREEN_WIDTH, 0, 0);
if (curscr == NULL)
errx(1, "Can't create curscr");
# 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++) {
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
*/
void
do_message()
{
long version;
if (read(Socket, (char *) &version, LONGLEN) != LONGLEN) {
bad_con();
/* NOTREACHED */
}
if (ntohl(version) != (unsigned long)HUNT_VERSION) {
bad_ver();
/* NOTREACHED */
}
# ifdef INTERNET
if (write(Socket, Send_message, strlen(Send_message)) < 0) {
bad_con();
/* NOTREACHED */
}
# endif
(void) close(Socket);
}