use crate::{Exit, ExitInstance, Instance, mock, Position, from_base36, ToBase36}; #[derive(Debug, Eq, PartialEq)] pub struct Room { pub id: u64, pub palette_id: u64, // id pub name: Option, pub tiles: Vec, // tile ids pub items: Vec, pub exits: Vec, pub endings: Vec, } impl From for Room { fn from(string: String) -> Room { // todo handle room_format? let mut lines: Vec<&str> = string.lines().collect(); let id = from_base36(&lines[0].replace("ROOM ", "")); let mut name = None; let mut palette_id = 0; let mut items: Vec = Vec::new(); let mut exits: Vec = Vec::new(); let mut endings: Vec = Vec::new(); loop { let last_line = lines.pop().unwrap(); if last_line.starts_with("NAME") { name = Some(last_line.replace("NAME ", "").to_string()); } else if last_line.starts_with("PAL") { palette_id = from_base36(&last_line.replace("PAL ", "")); } else if last_line.starts_with("ITM") { let last_line = last_line.replace("ITM ", ""); let item_position: Vec<&str> = last_line.split(' ').collect(); let item_id = item_position[0]; let position = item_position[1]; let position = Position::from(position.to_string()); items.push(Instance { position, id: item_id.to_string() }); } else if last_line.starts_with("EXT") { let last_line = last_line.replace("EXT ", ""); let parts: Vec<&str> = last_line.split(' ').collect(); let position = Position::from(parts[0].to_string()); let exit = Exit::from(format!("{} {}", parts[1], parts[2])); exits.push(ExitInstance { position, exit }); } else if last_line.starts_with("END") { let last_line = last_line.replace("END ", ""); let ending_position: Vec<&str> = last_line.split(' ').collect(); let ending = ending_position[0].to_string(); let position = ending_position[1].to_string(); let position = Position::from(position); endings.push(Instance { position, id: ending }); } else { lines.push(last_line); break; } } let lines = &lines[1..]; let mut tiles: Vec = Vec::new(); for line in lines.into_iter() { let line: Vec<&str> = line.split(",").collect(); for tile_id in line { tiles.push(tile_id.to_string()); } } Room { id, palette_id, name, tiles, items, exits, endings } } } #[test] fn test_room_from_string() { assert_eq!( Room::from(include_str!("../test/resources/room").to_string()), mock::room() ); } impl ToString for Room { fn to_string(&self) -> String { let mut tiles = String::new(); let mut items = String::new(); let mut exits = String::new(); let mut endings = String::new(); let sqrt = (self.tiles.len() as f64).sqrt() as usize; // 8 for SD, 16 for HD for line in self.tiles.chunks(sqrt) { for tile in line { tiles.push_str(&format!("{},", tile)); } tiles.pop(); // remove trailing comma tiles.push_str("\n"); } tiles.pop(); // remove trailing newline for instance in &self.items { items.push_str( &format!("\nITM {} {}", instance.id, instance.position.to_string()) ); } for instance in &self.exits { exits.push_str( &format!( "\nEXT {} {}", instance.position.to_string(), instance.exit.to_string(), ) ); } for instance in &self.endings { endings.push_str( &format!("\nEND {} {}", instance.id, instance.position.to_string()) ); } format!( "ROOM {}\n{}{}{}{}{}\nPAL {}", self.id.to_base36(), tiles, if self.name.as_ref().is_some() { format!("\nNAME {}", self.name.as_ref().unwrap()) } else { "".to_string() }, items, exits, endings, self.palette_id.to_base36() ) } } #[test] fn test_room_to_string() { assert_eq!(mock::room().to_string(), include_str!("../test/resources/room").to_string()); }