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