use crate::constants::MAX_ARROW_FLIGHT;
use crate::map::{Room, WumpusMap};
use crate::play::game::ExitStatus;
use crate::play::game::ExitStatus::NormalExit;
use crate::play::magic::{is_magic_tunnel_for_some_reason, select_random_room};
use crate::play::messages::{kill_wump, no_arrows, shoot_self, wump_kill};
use crate::play::movement::move_wump;
use crate::play::Things;
use crate::{dprint, Args};
use rand::prelude::ThreadRng;
use rand::Rng;
fn follow_arrow_flight<'a>(
rooms: &[usize],
things: &mut Things,
wumpus_map: &'a WumpusMap,
rng: &mut ThreadRng,
) -> anyhow::Result<&'a Room> {
let player_room = wumpus_map.get_room(&things.player);
let mut current_room = player_room;
for (room_count, arrow_room) in rooms
.iter()
.map(|&r| wumpus_map.get_room_from_room_number(r))
.enumerate()
{
let arrow_next_room = arrow_room?;
let arrow_can_advance = current_room.connects_to(arrow_next_room, wumpus_map)?;
dprint!(
"Following arrow flight: count {}, room {}, can advance {}",
room_count,
arrow_next_room.number,
arrow_can_advance
);
if room_count > MAX_ARROW_FLIGHT as usize {
println!("The arrow wavers in its flight and and can go no further!");
return Ok(current_room);
}
if arrow_can_advance {
if is_magic_tunnel_for_some_reason(arrow_next_room, wumpus_map)? {
print!("A faint gleam tells you the arrow has gone through a magic tunnel!\n");
current_room = select_random_room(wumpus_map, rng)?;
} else {
current_room = arrow_next_room;
}
} else {
dprint!("Arrow randomized\n");
let neighbors = current_room.get_vertex(wumpus_map)?.neighbors();
let links = neighbors.len();
let next_vertex = neighbors[rng.gen_range(0..links)];
let random_next_room = wumpus_map.get_room(&next_vertex);
if next_vertex == player_room.key {
println!(
"*thunk* The arrow can't find a way from {} to {} and files back into",
current_room.number, arrow_next_room.number
);
println!("your room!")
}
else if is_magic_tunnel_for_some_reason(arrow_next_room, wumpus_map)? {
print!(
"*thunk* The arrow files randomly into a magic tunnel, thence into\n\
room {}!\n",
arrow_next_room.number
);
} else {
println!(
"*thunk* The arrow can't find a way from {} to {} and files randomly",
current_room.number, arrow_next_room.number
);
println!("into room {}!", random_next_room.number);
}
current_room = random_next_room;
return Ok(current_room);
}
let likelihood_of_proper_archery = rng.gen_range(0..10);
if room_count == 3 && likelihood_of_proper_archery < 2 {
print!("Your bowstring breaks! *twaaaaaang*\n");
print!("The arrow is weakly shot and can go no further!\n");
return Ok(current_room);
} else if room_count == 4 && likelihood_of_proper_archery < 6 {
print!("The arrow wavers in its flight and and can go no further!\n");
return Ok(current_room);
}
}
Ok(current_room)
}
#[allow(unused_variables)]
pub fn shoot_arrow(
rooms: Vec<usize>,
things: &mut Things,
arrows: &mut u32,
wumpus_map: &WumpusMap,
rng: &mut ThreadRng,
config: &Args,
) -> anyhow::Result<ExitStatus> {
let room_total_count = rooms.len();
if room_total_count == 0 {
println!("The arrow falls to the ground at your feet!");
return Ok(ExitStatus::Continue);
}
let arrow_landed_room = follow_arrow_flight(&rooms, things, wumpus_map, rng)?;
dprint!("Arrow landed in room {}.", arrow_landed_room.number);
*arrows -= 1;
if things.get_wumpus_location() == arrow_landed_room.key {
kill_wump();
Ok(ExitStatus::NormalExit)
} else if things.player == arrow_landed_room.key {
shoot_self();
Ok(ExitStatus::NormalExit)
} else if *arrows == 0 {
no_arrows();
Ok(ExitStatus::NormalExit)
} else {
let safety_tolerance = if config.hard { 9 } else { 12 };
things.wumpus_movement_likelihood += 2;
if rng.gen_range(0..safety_tolerance) < things.wumpus_movement_likelihood {
move_wump(things, wumpus_map, rng)?;
if things.player_wumpus_collision() {
wump_kill();
return Ok(NormalExit);
}
things.wumpus_movement_likelihood = rng.gen_range(0..3);
}
Ok(ExitStatus::Continue)
}
}