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