diff --git a/menu_background.png b/menu_background.png new file mode 100644 index 0000000..3690898 Binary files /dev/null and b/menu_background.png differ diff --git a/src/main.rs b/src/main.rs index 9b3fb41..094cd4f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -697,7 +697,11 @@ fn menu>(header: &str, options: &[T], width: i32, root: &mut Root) ); // Calculate total height for the header (after auto-wrap) and one line per option - let header_height = root.get_height_rect(0, 0, width, SCREEN_HEIGHT, header); + let header_height = if header.is_empty() { + 0 + } else { + root.get_height_rect(0, 0, width, SCREEN_HEIGHT, header) + }; let height = options.len() as i32 + header_height; // Create an off-screen console that represents the menu's window @@ -1191,25 +1195,21 @@ fn render_all(tcod: &mut Tcod, game: &mut Game, objects: &[Object], fov_recomput ); } -fn main() { - tcod::system::set_fps(FPS); - - let root = Root::initializer() - .font("arial10x10.png", FontLayout::Tcod) - .font_type(FontType::Greyscale) - .size(SCREEN_WIDTH, SCREEN_HEIGHT) - .title("Rust/libtcod tutorial") - .init(); - - let mut tcod = Tcod { - root, - con: Offscreen::new(MAP_WIDTH, MAP_HEIGHT), - panel: Offscreen::new(SCREEN_WIDTH, PANEL_HEIGHT), - fov: FovMap::new(MAP_WIDTH, MAP_HEIGHT), - key: Default::default(), - mouse: Default::default(), - }; +fn initialise_fov(tcod: &mut Tcod, map: &Map) { + // Populate FOV map, according to generated map + for y in 0..MAP_HEIGHT { + for x in 0..MAP_WIDTH { + tcod.fov.set( + x, + y, + !map[x as usize][y as usize].block_sight, + !map[x as usize][y as usize].blocked, + ) + } + } +} +fn new_game(tcod: &mut Tcod) -> (Game, Vec) { // Create player object let mut player = Object::new(0, 0, '@', "player", WHITE, true); player.alive = true; @@ -1231,19 +1231,7 @@ fn main() { inventory: vec![], }; - // Populate FOV map, according to generated map - for y in 0..MAP_HEIGHT { - for x in 0..MAP_WIDTH { - tcod.fov.set( - x, - y, - !game.map[x as usize][y as usize].block_sight, - !game.map[x as usize][y as usize].blocked, - ) - } - } - - let mut previous_player_position = (-1, -1); + initialise_fov(tcod, &game.map); // A warm welcoming message! game.messages.add( @@ -1251,21 +1239,33 @@ fn main() { RED, ); + (game, objects) +} + +fn play_game(tcod: &mut Tcod, game: &mut Game, objects: &mut Vec) { + // force FOV "recompute" first time through the game loop + let mut previous_player_position = (-1, -1); + // Main game loop while !tcod.root.window_closed() { + // clear the screen of the previous frame + tcod.con.clear(); + match input::check_for_event(input::MOUSE | input::KEY_PRESS) { Some((_, Event::Mouse(m))) => tcod.mouse = m, Some((_, Event::Key(k))) => tcod.key = k, _ => tcod.key = Default::default(), } - tcod.con.clear(); + // Render the screen let fov_recompute = previous_player_position != (objects[PLAYER].pos()); - render_all(&mut tcod, &mut game, &objects, fov_recompute); + render_all(tcod, game, &objects, fov_recompute); + tcod.root.flush(); + // Handle keys and exit game if needed previous_player_position = objects[PLAYER].pos(); - let player_action = handle_keys(&mut tcod, &mut game, &mut objects); + let player_action = handle_keys(tcod, game, objects); if player_action == PlayerAction::Exit { break; } @@ -1274,9 +1274,75 @@ fn main() { if objects[PLAYER].alive && player_action != PlayerAction::DidntTakeTurn { for id in 0..objects.len() { if objects[id].ai.is_some() { - ai_take_turn(id, &tcod, &mut game, &mut objects); + ai_take_turn(id, tcod, game, objects); } } } } } + +fn main_menu(tcod: &mut Tcod) { + let img = tcod::image::Image::from_file("menu_background.png") + .ok() + .expect("Background image not found"); + + while !tcod.root.window_closed() { + // Show the background image, at twice the regular console resolution + tcod::image::blit_2x(&img, (0, 0), (-1, -1), &mut tcod.root, (0, 0)); + + tcod.root.set_default_foreground(LIGHT_YELLOW); + tcod.root.print_ex( + SCREEN_WIDTH / 2, + SCREEN_HEIGHT / 2 - 4, + BackgroundFlag::None, + TextAlignment::Center, + "TOMB OF DOOM", + ); + tcod.root.print_ex( + SCREEN_WIDTH / 2, + SCREEN_HEIGHT - 2, + BackgroundFlag::None, + TextAlignment::Center, + "By m", + ); + + // Show options and wait for the player's choice + let choices = &["Play a new game", "Continue last game", "Quit"]; + let choice = menu("", choices, 24, &mut tcod.root); + + match choice { + Some(0) => { + // New game + let (mut game, mut objects) = new_game(tcod); + play_game(tcod, &mut game, &mut objects); + } + Some(2) => { + // Quit + break; + } + _ => {} + } + } +} + +fn main() { + tcod::system::set_fps(FPS); + + let root = Root::initializer() + .font("arial10x10.png", FontLayout::Tcod) + .font_type(FontType::Greyscale) + .size(SCREEN_WIDTH, SCREEN_HEIGHT) + .title("Rust/libtcod tutorial") + .init(); + + let mut tcod = Tcod { + root, + con: Offscreen::new(MAP_WIDTH, MAP_HEIGHT), + panel: Offscreen::new(SCREEN_WIDTH, PANEL_HEIGHT), + fov: FovMap::new(MAP_WIDTH, MAP_HEIGHT), + key: Default::default(), + mouse: Default::default(), + }; + + main_menu(&mut tcod); +}