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