Home | History | Annotate | Line # | Download | only in huntd
answer.c revision 1.3
      1 /*	$NetBSD: answer.c,v 1.3 1997/10/10 16:32:50 lukem Exp $	*/
      2 /*
      3  *  Hunt
      4  *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
      5  *  San Francisco, California
      6  */
      7 
      8 #include <sys/cdefs.h>
      9 #ifndef lint
     10 __RCSID("$NetBSD: answer.c,v 1.3 1997/10/10 16:32:50 lukem Exp $");
     11 #endif /* not lint */
     12 
     13 # include	<ctype.h>
     14 # include	<errno.h>
     15 # include	<fcntl.h>
     16 # include	<stdlib.h>
     17 # include	<unistd.h>
     18 # include	"hunt.h"
     19 
     20 # define	SCOREDECAY	15
     21 
     22 static char	Ttyname[NAMELEN];
     23 
     24 int
     25 answer()
     26 {
     27 	PLAYER			*pp;
     28 	int			newsock;
     29 	static u_long		mode;
     30 	static char		name[NAMELEN];
     31 	static char		team;
     32 	static int		enter_status;
     33 	static int		socklen;
     34 	static u_long		machine;
     35 	static u_long		uid;
     36 	static SOCKET		sockstruct;
     37 	char			*cp1, *cp2;
     38 	int			flags;
     39 	long			version;
     40 
     41 # ifdef INTERNET
     42 	socklen = sizeof sockstruct;
     43 # else
     44 	socklen = sizeof sockstruct - 1;
     45 # endif
     46 	errno = 0;
     47 	newsock = accept(Socket, (struct sockaddr *) &sockstruct, &socklen);
     48 	if (newsock < 0)
     49 	{
     50 		if (errno == EINTR)
     51 			return FALSE;
     52 # ifdef LOG
     53 		syslog(LOG_ERR, "accept: %m");
     54 # else
     55 		perror("accept");
     56 # endif
     57 		cleanup(1);
     58 	}
     59 
     60 # ifdef INTERNET
     61 	machine = ntohl(((struct sockaddr_in *) &sockstruct)->sin_addr.s_addr);
     62 # else
     63 	if (machine == 0)
     64 		machine = gethostid();
     65 # endif
     66 	version = htonl((u_int32_t) HUNT_VERSION);
     67 	(void) write(newsock, (char *) &version, LONGLEN);
     68 	(void) read(newsock, (char *) &uid, LONGLEN);
     69 	uid = ntohl((unsigned long) uid);
     70 	(void) read(newsock, name, NAMELEN);
     71 	(void) read(newsock, &team, 1);
     72 	(void) read(newsock, (char *) &enter_status, LONGLEN);
     73 	enter_status = ntohl((unsigned long) enter_status);
     74 	(void) read(newsock, Ttyname, NAMELEN);
     75 	(void) read(newsock, (char *) &mode, sizeof mode);
     76 	mode = ntohl(mode);
     77 
     78 	/*
     79 	 * Turn off blocking I/O, so a slow or dead terminal won't stop
     80 	 * the game.  All subsequent reads check how many bytes they read.
     81 	 */
     82 	flags = fcntl(newsock, F_GETFL, 0);
     83 	flags |= O_NDELAY;
     84 	(void) fcntl(newsock, F_SETFL, flags);
     85 
     86 	/*
     87 	 * Make sure the name contains only printable characters
     88 	 * since we use control characters for cursor control
     89 	 * between driver and player processes
     90 	 */
     91 	for (cp1 = cp2 = name; *cp1 != '\0'; cp1++)
     92 		if (isprint(*cp1) || *cp1 == ' ')
     93 			*cp2++ = *cp1;
     94 	*cp2 = '\0';
     95 
     96 # ifdef INTERNET
     97 	if (mode == C_MESSAGE) {
     98 		char	buf[BUFSIZ + 1];
     99 		int	n;
    100 
    101 		if (team == ' ')
    102 			(void) sprintf(buf, "%s: ", name);
    103 		else
    104 			(void) sprintf(buf, "%s[%c]: ", name, team);
    105 		n = strlen(buf);
    106 		for (pp = Player; pp < End_player; pp++) {
    107 			cgoto(pp, HEIGHT, 0);
    108 			outstr(pp, buf, n);
    109 		}
    110 		while ((n = read(newsock, buf, BUFSIZ)) > 0)
    111 			for (pp = Player; pp < End_player; pp++)
    112 				outstr(pp, buf, n);
    113 		for (pp = Player; pp < End_player; pp++) {
    114 			ce(pp);
    115 			sendcom(pp, REFRESH);
    116 			sendcom(pp, READY, 0);
    117 			(void) fflush(pp->p_output);
    118 		}
    119 		(void) close(newsock);
    120 		return FALSE;
    121 	}
    122 	else
    123 # endif
    124 # ifdef MONITOR
    125 	if (mode == C_MONITOR)
    126 		if (End_monitor < &Monitor[MAXMON])
    127 			pp = End_monitor++;
    128 		else {
    129 			socklen = 0;
    130 			(void) write(newsock, (char *) &socklen,
    131 				sizeof socklen);
    132 			(void) close(newsock);
    133 			return FALSE;
    134 		}
    135 	else
    136 # endif
    137 		if (End_player < &Player[MAXPL])
    138 			pp = End_player++;
    139 		else {
    140 			socklen = 0;
    141 			(void) write(newsock, (char *) &socklen,
    142 				sizeof socklen);
    143 			(void) close(newsock);
    144 			return FALSE;
    145 		}
    146 
    147 #ifdef MONITOR
    148 	if (mode == C_MONITOR && team == ' ')
    149 		team = '*';
    150 #endif
    151 	pp->p_ident = get_ident(machine, uid, name, team);
    152 	pp->p_output = fdopen(newsock, "w");
    153 	pp->p_death[0] = '\0';
    154 	pp->p_fd = newsock;
    155 	FD_SET(pp->p_fd, &Fds_mask);
    156 	if (pp->p_fd >= Num_fds)
    157 		Num_fds = pp->p_fd + 1;
    158 
    159 	pp->p_y = 0;
    160 	pp->p_x = 0;
    161 
    162 # ifdef MONITOR
    163 	if (mode == C_MONITOR)
    164 		stmonitor(pp);
    165 	else
    166 # endif
    167 		stplayer(pp, enter_status);
    168 	return TRUE;
    169 }
    170 
    171 # ifdef MONITOR
    172 void
    173 stmonitor(pp)
    174 	PLAYER	*pp;
    175 {
    176 	int	line;
    177 	PLAYER	*npp;
    178 
    179 	memcpy(pp->p_maze, Maze, sizeof Maze);
    180 
    181 	drawmaze(pp);
    182 
    183 	(void) sprintf(Buf, "%5.5s%c%-10.10s %c", " ", stat_char(pp),
    184 		pp->p_ident->i_name, pp->p_ident->i_team);
    185 	line = STAT_MON_ROW + 1 + (pp - Monitor);
    186 	for (npp = Player; npp < End_player; npp++) {
    187 		cgoto(npp, line, STAT_NAME_COL);
    188 		outstr(npp, Buf, STAT_NAME_LEN);
    189 	}
    190 	for (npp = Monitor; npp < End_monitor; npp++) {
    191 		cgoto(npp, line, STAT_NAME_COL);
    192 		outstr(npp, Buf, STAT_NAME_LEN);
    193 	}
    194 
    195 	sendcom(pp, REFRESH);
    196 	sendcom(pp, READY, 0);
    197 	(void) fflush(pp->p_output);
    198 }
    199 # endif
    200 
    201 void
    202 stplayer(newpp, enter_status)
    203 	PLAYER	*newpp;
    204 	int	enter_status;
    205 {
    206 	int	x, y;
    207 	PLAYER	*pp;
    208 
    209 	Nplayer++;
    210 
    211 	for (y = 0; y < UBOUND; y++)
    212 		for (x = 0; x < WIDTH; x++)
    213 			newpp->p_maze[y][x] = Maze[y][x];
    214 	for (     ; y < DBOUND; y++) {
    215 		for (x = 0; x < LBOUND; x++)
    216 			newpp->p_maze[y][x] = Maze[y][x];
    217 		for (     ; x < RBOUND; x++)
    218 			newpp->p_maze[y][x] = SPACE;
    219 		for (     ; x < WIDTH;  x++)
    220 			newpp->p_maze[y][x] = Maze[y][x];
    221 	}
    222 	for (     ; y < HEIGHT; y++)
    223 		for (x = 0; x < WIDTH; x++)
    224 			newpp->p_maze[y][x] = Maze[y][x];
    225 
    226 	do {
    227 		x = rand_num(WIDTH - 1) + 1;
    228 		y = rand_num(HEIGHT - 1) + 1;
    229 	} while (Maze[y][x] != SPACE);
    230 	newpp->p_over = SPACE;
    231 	newpp->p_x = x;
    232 	newpp->p_y = y;
    233 	newpp->p_undershot = FALSE;
    234 
    235 # ifdef FLY
    236 	if (enter_status == Q_FLY) {
    237 		newpp->p_flying = rand_num(20);
    238 		newpp->p_flyx = 2 * rand_num(6) - 5;
    239 		newpp->p_flyy = 2 * rand_num(6) - 5;
    240 		newpp->p_face = FLYER;
    241 	}
    242 	else
    243 # endif
    244 	{
    245 		newpp->p_flying = -1;
    246 		newpp->p_face = rand_dir();
    247 	}
    248 	newpp->p_damage = 0;
    249 	newpp->p_damcap = MAXDAM;
    250 	newpp->p_nchar = 0;
    251 	newpp->p_ncount = 0;
    252 	newpp->p_nexec = 0;
    253 	newpp->p_ammo = ISHOTS;
    254 # ifdef BOOTS
    255 	newpp->p_nboots = 0;
    256 # endif
    257 	if (enter_status == Q_SCAN) {
    258 		newpp->p_scan = SCANLEN;
    259 		newpp->p_cloak = 0;
    260 	}
    261 	else {
    262 		newpp->p_scan = 0;
    263 		newpp->p_cloak = CLOAKLEN;
    264 	}
    265 	newpp->p_ncshot = 0;
    266 
    267 	do {
    268 		x = rand_num(WIDTH - 1) + 1;
    269 		y = rand_num(HEIGHT - 1) + 1;
    270 	} while (Maze[y][x] != SPACE);
    271 	Maze[y][x] = GMINE;
    272 # ifdef MONITOR
    273 	for (pp = Monitor; pp < End_monitor; pp++)
    274 		check(pp, y, x);
    275 # endif
    276 
    277 	do {
    278 		x = rand_num(WIDTH - 1) + 1;
    279 		y = rand_num(HEIGHT - 1) + 1;
    280 	} while (Maze[y][x] != SPACE);
    281 	Maze[y][x] = MINE;
    282 # ifdef MONITOR
    283 	for (pp = Monitor; pp < End_monitor; pp++)
    284 		check(pp, y, x);
    285 # endif
    286 
    287 	(void) sprintf(Buf, "%5.2f%c%-10.10s %c", newpp->p_ident->i_score,
    288 		stat_char(newpp), newpp->p_ident->i_name,
    289 		newpp->p_ident->i_team);
    290 	y = STAT_PLAY_ROW + 1 + (newpp - Player);
    291 	for (pp = Player; pp < End_player; pp++) {
    292 		if (pp != newpp) {
    293 			char	smallbuf[10];
    294 
    295 			pp->p_ammo += NSHOTS;
    296 			newpp->p_ammo += NSHOTS;
    297 			cgoto(pp, y, STAT_NAME_COL);
    298 			outstr(pp, Buf, STAT_NAME_LEN);
    299 			(void) sprintf(smallbuf, "%3d", pp->p_ammo);
    300 			cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
    301 			outstr(pp, smallbuf, 3);
    302 		}
    303 	}
    304 # ifdef MONITOR
    305 	for (pp = Monitor; pp < End_monitor; pp++) {
    306 		cgoto(pp, y, STAT_NAME_COL);
    307 		outstr(pp, Buf, STAT_NAME_LEN);
    308 	}
    309 # endif
    310 
    311 	drawmaze(newpp);
    312 	drawplayer(newpp, TRUE);
    313 	look(newpp);
    314 # ifdef	FLY
    315 	if (enter_status == Q_FLY)
    316 		/* Make sure that the position you enter in will be erased */
    317 		showexpl(newpp->p_y, newpp->p_x, FLYER);
    318 # endif
    319 	sendcom(newpp, REFRESH);
    320 	sendcom(newpp, READY, 0);
    321 	(void) fflush(newpp->p_output);
    322 }
    323 
    324 /*
    325  * rand_dir:
    326  *	Return a random direction
    327  */
    328 int
    329 rand_dir()
    330 {
    331 	switch (rand_num(4)) {
    332 	  case 0:
    333 		return LEFTS;
    334 	  case 1:
    335 		return RIGHT;
    336 	  case 2:
    337 		return BELOW;
    338 	  case 3:
    339 		return ABOVE;
    340 	}
    341 	/* NOTREACHED */
    342 	return(-1);
    343 }
    344 
    345 /*
    346  * get_ident:
    347  *	Get the score structure of a player
    348  */
    349 IDENT *
    350 get_ident(machine, uid, name, team)
    351 	u_long	machine;
    352 	u_long	uid;
    353 	char	*name;
    354 	char	team;
    355 {
    356 	IDENT		*ip;
    357 	static IDENT	punt;
    358 
    359 	for (ip = Scores; ip != NULL; ip = ip->i_next)
    360 		if (ip->i_machine == machine
    361 		&&  ip->i_uid == uid
    362 		&&  ip->i_team == team
    363 		&&  strncmp(ip->i_name, name, NAMELEN) == 0)
    364 			break;
    365 
    366 	if (ip != NULL) {
    367 		if (ip->i_entries < SCOREDECAY)
    368 			ip->i_entries++;
    369 		else
    370 			ip->i_kills = (ip->i_kills * (SCOREDECAY - 1))
    371 				/ SCOREDECAY;
    372 		ip->i_score = ip->i_kills / (double) ip->i_entries;
    373 	}
    374 	else {
    375 		ip = (IDENT *) malloc(sizeof (IDENT));
    376 		if (ip == NULL) {
    377 			/* Fourth down, time to punt */
    378 			ip = &punt;
    379 		}
    380 		ip->i_machine = machine;
    381 		ip->i_team = team;
    382 		ip->i_uid = uid;
    383 		strncpy(ip->i_name, name, NAMELEN);
    384 		ip->i_kills = 0;
    385 		ip->i_entries = 1;
    386 		ip->i_score = 0;
    387 		ip->i_absorbed = 0;
    388 		ip->i_faced = 0;
    389 		ip->i_shot = 0;
    390 		ip->i_robbed = 0;
    391 		ip->i_slime = 0;
    392 		ip->i_missed = 0;
    393 		ip->i_ducked = 0;
    394 		ip->i_gkills = ip->i_bkills = ip->i_deaths = 0;
    395 		ip->i_stillb = ip->i_saved = 0;
    396 		ip->i_next = Scores;
    397 		Scores = ip;
    398 	}
    399 
    400 	return ip;
    401 }
    402