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