1 /* $NetBSD: answer.c,v 1.14 2009/07/04 04:29:54 dholland Exp $ */ 2 /* 3 * Copyright (c) 1983-2003, Regents of the University of California. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * + Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * + Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * + Neither the name of the University of California, San Francisco nor 16 * the names of its contributors may be used to endorse or promote 17 * products derived from this software without specific prior written 18 * permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 #ifndef lint 35 __RCSID("$NetBSD: answer.c,v 1.14 2009/07/04 04:29:54 dholland Exp $"); 36 #endif /* not lint */ 37 38 #include <ctype.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <stdlib.h> 42 #include <unistd.h> 43 #include "hunt.h" 44 45 #define SCOREDECAY 15 46 47 static char Ttyname[NAMELEN]; 48 49 int 50 answer(void) 51 { 52 PLAYER *pp; 53 int newsock; 54 static u_long mode; 55 static char name[NAMELEN]; 56 static char team; 57 static int enter_status; 58 static socklen_t socklen; 59 static uint32_t machine; 60 static uint32_t uid; 61 static SOCKET sockstruct; 62 char *cp1, *cp2; 63 int flags; 64 u_int32_t version; 65 int i; 66 67 #ifdef INTERNET 68 socklen = sizeof sockstruct; 69 #else 70 socklen = sizeof sockstruct - 1; 71 #endif 72 errno = 0; 73 newsock = accept(Socket, (struct sockaddr *) &sockstruct, &socklen); 74 if (newsock < 0) 75 { 76 if (errno == EINTR) 77 return FALSE; 78 #ifdef LOG 79 syslog(LOG_ERR, "accept: %m"); 80 #else 81 perror("accept"); 82 #endif 83 cleanup(1); 84 } 85 86 #ifdef INTERNET 87 machine = ntohl(((struct sockaddr_in *) &sockstruct)->sin_addr.s_addr); 88 #else 89 if (machine == 0) 90 machine = gethostid(); 91 #endif 92 version = htonl((u_int32_t) HUNT_VERSION); 93 (void) write(newsock, &version, LONGLEN); 94 (void) read(newsock, &uid, LONGLEN); 95 uid = ntohl(uid); 96 (void) read(newsock, name, NAMELEN); 97 (void) read(newsock, &team, 1); 98 (void) read(newsock, &enter_status, LONGLEN); 99 enter_status = ntohl((unsigned long) enter_status); 100 (void) read(newsock, Ttyname, NAMELEN); 101 (void) read(newsock, &mode, sizeof mode); 102 mode = ntohl(mode); 103 104 /* 105 * Ensure null termination. 106 */ 107 name[sizeof(name)-1] = '\0'; 108 Ttyname[sizeof(Ttyname)-1] = '\0'; 109 110 /* 111 * Turn off blocking I/O, so a slow or dead terminal won't stop 112 * the game. All subsequent reads check how many bytes they read. 113 */ 114 flags = fcntl(newsock, F_GETFL, 0); 115 flags |= O_NDELAY; 116 (void) fcntl(newsock, F_SETFL, flags); 117 118 /* 119 * Make sure the name contains only printable characters 120 * since we use control characters for cursor control 121 * between driver and player processes 122 */ 123 for (cp1 = cp2 = name; *cp1 != '\0'; cp1++) 124 if (isprint((unsigned char)*cp1) || *cp1 == ' ') 125 *cp2++ = *cp1; 126 *cp2 = '\0'; 127 128 #ifdef INTERNET 129 if (mode == C_MESSAGE) { 130 char buf[BUFSIZ + 1]; 131 int n; 132 133 if (team == ' ') 134 (void) snprintf(buf, sizeof(buf), "%s: ", name); 135 else 136 (void) snprintf(buf, sizeof(buf), "%s[%c]: ", name, 137 team); 138 n = strlen(buf); 139 for (pp = Player; pp < End_player; pp++) { 140 cgoto(pp, HEIGHT, 0); 141 outstr(pp, buf, n); 142 } 143 while ((n = read(newsock, buf, BUFSIZ)) > 0) 144 for (pp = Player; pp < End_player; pp++) 145 outstr(pp, buf, n); 146 for (pp = Player; pp < End_player; pp++) { 147 ce(pp); 148 sendcom(pp, REFRESH); 149 sendcom(pp, READY, 0); 150 (void) fflush(pp->p_output); 151 } 152 (void) close(newsock); 153 return FALSE; 154 } 155 else 156 #endif 157 #ifdef MONITOR 158 if (mode == C_MONITOR) 159 if (End_monitor < &Monitor[MAXMON]) { 160 pp = End_monitor++; 161 i = pp - Monitor + MAXPL + 3; 162 } else { 163 socklen = 0; 164 (void) write(newsock, &socklen, 165 sizeof socklen); 166 (void) close(newsock); 167 return FALSE; 168 } 169 else 170 #endif 171 if (End_player < &Player[MAXPL]) { 172 pp = End_player++; 173 i = pp - Player + 3; 174 } else { 175 socklen = 0; 176 (void) write(newsock, &socklen, 177 sizeof socklen); 178 (void) close(newsock); 179 return FALSE; 180 } 181 182 #ifdef MONITOR 183 if (mode == C_MONITOR && team == ' ') 184 team = '*'; 185 #endif 186 pp->p_ident = get_ident(machine, uid, name, team); 187 pp->p_output = fdopen(newsock, "w"); 188 pp->p_death[0] = '\0'; 189 pp->p_fd = newsock; 190 fdset[i].fd = newsock; 191 fdset[i].events = POLLIN; 192 193 pp->p_y = 0; 194 pp->p_x = 0; 195 196 #ifdef MONITOR 197 if (mode == C_MONITOR) 198 stmonitor(pp); 199 else 200 #endif 201 stplayer(pp, enter_status); 202 return TRUE; 203 } 204 205 #ifdef MONITOR 206 void 207 stmonitor(PLAYER *pp) 208 { 209 int line; 210 PLAYER *npp; 211 212 memcpy(pp->p_maze, Maze, sizeof Maze); 213 214 drawmaze(pp); 215 216 (void) snprintf(Buf, sizeof(Buf), "%5.5s%c%-10.10s %c", " ", 217 stat_char(pp), 218 pp->p_ident->i_name, pp->p_ident->i_team); 219 line = STAT_MON_ROW + 1 + (pp - Monitor); 220 for (npp = Player; npp < End_player; npp++) { 221 cgoto(npp, line, STAT_NAME_COL); 222 outstr(npp, Buf, STAT_NAME_LEN); 223 } 224 for (npp = Monitor; npp < End_monitor; npp++) { 225 cgoto(npp, line, STAT_NAME_COL); 226 outstr(npp, Buf, STAT_NAME_LEN); 227 } 228 229 sendcom(pp, REFRESH); 230 sendcom(pp, READY, 0); 231 (void) fflush(pp->p_output); 232 } 233 #endif 234 235 void 236 stplayer(PLAYER *newpp, int enter_status) 237 { 238 int x, y; 239 PLAYER *pp; 240 241 Nplayer++; 242 243 for (y = 0; y < UBOUND; y++) 244 for (x = 0; x < WIDTH; x++) 245 newpp->p_maze[y][x] = Maze[y][x]; 246 for ( ; y < DBOUND; y++) { 247 for (x = 0; x < LBOUND; x++) 248 newpp->p_maze[y][x] = Maze[y][x]; 249 for ( ; x < RBOUND; x++) 250 newpp->p_maze[y][x] = SPACE; 251 for ( ; x < WIDTH; x++) 252 newpp->p_maze[y][x] = Maze[y][x]; 253 } 254 for ( ; y < HEIGHT; y++) 255 for (x = 0; x < WIDTH; x++) 256 newpp->p_maze[y][x] = Maze[y][x]; 257 258 do { 259 x = rand_num(WIDTH - 1) + 1; 260 y = rand_num(HEIGHT - 1) + 1; 261 } while (Maze[y][x] != SPACE); 262 newpp->p_over = SPACE; 263 newpp->p_x = x; 264 newpp->p_y = y; 265 newpp->p_undershot = FALSE; 266 267 #ifdef FLY 268 if (enter_status == Q_FLY) { 269 newpp->p_flying = rand_num(20); 270 newpp->p_flyx = 2 * rand_num(6) - 5; 271 newpp->p_flyy = 2 * rand_num(6) - 5; 272 newpp->p_face = FLYER; 273 } 274 else 275 #endif 276 { 277 newpp->p_flying = -1; 278 newpp->p_face = rand_dir(); 279 } 280 newpp->p_damage = 0; 281 newpp->p_damcap = MAXDAM; 282 newpp->p_nchar = 0; 283 newpp->p_ncount = 0; 284 newpp->p_nexec = 0; 285 newpp->p_ammo = ISHOTS; 286 #ifdef BOOTS 287 newpp->p_nboots = 0; 288 #endif 289 if (enter_status == Q_SCAN) { 290 newpp->p_scan = SCANLEN; 291 newpp->p_cloak = 0; 292 } 293 else { 294 newpp->p_scan = 0; 295 newpp->p_cloak = CLOAKLEN; 296 } 297 newpp->p_ncshot = 0; 298 299 do { 300 x = rand_num(WIDTH - 1) + 1; 301 y = rand_num(HEIGHT - 1) + 1; 302 } while (Maze[y][x] != SPACE); 303 Maze[y][x] = GMINE; 304 #ifdef MONITOR 305 for (pp = Monitor; pp < End_monitor; pp++) 306 check(pp, y, x); 307 #endif 308 309 do { 310 x = rand_num(WIDTH - 1) + 1; 311 y = rand_num(HEIGHT - 1) + 1; 312 } while (Maze[y][x] != SPACE); 313 Maze[y][x] = MINE; 314 #ifdef MONITOR 315 for (pp = Monitor; pp < End_monitor; pp++) 316 check(pp, y, x); 317 #endif 318 319 (void) snprintf(Buf, sizeof(Buf), "%5.2f%c%-10.10s %c", 320 newpp->p_ident->i_score, 321 stat_char(newpp), newpp->p_ident->i_name, 322 newpp->p_ident->i_team); 323 y = STAT_PLAY_ROW + 1 + (newpp - Player); 324 for (pp = Player; pp < End_player; pp++) { 325 if (pp != newpp) { 326 char smallbuf[16]; 327 328 pp->p_ammo += NSHOTS; 329 newpp->p_ammo += NSHOTS; 330 cgoto(pp, y, STAT_NAME_COL); 331 outstr(pp, Buf, STAT_NAME_LEN); 332 (void) snprintf(smallbuf, sizeof(smallbuf), 333 "%3d", pp->p_ammo); 334 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); 335 outstr(pp, smallbuf, 3); 336 } 337 } 338 #ifdef MONITOR 339 for (pp = Monitor; pp < End_monitor; pp++) { 340 cgoto(pp, y, STAT_NAME_COL); 341 outstr(pp, Buf, STAT_NAME_LEN); 342 } 343 #endif 344 345 drawmaze(newpp); 346 drawplayer(newpp, TRUE); 347 look(newpp); 348 #ifdef FLY 349 if (enter_status == Q_FLY) 350 /* Make sure that the position you enter in will be erased */ 351 showexpl(newpp->p_y, newpp->p_x, FLYER); 352 #endif 353 sendcom(newpp, REFRESH); 354 sendcom(newpp, READY, 0); 355 (void) fflush(newpp->p_output); 356 } 357 358 /* 359 * rand_dir: 360 * Return a random direction 361 */ 362 int 363 rand_dir(void) 364 { 365 switch (rand_num(4)) { 366 case 0: 367 return LEFTS; 368 case 1: 369 return RIGHT; 370 case 2: 371 return BELOW; 372 case 3: 373 return ABOVE; 374 } 375 /* NOTREACHED */ 376 return(-1); 377 } 378 379 /* 380 * get_ident: 381 * Get the score structure of a player 382 */ 383 IDENT * 384 get_ident(uint32_t machine, uint32_t uid, char *name, char team) 385 { 386 IDENT *ip; 387 static IDENT punt; 388 389 for (ip = Scores; ip != NULL; ip = ip->i_next) 390 if (ip->i_machine == machine 391 && ip->i_uid == uid 392 && ip->i_team == team 393 && strncmp(ip->i_name, name, NAMELEN) == 0) 394 break; 395 396 if (ip != NULL) { 397 if (ip->i_entries < SCOREDECAY) 398 ip->i_entries++; 399 else 400 ip->i_kills = (ip->i_kills * (SCOREDECAY - 1)) 401 / SCOREDECAY; 402 ip->i_score = ip->i_kills / (double) ip->i_entries; 403 } 404 else { 405 ip = malloc(sizeof(*ip)); 406 if (ip == NULL) { 407 /* Fourth down, time to punt */ 408 ip = &punt; 409 } 410 ip->i_machine = machine; 411 ip->i_team = team; 412 ip->i_uid = uid; 413 strncpy(ip->i_name, name, NAMELEN); 414 ip->i_kills = 0; 415 ip->i_entries = 1; 416 ip->i_score = 0; 417 ip->i_absorbed = 0; 418 ip->i_faced = 0; 419 ip->i_shot = 0; 420 ip->i_robbed = 0; 421 ip->i_slime = 0; 422 ip->i_missed = 0; 423 ip->i_ducked = 0; 424 ip->i_gkills = ip->i_bkills = ip->i_deaths = 0; 425 ip->i_stillb = ip->i_saved = 0; 426 ip->i_next = Scores; 427 Scores = ip; 428 } 429 430 return ip; 431 } 432