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