bitsy-parser/src/lib.rs

1355 lines
46 KiB
Rust
Raw Normal View History

2020-04-05 22:02:03 +00:00
#[derive(Debug, Eq, PartialEq)]
2020-04-05 17:58:04 +00:00
struct Colour {
red: u8,
green: u8,
blue: u8,
}
2020-04-05 22:02:03 +00:00
#[derive(Debug, Eq, PartialEq)]
2020-04-05 17:58:04 +00:00
struct Palette {
id: String, // base36 string (why??)
name: Option<String>,
colours: Vec<Colour>,
}
2020-04-05 22:02:03 +00:00
#[derive(Debug, Eq, PartialEq)]
2020-04-05 17:58:04 +00:00
struct Image {
2020-04-05 21:28:23 +00:00
pixels: Vec<u8>, // 64 for SD, 256 for HD
2020-04-05 17:58:04 +00:00
}
2020-04-05 22:02:03 +00:00
#[derive(Debug, Eq, PartialEq)]
2020-04-05 17:58:04 +00:00
struct Tile {
id: String, // base36 string
name: Option<String>,
wall: bool,
animation_frames: Vec<Image>,
}
2020-04-10 15:27:23 +00:00
#[derive(Debug, Eq, PartialEq)]
2020-04-05 19:46:55 +00:00
struct Position {
x: u8,
y: u8,
}
2020-04-10 15:27:23 +00:00
#[derive(Debug, Eq, PartialEq)]
struct Instance {
position: Position,
id: String, // item / ending id
}
#[derive(Debug, Eq, PartialEq)]
struct ExitInstance {
position: Position,
exit: Exit,
}
2020-04-05 22:02:03 +00:00
#[derive(Debug, Eq, PartialEq)]
2020-04-05 19:46:55 +00:00
struct Dialogue {
id: String,
contents: String,
}
2020-04-05 22:02:03 +00:00
#[derive(Debug, Eq, PartialEq)]
2020-04-05 19:46:55 +00:00
struct Sprite {
id: String, // lowercase base36
name: Option<String>,
animation_frames: Vec<Image>,
2020-04-05 22:58:10 +00:00
dialogue: Option<String>, /// dialogue id
room: String, /// room id
2020-04-05 19:46:55 +00:00
position: Position,
}
2020-04-06 07:54:43 +00:00
/// avatar is a "sprite" in the game data but with a specific id
2020-04-05 22:02:03 +00:00
#[derive(Debug, Eq, PartialEq)]
2020-04-05 19:46:55 +00:00
struct Avatar {
animation_frames: Vec<Image>,
room: String, /// room id
2020-04-05 19:46:55 +00:00
position: Position,
}
2020-04-05 22:02:03 +00:00
#[derive(Debug, Eq, PartialEq)]
2020-04-05 19:46:55 +00:00
struct Item {
id: String,
animation_frames: Vec<Image>,
name: Option<String>,
2020-04-06 07:54:43 +00:00
dialogue: Option<String>, // dialogue id
2020-04-05 19:46:55 +00:00
}
2020-04-05 22:02:03 +00:00
#[derive(Debug, Eq, PartialEq)]
2020-04-05 20:02:45 +00:00
struct Exit {
/// destination
room: String, /// id
position: Position,
}
// same as a dialogue basically
2020-04-05 22:02:03 +00:00
#[derive(Debug, Eq, PartialEq)]
2020-04-05 20:02:45 +00:00
struct Ending {
2020-04-06 13:11:56 +00:00
id: String,
dialogue: String,
2020-04-05 20:02:45 +00:00
}
2020-04-05 22:02:03 +00:00
#[derive(Debug, Eq, PartialEq)]
2020-04-05 20:02:45 +00:00
struct Room {
id: String,
palette: String, // id
2020-04-05 20:02:45 +00:00
name: Option<String>,
tiles: Vec<String>, // tile ids
2020-04-10 15:27:23 +00:00
items: Vec<Instance>,
exits: Vec<ExitInstance>,
endings: Vec<Instance>,
2020-04-05 20:02:45 +00:00
}
2020-04-06 13:22:35 +00:00
#[derive(Debug, Eq, PartialEq)]
struct Variable {
id: String,
2020-04-06 18:11:41 +00:00
initial_value: String,
2020-04-06 13:22:35 +00:00
}
#[derive(Debug, PartialEq)]
2020-04-05 17:58:04 +00:00
struct Game {
name: String,
version: f64,
room_format: u8,
2020-04-05 17:58:04 +00:00
palettes: Vec<Palette>,
2020-04-11 21:40:26 +00:00
rooms: Vec<Room>,
tiles: Vec<Tile>,
avatar: Avatar,
sprites: Vec<Sprite>,
items: Vec<Item>,
dialogues: Vec<Dialogue>,
endings: Vec<Ending>,
2020-04-06 13:22:35 +00:00
variables: Vec<Variable>,
2020-04-05 17:58:04 +00:00
}
fn example_image_chequers_1() -> Image {
2020-04-06 11:26:26 +00:00
Image {
pixels: vec![
1,0,1,0,1,0,1,0,
0,1,0,1,0,1,0,1,
1,0,1,0,1,0,1,0,
0,1,0,1,0,1,0,1,
1,0,1,0,1,0,1,0,
0,1,0,1,0,1,0,1,
1,0,1,0,1,0,1,0,
0,1,0,1,0,1,0,1,
]
}
}
fn example_image_chequers_2() -> Image {
2020-04-06 11:26:26 +00:00
Image {
pixels: vec![
0,1,0,1,0,1,0,1,
1,0,1,0,1,0,1,0,
0,1,0,1,0,1,0,1,
1,0,1,0,1,0,1,0,
0,1,0,1,0,1,0,1,
1,0,1,0,1,0,1,0,
0,1,0,1,0,1,0,1,
1,0,1,0,1,0,1,0,
]
}
}
fn example_avatar() -> Avatar {
Avatar {
animation_frames: vec![
Image {
pixels: vec![
0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,
0,1,1,1,1,1,1,0,
1,1,1,0,1,1,1,0,
1,0,0,1,1,0,0,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
0,1,1,1,1,1,1,0,
]
},
Image {
pixels: vec![
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,
0,1,1,1,1,1,1,0,
1,1,1,0,1,1,1,0,
1,0,0,1,1,0,0,1,
1,1,1,1,1,1,1,1,
0,1,1,1,0,1,1,0,
]
},
],
room: "0".to_string(),
position: Position { x: 2, y: 5 }
}
}
fn example_sprite() -> Sprite {
2020-04-06 11:26:26 +00:00
Sprite {
id: "a".to_string(),
name: Some("hatch".to_string()),
animation_frames: vec![
Image {
pixels: vec![
0,0,0,0,0,0,0,0,
0,1,1,1,1,0,0,0,
0,1,0,0,1,0,0,0,
0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,
0,1,0,1,1,1,1,0,
0,1,0,1,1,1,1,0,
0,1,1,0,1,1,1,1,
]
}
],
dialogue: Some("SPR_0".to_string()),
room: "4".to_string(),
position: Position {
x: 9,
y: 7
}
}
}
fn example_item() -> Item {
2020-04-06 11:26:26 +00:00
Item {
id: "6".to_string(),
animation_frames: vec![
Image {
pixels: vec![
0,1,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,1,0,0,
0,0,1,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,1,0,
]
}
],
name: Some("door".to_string()),
dialogue: Some("ITM_2".to_string())
}
}
fn example_room() -> Room {
2020-04-09 07:28:08 +00:00
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()
],
2020-04-10 15:27:23 +00:00
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()},
],
2020-04-09 07:28:08 +00:00
}
}
fn example_room_string() -> String {
include_str!("../test/resources/room").to_string()
2020-04-09 07:28:08 +00:00
}
fn example_game_default() -> Game {
Game {
name: "Write your game's title here".to_string(),
version: 6.5,
room_format: 1,
palettes: vec![
Palette {
id: "0".to_string(),
name: None,
colours: vec![
Colour {red: 0, green: 82, blue: 204 },
Colour {red: 128, green: 159, blue: 255 },
Colour {red: 255, green: 255, blue: 255 },
]
}
],
rooms: vec![
Room {
id: "0".to_string(),
palette: "0".to_string(),
name: None,
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(),"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(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"0".to_string(),
"0".to_string(),"a".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(),"a".to_string(),"0".to_string(),
"0".to_string(),"a".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(),"a".to_string(),"0".to_string(),
"0".to_string(),"a".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(),"a".to_string(),"0".to_string(),
"0".to_string(),"a".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(),"a".to_string(),"0".to_string(),
"0".to_string(),"a".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(),"a".to_string(),"0".to_string(),
"0".to_string(),"a".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(),"a".to_string(),"0".to_string(),
"0".to_string(),"a".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(),"a".to_string(),"0".to_string(),
"0".to_string(),"a".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(),"a".to_string(),"0".to_string(),
"0".to_string(),"a".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(),"a".to_string(),"0".to_string(),
"0".to_string(),"a".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(),"a".to_string(),"0".to_string(),
"0".to_string(),"a".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(),"a".to_string(),"0".to_string(),
"0".to_string(),"a".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(),"a".to_string(),"0".to_string(),
"0".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".to_string(),"a".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![],
exits: vec![],
endings: vec![]
}
],
tiles: vec![
Tile {
id: "a".to_string(),
name: None,
wall: false,
animation_frames: vec![
Image {
pixels: vec![
1,1,1,1,1,1,1,1,
1,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,1,
1,0,0,1,1,0,0,1,
1,0,0,1,1,0,0,1,
1,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,1,
1,1,1,1,1,1,1,1,
]
}
]
}
],
avatar: Avatar {
animation_frames: vec![
Image {
pixels: vec![
0,0,0,1,1,0,0,0,
0,0,0,1,1,0,0,0,
0,0,0,1,1,0,0,0,
0,0,1,1,1,1,0,0,
0,1,1,1,1,1,1,0,
1,0,1,1,1,1,0,1,
0,0,1,0,0,1,0,0,
0,0,1,0,0,1,0,0,
]
}
],
room: "0".to_string(),
position: Position { x: 4, y: 4 }
},
sprites: vec![
Sprite {
id: "a".to_string(),
name: None,
animation_frames: vec![
Image {
pixels: vec![
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,1,0,1,0,0,0,1,
0,1,1,1,0,0,0,1,
0,1,1,1,0,0,1,0,
0,1,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,
0,0,1,0,0,1,0,0,
]
}
],
dialogue: Some("SPR_0".to_string()),
room: "0".to_string(),
position: Position { x: 8, y: 12 }
}
],
items: vec![
Item {
id: "0".to_string(),
animation_frames: vec![
Image {
pixels: vec![
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,
0,1,1,0,0,1,0,0,
0,0,1,0,0,1,0,0,
0,0,0,1,1,0,0,0,
0,0,0,0,0,0,0,0,
]
},
],
name: Some("tea".to_string()),
dialogue: Some("ITM_0".to_string())
},
],
dialogues: vec![
Dialogue {
id: "SPR_0".to_string(),
contents: "I'm a cat".to_string(),
},
Dialogue {
id: "ITM_0".to_string(),
contents: "You found a nice warm cup of tea".to_string(),
},
],
endings: vec![],
variables: vec![
Variable { id: "a".to_string(), initial_value: "42".to_string() }
],
}
}
2020-04-12 10:26:59 +00:00
impl From<String> for Image {
#[inline]
fn from(string: String) -> Image {
let string = string.replace("\n", "");
let pixels: Vec<&str> = string.split("").collect();
// the above seems to add an extra "" at the start and end of the vec, so strip them below
let pixels = &pixels[1..(pixels.len() - 1)];
let pixels: Vec<u8> = pixels.iter().map(|&pixel| {
pixel.parse::<u8>().unwrap()
}).collect();
Image { pixels }
}
2020-04-05 17:58:04 +00:00
}
2020-04-05 21:28:23 +00:00
#[test]
fn test_image_from_string() {
2020-04-12 10:26:59 +00:00
let output = Image::from(include_str!("../test/resources/image").to_string());
2020-04-05 21:28:23 +00:00
let expected = Image {
pixels: vec![
1,1,1,1,1,1,1,1,
1,1,0,0,1,1,1,1,
1,0,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
]
};
assert_eq!(output, expected)
}
2020-04-12 09:24:21 +00:00
impl ToString for Image {
#[inline]
fn to_string(&self) -> String {
let mut string = String::new();
let sqrt = (self.pixels.len() as f64).sqrt() as usize; // 8 for SD, 16 for HD
for line in self.pixels.chunks(sqrt) {
for pixel in line {
string.push_str(&format!("{}", *pixel));
}
string.push('\n');
2020-04-05 17:58:04 +00:00
}
2020-04-12 09:24:21 +00:00
string.pop(); // remove trailing newline
2020-04-05 17:58:04 +00:00
2020-04-12 09:24:21 +00:00
string
}
2020-04-05 17:58:04 +00:00
}
#[test]
fn test_image_to_string() {
2020-04-12 09:24:21 +00:00
let output = example_image_chequers_1().to_string();
let expected = include_str!("../test/resources/image-chequers-1").to_string();
2020-04-05 17:58:04 +00:00
assert_eq!(output, expected);
}
pub trait AnimationFrames {
fn to_string(&self) -> String;
}
impl AnimationFrames for Vec<Image> {
#[inline]
fn to_string(&self) -> String {
let mut string = String::new();
let last_frame = self.len() - 1;
for (i, frame) in self.into_iter().enumerate() {
string.push_str(&frame.to_string());
if i < last_frame {
string.push_str(&"\n>\n".to_string());
}
}
string
}
}
2020-04-12 10:29:13 +00:00
impl From<String> for Tile {
fn from(string: String) -> Tile {
let mut lines: Vec<&str> = string.lines().collect();
2020-04-05 17:58:04 +00:00
2020-04-12 10:29:13 +00:00
let id = lines[0].replace("TIL ", "");
2020-04-05 17:58:04 +00:00
2020-04-12 10:29:13 +00:00
let last_line = lines.pop().unwrap();
let wall = match last_line == "WAL true" {
true => true,
false => {
lines.push(last_line);
false
}
};
2020-04-05 17:58:04 +00:00
2020-04-12 10:29:13 +00:00
let last_line = lines.pop().unwrap();
let name = match last_line.starts_with("NAME") {
true => Some(last_line.replace("NAME ", "").to_string()),
false => {
lines.push(last_line);
None
}
};
2020-04-05 17:58:04 +00:00
2020-04-12 10:29:13 +00:00
let animation_frames = lines[1..].join("");
let animation_frames: Vec<&str> = animation_frames.split("\n>\n").collect();
let animation_frames: Vec<Image> = animation_frames.iter().map(|&frame| {
Image::from(frame.to_string())
}).collect();
2020-04-05 17:58:04 +00:00
2020-04-12 10:29:13 +00:00
Tile { id, name, wall, animation_frames }
}
2020-04-05 17:58:04 +00:00
}
#[test]
fn test_tile_from_string() {
2020-04-12 10:29:13 +00:00
let output = Tile::from(include_str!("../test/resources/tile").to_string());
2020-04-05 17:58:04 +00:00
let expected = Tile {
id: "z".to_string(),
name: Some("concrete 1".to_string()),
wall: true,
animation_frames: vec![
Image {
2020-04-05 21:28:23 +00:00
pixels: vec![1; 64]
2020-04-05 17:58:04 +00:00
}
],
};
assert_eq!(output, expected);
}
impl ToString for Tile {
#[inline]
fn to_string(&self) -> String {
format!(
"TIL {}\n{}{}{}",
self.id,
self.animation_frames.to_string(),
if self.name.as_ref().is_some() { format!("\nNAME {}", self.name.as_ref().unwrap())} else {"".to_string() },
if self.wall {"\nWAL true"} else {""}
)
}
2020-04-05 17:58:04 +00:00
}
#[test]
fn test_tile_to_string() {
let output = Tile {
id: "7a".to_string(),
name: Some("chequers".to_string()),
wall: false,
animation_frames: vec![
example_image_chequers_1(),
example_image_chequers_2(),
]
}.to_string();
let expected = include_str!("../test/resources/tile-chequers").to_string();
assert_eq!(output, expected);
}
2020-04-05 17:58:04 +00:00
2020-04-12 10:31:18 +00:00
impl From<String> for Colour {
fn from(string: String) -> Colour {
let values: Vec<&str> = string.split(',').collect();
2020-04-05 17:58:04 +00:00
2020-04-12 10:31:18 +00:00
let red: u8 = values[0].parse().unwrap_or(0);
let green: u8 = values[1].parse().unwrap_or(0);
let blue: u8 = values[2].parse().unwrap_or(0);
2020-04-05 17:58:04 +00:00
2020-04-12 10:31:18 +00:00
Colour { red, green, blue }
}
2020-04-05 17:58:04 +00:00
}
#[test]
fn test_colour_from_string() {
assert_eq!(
2020-04-12 10:31:18 +00:00
Colour::from("0,255,0".to_string()),
2020-04-05 17:58:04 +00:00
Colour { red: 0, green: 255, blue: 0 }
);
}
impl ToString for Colour {
#[inline]
fn to_string(&self) -> String {
format!("{},{},{}", self.red, self.green, self.blue)
}
2020-04-05 21:28:35 +00:00
}
2020-04-05 17:58:04 +00:00
#[test]
fn test_colour_to_string() {
assert_eq!(
Colour { red: 22, green: 33, blue: 44 }.to_string(),
2020-04-05 17:58:04 +00:00
"22,33,44".to_string()
);
}
2020-04-12 10:51:30 +00:00
impl From<String> for Palette {
fn from(string: String) -> Palette {
let lines: Vec<&str> = string.lines().collect();
2020-04-05 17:58:04 +00:00
2020-04-12 10:51:30 +00:00
let id = lines[0].replace("PAL ", "");
2020-04-05 17:58:04 +00:00
2020-04-12 10:51:30 +00:00
let name = match lines[1].starts_with("NAME") {
true => Some(lines[1].replace("NAME ", "").to_string()),
false => None,
};
2020-04-05 17:58:04 +00:00
2020-04-12 10:51:30 +00:00
let colour_start_index = if name.is_some() { 2 } else { 1 };
2020-04-05 17:58:04 +00:00
2020-04-12 10:51:30 +00:00
let colours = lines[colour_start_index..].iter().map(|&line| {
Colour::from(line.to_string())
}).collect();
2020-04-05 17:58:04 +00:00
2020-04-12 10:51:30 +00:00
Palette { id, name, colours }
}
2020-04-05 17:58:04 +00:00
}
#[test]
fn test_palette_from_string() {
2020-04-12 10:51:30 +00:00
let output = Palette::from(
2020-04-05 17:58:04 +00:00
"PAL 1\nNAME lamplight\n45,45,59\n66,60,39\n140,94,1".to_string()
);
let expected = Palette {
id: "1".to_string(),
name: Some("lamplight".to_string()),
colours: vec![
Colour {red: 45, green: 45, blue: 59},
Colour {red: 66, green: 60, blue: 39},
Colour {red: 140, green: 94, blue: 1 },
],
};
assert_eq!(output, expected);
}
#[test]
fn test_palette_from_string_no_name() {
2020-04-12 10:51:30 +00:00
let output = Palette::from(
2020-04-05 17:58:04 +00:00
"PAL 9\n45,45,59\n66,60,39\n140,94,1".to_string()
);
let expected = Palette {
id: "9".to_string(),
name: None,
colours: vec![
Colour {red: 45, green: 45, blue: 59},
Colour {red: 66, green: 60, blue: 39},
Colour {red: 140, green: 94, blue: 1 },
],
};
assert_eq!(output, expected);
}
2020-04-12 09:15:51 +00:00
impl ToString for Palette {
#[inline]
fn to_string(&self) -> String {
let name = if self.name.as_ref().is_some() {
format!("NAME {}\n", self.name.as_ref().unwrap())
} else {
"".to_string()
};
2020-04-11 22:05:47 +00:00
2020-04-12 09:15:51 +00:00
let mut colours = String::new();
for colour in &self.colours {
colours.push_str(&format!("{}\n", colour.to_string()));
}
colours.pop();
2020-04-11 22:05:47 +00:00
2020-04-12 09:15:51 +00:00
format!("PAL {}\n{}{}", self.id, name, colours)
}
2020-04-11 22:05:47 +00:00
}
#[test]
fn test_palette_to_string() {
2020-04-12 09:15:51 +00:00
let output = Palette {
id: "g".to_string(),
name: Some("moss".to_string()),
colours: vec![
Colour {red: 1, green: 2, blue: 3 },
Colour {red: 255, green: 254, blue: 253},
Colour {red: 126, green: 127, blue: 128},
]
2020-04-12 09:15:51 +00:00
}.to_string();
let expected = "PAL g\nNAME moss\n1,2,3\n255,254,253\n126,127,128".to_string();
assert_eq!(output, expected);
}
2020-04-12 10:51:30 +00:00
impl From<String> for Position {
fn from(string: String) -> Position {
// e.g. "2,5"
let xy: Vec<&str> = string.split(',').collect();
let x = xy[0].parse().unwrap();
let y = xy[1].parse().unwrap();
2020-04-05 22:00:15 +00:00
2020-04-12 10:51:30 +00:00
Position { x, y }
}
2020-04-05 22:00:15 +00:00
}
#[test]
fn test_position_from_string() {
2020-04-12 10:51:30 +00:00
assert_eq!(Position::from("4,12".to_string()), Position { x: 4, y: 12 });
2020-04-05 22:00:15 +00:00
}
2020-04-12 09:20:51 +00:00
impl ToString for Position {
#[inline]
fn to_string(&self) -> String {
format!("{},{}", self.x, self.y)
}
2020-04-05 22:00:15 +00:00
}
#[test]
fn test_position_to_string() {
2020-04-12 09:21:38 +00:00
assert_eq!(Position { x: 4, y: 12 }.to_string(), "4,12".to_string())
2020-04-05 22:00:15 +00:00
}
2020-04-12 10:51:30 +00:00
impl From<String> for Avatar {
fn from(string: String) -> Avatar {
let string = string.replace("SPR A\n", "");
let mut lines: Vec<&str> = string.lines().collect();
let room_pos = lines.pop().unwrap().replace("POS ", "");
let room_pos: Vec<&str> = room_pos.split_whitespace().collect();
let room = room_pos[0].to_string();
let position = Position::from(room_pos[1].to_string());
let animation_frames: String = lines.join("\n");
let animation_frames: Vec<&str> = animation_frames.split("\n>\n").collect();
let animation_frames: Vec<Image> = animation_frames.iter().map(|&frame| {
Image::from(frame.to_string())
}).collect();
2020-04-12 10:51:30 +00:00
Avatar { animation_frames, room, position }
}
}
#[test]
fn test_avatar_from_string() {
2020-04-12 10:51:30 +00:00
let output = Avatar::from(
include_str!("../test/resources/avatar").to_string()
);
2020-04-12 10:51:30 +00:00
let expected = example_avatar();
assert_eq!(output, expected);
}
impl ToString for Avatar {
#[inline]
fn to_string(&self) -> String {
format!(
"SPR A\n{}\nPOS {} {}",
self.animation_frames.to_string(),
self.room,
self.position.to_string()
)
}
}
#[test]
fn test_avatar_to_string() {
assert_eq!(example_avatar().to_string(), include_str!("../test/resources/avatar"));
}
2020-04-12 10:51:30 +00:00
impl From<String> for Sprite {
fn from(string: String) -> Sprite {
let mut lines: Vec<&str> = string.lines().collect();
2020-04-05 22:58:10 +00:00
2020-04-12 10:51:30 +00:00
let id = lines[0].replace("SPR ", "");
let mut name = None;
let mut dialogue = None;
let mut room: Option<String> = None;
let mut position: Option<Position> = None;
for _ in 0..3 {
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("DLG") {
dialogue = Some(last_line.replace("DLG ", "").to_string());
} else if last_line.starts_with("POS") {
let last_line = last_line.replace("POS ", "");
let room_position: Vec<&str> = last_line.split(' ').collect();
room = Some(room_position[0].to_string());
position = Some(Position::from(room_position[1].to_string()));
} else {
lines.push(last_line);
break;
}
2020-04-05 22:58:10 +00:00
}
2020-04-12 10:51:30 +00:00
let room = room.unwrap();
let position = position.unwrap();
2020-04-05 22:58:10 +00:00
2020-04-12 10:51:30 +00:00
// todo dedupe
let animation_frames = lines[1..].join("");
let animation_frames: Vec<&str> = animation_frames.split("\n>\n").collect();
let animation_frames: Vec<Image> = animation_frames.iter().map(|&frame| {
Image::from(frame.to_string())
}).collect();
2020-04-05 22:58:10 +00:00
2020-04-12 10:51:30 +00:00
Sprite { id, name, animation_frames, dialogue, room, position }
}
2020-04-05 22:58:10 +00:00
}
#[test]
fn test_sprite_from_string() {
2020-04-12 10:51:30 +00:00
let output = Sprite::from(
include_str!("../test/resources/sprite").to_string()
);
let expected = example_sprite();
2020-04-05 22:58:10 +00:00
assert_eq!(output, expected);
}
2020-04-05 19:46:55 +00:00
impl ToString for Sprite {
#[inline]
fn to_string(&self) -> String {
format!(
"SPR {}\n{}{}{}\nPOS {} {}",
self.id,
self.animation_frames.to_string(),
if self.name.as_ref().is_some() { format!("\nNAME {}", self.name.as_ref().unwrap()) } else { "".to_string() },
if self.dialogue.as_ref().is_some() { format!("\nDLG {}", self.dialogue.as_ref().unwrap()) } else { "".to_string() },
self.room,
self.position.to_string(),
)
}
}
2020-04-06 07:27:08 +00:00
#[test]
fn test_sprite_to_string() {
assert_eq!(example_sprite().to_string(), include_str!("../test/resources/sprite").to_string());
2020-04-06 07:27:08 +00:00
}
2020-04-12 10:51:30 +00:00
impl From<String> for Item {
fn from(string: String) -> Item {
let mut lines: Vec<&str> = string.lines().collect();
2020-04-06 07:54:43 +00:00
2020-04-12 10:51:30 +00:00
let id = lines[0].replace("ITM ", "");
let mut name = None;
let mut dialogue = None;
2020-04-06 07:54:43 +00:00
2020-04-12 10:51:30 +00:00
for _ in 0..2 {
let last_line = lines.pop().unwrap();
2020-04-06 07:54:43 +00:00
2020-04-12 10:51:30 +00:00
if last_line.starts_with("NAME") {
name = Some(last_line.replace("NAME ", "").to_string());
} else if last_line.starts_with("DLG") {
dialogue = Some(last_line.replace("DLG ", "").to_string());
} else {
lines.push(last_line);
break;
}
2020-04-06 07:54:43 +00:00
}
2020-04-12 10:51:30 +00:00
// todo dedupe
let animation_frames = lines[1..].join("");
let animation_frames: Vec<&str> = animation_frames.split("\n>\n").collect();
let animation_frames: Vec<Image> = animation_frames.iter().map(|&frame| {
Image::from(frame.to_string())
}).collect();
Item { id, name, animation_frames, dialogue }
2020-04-06 07:54:43 +00:00
}
}
#[test]
fn test_item_from_string() {
2020-04-12 10:51:30 +00:00
let output = Item::from(include_str!("../test/resources/item").to_string());
let expected = example_item();
2020-04-06 08:02:52 +00:00
assert_eq!(output, expected);
}
impl ToString for Item {
#[inline]
fn to_string(&self) -> String {
format!(
"ITM {}\n{}{}{}",
self.id,
self.animation_frames.to_string(),
if self.name.is_some() { format!("\nNAME {}", self.name.as_ref().unwrap()) } else { "".to_string() },
if self.dialogue.is_some() { format!("\nDLG {}", self.dialogue.as_ref().unwrap()) } else { "".to_string() },
)
}
2020-04-06 08:02:52 +00:00
}
#[test]
fn test_item_to_string() {
let output = example_item().to_string();
let expected = include_str!("../test/resources/item").to_string();
2020-04-06 07:54:43 +00:00
assert_eq!(output, expected);
}
2020-04-12 10:51:30 +00:00
impl From<String> for Exit {
fn from(string: String) -> Exit {
// e.g. "4 3,3"
let room_position: Vec<&str> = string.split(' ').collect();
let room = room_position[0].to_string();
let position = Position::from(room_position[1].to_string());
2020-04-12 10:51:30 +00:00
Exit { room, position }
}
}
#[test]
fn test_exit_from_string() {
assert_eq!(
2020-04-12 10:51:30 +00:00
Exit::from("a 12,13".to_string()),
2020-04-11 17:24:43 +00:00
Exit { room: "a".to_string(), position: Position { x: 12, y: 13 } }
);
}
impl ToString for Exit {
fn to_string(&self) -> String {
format!("{} {}", self.room, self.position.to_string())
}
}
#[test]
fn test_exit_to_string() {
assert_eq!(
Exit { room: "8".to_string(), position: Position { x: 5, y: 6 } }.to_string(),
"8 5,6".to_string()
);
}
2020-04-12 10:51:30 +00:00
impl From<String> for Ending {
fn from(string: String) -> Ending {
let string = string.replace("END ", "");
let id_dialogue: Vec<&str> = string.lines().collect();
let id = id_dialogue[0].to_string();
let dialogue = id_dialogue[1].to_string();
2020-04-06 13:11:56 +00:00
2020-04-12 10:51:30 +00:00
Ending { id, dialogue }
}
2020-04-06 13:11:56 +00:00
}
#[test]
fn test_ending_from_string() {
assert_eq!(
2020-04-12 10:51:30 +00:00
Ending::from(include_str!("../test/resources/ending").to_string()),
Ending {
id: "a".to_string(),
dialogue: "This is a long line of dialogue. Blah blah blah".to_string()
}
2020-04-06 13:11:56 +00:00
);
}
impl ToString for Ending {
#[inline]
fn to_string(&self) -> String {
format!("END {}\n{}", self.id, self.dialogue)
}
2020-04-06 13:11:56 +00:00
}
#[test]
fn test_ending_to_string() {
assert_eq!(
Ending {
id: "7".to_string(),
dialogue: "This is another long ending. So long, farewell, etc.".to_string()
}.to_string(),
2020-04-06 13:11:56 +00:00
"END 7\nThis is another long ending. So long, farewell, etc.".to_string()
);
}
2020-04-12 10:51:30 +00:00
impl From<String> for Dialogue {
fn from(string: String) -> Dialogue {
let lines: Vec<&str> = string.lines().collect();
let id = lines[0].replace("DLG ", "").to_string();
let contents = lines[1..].join("\n");
2020-04-06 16:18:17 +00:00
2020-04-12 10:51:30 +00:00
Dialogue { id, contents }
}
2020-04-06 16:18:17 +00:00
}
#[test]
fn test_dialogue_from_string() {
assert_eq!(
2020-04-12 10:51:30 +00:00
Dialogue::from("DLG h\nhello\ngoodbye".to_string()),
2020-04-06 16:18:17 +00:00
Dialogue { id: "h".to_string(), contents: "hello\ngoodbye".to_string()}
)
}
2020-04-12 09:37:41 +00:00
impl ToString for Dialogue {
#[inline]
fn to_string(&self) -> String {
format!("DLG {}\n{}", self.id, self.contents)
}
2020-04-06 16:18:17 +00:00
}
#[test]
fn test_dialogue_to_string() {
assert_eq!(
2020-04-12 09:37:41 +00:00
Dialogue {
id: "y".to_string(),
contents: "This is a bit of dialogue,\nblah blah\nblah blah".to_string()
}.to_string(),
2020-04-06 16:18:17 +00:00
"DLG y\nThis is a bit of dialogue,\nblah blah\nblah blah".to_string()
);
}
2020-04-12 10:51:30 +00:00
impl From<String> for Variable {
fn from(string: String) -> Variable {
let id_value: Vec<&str> = string.split('\n').collect();
let id = id_value[0].replace("VAR ", "").to_string();
let initial_value = id_value[1].to_string();
2020-04-06 18:11:41 +00:00
2020-04-12 10:51:30 +00:00
Variable { id, initial_value }
}
2020-04-06 18:11:41 +00:00
}
#[test]
fn test_variable_from_string() {
assert_eq!(
2020-04-12 10:51:30 +00:00
Variable::from("VAR a\n42".to_string()),
2020-04-06 18:11:41 +00:00
Variable { id: "a".to_string(), initial_value: "42".to_string()}
);
}
impl ToString for Variable {
#[inline]
fn to_string(&self) -> String {
format!("VAR {}\n{}", self.id, self.initial_value)
}
2020-04-06 18:11:41 +00:00
}
#[test]
fn test_variable_to_string() {
let output = Variable { id: "c".to_string(), initial_value: "57".to_string() }.to_string();
2020-04-06 18:11:41 +00:00
let expected = "VAR c\n57".to_string();
assert_eq!(output, expected);
}
2020-04-12 10:51:30 +00:00
impl From<String> 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<Instance> = Vec::new();
let mut exits: Vec<ExitInstance> = Vec::new();
let mut endings: Vec<Instance> = 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;
}
}
2020-04-12 10:51:30 +00:00
let lines = &lines[1..];
2020-04-06 19:41:33 +00:00
2020-04-12 10:51:30 +00:00
let mut tiles: Vec<String> = Vec::new();
2020-04-06 19:41:33 +00:00
2020-04-12 10:51:30 +00:00
for line in lines.into_iter() {
let line: Vec<&str> = line.split(",").collect();
2020-04-06 19:41:33 +00:00
2020-04-12 10:51:30 +00:00
for tile_id in line {
tiles.push(tile_id.to_string());
}
2020-04-06 19:41:33 +00:00
}
2020-04-12 10:51:30 +00:00
Room { id, palette, name, tiles, items, exits, endings }
}
}
#[test]
fn test_room_from_string() {
2020-04-12 10:51:30 +00:00
assert_eq!(Room::from(example_room_string()), example_room());
2020-04-09 07:28:08 +00:00
}
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
2020-04-09 07:28:08 +00:00
for instance in &self.items {
items.push_str(
&format!("\nITM {} {}", instance.id, instance.position.to_string())
);
2020-04-09 07:28:08 +00:00
}
for instance in &self.exits {
exits.push_str(
&format!(
"\nEXT {} {}",
instance.position.to_string(),
instance.exit.to_string(),
)
);
}
2020-04-09 07:28:08 +00:00
for instance in &self.endings {
endings.push_str(
&format!("\nEND {} {}", instance.id, instance.position.to_string())
);
}
2020-04-09 07:28:08 +00:00
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
)
2020-04-09 07:28:08 +00:00
}
}
#[test]
fn test_room_to_string() {
assert_eq!(example_room().to_string(), example_room_string());
}
2020-04-12 10:51:30 +00:00
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));
}
2020-04-11 21:40:26 +00:00
}
2020-04-12 10:51:30 +00:00
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();
2020-04-11 21:40:26 +00:00
2020-04-12 10:51:30 +00:00
for segment in ending_segments {
let segment = format!("END{}", segment);
endings.push(Ending::from(segment));
}
2020-04-11 21:40:26 +00:00
}
2020-04-12 10:51:30 +00:00
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));
}
2020-04-11 21:40:26 +00:00
2020-04-12 10:51:30 +00:00
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));
}
2020-04-11 21:40:26 +00:00
}
2020-04-12 10:51:30 +00:00
assert!(avatar.is_some());
let avatar = avatar.unwrap();
Game {
name,
version,
room_format,
palettes,
rooms,
tiles,
avatar,
sprites,
items,
dialogues,
endings,
variables,
}
2020-04-11 21:40:26 +00:00
}
}
#[test]
fn test_game_from_string() {
2020-04-12 10:51:30 +00:00
let output = Game::from(
2020-04-11 21:40:26 +00:00
include_str!["../test/resources/default.bitsy"].to_string()
);
2020-04-12 10:51:30 +00:00
let expected = example_game_default();
2020-04-11 21:40:26 +00:00
assert_eq!(output, expected);
}
2020-04-06 07:54:43 +00:00
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_to_string() {
let output = example_game_default().to_string();
let expected = include_str!["../test/resources/default.bitsy"].to_string();
assert_eq!(output, expected);
}