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