/** * Initialize the terminal of a player. * @param[in] pp A player. * [PSR] */ void stmonitor(PLAYER *pp) { int line; PLAYER *npp; memcpy(pp->p_maze, maze, sizeof maze); drawmaze(pp); (void) sprintf(gen_buf, "%5.5s%c%-10.10s %c", " ", stat_char(pp), pp->p_ident->i_name, pp->p_ident->i_team); line = STAT_MON_ROW + 1 + (pp - monitor); for (npp = player; npp < end_player; npp++) { cgoto(npp, line, STAT_NAME_COL); outstr(npp, gen_buf, STAT_NAME_LEN); } for (npp = monitor; npp < end_monitor; npp++) { cgoto(npp, line, STAT_NAME_COL); outstr(npp, gen_buf, STAT_NAME_LEN); } sendcom(pp, REFRESH); sendcom(pp, READY, 0); (void) fflush(pp->p_output); }
/* * fire_slime: * Fire a slime shot in the given direction */ static void fire_slime(PLAYER *pp, int req_index) { if (pp == NULL) return; /* Check configuration: */ if (!conf_ooze) return; /* Drop the slime type back util we can afford it: */ while (req_index >= 0 && pp->p_ammo < slime_req[req_index]) req_index--; /* Can we afford to slime at all? */ if (req_index < 0) { message(pp, "Not enough charges."); return; } /* Is the gun too hot? */ if (pp->p_ncshot > conf_maxncshot) return; /* Heat up the gun: */ if (pp->p_ncshot++ == conf_maxncshot) { /* The gun has overheated: */ outyx(pp, STAT_GUN_ROW, STAT_VALUE_COL, " "); } /* Use up some ammo: */ pp->p_ammo -= slime_req[req_index]; ammo_update(pp); /* Start the slime moving: */ add_shot(SLIME, pp->p_y, pp->p_x, pp->p_face, slime_req[req_index] * conf_slimefactor, pp, FALSE, pp->p_face); pp->p_undershot = TRUE; /* Show the object to everyone: */ showexpl(pp->p_y, pp->p_x, SLIME); sendcom(ALL_PLAYERS, REFRESH); }
/* * mon_execute: * Execute a single monitor command */ void mon_execute(PLAYER *pp) { char ch; ch = pp->p_cbuf[pp->p_ncount++]; switch (ch) { case CTRL('L'): /* Redraw messed-up screen */ sendcom(pp, REDRAW); break; case 'q': /* Quit client */ (void) strlcpy(pp->p_death, "| Quit |", sizeof pp->p_death); break; default: /* Ignore everything else */ ; } }
/* * fire: * Fire a shot of the given type in the given direction */ static void fire(PLAYER *pp, int req_index) { if (pp == NULL) return; /* Drop the shot type down until we can afford it: */ while (req_index >= 0 && pp->p_ammo < shot_req[req_index]) req_index--; /* Can we shoot at all? */ if (req_index < 0) { message(pp, "Not enough charges."); return; } /* Check if the gun is too hot: */ if (pp->p_ncshot > conf_maxncshot) return; /* Heat up the gun: */ if (pp->p_ncshot++ == conf_maxncshot) { /* The gun has overheated: */ outyx(pp, STAT_GUN_ROW, STAT_VALUE_COL, " "); } /* Use up some ammo: */ pp->p_ammo -= shot_req[req_index]; ammo_update(pp); /* Start the bullet moving: */ add_shot(shot_type[req_index], pp->p_y, pp->p_x, pp->p_face, shot_req[req_index], pp, FALSE, pp->p_face); pp->p_undershot = TRUE; /* Show the bullet to everyone: */ showexpl(pp->p_y, pp->p_x, shot_type[req_index]); sendcom(ALL_PLAYERS, REFRESH); }
/* * cleanup: * Exit with the given value, cleaning up any droppings lying around */ void cleanup(int eval) { PLAYER *pp; /* Place their cursor in a friendly position: */ cgoto(ALL_PLAYERS, HEIGHT, 0); /* Send them all the ENDWIN command: */ sendcom(ALL_PLAYERS, ENDWIN, LAST_PLAYER); /* And close their connections: */ for (pp = Player; pp < End_player; pp++) (void) fclose(pp->p_output); for (pp = Monitor; pp < End_monitor; pp++) (void) fclose(pp->p_output); /* Close the server socket: */ (void) close(Socket); /* The end: */ logx(LOG_INFO, "game over"); exit(eval); }
/* * move_player: * Execute a move in the given direction */ static void move_player(PLAYER *pp, int dir) { PLAYER *newp; int x, y; bool moved; BULLET *bp; y = pp->p_y; x = pp->p_x; switch (dir) { case LEFTS: x--; break; case RIGHT: x++; break; case ABOVE: y--; break; case BELOW: y++; break; } moved = false; switch (Maze[y][x]) { case SPACE: #ifdef RANDOM case DOOR: #endif moved = true; break; case WALL1: case WALL2: case WALL3: #ifdef REFLECT case WALL4: case WALL5: #endif break; case MINE: case GMINE: if (dir == pp->p_face) pickup(pp, y, x, 2, Maze[y][x]); else if (opposite(dir, pp->p_face)) pickup(pp, y, x, 95, Maze[y][x]); else pickup(pp, y, x, 50, Maze[y][x]); Maze[y][x] = SPACE; moved = true; break; case SHOT: case GRENADE: case SATCHEL: case BOMB: #ifdef OOZE case SLIME: #endif #ifdef DRONE case DSHOT: #endif bp = is_bullet(y, x); if (bp != NULL) bp->b_expl = true; Maze[y][x] = SPACE; moved = true; break; case LEFTS: case RIGHT: case ABOVE: case BELOW: if (dir != pp->p_face) sendcom(pp, BELL); else { newp = play_at(y, x); checkdam(newp, pp, pp->p_ident, STABDAM, KNIFE); } break; #ifdef FLY case FLYER: newp = play_at(y, x); message(newp, "Oooh, there's a short guy waving at you!"); message(pp, "You couldn't quite reach him!"); break; #endif #ifdef BOOTS case BOOT: case BOOT_PAIR: if (Maze[y][x] == BOOT) pp->p_nboots++; else pp->p_nboots += 2; for (newp = Boot; newp < &Boot[NBOOTS]; newp++) { if (newp->p_flying < 0) continue; if (newp->p_y == y && newp->p_x == x) { newp->p_flying = -1; if (newp->p_undershot) fixshots(y, x, newp->p_over); } } if (pp->p_nboots == 2) message(pp, "Wow! A pair of boots!"); else message(pp, "You can hobble around on one boot."); Maze[y][x] = SPACE; moved = true; break; #endif } if (moved) { if (pp->p_ncshot > 0) if (--pp->p_ncshot == MAXNCSHOT) { cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL); outstr(pp, " ok", 3); } if (pp->p_undershot) { fixshots(pp->p_y, pp->p_x, pp->p_over); pp->p_undershot = false; } drawplayer(pp, false); pp->p_over = Maze[y][x]; pp->p_y = y; pp->p_x = x; drawplayer(pp, true); } }
/* * main: * The main program. */ int main(int ac, char **av) { PLAYER *pp; int had_char; static fd_set read_fds; static FLAG first = TRUE; static FLAG server = FALSE; int c; static struct timeval linger = { 0, 0 }; static struct timeval timeout = { 0, 0 }, *to; struct spawn *sp, *spnext; int ret; int nready; int fd; First_arg = av[0]; config(); while ((c = getopt(ac, av, "sp:a:D:")) != -1) { switch (c) { case 's': server = TRUE; break; case 'p': should_announce = FALSE; Server_port = atoi(optarg); break; case 'a': if (!inet_aton(optarg, (struct in_addr *)&Server_addr)) err(1, "bad interface address: %s", optarg); break; case 'D': config_arg(optarg); break; default: erred: fprintf(stderr, "usage: %s [-s] [-a addr] [-Dvar=value ...] " "[-p port]\n", av[0]); exit(2); } } if (optind < ac) goto erred; /* Open syslog: */ openlog("huntd", LOG_PID | (conf_logerr && !server? LOG_PERROR : 0), LOG_DAEMON); /* Initialise game parameters: */ init(); again: do { /* First, poll to see if we can get input */ do { read_fds = Fds_mask; errno = 0; timerclear(&timeout); nready = select(Num_fds, &read_fds, NULL, NULL, &timeout); if (nready < 0 && errno != EINTR) { logit(LOG_ERR, "select"); cleanup(1); } } while (nready < 0); if (nready == 0) { /* * Nothing was ready. We do some work now * to see if the simulation has any pending work * to do, and decide if we need to block * indefinitely or just timeout. */ do { if (conf_simstep && can_moveshots()) { /* * block for a short time before continuing * with explosions, bullets and whatnot */ to = &timeout; to->tv_sec = conf_simstep / 1000000; to->tv_usec = conf_simstep % 1000000; } else /* * since there's nothing going on, * just block waiting for external activity */ to = NULL; read_fds = Fds_mask; errno = 0; nready = select(Num_fds, &read_fds, NULL, NULL, to); if (nready < 0 && errno != EINTR) { logit(LOG_ERR, "select"); cleanup(1); } } while (nready < 0); } /* Remember which descriptors are active: */ Have_inp = read_fds; /* Answer new player connections: */ if (FD_ISSET(Socket, &Have_inp)) answer_first(); /* Continue answering new player connections: */ for (sp = Spawn; sp; ) { spnext = sp->next; fd = sp->fd; if (FD_ISSET(fd, &Have_inp) && answer_next(sp)) { /* * Remove from the spawn list. (fd remains in * read set). */ *sp->prevnext = sp->next; if (sp->next) sp->next->prevnext = sp->prevnext; free(sp); /* We probably consumed all data. */ FD_CLR(fd, &Have_inp); /* Announce game if this is the first spawn. */ if (first && should_announce) announce_game(); first = FALSE; } sp = spnext; } /* Process input and move bullets until we've exhausted input */ had_char = TRUE; while (had_char) { moveshots(); for (pp = Player; pp < End_player; ) if (pp->p_death[0] != '\0') zap(pp, TRUE); else pp++; for (pp = Monitor; pp < End_monitor; ) if (pp->p_death[0] != '\0') zap(pp, FALSE); else pp++; had_char = FALSE; for (pp = Player; pp < End_player; pp++) if (havechar(pp)) { execute(pp); pp->p_nexec++; had_char = TRUE; } for (pp = Monitor; pp < End_monitor; pp++) if (havechar(pp)) { mon_execute(pp); pp->p_nexec++; had_char = TRUE; } } /* Handle a datagram sent to the server socket: */ if (FD_ISSET(Server_socket, &Have_inp)) handle_wkport(Server_socket); /* Answer statistics connections: */ if (FD_ISSET(Status, &Have_inp)) send_stats(); /* Flush/synchronize all the displays: */ for (pp = Player; pp < End_player; pp++) { if (FD_ISSET(pp->p_fd, &read_fds)) { sendcom(pp, READY, pp->p_nexec); pp->p_nexec = 0; } flush(pp); } for (pp = Monitor; pp < End_monitor; pp++) { if (FD_ISSET(pp->p_fd, &read_fds)) { sendcom(pp, READY, pp->p_nexec); pp->p_nexec = 0; } flush(pp); } } while (Nplayer > 0); /* No more players! */ /* No players yet or a continuous game? */ if (first || conf_linger < 0) goto again; /* Wait a short while for one to come back: */ read_fds = Fds_mask; linger.tv_sec = conf_linger; while ((ret = select(Num_fds, &read_fds, NULL, NULL, &linger)) < 0) { if (errno != EINTR) { logit(LOG_WARNING, "select"); break; } read_fds = Fds_mask; linger.tv_sec = conf_linger; linger.tv_usec = 0; } if (ret > 0) /* Someone returned! Resume the game: */ goto again; /* else, it timed out, and the game is really over. */ /* If we are an inetd server, we should re-init the map and restart: */ if (server) { clear_scores(); makemaze(); clearwalls(); makeboots(); first = TRUE; goto again; } /* Get rid of any attached monitors: */ for (pp = Monitor; pp < End_monitor; ) zap(pp, FALSE); /* Fin: */ cleanup(0); exit(0); }
/* * zap: * Kill off a player and take them out of the game. * The 'was_player' flag indicates that the player was not * a monitor and needs extra cleaning up. */ static void zap(PLAYER *pp, FLAG was_player) { int len; BULLET *bp; PLAYER *np; int x, y; int savefd; if (was_player) { /* If they died from a shot, clean up shrapnel */ if (pp->p_undershot) fixshots(pp->p_y, pp->p_x, pp->p_over); /* Let the player see their last position: */ drawplayer(pp, FALSE); /* Remove from game: */ Nplayer--; } /* Display the cause of death in the centre of the screen: */ len = strlen(pp->p_death); x = (WIDTH - len) / 2; outyx(pp, HEIGHT / 2, x, "%s", pp->p_death); /* Put some horizontal lines around and below the death message: */ memset(pp->p_death + 1, '-', len - 2); pp->p_death[0] = '+'; pp->p_death[len - 1] = '+'; outyx(pp, HEIGHT / 2 - 1, x, "%s", pp->p_death); outyx(pp, HEIGHT / 2 + 1, x, "%s", pp->p_death); /* Move to bottom left */ cgoto(pp, HEIGHT, 0); savefd = pp->p_fd; if (was_player) { int expl_charge; int expl_type; int ammo_exploding; /* Check all the bullets: */ for (bp = Bullets; bp != NULL; bp = bp->b_next) { if (bp->b_owner == pp) /* Zapped players can't own bullets: */ bp->b_owner = NULL; if (bp->b_x == pp->p_x && bp->b_y == pp->p_y) /* Bullets over the player are now over air: */ bp->b_over = SPACE; } /* Explode a random fraction of the player's ammo: */ ammo_exploding = rand_num(pp->p_ammo); /* Determine the type and amount of detonation: */ expl_charge = rand_num(ammo_exploding + 1); if (pp->p_ammo == 0) /* Ignore the no-ammo case: */ expl_charge = expl_type = 0; else if (ammo_exploding >= pp->p_ammo - 1) { /* Maximal explosions always appear as slime: */ expl_charge = pp->p_ammo; expl_type = SLIME; } else { /* * Figure out the best effective explosion * type to use, given the amount of charge */ int btype, stype; for (btype = MAXBOMB - 1; btype > 0; btype--) if (expl_charge >= shot_req[btype]) break; for (stype = MAXSLIME - 1; stype > 0; stype--) if (expl_charge >= slime_req[stype]) break; /* Pick the larger of the bomb or slime: */ if (btype >= 0 && stype >= 0) { if (shot_req[btype] > slime_req[btype]) btype = -1; } if (btype >= 0) { expl_type = shot_type[btype]; expl_charge = shot_req[btype]; } else expl_type = SLIME; } if (expl_charge > 0) { char buf[BUFSIZ]; /* Detonate: */ (void) add_shot(expl_type, pp->p_y, pp->p_x, pp->p_face, expl_charge, NULL, TRUE, SPACE); /* Explain what the explosion is about. */ snprintf(buf, sizeof buf, "%s detonated.", pp->p_ident->i_name); message(ALL_PLAYERS, buf); while (pp->p_nboots-- > 0) { /* Throw one of the boots away: */ for (np = Boot; np < &Boot[NBOOTS]; np++) if (np->p_flying < 0) break; #ifdef DIAGNOSTIC if (np >= &Boot[NBOOTS]) err(1, "Too many boots"); #endif /* Start the boots from where the player is */ np->p_undershot = FALSE; np->p_x = pp->p_x; np->p_y = pp->p_y; /* Throw for up to 20 steps */ np->p_flying = rand_num(20); np->p_flyx = 2 * rand_num(6) - 5; np->p_flyy = 2 * rand_num(6) - 5; np->p_over = SPACE; np->p_face = BOOT; showexpl(np->p_y, np->p_x, BOOT); } } /* No explosion. Leave the player's boots behind. */ else if (pp->p_nboots > 0) { if (pp->p_nboots == 2) Maze[pp->p_y][pp->p_x] = BOOT_PAIR; else Maze[pp->p_y][pp->p_x] = BOOT; if (pp->p_undershot) fixshots(pp->p_y, pp->p_x, Maze[pp->p_y][pp->p_x]); } /* Any unexploded ammo builds up in the volcano: */ volcano += pp->p_ammo - expl_charge; /* Volcano eruption: */ if (conf_volcano && rand_num(100) < volcano / conf_volcano_max) { /* Erupt near the middle of the map */ do { x = rand_num(WIDTH / 2) + WIDTH / 4; y = rand_num(HEIGHT / 2) + HEIGHT / 4; } while (Maze[y][x] != SPACE); /* Convert volcano charge into lava: */ (void) add_shot(LAVA, y, x, LEFTS, volcano, NULL, TRUE, SPACE); volcano = 0; /* Tell eveyone what's happening */ message(ALL_PLAYERS, "Volcano eruption."); } /* Drone: */ if (conf_drone && rand_num(100) < 2) { /* Find a starting place near the middle of the map: */ do { x = rand_num(WIDTH / 2) + WIDTH / 4; y = rand_num(HEIGHT / 2) + HEIGHT / 4; } while (Maze[y][x] != SPACE); /* Start the drone going: */ add_shot(DSHOT, y, x, rand_dir(), shot_req[conf_mindshot + rand_num(MAXBOMB - conf_mindshot)], NULL, FALSE, SPACE); } /* Tell the zapped player's client to shut down. */ sendcom(pp, ENDWIN, ' '); (void) fclose(pp->p_output); /* Close up the gap in the Player array: */ End_player--; if (pp != End_player) { /* Move the last player into the gap: */ memcpy(pp, End_player, sizeof *pp); outyx(ALL_PLAYERS, STAT_PLAY_ROW + 1 + (pp - Player), STAT_NAME_COL, "%5.2f%c%-10.10s %c", pp->p_ident->i_score, stat_char(pp), pp->p_ident->i_name, pp->p_ident->i_team); } /* Erase the last player from the display: */ cgoto(ALL_PLAYERS, STAT_PLAY_ROW + 1 + Nplayer, STAT_NAME_COL); ce(ALL_PLAYERS); } else { /* Zap a monitor */ /* Close the session: */ sendcom(pp, ENDWIN, LAST_PLAYER); (void) fclose(pp->p_output); /* shuffle the monitor table */ End_monitor--; if (pp != End_monitor) { memcpy(pp, End_monitor, sizeof *pp); outyx(ALL_PLAYERS, STAT_MON_ROW + 1 + (pp - Player), STAT_NAME_COL, "%5.5s %-10.10s %c", " ", pp->p_ident->i_name, pp->p_ident->i_team); } /* Erase the last monitor in the list */ cgoto(ALL_PLAYERS, STAT_MON_ROW + 1 + (End_monitor - Monitor), STAT_NAME_COL); ce(ALL_PLAYERS); } /* Update the file descriptor sets used by select: */ FD_CLR(savefd, &Fds_mask); if (Num_fds == savefd + 1) { Num_fds = Socket; if (Server_socket > Socket) Num_fds = Server_socket; for (np = Player; np < End_player; np++) if (np->p_fd > Num_fds) Num_fds = np->p_fd; for (np = Monitor; np < End_monitor; np++) if (np->p_fd > Num_fds) Num_fds = np->p_fd; Num_fds++; } }
/* * ref; * Refresh the screen */ void ref(PLAYER *pp) { sendcom(pp, REFRESH); }
/* * ce: * Clear to the end of the line */ void ce(PLAYER *pp) { sendcom(pp, CLRTOEOL); }
/** * Manages the messages submission. * \return True in case of success, false instead. * [PSR] */ int answer() { PLAYER *pp; int newsock; static unsigned long mode; /* Changed from u_long. [PSR] */ static char name[NAMELEN]; static char team; static int enter_status; static unsigned int socklen; /* Edited from static int in order to match accept() parameter. [PSR] */ static unsigned long machine; /* Edited from u_long in order to match accept() parameter. [PSR] */ static u_int32_t uid; static SOCKET sockstruct; char *cp1, *cp2; int flags; u_int32_t version; int i; # ifdef INTERNET socklen = sizeof sockstruct; # else socklen = sizeof sockstruct - 1; # endif errno = 0; newsock = accept(main_socket, (struct sockaddr *) &sockstruct, &socklen); if (newsock < 0) { if (errno == EINTR) { return false; } # ifdef LOG iso_syslog(LOG_ERR, "accept: %m"); # else perror("accept"); # endif cleanup(1); } # ifdef INTERNET machine = ntohl(((struct sockaddr_in *) &sockstruct)->sin_addr.s_addr); # else if (machine == 0) { machine = gethostid(); } # endif version = htonl((u_int32_t) HUNT_VERSION); write_and_push(newsock, (char *) &version, LONGLEN); /* Authentication. [PSR] */ #ifdef INTERNET if(password_hash!=NULL) { /* A password has been set. [PSR] */ write_and_push(newsock, &c_auth, SHORTLEN); bool auth = false; for(i=0; i<MAXATTEMPT && !auth; i++) { /* 3 password attempts. [PSR] */ safe_read(newsock, &client_psw, (13 + 1) * sizeof(char)); if(strcmp(client_psw, password_hash)!=0) { /* Authentication failed. New request. [PSR] */ write_and_push(newsock, &c_auth, SHORTLEN); } else { /* Authentication successful. [PSR]*/ write_and_push(newsock, &c_auth_success, SHORTLEN); auth = true; } } if(!auth) { write_and_push(newsock, &c_refuse, SHORTLEN); safe_close(newsock); return false; } } else { /* No authentication. [PSR] */ write_and_push(newsock, &c_auth_success, SHORTLEN); } #endif safe_read(newsock, (char *) &uid, LONGLEN); uid = ntohl((unsigned long) uid); safe_read(newsock, name, NAMELEN); safe_read(newsock, &team, 1); safe_read(newsock, (char *) &enter_status, LONGLEN); enter_status = ntohl((unsigned long) enter_status); safe_read(newsock, ttyname_glob, NAMELEN); safe_read(newsock, (char *) &mode, sizeof mode); mode = ntohl(mode); /* * Turn off blocking I/O, so a slow or dead terminal won't stop * the game. All subsequent reads check how many bytes they read. */ flags = fcntl(newsock, F_GETFL, 0); flags |= O_NDELAY; (void) fcntl(newsock, F_SETFL, flags); /* * Make sure the name contains only printable characters * since we use control characters for cursor control * between driver and player processes */ for (cp1 = cp2 = name; *cp1 != '\0'; cp1++) { if (isprint((unsigned char)*cp1) || *cp1 == ' ') { *cp2++ = *cp1; } } *cp2 = '\0'; # ifdef INTERNET if (mode == C_MESSAGE) { char buf[BUFSIZ + 1]; int n; if (team == ' ') { (void) sprintf(buf, "%s: ", name); } else { (void) sprintf(buf, "%s[%c]: ", name, team); } n = strlen(buf); for (pp = player; pp < end_player; pp++) { cgoto(pp, HEIGHT, 0); outstr(pp, buf, n); } while ((n = read(newsock, buf, BUFSIZ)) > 0) for (pp = player; pp < end_player; pp++) { outstr(pp, buf, n); } for (pp = player; pp < end_player; pp++) { ce(pp); sendcom(pp, REFRESH); sendcom(pp, READY, 0); (void) fflush(pp->p_output); } safe_close(newsock); return false; } else # endif # ifdef MONITOR if (mode == C_MONITOR) { if (end_monitor < &monitor[MAXMON]) { pp = end_monitor++; i = pp - monitor + MAXPL + 3; } else { socklen = 0; write_and_push(newsock, (char *) &socklen, sizeof socklen); safe_close(newsock); return false; } } else # endif if (end_player < &player[MAXPL]) { pp = end_player++; i = pp - player + 3; } else { socklen = 0; write_and_push(newsock, (char *) &socklen, sizeof socklen); safe_close(newsock); return false; } #ifdef MONITOR if (mode == C_MONITOR && team == ' ') { team = '*'; } #endif pp->p_ident = get_ident(machine, uid, name, team); pp->p_output = fdopen(newsock, "w"); pp->p_death[0] = '\0'; pp->p_fd = newsock; fdset[i].fd = newsock; fdset[i].events = POLLIN; pp->p_y = 0; pp->p_x = 0; # ifdef MONITOR if (mode == C_MONITOR) { stmonitor(pp); } else # endif stplayer(pp, enter_status); return true; }
/** * Initializes a player status. * @param[out] newpp The new player to initialize. * @param[in] enter_status The enter mode of a player. * [PSR] */ void stplayer(PLAYER *newpp, int enter_status) { int x, y; PLAYER *pp; nplayer++; for (y = 0; y < UBOUND; y++) { for (x = 0; x < WIDTH; x++) { newpp->p_maze[y][x] = maze[y][x]; } } for (; y < DBOUND; y++) { for (x = 0; x < LBOUND; x++) { newpp->p_maze[y][x] = maze[y][x]; } for (; x < RBOUND; x++) { newpp->p_maze[y][x] = SPACE; } for (; x < WIDTH; x++) { newpp->p_maze[y][x] = maze[y][x]; } } for (; y < HEIGHT; y++) { for (x = 0; x < WIDTH; x++) { newpp->p_maze[y][x] = maze[y][x]; } } do { x = rand_num(WIDTH - 1) + 1; y = rand_num(HEIGHT - 1) + 1; } while (maze[y][x] != SPACE); newpp->p_over = SPACE; newpp->p_x = x; newpp->p_y = y; newpp->p_undershot = false; # ifdef FLY if (enter_status == Q_FLY) { newpp->p_flying = rand_num(20); newpp->p_flyx = 2 * rand_num(6) - 5; newpp->p_flyy = 2 * rand_num(6) - 5; newpp->p_face = FLYER; } else # endif { # ifdef FLY newpp->p_flying = -1; # endif newpp->p_face = rand_dir(); } newpp->p_damage = 0; newpp->p_damcap = MAXDAM; newpp->p_nchar = 0; newpp->p_ncount = 0; newpp->p_nexec = 0; newpp->p_ammo = ISHOTS; # ifdef BOOTS newpp->p_nboots = 0; # endif if (enter_status == Q_SCAN) { newpp->p_scan = SCANLEN; newpp->p_cloak = 0; } else { newpp->p_scan = 0; newpp->p_cloak = CLOAKLEN; } newpp->p_ncshot = 0; do { x = rand_num(WIDTH - 1) + 1; y = rand_num(HEIGHT - 1) + 1; } while (maze[y][x] != SPACE); maze[y][x] = GMINE; # ifdef MONITOR for (pp = monitor; pp < end_monitor; pp++) { check(pp, y, x); } # endif do { x = rand_num(WIDTH - 1) + 1; y = rand_num(HEIGHT - 1) + 1; } while (maze[y][x] != SPACE); maze[y][x] = MINE; # ifdef MONITOR for (pp = monitor; pp < end_monitor; pp++) { check(pp, y, x); } # endif (void) sprintf(gen_buf, "%5.2f%c%-10.10s %c", newpp->p_ident->i_score, stat_char(newpp), newpp->p_ident->i_name, newpp->p_ident->i_team); y = STAT_PLAY_ROW + 1 + (newpp - player); for (pp = player; pp < end_player; pp++) { if (pp != newpp) { char smallbuf[10]; pp->p_ammo += NSHOTS; newpp->p_ammo += NSHOTS; cgoto(pp, y, STAT_NAME_COL); outstr(pp, gen_buf, STAT_NAME_LEN); (void) sprintf(smallbuf, "%3d", pp->p_ammo); cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); outstr(pp, smallbuf, 3); } } # ifdef MONITOR for (pp = monitor; pp < end_monitor; pp++) { cgoto(pp, y, STAT_NAME_COL); outstr(pp, gen_buf, STAT_NAME_LEN); } # endif drawmaze(newpp); drawplayer(newpp, true); look(newpp); # ifdef FLY if (enter_status == Q_FLY) { /* Make sure that the position you enter in will be erased */ showexpl(newpp->p_y, newpp->p_x, FLYER); } # endif sendcom(newpp, REFRESH); sendcom(newpp, READY, 0); (void) fflush(newpp->p_output); }
/* * execute: * Execute a single command from a player */ void execute(PLAYER *pp) { char ch; ch = pp->p_cbuf[pp->p_ncount++]; /* When flying, only allow refresh and quit. */ if (pp->p_flying >= 0) { switch (ch) { case CTRL('L'): sendcom(pp, REDRAW); break; case 'q': (void) strlcpy(pp->p_death, "| Quit |", sizeof pp->p_death); break; } return; } /* Decode the command character: */ switch (ch) { case CTRL('L'): sendcom(pp, REDRAW); /* Refresh */ break; case 'h': move_player(pp, LEFTS); /* Move left */ break; case 'H': face(pp, LEFTS); /* Face left */ break; case 'j': move_player(pp, BELOW); /* Move down */ break; case 'J': face(pp, BELOW); /* Face down */ break; case 'k': move_player(pp, ABOVE); /* Move up */ break; case 'K': face(pp, ABOVE); /* Face up */ break; case 'l': move_player(pp, RIGHT); /* Move right */ break; case 'L': face(pp, RIGHT); /* Face right */ break; case 'f': case '1': fire(pp, 0); /* SHOT */ break; case 'g': case '2': fire(pp, 1); /* GRENADE */ break; case 'F': case '3': fire(pp, 2); /* SATCHEL */ break; case 'G': case '4': fire(pp, 3); /* 7x7 BOMB */ break; case '5': fire(pp, 4); /* 9x9 BOMB */ break; case '6': fire(pp, 5); /* 11x11 BOMB */ break; case '7': fire(pp, 6); /* 13x13 BOMB */ break; case '8': fire(pp, 7); /* 15x15 BOMB */ break; case '9': fire(pp, 8); /* 17x17 BOMB */ break; case '0': fire(pp, 9); /* 19x19 BOMB */ break; case '@': fire(pp, 10); /* 21x21 BOMB */ break; case 'o': fire_slime(pp, 0); /* SLIME */ break; case 'O': fire_slime(pp, 1); /* SSLIME */ break; case 'p': fire_slime(pp, 2); /* large slime */ break; case 'P': fire_slime(pp, 3); /* very large slime */ break; case 's': /* start scanning */ scan(pp); break; case 'c': /* start cloaking */ cloak(pp); break; case 'q': /* quit */ (void) strlcpy(pp->p_death, "| Quit |", sizeof pp->p_death); break; } }
/* * execute: * Execute a single command */ void execute(PLAYER *pp) { char ch; ch = pp->p_cbuf[pp->p_ncount++]; #ifdef FLY if (pp->p_flying >= 0) { switch (ch) { case CTRL('L'): sendcom(pp, REDRAW); break; case 'q': (void) strcpy(pp->p_death, "| Quit |"); break; } return; } #endif switch (ch) { case CTRL('L'): sendcom(pp, REDRAW); break; case 'h': move_player(pp, LEFTS); break; case 'H': turn_player(pp, LEFTS); break; case 'j': move_player(pp, BELOW); break; case 'J': turn_player(pp, BELOW); break; case 'k': move_player(pp, ABOVE); break; case 'K': turn_player(pp, ABOVE); break; case 'l': move_player(pp, RIGHT); break; case 'L': turn_player(pp, RIGHT); break; case 'f': case '1': fire(pp, 0); /* SHOT */ break; case 'g': case '2': fire(pp, 1); /* GRENADE */ break; case 'F': case '3': fire(pp, 2); /* SATCHEL */ break; case 'G': case '4': fire(pp, 3); /* 7x7 BOMB */ break; case '5': fire(pp, 4); /* 9x9 BOMB */ break; case '6': fire(pp, 5); /* 11x11 BOMB */ break; case '7': fire(pp, 6); /* 13x13 BOMB */ break; case '8': fire(pp, 7); /* 15x15 BOMB */ break; case '9': fire(pp, 8); /* 17x17 BOMB */ break; case '0': fire(pp, 9); /* 19x19 BOMB */ break; case '@': fire(pp, 10); /* 21x21 BOMB */ break; #ifdef OOZE case 'o': fire_slime(pp, 0); /* SLIME */ break; case 'O': fire_slime(pp, 1); /* SSLIME */ break; case 'p': fire_slime(pp, 2); break; case 'P': fire_slime(pp, 3); break; #endif case 's': scan(pp); break; case 'c': cloak(pp); break; case 'q': (void) strcpy(pp->p_death, "| Quit |"); break; } }
int answer() { PLAYER *pp; int newsock; static u_long mode; static char name[NAMELEN]; static char team; static int enter_status; static int socklen; static u_long machine; static u_int32_t uid; static SOCKET sockstruct; char *cp1, *cp2; int flags; u_int32_t version; int i; # ifdef INTERNET socklen = sizeof sockstruct; # else socklen = sizeof sockstruct - 1; # endif errno = 0; newsock = accept(Socket, (struct sockaddr *) &sockstruct, &socklen); if (newsock < 0) { if (errno == EINTR) return FALSE; # ifdef LOG syslog(LOG_ERR, "accept: %m"); # else perror("accept"); # endif cleanup(1); } # ifdef INTERNET machine = ntohl(((struct sockaddr_in *) &sockstruct)->sin_addr.s_addr); # else if (machine == 0) machine = gethostid(); # endif version = htonl((u_int32_t) HUNT_VERSION); (void) write(newsock, (char *) &version, LONGLEN); (void) read(newsock, (char *) &uid, LONGLEN); uid = ntohl((unsigned long) uid); (void) read(newsock, name, NAMELEN); (void) read(newsock, &team, 1); (void) read(newsock, (char *) &enter_status, LONGLEN); enter_status = ntohl((unsigned long) enter_status); (void) read(newsock, Ttyname, NAMELEN); (void) read(newsock, (char *) &mode, sizeof mode); mode = ntohl(mode); /* * Turn off blocking I/O, so a slow or dead terminal won't stop * the game. All subsequent reads check how many bytes they read. */ flags = fcntl(newsock, F_GETFL, 0); flags |= O_NDELAY; (void) fcntl(newsock, F_SETFL, flags); /* * Make sure the name contains only printable characters * since we use control characters for cursor control * between driver and player processes */ for (cp1 = cp2 = name; *cp1 != '\0'; cp1++) if (isprint((unsigned char)*cp1) || *cp1 == ' ') *cp2++ = *cp1; *cp2 = '\0'; # ifdef INTERNET if (mode == C_MESSAGE) { char buf[BUFSIZ + 1]; int n; if (team == ' ') (void) sprintf(buf, "%s: ", name); else (void) sprintf(buf, "%s[%c]: ", name, team); n = strlen(buf); for (pp = Player; pp < End_player; pp++) { cgoto(pp, HEIGHT, 0); outstr(pp, buf, n); } while ((n = read(newsock, buf, BUFSIZ)) > 0) for (pp = Player; pp < End_player; pp++) outstr(pp, buf, n); for (pp = Player; pp < End_player; pp++) { ce(pp); sendcom(pp, REFRESH); sendcom(pp, READY, 0); (void) fflush(pp->p_output); } (void) close(newsock); return FALSE; } else # endif # ifdef MONITOR if (mode == C_MONITOR) if (End_monitor < &Monitor[MAXMON]) { pp = End_monitor++; i = pp - Monitor + MAXPL + 3; } else { socklen = 0; (void) write(newsock, (char *) &socklen, sizeof socklen); (void) close(newsock); return FALSE; } else # endif if (End_player < &Player[MAXPL]) { pp = End_player++; i = pp - Player + 3; } else { socklen = 0; (void) write(newsock, (char *) &socklen, sizeof socklen); (void) close(newsock); return FALSE; } #ifdef MONITOR if (mode == C_MONITOR && team == ' ') team = '*'; #endif pp->p_ident = get_ident(machine, uid, name, team); pp->p_output = fdopen(newsock, "w"); pp->p_death[0] = '\0'; pp->p_fd = newsock; fdset[i].fd = newsock; fdset[i].events = POLLIN; pp->p_y = 0; pp->p_x = 0; # ifdef MONITOR if (mode == C_MONITOR) stmonitor(pp); else # endif stplayer(pp, enter_status); return TRUE; }
/* * moveshots: * Move the shots already in the air, taking explosions into account */ void moveshots(void) { BULLET *bp, *next; PLAYER *pp; int x, y; BULLET *blist; rollexpl(); if (Bullets == NULL) goto no_bullets; /* * First we move through the bullet list conf_bulspd times, looking * for things we may have run into. If we do run into * something, we set up the explosion and disappear, checking * for damage to any player who got in the way. */ /* Move the list to a working list */ blist = Bullets; Bullets = NULL; /* Work with bullets on the working list (blist) */ for (bp = blist; bp != NULL; bp = next) { next = bp->b_next; x = bp->b_x; y = bp->b_y; /* Un-draw the bullet on all screens: */ Maze[y][x] = bp->b_over; check(ALL_PLAYERS, y, x); /* Decide how to move the bullet: */ switch (bp->b_type) { /* Normal, atomic bullets: */ case SHOT: case GRENADE: case SATCHEL: case BOMB: if (move_normal_shot(bp)) { /* Still there: put back on the active list */ bp->b_next = Bullets; Bullets = bp; } break; /* Slime bullets that explode into slime on impact: */ case SLIME: if (bp->b_expl || move_normal_shot(bp)) { /* Still there: put back on the active list */ bp->b_next = Bullets; Bullets = bp; } break; /* Drones that wander about: */ case DSHOT: if (move_drone(bp)) { /* Still there: put back on the active list */ bp->b_next = Bullets; Bullets = bp; } break; /* Other/unknown: */ default: /* Place it back on the active list: */ bp->b_next = Bullets; Bullets = bp; break; } } /* Again, hang the Bullets list off `blist' and work with that: */ blist = Bullets; Bullets = NULL; for (bp = blist; bp != NULL; bp = next) { next = bp->b_next; /* Is the bullet exploding? */ if (!bp->b_expl) { /* * Its still flying through the air. * Put it back on the bullet list. */ save_bullet(bp); /* All the monitors can see the bullet: */ for (pp = Monitor; pp < End_monitor; pp++) check(pp, bp->b_y, bp->b_x); /* All the scanning players can see the drone: */ if (bp->b_type == DSHOT) for (pp = Player; pp < End_player; pp++) if (pp->p_scan >= 0) check(pp, bp->b_y, bp->b_x); } else { /* It is exploding. Check what we hit: */ chkshot(bp, next); /* Release storage for the destroyed bullet: */ free(bp); } } /* Re-draw all the players: (in case a bullet wiped them out) */ for (pp = Player; pp < End_player; pp++) Maze[pp->p_y][pp->p_x] = pp->p_face; no_bullets: /* Move flying boots through the air: */ for (pp = Boot; pp < &Boot[NBOOTS]; pp++) if (pp->p_flying >= 0) move_flyer(pp); /* Move flying players through the air: */ for (pp = Player; pp < End_player; pp++) { if (pp->p_flying >= 0) move_flyer(pp); /* Flush out the explosions: */ sendcom(pp, REFRESH); look(pp); } /* Flush out and synchronise all the displays: */ sendcom(ALL_PLAYERS, REFRESH); }
/* * move_player: * Try to move player 'pp' in direction 'dir'. */ static void move_player(PLAYER *pp, int dir) { PLAYER *newp; int x, y; FLAG moved; BULLET *bp; y = pp->p_y; x = pp->p_x; switch (dir) { case LEFTS: x--; break; case RIGHT: x++; break; case ABOVE: y--; break; case BELOW: y++; break; } moved = FALSE; /* What would the player move over: */ switch (Maze[y][x]) { /* Players can move through spaces and doors, no problem: */ case SPACE: case DOOR: moved = TRUE; break; /* Can't move through walls: */ case WALL1: case WALL2: case WALL3: case WALL4: case WALL5: break; /* Moving over a mine - try to pick it up: */ case MINE: case GMINE: if (dir == pp->p_face) /* facing it: 2% chance of trip */ pickup(pp, y, x, conf_ptrip_face, Maze[y][x]); else if (opposite(dir, pp->p_face)) /* facing away: 95% chance of trip */ pickup(pp, y, x, conf_ptrip_back, Maze[y][x]); else /* facing sideways: 50% chance of trip */ pickup(pp, y, x, conf_ptrip_side, Maze[y][x]); /* Remove the mine: */ Maze[y][x] = SPACE; moved = TRUE; break; /* Moving into a bullet: */ case SHOT: case GRENADE: case SATCHEL: case BOMB: case SLIME: case DSHOT: /* Find which bullet: */ bp = is_bullet(y, x); if (bp != NULL) /* Detonate it: */ bp->b_expl = TRUE; /* Remove it: */ Maze[y][x] = SPACE; moved = TRUE; break; /* Moving into another player: */ case LEFTS: case RIGHT: case ABOVE: case BELOW: if (dir != pp->p_face) /* Can't walk backwards/sideways into another player: */ sendcom(pp, BELL); else { /* Stab the other player */ newp = play_at(y, x); checkdam(newp, pp, pp->p_ident, conf_stabdam, KNIFE); } break; /* Moving into a player flying overhead: */ case FLYER: newp = play_at(y, x); message(newp, "Oooh, there's a short guy waving at you!"); message(pp, "You couldn't quite reach him!"); break; /* Picking up a boot, or two: */ case BOOT_PAIR: pp->p_nboots++; case BOOT: pp->p_nboots++; for (newp = Boot; newp < &Boot[NBOOTS]; newp++) { if (newp->p_flying < 0) continue; if (newp->p_y == y && newp->p_x == x) { newp->p_flying = -1; if (newp->p_undershot) fixshots(y, x, newp->p_over); } } if (pp->p_nboots == 2) message(pp, "Wow! A pair of boots!"); else message(pp, "You can hobble around on one boot."); Maze[y][x] = SPACE; moved = TRUE; break; } /* Can the player be moved? */ if (moved) { /* Check the gun status: */ if (pp->p_ncshot > 0) if (--pp->p_ncshot == conf_maxncshot) outyx(pp, STAT_GUN_ROW, STAT_VALUE_COL, " ok"); /* Check for bullets flying past: */ if (pp->p_undershot) { fixshots(pp->p_y, pp->p_x, pp->p_over); pp->p_undershot = FALSE; } /* Erase the player: */ drawplayer(pp, FALSE); /* Save under: */ pp->p_over = Maze[y][x]; /* Move the player: */ pp->p_y = y; pp->p_x = x; /* Draw the player in their new position */ drawplayer(pp, TRUE); } }