bitsy-parser/src/game.rs

183 lines
5.9 KiB
Rust
Raw Normal View History

2020-04-12 13:38:07 +00:00
use crate::{Avatar, Dialogue, Ending, Item, Palette, Room, Sprite, Tile, Variable, mock};
#[derive(Debug, PartialEq)]
pub struct Game {
pub(crate) name: String,
pub(crate) version: f64,
pub(crate) room_format: u8,
pub(crate) palettes: Vec<Palette>,
pub(crate) rooms: Vec<Room>,
pub(crate) tiles: Vec<Tile>,
pub(crate) avatar: Avatar,
pub(crate) sprites: Vec<Sprite>,
pub(crate) items: Vec<Item>,
pub(crate) dialogues: Vec<Dialogue>,
pub(crate) endings: Vec<Ending>,
pub(crate) variables: Vec<Variable>,
}
impl From<String> for Game {
fn from(string: String) -> Game {
// dialogues and endings can have 2+ line breaks inside, so deal with these separately
// otherwise, everything can be split on a double line break (\n\n)
let mut dialogues: Vec<Dialogue> = Vec::new();
let mut endings: Vec<Ending> = Vec::new();
let mut variables: Vec<Variable> = Vec::new();
let main_split: Vec<&str> = string.split("\n\nDLG").collect();
let main = main_split[0].to_string();
let mut dialogues_endings_variables: String = main_split[1..].join("\n\nDLG");
let variable_segments = dialogues_endings_variables.clone();
let variable_segments: Vec<&str> = variable_segments.split("\n\nVAR").collect();
if variable_segments.len() > 0 {
dialogues_endings_variables = variable_segments[0].to_string();
let variable_segments = variable_segments[1..].to_owned();
for segment in variable_segments {
let segment = format!("VAR{}", segment);
variables.push(Variable::from(segment));
}
}
let ending_segments = dialogues_endings_variables.clone();
let ending_segments: Vec<&str> = ending_segments.split("\n\nEND").collect();
if ending_segments.len() > 0 {
dialogues_endings_variables = ending_segments[0].to_string();
let ending_segments = ending_segments[1..].to_owned();
for segment in ending_segments {
let segment = format!("END{}", segment);
endings.push(Ending::from(segment));
}
}
let dialogue_segments = format!("\n\nDLG {}", dialogues_endings_variables.trim());
let dialogue_segments: Vec<&str> = dialogue_segments.split("\n\nDLG").collect();
for segment in dialogue_segments[1..].to_owned() {
let segment = format!("DLG{}", segment);
dialogues.push(Dialogue::from(segment));
}
let segments: Vec<&str> = main.split("\n\n").collect();
let name = segments[0].to_string();
let mut version: f64 = 1.0;
let mut room_format: u8 = 1;
let mut palettes: Vec<Palette> = Vec::new();
let mut rooms: Vec<Room> = Vec::new();
let mut tiles: Vec<Tile> = Vec::new();
let mut avatar: Option<Avatar> = None; // unwrap this later
let mut sprites: Vec<Sprite> = Vec::new();
let mut items: Vec<Item> = Vec::new();
for segment in segments[1..].to_owned() {
let segment = segment.to_string();
if segment.starts_with("# BITSY VERSION") {
version = segment.replace("# BITSY VERSION ", "").parse().unwrap();
} else if segment.starts_with("! ROOM_FORMAT") {
room_format = segment.replace("! ROOM_FORMAT ", "").parse().unwrap();
} else if segment.starts_with("PAL") {
palettes.push(Palette::from(segment));
} else if segment.starts_with("ROOM") {
rooms.push(Room::from(segment));
} else if segment.starts_with("TIL") {
tiles.push(Tile::from(segment));
} else if segment.starts_with("SPR A") {
avatar = Some(Avatar::from(segment));
} else if segment.starts_with("SPR") {
sprites.push(Sprite::from(segment));
} else if segment.starts_with("ITM") {
items.push(Item::from(segment));
}
}
assert!(avatar.is_some());
let avatar = avatar.unwrap();
Game {
name,
version,
room_format,
palettes,
rooms,
tiles,
avatar,
sprites,
items,
dialogues,
endings,
variables,
}
}
}
impl ToString for Game {
#[inline]
fn to_string(&self) -> String {
let mut segments: Vec<String> = Vec::new();
// todo refactor
for palette in &self.palettes {
segments.push(palette.to_string());
}
for room in &self.rooms {
segments.push(room.to_string());
}
for tile in &self.tiles {
segments.push(tile.to_string());
}
segments.push(self.avatar.to_string());
for sprite in &self.sprites {
segments.push(sprite.to_string());
}
for item in &self.items {
segments.push(item.to_string());
}
for dialogue in &self.dialogues {
segments.push(dialogue.to_string());
}
for ending in &self.endings {
segments.push(ending.to_string());
}
for variable in &self.variables {
segments.push(variable.to_string());
}
format!(
"{}\n\n# BITSY VERSION {}\n\n! ROOM_FORMAT {}\n\n{}\n\n",
&self.name,
&self.version,
&self.room_format,
segments.join("\n\n"),
)
}
}
#[test]
fn test_game_from_string() {
let output = Game::from(
include_str!["../test/resources/default.bitsy"].to_string()
);
let expected = mock::game_default();
assert_eq!(output, expected);
}
#[test]
fn test_game_to_string() {
let output = mock::game_default().to_string();
let expected = include_str!["../test/resources/default.bitsy"].to_string();
assert_eq!(output, expected);
}