use crate::{Exit, ExitInstance, Instance, mock, Position}; #[derive(Debug, Eq, PartialEq)] pub struct Room { pub(crate) id: String, pub(crate) palette: String, // id pub(crate) name: Option, pub(crate) tiles: Vec, // tile ids pub(crate) items: Vec, pub(crate) exits: Vec, pub(crate) 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 = lines[0].replace("ROOM ", ""); let mut name = None; let mut palette = "0".to_string(); 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 = last_line.replace("PAL ", "").to_string(); } 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, 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, tiles, if self.name.as_ref().is_some() { format!("\nNAME {}", self.name.as_ref().unwrap()) } else { "".to_string() }, items, exits, endings, self.palette ) } } #[test] fn test_room_to_string() { assert_eq!(mock::room().to_string(), include_str!("../test/resources/room").to_string()); }