diff --git a/src/lib.rs b/src/lib.rs index 68daec0..7115514 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ pub mod image; pub mod item; pub mod mock; pub mod position; +pub mod room; pub mod sprite; pub mod tile; pub mod variable; @@ -21,6 +22,7 @@ use palette::Palette; use image::Image; use item::Item; use position::Position; +use room::Room; use sprite::Sprite; use tile::Tile; use variable::Variable; @@ -37,17 +39,6 @@ pub struct ExitInstance { exit: Exit, } -#[derive(Debug, Eq, PartialEq)] -pub struct Room { - id: String, - palette: String, // id - name: Option, - tiles: Vec, // tile ids - items: Vec, - exits: Vec, - endings: Vec, -} - #[derive(Debug, PartialEq)] pub struct Game { name: String, @@ -64,52 +55,6 @@ pub struct Game { variables: Vec, } -fn example_room() -> Room { - Room { - id: "a".to_string(), - palette: "9".to_string(), - name: Some("cellar 7".to_string()), - tiles: vec![ - "0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"1l".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(), - "y".to_string(),"x".to_string(),"0".to_string(),"0".to_string(),"1j".to_string(),"0".to_string(),"0".to_string(),"1j".to_string(),"1l".to_string(),"0".to_string(),"1j".to_string(),"0".to_string(),"0".to_string(),"1j".to_string(),"0".to_string(),"0".to_string(), - "y".to_string(),"y".to_string(),"x".to_string(),"k".to_string(),"k".to_string(),"1c".to_string(),"1x".to_string(),"1y".to_string(),"1m".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(), - "y".to_string(),"y".to_string(),"y".to_string(),"x".to_string(),"k".to_string(),"s".to_string(),"s".to_string(),"s".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"1g".to_string(),"1f".to_string(),"k".to_string(), - "k".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"1i".to_string(),"1u".to_string(),"1u".to_string(),"1u".to_string(),"1v".to_string(),"11".to_string(),"19".to_string(),"1b".to_string(),"1a".to_string(),"1e".to_string(),"10".to_string(),"k".to_string(), - "k".to_string(),"z".to_string(),"z".to_string(),"11".to_string(),"12".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"10".to_string(),"17".to_string(),"z".to_string(),"18".to_string(),"1e".to_string(),"12".to_string(),"k".to_string(), - "k".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"1k".to_string(),"14".to_string(),"15".to_string(),"16".to_string(),"1h".to_string(),"z".to_string(),"k".to_string(), - "k".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"10".to_string(),"1d".to_string(),"1v".to_string(),"1r".to_string(),"1s".to_string(),"1r".to_string(),"1q".to_string(),"1z".to_string(),"k".to_string(), - "k".to_string(),"z".to_string(),"z".to_string(),"12".to_string(),"10".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"1i".to_string(),"1n".to_string(),"1o".to_string(),"1o".to_string(),"1o".to_string(),"1p".to_string(),"z".to_string(),"k".to_string(), - "k".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"10".to_string(),"z".to_string(),"z".to_string(),"k".to_string(), - "k".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"11".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"k".to_string(), - "k".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"12".to_string(),"z".to_string(),"z".to_string(),"10".to_string(),"12".to_string(),"k".to_string(), - "k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(), - "0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(), - "0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(), - "0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string() - ], - items: vec![ - Instance {position: Position { x: 11, y: 5}, id: "d".to_string()}, - Instance {position: Position { x: 8, y: 3}, id: "e".to_string()}, - Instance {position: Position { x: 1, y: 0}, id: "5".to_string()}, - Instance {position: Position { x: 2, y: 1}, id: "6".to_string()}, - Instance {position: Position { x: 3, y: 2}, id: "6".to_string()}, - ], - exits: vec![ - ExitInstance { - position: Position { x: 3, y: 3}, - exit: Exit { room: "3".to_string(), position: Position { x: 10, y: 6}} - }, - ], - endings: vec![ - Instance{position: Position { x: 8, y: 7 }, id: "undefined".to_string()}, - ], - } -} - -fn example_room_string() -> String { - include_str!("../test/resources/room").to_string() -} - fn example_game_default() -> Game { Game { name: "Write your game's title here".to_string(), @@ -276,131 +221,6 @@ impl AnimationFrames for 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(example_room_string()), example_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!(example_room().to_string(), example_room_string()); -} - impl From for Game { fn from(string: String) -> Game { // dialogues and endings can have 2+ line breaks inside, so deal with these separately diff --git a/src/mock.rs b/src/mock.rs index 5364201..5839d4f 100644 --- a/src/mock.rs +++ b/src/mock.rs @@ -1,7 +1,7 @@ -use crate::{Avatar, Image, Item, Position, Sprite}; +use crate::{Avatar, Exit, Image, Item, Position, Room, Sprite, Instance, ExitInstance}; pub mod image { - use crate::image::Image; + use crate::Image; pub(crate) fn chequers_1() -> Image { Image { @@ -115,3 +115,45 @@ pub fn item() -> Item { dialogue: Some("ITM_2".to_string()) } } + +pub fn room() -> Room { + Room { + id: "a".to_string(), + palette: "9".to_string(), + name: Some("cellar 7".to_string()), + tiles: vec![ + "0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"1l".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(), + "y".to_string(),"x".to_string(),"0".to_string(),"0".to_string(),"1j".to_string(),"0".to_string(),"0".to_string(),"1j".to_string(),"1l".to_string(),"0".to_string(),"1j".to_string(),"0".to_string(),"0".to_string(),"1j".to_string(),"0".to_string(),"0".to_string(), + "y".to_string(),"y".to_string(),"x".to_string(),"k".to_string(),"k".to_string(),"1c".to_string(),"1x".to_string(),"1y".to_string(),"1m".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(), + "y".to_string(),"y".to_string(),"y".to_string(),"x".to_string(),"k".to_string(),"s".to_string(),"s".to_string(),"s".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"1g".to_string(),"1f".to_string(),"k".to_string(), + "k".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"1i".to_string(),"1u".to_string(),"1u".to_string(),"1u".to_string(),"1v".to_string(),"11".to_string(),"19".to_string(),"1b".to_string(),"1a".to_string(),"1e".to_string(),"10".to_string(),"k".to_string(), + "k".to_string(),"z".to_string(),"z".to_string(),"11".to_string(),"12".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"10".to_string(),"17".to_string(),"z".to_string(),"18".to_string(),"1e".to_string(),"12".to_string(),"k".to_string(), + "k".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"1k".to_string(),"14".to_string(),"15".to_string(),"16".to_string(),"1h".to_string(),"z".to_string(),"k".to_string(), + "k".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"10".to_string(),"1d".to_string(),"1v".to_string(),"1r".to_string(),"1s".to_string(),"1r".to_string(),"1q".to_string(),"1z".to_string(),"k".to_string(), + "k".to_string(),"z".to_string(),"z".to_string(),"12".to_string(),"10".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"1i".to_string(),"1n".to_string(),"1o".to_string(),"1o".to_string(),"1o".to_string(),"1p".to_string(),"z".to_string(),"k".to_string(), + "k".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"10".to_string(),"z".to_string(),"z".to_string(),"k".to_string(), + "k".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"11".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"k".to_string(), + "k".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"z".to_string(),"12".to_string(),"z".to_string(),"z".to_string(),"10".to_string(),"12".to_string(),"k".to_string(), + "k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(),"k".to_string(), + "0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(), + "0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(), + "0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string(),"0".to_string() + ], + items: vec![ + Instance {position: Position { x: 11, y: 5}, id: "d".to_string()}, + Instance {position: Position { x: 8, y: 3}, id: "e".to_string()}, + Instance {position: Position { x: 1, y: 0}, id: "5".to_string()}, + Instance {position: Position { x: 2, y: 1}, id: "6".to_string()}, + Instance {position: Position { x: 3, y: 2}, id: "6".to_string()}, + ], + exits: vec![ + ExitInstance { + position: Position { x: 3, y: 3}, + exit: Exit { room: "3".to_string(), position: Position { x: 10, y: 6}} + }, + ], + endings: vec![ + Instance{position: Position { x: 8, y: 7 }, id: "undefined".to_string()}, + ], + } +} diff --git a/src/room.rs b/src/room.rs new file mode 100644 index 0000000..041bc9d --- /dev/null +++ b/src/room.rs @@ -0,0 +1,140 @@ +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()); +}