/* * move_flyer: * Update the position of a player in flight */ static void move_flyer(PLAYER *pp) { int x, y; if (pp->p_undershot) { fixshots(pp->p_y, pp->p_x, pp->p_over); pp->p_undershot = FALSE; } /* Restore what the flier was flying over */ Maze[pp->p_y][pp->p_x] = pp->p_over; /* Fly: */ x = pp->p_x + pp->p_flyx; y = pp->p_y + pp->p_flyy; /* Bouncing off the edges of the maze: */ if (x < 1) { x = 1 - x; pp->p_flyx = -pp->p_flyx; } else if (x > WIDTH - 2) { x = (WIDTH - 2) - (x - (WIDTH - 2)); pp->p_flyx = -pp->p_flyx; } if (y < 1) { y = 1 - y; pp->p_flyy = -pp->p_flyy; } else if (y > HEIGHT - 2) { y = (HEIGHT - 2) - (y - (HEIGHT - 2)); pp->p_flyy = -pp->p_flyy; } /* Make sure we don't land on something we can't: */ again: switch (Maze[y][x]) { default: /* * Flier is over something other than space, a wall * or a door. Randomly move (drift) the flier a little bit * and then try again: */ switch (rand_num(4)) { case 0: PLUS_DELTA(x, WIDTH - 2); break; case 1: MINUS_DELTA(x, 1); break; case 2: PLUS_DELTA(y, HEIGHT - 2); break; case 3: MINUS_DELTA(y, 1); break; } goto again; /* Give a little boost when about to land on a wall or door: */ case WALL1: case WALL2: case WALL3: case WALL4: case WALL5: case DOOR: if (pp->p_flying == 0) pp->p_flying++; break; /* Spaces are okay: */ case SPACE: break; } /* Update flier's coordinates: */ pp->p_y = y; pp->p_x = x; /* Consume 'flying' time: */ if (pp->p_flying-- == 0) { /* Land: */ if (pp->p_face != BOOT && pp->p_face != BOOT_PAIR) { /* Land a player - they stustain a fall: */ checkdam(pp, NULL, NULL, rand_num(pp->p_damage / conf_fall_frac), FALL); pp->p_face = rand_dir(); showstat(pp); } else { /* Land boots: */ if (Maze[y][x] == BOOT) pp->p_face = BOOT_PAIR; Maze[y][x] = SPACE; } } /* Save under the flier: */ pp->p_over = Maze[y][x]; /* Draw in the flier: */ Maze[y][x] = pp->p_face; showexpl(y, x, pp->p_face); }
/* * Constructs a tunnel between two points * * This function must be called BEFORE any streamers are created, * since we use the special "granite wall" sub-types to keep track * of legal places for corridors to pierce rooms. * * We use "door_flag" to prevent excessive construction of doors * along overlapping corridors. * * We queue the tunnel grids to prevent door creation along a corridor * which intersects itself. * * We queue the wall piercing grids to prevent a corridor from leaving * a room and then coming back in through the same entrance. * * We "pierce" grids which are "outer" walls of rooms, and when we * do so, we change all adjacent "outer" walls of rooms into "solid" * walls so that no two corridors may use adjacent grids for exits. * * The "solid" wall check prevents corridors from "chopping" the * corners of rooms off, as well as "silly" door placement, and * "excessively wide" room entrances. * * Kind of walls: * extra -- walls * inner -- inner room walls * outer -- outer room walls * solid -- solid room walls */ bool build_tunnel(int row1, int col1, int row2, int col2) { int y, x; int tmp_row, tmp_col; int row_dir, col_dir; int start_row, start_col; int main_loop_count = 0; bool door_flag = FALSE; cave_type *c_ptr; /* Save the starting location */ start_row = row1; start_col = col1; /* Start out in the correct direction */ correct_dir(&row_dir, &col_dir, row1, col1, row2, col2); /* Keep going until done (or bored) */ while ((row1 != row2) || (col1 != col2)) { /* Mega-Hack -- Paranoia -- prevent infinite loops */ if (main_loop_count++ > 2000) return FALSE; /* Allow bends in the tunnel */ if (randint0(100) < dun_tun_chg) { /* Acquire the correct direction */ correct_dir(&row_dir, &col_dir, row1, col1, row2, col2); /* Random direction */ if (randint0(100) < dun_tun_rnd) { rand_dir(&row_dir, &col_dir); } } /* Get the next location */ tmp_row = row1 + row_dir; tmp_col = col1 + col_dir; /* Extremely Important -- do not leave the dungeon */ while (!in_bounds(tmp_row, tmp_col)) { /* Acquire the correct direction */ correct_dir(&row_dir, &col_dir, row1, col1, row2, col2); /* Random direction */ if (randint0(100) < dun_tun_rnd) { rand_dir(&row_dir, &col_dir); } /* Get the next location */ tmp_row = row1 + row_dir; tmp_col = col1 + col_dir; } /* Access the location */ c_ptr = &cave[tmp_row][tmp_col]; /* Avoid "solid" walls */ if (is_solid_grid(c_ptr)) continue; /* Pierce "outer" walls of rooms */ if (is_outer_grid(c_ptr)) { /* Acquire the "next" location */ y = tmp_row + row_dir; x = tmp_col + col_dir; /* Hack -- Avoid outer/solid walls */ if (is_outer_bold(y, x)) continue; if (is_solid_bold(y, x)) continue; /* Accept this location */ row1 = tmp_row; col1 = tmp_col; /* Save the wall location */ if (dun->wall_n < WALL_MAX) { dun->wall[dun->wall_n].y = row1; dun->wall[dun->wall_n].x = col1; dun->wall_n++; } else return FALSE; /* Forbid re-entry near this piercing */ for (y = row1 - 1; y <= row1 + 1; y++) { for (x = col1 - 1; x <= col1 + 1; x++) { /* Convert adjacent "outer" walls as "solid" walls */ if (is_outer_bold(y, x)) { /* Change the wall to a "solid" wall */ place_solid_noperm_bold(y, x); } } } } /* Travel quickly through rooms */ else if (c_ptr->info & (CAVE_ROOM)) { /* Accept the location */ row1 = tmp_row; col1 = tmp_col; } /* Tunnel through all other walls */ else if (is_extra_grid(c_ptr) || is_inner_grid(c_ptr) || is_solid_grid(c_ptr)) { /* Accept this location */ row1 = tmp_row; col1 = tmp_col; /* Save the tunnel location */ if (dun->tunn_n < TUNN_MAX) { dun->tunn[dun->tunn_n].y = row1; dun->tunn[dun->tunn_n].x = col1; dun->tunn_n++; } else return FALSE; /* Allow door in next grid */ door_flag = FALSE; } /* Handle corridor intersections or overlaps */ else { /* Accept the location */ row1 = tmp_row; col1 = tmp_col; /* Collect legal door locations */ if (!door_flag) { /* Save the door location */ if (dun->door_n < DOOR_MAX) { dun->door[dun->door_n].y = row1; dun->door[dun->door_n].x = col1; dun->door_n++; } else return FALSE; /* No door in next grid */ door_flag = TRUE; } /* Hack -- allow pre-emptive tunnel termination */ if (randint0(100) >= dun_tun_con) { /* Distance between row1 and start_row */ tmp_row = row1 - start_row; if (tmp_row < 0) tmp_row = (-tmp_row); /* Distance between col1 and start_col */ tmp_col = col1 - start_col; if (tmp_col < 0) tmp_col = (-tmp_col); /* Terminate the tunnel */ if ((tmp_row > 10) || (tmp_col > 10)) break; } } } return TRUE; }
/* * 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++; } }
/** * 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); }