xref: /openbsd-src/games/hunt/huntd/answer.c (revision ac1fa6a8a418bc90e3475167b0e6680f850eeb92)
1*ac1fa6a8Skrw /*	$OpenBSD: answer.c,v 1.22 2017/01/21 08:22:57 krw Exp $	*/
23faf6791Sd /*	$NetBSD: answer.c,v 1.3 1997/10/10 16:32:50 lukem Exp $	*/
33faf6791Sd /*
4598075eaSpjanzen  * Copyright (c) 1983-2003, Regents of the University of California.
5598075eaSpjanzen  * All rights reserved.
6598075eaSpjanzen  *
7598075eaSpjanzen  * Redistribution and use in source and binary forms, with or without
8598075eaSpjanzen  * modification, are permitted provided that the following conditions are
9598075eaSpjanzen  * met:
10598075eaSpjanzen  *
11598075eaSpjanzen  * + Redistributions of source code must retain the above copyright
12598075eaSpjanzen  *   notice, this list of conditions and the following disclaimer.
13598075eaSpjanzen  * + Redistributions in binary form must reproduce the above copyright
14598075eaSpjanzen  *   notice, this list of conditions and the following disclaimer in the
15598075eaSpjanzen  *   documentation and/or other materials provided with the distribution.
16598075eaSpjanzen  * + Neither the name of the University of California, San Francisco nor
17598075eaSpjanzen  *   the names of its contributors may be used to endorse or promote
18598075eaSpjanzen  *   products derived from this software without specific prior written
19598075eaSpjanzen  *   permission.
20598075eaSpjanzen  *
21598075eaSpjanzen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22598075eaSpjanzen  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23598075eaSpjanzen  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24598075eaSpjanzen  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25598075eaSpjanzen  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26598075eaSpjanzen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27598075eaSpjanzen  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28598075eaSpjanzen  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29598075eaSpjanzen  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30598075eaSpjanzen  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31598075eaSpjanzen  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
323faf6791Sd  */
333faf6791Sd 
34e29f8a1bSguenther #include <sys/select.h>
35e29f8a1bSguenther 
369ef48543Smestre #include <arpa/inet.h>
379ef48543Smestre #include <netinet/in.h>
389ef48543Smestre 
393faf6791Sd #include <ctype.h>
403faf6791Sd #include <fcntl.h>
413faf6791Sd #include <stdlib.h>
42fab1dce0Sd #include <string.h>
439ef48543Smestre #include <syslog.h>
449ef48543Smestre #include <unistd.h>
45fab1dce0Sd 
469ef48543Smestre #include "conf.h"
473faf6791Sd #include "hunt.h"
48fab1dce0Sd #include "server.h"
493faf6791Sd 
50fab1dce0Sd /* Exported symbols for hosts_access(): */
51fab1dce0Sd int allow_severity	= LOG_INFO;
52fab1dce0Sd int deny_severity	= LOG_WARNING;
533faf6791Sd 
54c6d62522Sd 
55c6d62522Sd /* List of spawning connections: */
56c6d62522Sd struct spawn		*Spawn = NULL;
57c6d62522Sd 
58c72b5b24Smillert static void	stplayer(PLAYER *, int);
59c72b5b24Smillert static void	stmonitor(PLAYER *);
60c72b5b24Smillert static IDENT *	get_ident(struct sockaddr *, int, u_long, char *, char);
613faf6791Sd 
62c6d62522Sd void
answer_first(void)630f16a76cSmestre answer_first(void)
643faf6791Sd {
65c6d62522Sd 	struct sockaddr		sockstruct;
663faf6791Sd 	int			newsock;
672d84c14dSd 	socklen_t		socklen;
68c6d62522Sd 	struct spawn *sp;
693faf6791Sd 
705f13b87eSguenther 	/*
715f13b87eSguenther 	 * Answer the call to hunt, turning off blocking I/O, so a slow
725f13b87eSguenther 	 * or dead terminal won't stop the game.  All subsequent reads
735f13b87eSguenther 	 * check how many bytes they read.
745f13b87eSguenther 	 */
753faf6791Sd 	socklen = sizeof sockstruct;
765f13b87eSguenther 	newsock = accept4(Socket, (struct sockaddr *) &sockstruct, &socklen,
775f13b87eSguenther 	    SOCK_NONBLOCK);
78c6d62522Sd 	if (newsock < 0) {
793fc386a2Sespie 		logit(LOG_ERR, "accept");
80c6d62522Sd 		return;
813faf6791Sd 	}
823faf6791Sd 
83c6d62522Sd 	/* Remember this spawning connection: */
84f8c28d46Stedu 	sp = calloc(1, sizeof *sp);
85c6d62522Sd 	if (sp == NULL) {
86f8c28d46Stedu 		logit(LOG_ERR, "calloc");
87c6d62522Sd 		close(newsock);
88c6d62522Sd 		return;
89c6d62522Sd 	}
90c6d62522Sd 
91c6d62522Sd 	/* Keep the calling machine's source addr for ident purposes: */
92c6d62522Sd 	memcpy(&sp->source, &sockstruct, sizeof sp->source);
93c6d62522Sd 	sp->sourcelen = socklen;
94c6d62522Sd 
95c6d62522Sd 	/* Warn if we lose connection info: */
96c6d62522Sd 	if (socklen > sizeof Spawn->source)
97c6d62522Sd 		logx(LOG_WARNING,
981717b5a3Schl 		    "struct sockaddr is not big enough! (%d > %zu)",
99c6d62522Sd 		    socklen, sizeof Spawn->source);
1003faf6791Sd 
101c6d62522Sd 	/* Start listening to the spawning connection */
102c6d62522Sd 	sp->fd = newsock;
103c6d62522Sd 	FD_SET(sp->fd, &Fds_mask);
104c6d62522Sd 	if (sp->fd >= Num_fds)
105c6d62522Sd 		Num_fds = sp->fd + 1;
106c6d62522Sd 
1072d84c14dSd 	sp->reading_msg = 0;
1082d84c14dSd 	sp->inlen = 0;
109c6d62522Sd 
110c6d62522Sd 	/* Add to the spawning list */
111c6d62522Sd 	if ((sp->next = Spawn) != NULL)
112c6d62522Sd 		Spawn->prevnext = &sp->next;
113c6d62522Sd 	sp->prevnext = &Spawn;
114c6d62522Sd 	Spawn = sp;
115c6d62522Sd }
116c6d62522Sd 
117c6d62522Sd int
answer_next(struct spawn * sp)1180f16a76cSmestre answer_next(struct spawn *sp)
119c6d62522Sd {
120c6d62522Sd 	PLAYER			*pp;
121c6d62522Sd 	char			*cp1, *cp2;
122c6d62522Sd 	u_int32_t		version;
123c6d62522Sd 	FILE			*conn;
124c6d62522Sd 	int			len;
1252d84c14dSd 	char			teamstr[] = "[x]";
126c6d62522Sd 
1272d84c14dSd 	if (sp->reading_msg) {
1282d84c14dSd 		/* Receive a message from a player */
1292d84c14dSd 		len = read(sp->fd, sp->msg + sp->msglen,
1302d84c14dSd 		    sizeof sp->msg - sp->msglen);
1312d84c14dSd 		if (len < 0)
1322d84c14dSd 			goto error;
1332d84c14dSd 		sp->msglen += len;
1342d84c14dSd 		if (len && sp->msglen < sizeof sp->msg)
1352d84c14dSd 			return FALSE;
136c6d62522Sd 
137c6d62522Sd 		teamstr[1] = sp->team;
138c6d62522Sd 		outyx(ALL_PLAYERS, HEIGHT, 0, "%s%s: %.*s",
139c6d62522Sd 			sp->name,
140c6d62522Sd 			sp->team == ' ' ? "": teamstr,
141c6d62522Sd 			sp->msglen,
142c6d62522Sd 			sp->msg);
143c6d62522Sd 		ce(ALL_PLAYERS);
144c6d62522Sd 		sendcom(ALL_PLAYERS, REFRESH);
145c6d62522Sd 		sendcom(ALL_PLAYERS, READY, 0);
146c6d62522Sd 		flush(ALL_PLAYERS);
147c6d62522Sd 		goto close_it;
148c6d62522Sd 	}
149c6d62522Sd 
1502d84c14dSd 	/* Fill the buffer */
1512d84c14dSd 	len = read(sp->fd, sp->inbuf + sp->inlen,
1522d84c14dSd 	    sizeof sp->inbuf - sp->inlen);
1532d84c14dSd 	if (len <= 0)
1542d84c14dSd 		goto error;
1552d84c14dSd 	sp->inlen += len;
1562d84c14dSd 	if (sp->inlen < sizeof sp->inbuf)
157c6d62522Sd 		return FALSE;
1582d84c14dSd 
1592d84c14dSd 	/* Extract values from the buffer */
1602d84c14dSd 	cp1 = sp->inbuf;
1612d84c14dSd 	memcpy(&sp->uid, cp1, sizeof (u_int32_t));
1622d84c14dSd 	cp1+= sizeof(u_int32_t);
1632d84c14dSd 	memcpy(sp->name, cp1, NAMELEN);
1642d84c14dSd 	cp1+= NAMELEN;
1652d84c14dSd 	memcpy(&sp->team, cp1, sizeof (u_int8_t));
1662d84c14dSd 	cp1+= sizeof(u_int8_t);
1672d84c14dSd 	memcpy(&sp->enter_status, cp1, sizeof (u_int32_t));
1682d84c14dSd 	cp1+= sizeof(u_int32_t);
1692d84c14dSd 	memcpy(sp->ttyname, cp1, NAMELEN);
1702d84c14dSd 	cp1+= NAMELEN;
1712d84c14dSd 	memcpy(&sp->mode, cp1, sizeof (u_int32_t));
1722d84c14dSd 	cp1+= sizeof(u_int32_t);
173c6d62522Sd 
174c6d62522Sd 	/* Convert data from network byte order: */
175c6d62522Sd 	sp->uid = ntohl(sp->uid);
176c6d62522Sd 	sp->enter_status = ntohl(sp->enter_status);
177c6d62522Sd 	sp->mode = ntohl(sp->mode);
178c6d62522Sd 
1793faf6791Sd 	/*
1803faf6791Sd 	 * Make sure the name contains only printable characters
1813faf6791Sd 	 * since we use control characters for cursor control
1823faf6791Sd 	 * between driver and player processes
1833faf6791Sd 	 */
1842d84c14dSd 	sp->name[NAMELEN] = '\0';
185c6d62522Sd 	for (cp1 = cp2 = sp->name; *cp1 != '\0'; cp1++)
1860d35e948Smmcc 		if (isprint((unsigned char)*cp1) || *cp1 == ' ')
1873faf6791Sd 			*cp2++ = *cp1;
1883faf6791Sd 	*cp2 = '\0';
1893faf6791Sd 
1902d84c14dSd 	/* Make sure team name is valid */
1912d84c14dSd 	if (sp->team < '1' || sp->team > '9')
1922d84c14dSd 		sp->team = ' ';
1932d84c14dSd 
194c6d62522Sd 	/* Tell the other end this server's hunt driver version: */
195c6d62522Sd 	version = htonl((u_int32_t) HUNT_VERSION);
196c6d62522Sd 	(void) write(sp->fd, &version, sizeof version);
197c6d62522Sd 
198c6d62522Sd 	if (sp->mode == C_MESSAGE) {
1992d84c14dSd 		/* The clients only wants to send a message: */
2002d84c14dSd 		sp->msglen = 0;
2012d84c14dSd 		sp->reading_msg = 1;
2023faf6791Sd 		return FALSE;
2033faf6791Sd 	}
204fab1dce0Sd 
205c6d62522Sd 	/* Use a stdio file descriptor from now on: */
206c6d62522Sd 	conn = fdopen(sp->fd, "w");
207c6d62522Sd 
208fab1dce0Sd 	/* The player is a monitor: */
209c6d62522Sd 	if (sp->mode == C_MONITOR) {
210fab1dce0Sd 		if (conf_monitor && End_monitor < &Monitor[MAXMON]) {
2113faf6791Sd 			pp = End_monitor++;
212c6d62522Sd 			if (sp->team == ' ')
213c6d62522Sd 				sp->team = '*';
214fab1dce0Sd 		} else {
215fab1dce0Sd 			/* Too many monitors */
216c6d62522Sd 			fprintf(conn, "Too many monitors\n");
217c6d62522Sd 			fflush(conn);
218c6d62522Sd 			logx(LOG_NOTICE, "too many monitors");
219c6d62522Sd 			goto close_it;
2203faf6791Sd 		}
221fab1dce0Sd 
222fab1dce0Sd 	/* The player is a normal hunter: */
223fab1dce0Sd 	} else {
2243faf6791Sd 		if (End_player < &Player[MAXPL])
2253faf6791Sd 			pp = End_player++;
2263faf6791Sd 		else {
227c6d62522Sd 			fprintf(conn, "Too many players\n");
228c6d62522Sd 			fflush(conn);
229fab1dce0Sd 			/* Too many players */
230c6d62522Sd 			logx(LOG_NOTICE, "too many players");
231c6d62522Sd 			goto close_it;
2323faf6791Sd 		}
233fab1dce0Sd 	}
2343faf6791Sd 
235c6d62522Sd 	/* Find the player's running scorecard */
236c6d62522Sd 	pp->p_ident = get_ident(&sp->source, sp->sourcelen, sp->uid,
237c6d62522Sd 	    sp->name, sp->team);
238c6d62522Sd 	pp->p_output = conn;
2393faf6791Sd 	pp->p_death[0] = '\0';
240c6d62522Sd 	pp->p_fd = sp->fd;
2413faf6791Sd 
242c6d62522Sd 	/* No idea where the player starts: */
2433faf6791Sd 	pp->p_y = 0;
2443faf6791Sd 	pp->p_x = 0;
2453faf6791Sd 
246c6d62522Sd 	/* Mode-specific initialisation: */
247c6d62522Sd 	if (sp->mode == C_MONITOR)
2483faf6791Sd 		stmonitor(pp);
2493faf6791Sd 	else
250c6d62522Sd 		stplayer(pp, sp->enter_status);
251c6d62522Sd 
2522d84c14dSd 	/* And, they're off! Caller should remove and free sp. */
2533faf6791Sd 	return TRUE;
254c6d62522Sd 
2552d84c14dSd error:
2562d84c14dSd 	if (len < 0)
2573fc386a2Sespie 		logit(LOG_WARNING, "read");
2582d84c14dSd 	else
2592d84c14dSd 		logx(LOG_WARNING, "lost connection to new client");
2602d84c14dSd 
261c6d62522Sd close_it:
262c6d62522Sd 	/* Destroy the spawn */
263c6d62522Sd 	*sp->prevnext = sp->next;
264c6d62522Sd 	if (sp->next) sp->next->prevnext = sp->prevnext;
265c6d62522Sd 	FD_CLR(sp->fd, &Fds_mask);
266c6d62522Sd 	close(sp->fd);
267c6d62522Sd 	free(sp);
268c6d62522Sd 	return FALSE;
2693faf6791Sd }
2703faf6791Sd 
271fab1dce0Sd /* Start a monitor: */
272fab1dce0Sd static void
stmonitor(PLAYER * pp)2730f16a76cSmestre stmonitor(PLAYER *pp)
2743faf6791Sd {
2753faf6791Sd 
276fab1dce0Sd 	/* Monitors get to see the entire maze: */
277fab1dce0Sd 	memcpy(pp->p_maze, Maze, sizeof pp->p_maze);
2783faf6791Sd 	drawmaze(pp);
2793faf6791Sd 
280fab1dce0Sd 	/* Put the monitor's name near the bottom right on all screens: */
281fab1dce0Sd 	outyx(ALL_PLAYERS,
282fab1dce0Sd 		STAT_MON_ROW + 1 + (pp - Monitor), STAT_NAME_COL,
283fab1dce0Sd 		"%5.5s%c%-10.10s %c", " ",
284fab1dce0Sd 		stat_char(pp), pp->p_ident->i_name, pp->p_ident->i_team);
2853faf6791Sd 
286fab1dce0Sd 	/* Ready the monitor: */
2873faf6791Sd 	sendcom(pp, REFRESH);
2883faf6791Sd 	sendcom(pp, READY, 0);
289fab1dce0Sd 	flush(pp);
2903faf6791Sd }
2913faf6791Sd 
292fab1dce0Sd /* Start a player: */
293fab1dce0Sd static void
stplayer(PLAYER * newpp,int enter_status)2940f16a76cSmestre stplayer(PLAYER *newpp, int enter_status)
2953faf6791Sd {
2963faf6791Sd 	int	x, y;
2973faf6791Sd 	PLAYER	*pp;
298fab1dce0Sd 	int len;
2993faf6791Sd 
3003faf6791Sd 	Nplayer++;
3013faf6791Sd 
3023faf6791Sd 	for (y = 0; y < UBOUND; y++)
3033faf6791Sd 		for (x = 0; x < WIDTH; x++)
3043faf6791Sd 			newpp->p_maze[y][x] = Maze[y][x];
3053faf6791Sd 	for (     ; y < DBOUND; y++) {
3063faf6791Sd 		for (x = 0; x < LBOUND; x++)
3073faf6791Sd 			newpp->p_maze[y][x] = Maze[y][x];
3083faf6791Sd 		for (     ; x < RBOUND; x++)
3093faf6791Sd 			newpp->p_maze[y][x] = SPACE;
3103faf6791Sd 		for (     ; x < WIDTH;  x++)
3113faf6791Sd 			newpp->p_maze[y][x] = Maze[y][x];
3123faf6791Sd 	}
3133faf6791Sd 	for (     ; y < HEIGHT; y++)
3143faf6791Sd 		for (x = 0; x < WIDTH; x++)
3153faf6791Sd 			newpp->p_maze[y][x] = Maze[y][x];
3163faf6791Sd 
317fab1dce0Sd 	/* Drop the new player somewhere in the maze: */
3183faf6791Sd 	do {
3193faf6791Sd 		x = rand_num(WIDTH - 1) + 1;
3203faf6791Sd 		y = rand_num(HEIGHT - 1) + 1;
3213faf6791Sd 	} while (Maze[y][x] != SPACE);
3223faf6791Sd 	newpp->p_over = SPACE;
3233faf6791Sd 	newpp->p_x = x;
3243faf6791Sd 	newpp->p_y = y;
3253faf6791Sd 	newpp->p_undershot = FALSE;
3263faf6791Sd 
327fab1dce0Sd 	/* Send them flying if needed */
328fab1dce0Sd 	if (enter_status == Q_FLY && conf_fly) {
329fab1dce0Sd 		newpp->p_flying = rand_num(conf_flytime);
330fab1dce0Sd 		newpp->p_flyx = 2 * rand_num(conf_flystep + 1) - conf_flystep;
331fab1dce0Sd 		newpp->p_flyy = 2 * rand_num(conf_flystep + 1) - conf_flystep;
3323faf6791Sd 		newpp->p_face = FLYER;
333fab1dce0Sd 	} else {
3343faf6791Sd 		newpp->p_flying = -1;
3353faf6791Sd 		newpp->p_face = rand_dir();
3363faf6791Sd 	}
337fab1dce0Sd 
338fab1dce0Sd 	/* Initialize the new player's attributes: */
3393faf6791Sd 	newpp->p_damage = 0;
340fab1dce0Sd 	newpp->p_damcap = conf_maxdam;
3413faf6791Sd 	newpp->p_nchar = 0;
3423faf6791Sd 	newpp->p_ncount = 0;
3433faf6791Sd 	newpp->p_nexec = 0;
344fab1dce0Sd 	newpp->p_ammo = conf_ishots;
3453faf6791Sd 	newpp->p_nboots = 0;
346fab1dce0Sd 
347fab1dce0Sd 	/* Decide on what cloak/scan status to enter with */
348fab1dce0Sd 	if (enter_status == Q_SCAN && conf_scan) {
349fab1dce0Sd 		newpp->p_scan = conf_scanlen * Nplayer;
3503faf6791Sd 		newpp->p_cloak = 0;
351fab1dce0Sd 	} else if (conf_cloak) {
3523faf6791Sd 		newpp->p_scan = 0;
353fab1dce0Sd 		newpp->p_cloak = conf_cloaklen;
354fab1dce0Sd 	} else {
355fab1dce0Sd 		newpp->p_scan = 0;
356fab1dce0Sd 		newpp->p_cloak = 0;
3573faf6791Sd 	}
3583faf6791Sd 	newpp->p_ncshot = 0;
3593faf6791Sd 
360fab1dce0Sd 	/*
361fab1dce0Sd 	 * For each new player, place a large mine and
362fab1dce0Sd 	 * a small mine somewhere in the maze:
363fab1dce0Sd 	 */
3643faf6791Sd 	do {
3653faf6791Sd 		x = rand_num(WIDTH - 1) + 1;
3663faf6791Sd 		y = rand_num(HEIGHT - 1) + 1;
3673faf6791Sd 	} while (Maze[y][x] != SPACE);
3683faf6791Sd 	Maze[y][x] = GMINE;
3693faf6791Sd 	for (pp = Monitor; pp < End_monitor; pp++)
3703faf6791Sd 		check(pp, y, x);
3713faf6791Sd 
3723faf6791Sd 	do {
3733faf6791Sd 		x = rand_num(WIDTH - 1) + 1;
3743faf6791Sd 		y = rand_num(HEIGHT - 1) + 1;
3753faf6791Sd 	} while (Maze[y][x] != SPACE);
3763faf6791Sd 	Maze[y][x] = MINE;
3773faf6791Sd 	for (pp = Monitor; pp < End_monitor; pp++)
3783faf6791Sd 		check(pp, y, x);
3793faf6791Sd 
380fab1dce0Sd 	/* Create a score line for the new player: */
381fab1dce0Sd 	(void) snprintf(Buf, sizeof Buf, "%5.2f%c%-10.10s %c",
382fab1dce0Sd 		newpp->p_ident->i_score, stat_char(newpp),
383fab1dce0Sd 		newpp->p_ident->i_name, newpp->p_ident->i_team);
384fab1dce0Sd 	len = strlen(Buf);
3853faf6791Sd 	y = STAT_PLAY_ROW + 1 + (newpp - Player);
3863faf6791Sd 	for (pp = Player; pp < End_player; pp++) {
3873faf6791Sd 		if (pp != newpp) {
388fab1dce0Sd 			/* Give everyone a few more shots: */
389fab1dce0Sd 			pp->p_ammo += conf_nshots;
390fab1dce0Sd 			newpp->p_ammo += conf_nshots;
391fab1dce0Sd 			outyx(pp, y, STAT_NAME_COL, Buf, len);
392fab1dce0Sd 			ammo_update(pp);
393fab1dce0Sd 		}
394fab1dce0Sd 	}
395fab1dce0Sd 	for (pp = Monitor; pp < End_monitor; pp++)
396fab1dce0Sd 		outyx(pp, y, STAT_NAME_COL, Buf, len);
3973faf6791Sd 
398fab1dce0Sd 	/* Show the new player what they can see and where they are: */
3993faf6791Sd 	drawmaze(newpp);
4003faf6791Sd 	drawplayer(newpp, TRUE);
4013faf6791Sd 	look(newpp);
402fab1dce0Sd 
403fab1dce0Sd 	/* Make sure that the position they enter in will be erased: */
404fab1dce0Sd 	if (enter_status == Q_FLY && conf_fly)
4053faf6791Sd 		showexpl(newpp->p_y, newpp->p_x, FLYER);
406fab1dce0Sd 
407fab1dce0Sd 	/* Ready the new player: */
4083faf6791Sd 	sendcom(newpp, REFRESH);
4093faf6791Sd 	sendcom(newpp, READY, 0);
410fab1dce0Sd 	flush(newpp);
4113faf6791Sd }
4123faf6791Sd 
4133faf6791Sd /*
4143faf6791Sd  * rand_dir:
4153faf6791Sd  *	Return a random direction
4163faf6791Sd  */
4173faf6791Sd int
rand_dir(void)4180f16a76cSmestre rand_dir(void)
4193faf6791Sd {
4203faf6791Sd 	switch (rand_num(4)) {
4213faf6791Sd 	  case 0:
4223faf6791Sd 		return LEFTS;
4233faf6791Sd 	  case 1:
4243faf6791Sd 		return RIGHT;
4253faf6791Sd 	  case 2:
4263faf6791Sd 		return BELOW;
4273faf6791Sd 	  case 3:
4283faf6791Sd 		return ABOVE;
4293faf6791Sd 	}
4303faf6791Sd 	return(-1);
4313faf6791Sd }
4323faf6791Sd 
4333faf6791Sd /*
4343faf6791Sd  * get_ident:
4353faf6791Sd  *	Get the score structure of a player
4363faf6791Sd  */
437fab1dce0Sd static IDENT *
get_ident(struct sockaddr * sa,int salen,u_long uid,char * name,char team)4380f16a76cSmestre get_ident(struct sockaddr *sa, int salen, u_long uid, char *name, char team)
4393faf6791Sd {
4403faf6791Sd 	IDENT		*ip;
4413faf6791Sd 	static IDENT	punt;
442c6d62522Sd 	u_int32_t	machine;
443c6d62522Sd 
444c6d62522Sd 	if (sa->sa_family == AF_INET)
445c6d62522Sd 		machine = ntohl((u_long)((struct sockaddr_in *)sa)->sin_addr.s_addr);
446c6d62522Sd 	else
447c6d62522Sd 		machine = 0;
4483faf6791Sd 
4493faf6791Sd 	for (ip = Scores; ip != NULL; ip = ip->i_next)
4503faf6791Sd 		if (ip->i_machine == machine
4513faf6791Sd 		&&  ip->i_uid == uid
452fab1dce0Sd 		/* &&  ip->i_team == team */
4533faf6791Sd 		&&  strncmp(ip->i_name, name, NAMELEN) == 0)
4543faf6791Sd 			break;
4553faf6791Sd 
4563faf6791Sd 	if (ip != NULL) {
457fab1dce0Sd 		if (ip->i_team != team) {
458c6d62522Sd 			logx(LOG_INFO, "player %s %s team %c",
459fab1dce0Sd 				name,
460fab1dce0Sd 				team == ' ' ? "left" : ip->i_team == ' ' ?
461fab1dce0Sd 					"joined" : "changed to",
462fab1dce0Sd 				team == ' ' ? ip->i_team : team);
463fab1dce0Sd 			ip->i_team = team;
464fab1dce0Sd 		}
465fab1dce0Sd 		if (ip->i_entries < conf_scoredecay)
4663faf6791Sd 			ip->i_entries++;
4673faf6791Sd 		else
468fab1dce0Sd 			ip->i_kills = (ip->i_kills * (conf_scoredecay - 1))
469fab1dce0Sd 				/ conf_scoredecay;
4703faf6791Sd 		ip->i_score = ip->i_kills / (double) ip->i_entries;
4713faf6791Sd 	}
4723faf6791Sd 	else {
473fab1dce0Sd 		/* Alloc new entry -- it is released in clear_scores() */
474ca161728Sderaadt 		ip = malloc(sizeof (IDENT));
4753faf6791Sd 		if (ip == NULL) {
4763fc386a2Sespie 			logit(LOG_ERR, "malloc");
4773faf6791Sd 			/* Fourth down, time to punt */
4783faf6791Sd 			ip = &punt;
4793faf6791Sd 		}
4803faf6791Sd 		ip->i_machine = machine;
4813faf6791Sd 		ip->i_team = team;
4823faf6791Sd 		ip->i_uid = uid;
483fab1dce0Sd 		strlcpy(ip->i_name, name, sizeof ip->i_name);
4843faf6791Sd 		ip->i_kills = 0;
4853faf6791Sd 		ip->i_entries = 1;
4863faf6791Sd 		ip->i_score = 0;
4873faf6791Sd 		ip->i_absorbed = 0;
4883faf6791Sd 		ip->i_faced = 0;
4893faf6791Sd 		ip->i_shot = 0;
4903faf6791Sd 		ip->i_robbed = 0;
4913faf6791Sd 		ip->i_slime = 0;
4923faf6791Sd 		ip->i_missed = 0;
4933faf6791Sd 		ip->i_ducked = 0;
4943faf6791Sd 		ip->i_gkills = ip->i_bkills = ip->i_deaths = 0;
4953faf6791Sd 		ip->i_stillb = ip->i_saved = 0;
4963faf6791Sd 		ip->i_next = Scores;
4973faf6791Sd 		Scores = ip;
498fab1dce0Sd 
499c6d62522Sd 		logx(LOG_INFO, "new player: %s%s%c%s",
500fab1dce0Sd 			name,
501fab1dce0Sd 			team == ' ' ? "" : " (team ",
502fab1dce0Sd 			team,
503fab1dce0Sd 			team == ' ' ? "" : ")");
5043faf6791Sd 	}
5053faf6791Sd 
5063faf6791Sd 	return ip;
5073faf6791Sd }
508c6d62522Sd 
509c6d62522Sd void
answer_info(FILE * fp)5100f16a76cSmestre answer_info(FILE *fp)
511c6d62522Sd {
512c6d62522Sd 	struct spawn *sp;
513c6d62522Sd 	char buf[128];
514c6d62522Sd 	const char *bf;
515c6d62522Sd 	struct sockaddr_in *sa;
516c6d62522Sd 
517c6d62522Sd 	if (Spawn == NULL)
518c6d62522Sd 		return;
519c6d62522Sd 	fprintf(fp, "\nSpawning connections:\n");
520c6d62522Sd 	for (sp = Spawn; sp; sp = sp->next) {
521c6d62522Sd 		sa = (struct sockaddr_in *)&sp->source;
522c6d62522Sd 		bf = inet_ntop(AF_INET, &sa->sin_addr, buf, sizeof buf);
523c6d62522Sd 		if (!bf)  {
5243fc386a2Sespie 			logit(LOG_WARNING, "inet_ntop");
525c6d62522Sd 			bf = "?";
526c6d62522Sd 		}
527c6d62522Sd 		fprintf(fp, "fd %d: state %d, from %s:%d\n",
5282d84c14dSd 			sp->fd, sp->inlen + (sp->reading_msg ? sp->msglen : 0),
5292d84c14dSd 			bf, sa->sin_port);
530c6d62522Sd 	}
531c6d62522Sd }
532