use crate::archetype::Archetype; use crate::board::Board; use crate::floor::Floor; use crate::game::GameState; use crate::glyph::Glyph; use crate::utils::{Direction, PlayerPos, PortalDef}; use crate::world::World; use std::cell::RefCell; use std::collections::{BTreeMap, HashMap}; use std::rc::Rc; /// Builds a 3×3 board with the player at `(px, py)` and the given portals. fn make_board(px: i64, py: i64, portals: Vec) -> Board { Board { name: "test".into(), width: 3, height: 3, grid: vec![(Glyph::transparent(), Archetype::Empty); 9], floor: Floor::Blank, decorations: Vec::new(), player: PlayerPos { x: px, y: py }, objects: BTreeMap::new(), next_object_id: 1, portals, board_script_name: None, load_errors: Vec::new(), registry: HashMap::new(), } } /// Two-board world used by all tests in this module. /// /// - `"b1"`: player at `(0, 0)`, portal `"to_b2"` at `(2, 0)` → `"b2"` / `"from_b1"` /// - `"b2"`: player at `(0, 0)`, portal `"from_b1"` at `(1, 1)` → `"b1"` / `"to_b2"` fn two_board_world() -> World { let b1 = make_board( 0, 0, vec![PortalDef { name: "to_b2".into(), x: 2, y: 0, target_map: "b2".into(), target_entry: "from_b1".into(), }], ); let b2 = make_board( 0, 0, vec![PortalDef { name: "from_b1".into(), x: 1, y: 1, target_map: "b1".into(), target_entry: "to_b2".into(), }], ); World { name: "test".into(), start: "b1".into(), scripts: HashMap::new(), boards: HashMap::from([ ("b1".to_string(), Rc::new(RefCell::new(b1))), ("b2".to_string(), Rc::new(RefCell::new(b2))), ]), } } #[test] fn enter_board_switches_board() { let mut game = GameState::from_world(two_board_world()); game.enter_board("b2", "from_b1"); assert_eq!(game.current_board_name(), "b2"); } #[test] fn enter_board_places_player_at_arrival_portal() { let mut game = GameState::from_world(two_board_world()); game.enter_board("b2", "from_b1"); let board = game.board(); // Arrival portal "from_b1" is at (1, 1) on b2. assert_eq!(board.player.x, 1); assert_eq!(board.player.y, 1); } #[test] fn enter_board_sets_board_transition() { let mut game = GameState::from_world(two_board_world()); game.enter_board("b2", "from_b1"); assert_eq!(game.board_transition, Some(1.0)); } #[test] fn enter_board_unknown_board_logs_error() { let mut game = GameState::from_world(two_board_world()); game.enter_board("nope", "entry"); assert_eq!(game.current_board_name(), "b1", "board should not change"); assert!(!game.log.is_empty(), "an error should be logged"); } #[test] fn enter_board_unknown_entry_logs_error() { let mut game = GameState::from_world(two_board_world()); game.enter_board("b2", "nope"); assert_eq!(game.current_board_name(), "b1", "board should not change"); assert!(!game.log.is_empty(), "an error should be logged"); } #[test] fn try_move_onto_portal_switches_board() { let world = two_board_world(); // Start the player one cell west of the portal at (2, 0). world.boards["b1"].borrow_mut().player = PlayerPos { x: 1, y: 0 }; let mut game = GameState::from_world(world); game.try_move(Direction::East); assert_eq!(game.current_board_name(), "b2"); }