Compare commits
65 Commits
8cb32ef9b9
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 4388c75bb8 | |||
| a36313341d | |||
| eee3444c4d | |||
| 5577a05191 | |||
| 9363be8254 | |||
| a7c020f785 | |||
| 8148e3f725 | |||
| b8c30fe873 | |||
| b50bde1f64 | |||
| 4182079a73 | |||
| b95d9d28d4 | |||
| 9188529c9f | |||
| 34bcad51dd | |||
| 81da2960af | |||
| 7199ca30f9 | |||
| 4a05021bdd | |||
| de15ccbaa2 | |||
| b9415ade9e | |||
| e992e41635 | |||
| 46f8831c7b | |||
| 66cb9bdd4d | |||
| 1bbfaceeb4 | |||
| e9738b98b1 | |||
| 8f558a908f | |||
| fb290f07f4 | |||
| 889328f9a9 | |||
| 68ecc64c7b | |||
| 0dcddb9d8e | |||
| 1c5315ddad | |||
| a7a4a34ab8 | |||
| 67d4e28773 | |||
| d8183e29fc | |||
| dba84e01fa | |||
| 7896ef1232 | |||
| f7f08d9aba | |||
| 8068177736 | |||
| 59fc76a2d4 | |||
| 676c71cd45 | |||
| 5aa0c94810 | |||
| ad3eb102be | |||
| fe22e78423 | |||
| fd08bff10e | |||
| 1967be3635 | |||
| eede24b13c | |||
| 22c41fb032 | |||
| acfb0b6c8f | |||
| a6bcc763e9 | |||
| 1d7e3f0704 | |||
| 11c9430ccf | |||
| 45e113717e | |||
| fa6f5e1bcb | |||
| ee0e6af143 | |||
| c1cac86c1a | |||
| ff70efd115 | |||
| c79d33ddf2 | |||
| 575ad442d8 | |||
| b868ee4d04 | |||
| fe690a6d9b | |||
| 2d3bcc4f50 | |||
| 0763d15b0e | |||
| 91883079a3 | |||
| 689a89c18c | |||
| c4be0861cb | |||
| 73665796df | |||
| ed6937bbfd |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,3 @@
|
|||||||
/target
|
/target
|
||||||
/Cargo.lock
|
/Cargo.lock
|
||||||
/.idea/
|
/.idea/
|
||||||
/src/test-resources/
|
|
||||||
/src/test-resources/omnibus/
|
|
||||||
|
|||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "src/test-resources/omnibus"]
|
||||||
|
path = src/test-resources/omnibus
|
||||||
|
url = https://github.com/Ragzouken/bitsy-archive.git
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bitsy-parser"
|
name = "bitsy-parser"
|
||||||
version = "0.71.6"
|
version = "0.812.0"
|
||||||
authors = ["Max Bradbury <max@tinybird.info>"]
|
authors = ["Max Bradbury <max@tinybird.info>"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
description = "A parser and utilities for working with Bitsy game data"
|
description = "A parser and utilities for working with Bitsy game data"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://tinybird.dev/max/bitsy-parser"
|
repository = "https://tinybird.dev/max/bitsy-parser"
|
||||||
@@ -12,5 +12,6 @@ keywords = ["gamedev"]
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
radix_fmt = "1.0.0"
|
data-encoding = "^2.6.0"
|
||||||
loe = "0.2.0"
|
radix_fmt = "^1.0.0"
|
||||||
|
loe = "0.3.0"
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2020 Max Bradbury
|
Copyright © 2024 Max Bradbury
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
# bitsy-parser
|
# bitsy-parser
|
||||||
|
|
||||||

|
|
||||||

|

|
||||||
[](https://crates.io/crates/bitsy-parser)
|
[](https://crates.io/crates/bitsy-parser)
|
||||||
|
|
||||||
@@ -37,8 +36,7 @@ for use in your own Rust applications. can both parse and export Bitsy game data
|
|||||||
a simple example program:
|
a simple example program:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
extern crate bitsy_parser;
|
use bitsy_parser::Game;
|
||||||
use bitsy_parser::game::Game;
|
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
|
||||||
const SYNTAX_ERROR: &str = "No input path specified. Usage: `bitsy-validate filepath`";
|
const SYNTAX_ERROR: &str = "No input path specified. Usage: `bitsy-validate filepath`";
|
||||||
|
|||||||
9
TODO.md
Normal file
9
TODO.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# 8.0 changes
|
||||||
|
|
||||||
|
* NAME fields have moved underneath the main body of data
|
||||||
|
* "BGC *" / "BGC 1" property (transparent / palette colour index)
|
||||||
|
* flags near top of game data ("! VER_MAJ 8" etc.)
|
||||||
|
* blips
|
||||||
|
* implement from_str, display
|
||||||
|
* tunes
|
||||||
|
* implement from_str, display
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
extern crate bitsy_parser;
|
use bitsy_parser::Game;
|
||||||
use bitsy_parser::game::Game;
|
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
|
||||||
const SYNTAX_ERROR: &str = "No game data specified. Usage: `bitsy-dedupe input.bitsy output.bitsy`";
|
const SYNTAX_ERROR: &str = "No game data specified. Usage: `bitsy-dedupe input.bitsy output.bitsy`";
|
||||||
@@ -8,7 +7,7 @@ fn main() {
|
|||||||
let game = env::args().nth(1).expect(SYNTAX_ERROR);
|
let game = env::args().nth(1).expect(SYNTAX_ERROR);
|
||||||
let output = env::args().nth(2).expect(SYNTAX_ERROR);
|
let output = env::args().nth(2).expect(SYNTAX_ERROR);
|
||||||
|
|
||||||
let mut game = Game::from(fs::read_to_string(game).unwrap()).unwrap();
|
let (mut game, _err) = Game::from(fs::read_to_string(game).unwrap()).unwrap();
|
||||||
|
|
||||||
game.dedupe_tiles();
|
game.dedupe_tiles();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
extern crate bitsy_parser;
|
use bitsy_parser::Game;
|
||||||
use bitsy_parser::game::Game;
|
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
|
||||||
const SYNTAX_ERROR: &str = "No main game specified. Usage: `bitsy-merge main.bitsy additional.bitsy output.bitsy`";
|
const SYNTAX_ERROR: &str = "No main game specified. Usage: `bitsy-merge main.bitsy additional.bitsy output.bitsy`";
|
||||||
@@ -10,10 +9,10 @@ fn main() {
|
|||||||
let output = env::args().nth(3).expect(SYNTAX_ERROR);
|
let output = env::args().nth(3).expect(SYNTAX_ERROR);
|
||||||
// todo allow numerous additional games
|
// todo allow numerous additional games
|
||||||
|
|
||||||
let mut game_a = Game::from(fs::read_to_string(game_a).unwrap()).unwrap();
|
let (mut game_a, _) = Game::from(fs::read_to_string(game_a).unwrap()).unwrap();
|
||||||
let game_b = Game::from(fs::read_to_string(game_b).unwrap()).unwrap();
|
let ( game_b, _) = Game::from(fs::read_to_string(game_b).unwrap()).unwrap();
|
||||||
|
|
||||||
game_a.merge(game_b);
|
game_a.merge(&game_b);
|
||||||
|
|
||||||
fs::write(output, game_a.to_string())
|
fs::write(output, game_a.to_string())
|
||||||
.expect("Failed to write output file");
|
.expect("Failed to write output file");
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
extern crate bitsy_parser;
|
use bitsy_parser::Game;
|
||||||
use bitsy_parser::game::Game;
|
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
|
||||||
const SYNTAX_ERROR: &str = "Usage: `bitsy-parse input.bitsy output.bitsy`";
|
const SYNTAX_ERROR: &str = "Usage: `bitsy-parse input.bitsy output.bitsy`";
|
||||||
@@ -9,7 +8,7 @@ fn main() {
|
|||||||
let input = env::args().nth(1).expect(SYNTAX_ERROR);
|
let input = env::args().nth(1).expect(SYNTAX_ERROR);
|
||||||
let output = env::args().nth(2).expect(SYNTAX_ERROR);
|
let output = env::args().nth(2).expect(SYNTAX_ERROR);
|
||||||
|
|
||||||
let game = Game::from(fs::read_to_string(input).unwrap()).unwrap();
|
let (game, _err) = Game::from(fs::read_to_string(input).unwrap()).unwrap();
|
||||||
|
|
||||||
fs::write(output, game.to_string()).expect("Failed to write output file");
|
fs::write(output, game.to_string()).expect("Failed to write output file");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
extern crate bitsy_parser;
|
use bitsy_parser::Game;
|
||||||
use bitsy_parser::game::Game;
|
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
|
||||||
const SYNTAX_ERROR: &str = "No input path specified. Usage: `bitsy-validate filepath`";
|
const SYNTAX_ERROR: &str = "No input path specified. Usage: `bitsy-validate filepath`";
|
||||||
|
|||||||
76
src/blip.rs
Normal file
76
src/blip.rs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
use core::fmt;
|
||||||
|
use std::fmt::Formatter;
|
||||||
|
use crate::note::Note;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum PulseWidth {
|
||||||
|
/// 50% duty cycle
|
||||||
|
Half,
|
||||||
|
/// 25% duty cycle
|
||||||
|
Quarter,
|
||||||
|
/// 12.5% duty cycle
|
||||||
|
Eighth,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PulseWidth {
|
||||||
|
fn from(str: &str) -> Result<PulseWidth, crate::Error> {
|
||||||
|
match str {
|
||||||
|
"P2" => Ok(PulseWidth::Half),
|
||||||
|
"P4" => Ok(PulseWidth::Quarter),
|
||||||
|
"P8" => Ok(PulseWidth::Eighth),
|
||||||
|
_ => Err(crate::Error::PulseWidth),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for PulseWidth {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "SQR {}", match self {
|
||||||
|
PulseWidth::Half => "P2",
|
||||||
|
PulseWidth::Quarter => "P4",
|
||||||
|
PulseWidth::Eighth => "P8",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// thanks to Rumple_Frumpkins from Bitsy Talk for his help in figuring out the blip format.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Blip {
|
||||||
|
id: String,
|
||||||
|
notes: Vec<Note>,
|
||||||
|
name: Option<String>,
|
||||||
|
/// Attack (ms), Decay (ms), Sustain (level: 1-15), Hold (sustain duration, ms), Release (ms)
|
||||||
|
envelope: [u8; 5],
|
||||||
|
/// first value is milliseconds per note;
|
||||||
|
/// second value is a modifier to the first note (add or subtract milliseconds)
|
||||||
|
beat: [i16; 2],
|
||||||
|
pulse_width: PulseWidth,
|
||||||
|
/// Notes can cycle repeatedly, or just play once
|
||||||
|
repeat: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Blip {
|
||||||
|
fn from(str: &str) -> Self {
|
||||||
|
let mut id = String::new();
|
||||||
|
let mut notes = vec![];
|
||||||
|
let mut name = None;
|
||||||
|
let mut envelope = [0; 5];
|
||||||
|
let mut beat = [0; 2];
|
||||||
|
let mut pulse_width = PulseWidth::Half;
|
||||||
|
let mut repeat = false;
|
||||||
|
|
||||||
|
for line in str.lines() {
|
||||||
|
if line.starts_with("BLIP ") {
|
||||||
|
id = line.replace("BLIP ", "");
|
||||||
|
} else if line.starts_with("NAME ") {
|
||||||
|
name = Some(line.replace("NAME ", ""));
|
||||||
|
} else if line.starts_with("ENV ") {
|
||||||
|
let envelope_temp: Vec<u8> = line.replace("ENV ", "").split(' ').map(|v| v.parse().unwrap()).collect();
|
||||||
|
} else {
|
||||||
|
// notes = line.split(',').map(|n| Note::from(n)).collect().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { id, notes, name, envelope, beat, pulse_width, repeat }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,15 +5,12 @@ pub struct Colour {
|
|||||||
pub blue: u8,
|
pub blue: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct InvalidRgb;
|
|
||||||
|
|
||||||
impl Colour {
|
impl Colour {
|
||||||
pub(crate) fn from(string: &str) -> Result<Colour, InvalidRgb> {
|
pub fn from(string: &str) -> Result<Colour, crate::Error> {
|
||||||
let values: Vec<&str> = string.trim_matches(',').split(',').collect();
|
let values: Vec<&str> = string.trim_matches(',').split(',').collect();
|
||||||
|
|
||||||
if values.len() != 3 {
|
if values.len() != 3 {
|
||||||
return Err(InvalidRgb);
|
return Err(crate::Error::Colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
let red: u8 = values[0].parse().unwrap_or(0);
|
let red: u8 = values[0].parse().unwrap_or(0);
|
||||||
@@ -22,6 +19,13 @@ impl Colour {
|
|||||||
|
|
||||||
Ok(Colour { red, green, blue })
|
Ok(Colour { red, green, blue })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_hex(hex: &str) -> Result<Colour, crate::Error> {
|
||||||
|
let hex = hex.to_lowercase().trim_start_matches('#').to_string();
|
||||||
|
let rgb = data_encoding::HEXLOWER.decode(hex.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
Ok(Colour { red: rgb[0], green: rgb[1], blue: rgb[2], })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Colour {
|
impl ToString for Colour {
|
||||||
@@ -32,7 +36,7 @@ impl ToString for Colour {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::colour::Colour;
|
use crate::Colour;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn colour_from_string() {
|
fn colour_from_string() {
|
||||||
@@ -61,4 +65,18 @@ mod test {
|
|||||||
fn colour_extraneous_value() {
|
fn colour_extraneous_value() {
|
||||||
assert!(Colour::from("0,0,0,0").is_err());
|
assert!(Colour::from("0,0,0,0").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn colour_from_hex() {
|
||||||
|
let output = Colour::from_hex("#ffff00").unwrap();
|
||||||
|
let expected = Colour { red: 255, green: 255, blue: 0 };
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn colour_from_hex_upper() {
|
||||||
|
let output = Colour::from_hex("#ABCDEF").unwrap();
|
||||||
|
let expected = Colour { red: 171, green: 205, blue: 239 };
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use crate::optional_data_line;
|
use crate::optional_data_line;
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Dialogue {
|
pub struct Dialogue {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@@ -7,27 +9,35 @@ pub struct Dialogue {
|
|||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for Dialogue {
|
impl Dialogue {
|
||||||
#[inline]
|
pub fn from_str(str: &str) -> Result<Dialogue, crate::Error> {
|
||||||
fn from(string: String) -> Dialogue {
|
let mut lines: Vec<&str> = str.lines().collect();
|
||||||
let mut lines: Vec<&str> = string.lines().collect();
|
|
||||||
let id = lines[0].replace("DLG ", "").to_string();
|
|
||||||
|
|
||||||
let name = if lines.last().unwrap().starts_with("NAME ") {
|
if lines.is_empty() || !lines[0].starts_with("DLG ") {
|
||||||
Some(lines.pop().unwrap().replace("NAME ", ""))
|
return Err(crate::Error::Dialogue);
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = lines[0].replace("DLG ", "");
|
||||||
|
|
||||||
|
let last_line = lines.pop().unwrap();
|
||||||
|
|
||||||
|
let name = if last_line.starts_with("NAME ") {
|
||||||
|
Some(last_line.replace("NAME ", ""))
|
||||||
} else {
|
} else {
|
||||||
|
lines.push(last_line);
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let contents = lines[1..].join("\n");
|
let contents = lines[1..].join("\n");
|
||||||
|
|
||||||
Dialogue { id, contents, name }
|
Ok(Dialogue { id, contents, name })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Dialogue {
|
impl fmt::Display for Dialogue {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
format!(
|
write!(
|
||||||
|
f,
|
||||||
"DLG {}\n{}{}",
|
"DLG {}\n{}{}",
|
||||||
self.id,
|
self.id,
|
||||||
self.contents,
|
self.contents,
|
||||||
@@ -38,13 +48,13 @@ impl ToString for Dialogue {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::dialogue::Dialogue;
|
use crate::Dialogue;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dialogue_from_string() {
|
fn dialogue_from_str() {
|
||||||
let output = Dialogue::from(
|
let output = Dialogue::from_str(
|
||||||
"DLG h\nhello\nNAME not a dialogue name\nNAME a dialogue name".to_string()
|
"DLG h\nhello\nNAME not a dialogue name\nNAME a dialogue name"
|
||||||
);
|
).unwrap();
|
||||||
|
|
||||||
let expected = Dialogue {
|
let expected = Dialogue {
|
||||||
id: "h".to_string(),
|
id: "h".to_string(),
|
||||||
@@ -63,7 +73,7 @@ mod test {
|
|||||||
name: Some("a dialogue name".to_string())
|
name: Some("a dialogue name".to_string())
|
||||||
}.to_string();
|
}.to_string();
|
||||||
|
|
||||||
let expected = "DLG y\nThis is a bit of dialogue,\nblah blah\nblah blah\nNAME a dialogue name".to_string();
|
let expected = "DLG y\nThis is a bit of dialogue,\nblah blah\nblah blah\nNAME a dialogue name";
|
||||||
|
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::error::Error;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
// same as a dialogue basically
|
// same as a dialogue basically
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
@@ -9,14 +7,15 @@ pub struct Ending {
|
|||||||
pub dialogue: String,
|
pub dialogue: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for Ending {}
|
impl Ending {
|
||||||
|
pub fn from_str(s: &str) -> Result<Self, crate::Error> {
|
||||||
impl FromStr for Ending {
|
|
||||||
type Err = String;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
let lines: Vec<&str> = s.lines().collect();
|
let lines: Vec<&str> = s.lines().collect();
|
||||||
let id = lines[0].replace("END ", "").to_string();
|
|
||||||
|
if lines.is_empty() || !lines[0].starts_with("END ") {
|
||||||
|
return Err(crate::Error::Ending);
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = lines[0].replace("END ", "");
|
||||||
let dialogue = lines[1..].join("\n");
|
let dialogue = lines[1..].join("\n");
|
||||||
|
|
||||||
Ok(Ending { id, dialogue })
|
Ok(Ending { id, dialogue })
|
||||||
@@ -31,8 +30,7 @@ impl fmt::Display for Ending {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::ending::Ending;
|
use crate::Ending;
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ending_from_string() {
|
fn ending_from_string() {
|
||||||
|
|||||||
63
src/error.rs
Normal file
63
src/error.rs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum NotFound {
|
||||||
|
Anything,
|
||||||
|
Avatar,
|
||||||
|
Room,
|
||||||
|
Sprite,
|
||||||
|
Tile,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for NotFound {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f,"Not found: {} data", match self {
|
||||||
|
NotFound::Anything => "game",
|
||||||
|
NotFound::Avatar => "avatar",
|
||||||
|
NotFound::Room => "room",
|
||||||
|
NotFound::Sprite => "sprite",
|
||||||
|
NotFound::Tile => "tile",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum ImageError {
|
||||||
|
MalformedPixel,
|
||||||
|
WrongSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
Colour,
|
||||||
|
Dialogue,
|
||||||
|
Ending,
|
||||||
|
Exit,
|
||||||
|
Font,
|
||||||
|
Game {
|
||||||
|
missing: NotFound,
|
||||||
|
},
|
||||||
|
Image {
|
||||||
|
err: ImageError,
|
||||||
|
},
|
||||||
|
Item,
|
||||||
|
Palette,
|
||||||
|
Position,
|
||||||
|
PulseWidth,
|
||||||
|
RelativeNote,
|
||||||
|
Room,
|
||||||
|
Sprite,
|
||||||
|
Text,
|
||||||
|
Tile,
|
||||||
|
Transition,
|
||||||
|
Variable,
|
||||||
|
Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for Error {}
|
||||||
61
src/exit.rs
61
src/exit.rs
@@ -1,6 +1,5 @@
|
|||||||
use crate::Position;
|
use crate::Position;
|
||||||
use std::str::FromStr;
|
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
@@ -16,25 +15,25 @@ pub enum Transition {
|
|||||||
SlideRight,
|
SlideRight,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for Transition {
|
impl Transition {
|
||||||
fn from(str: &str) -> Transition {
|
pub fn from_str(str: &str) -> Result<Transition, crate::Error> {
|
||||||
match str {
|
match str {
|
||||||
"fade_w" => Transition::FadeToWhite,
|
"fade_w" => Ok(Transition::FadeToWhite),
|
||||||
"fade_b" => Transition::FadeToBlack,
|
"fade_b" => Ok(Transition::FadeToBlack),
|
||||||
"wave" => Transition::Wave,
|
"wave" => Ok(Transition::Wave),
|
||||||
"tunnel" => Transition::Tunnel,
|
"tunnel" => Ok(Transition::Tunnel),
|
||||||
"slide_u" => Transition::SlideUp,
|
"slide_u" => Ok(Transition::SlideUp),
|
||||||
"slide_d" => Transition::SlideDown,
|
"slide_d" => Ok(Transition::SlideDown),
|
||||||
"slide_l" => Transition::SlideLeft,
|
"slide_l" => Ok(Transition::SlideLeft),
|
||||||
"slide_r" => Transition::SlideRight,
|
"slide_r" => Ok(Transition::SlideRight),
|
||||||
_ => Transition::None,
|
_ => Err(crate::Error::Transition),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Transition {
|
impl fmt::Display for Transition {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match &self {
|
write!(f, "{}", match &self {
|
||||||
Transition::FadeToWhite => " FX fade_w",
|
Transition::FadeToWhite => " FX fade_w",
|
||||||
Transition::FadeToBlack => " FX fade_b",
|
Transition::FadeToBlack => " FX fade_b",
|
||||||
Transition::Wave => " FX wave",
|
Transition::Wave => " FX wave",
|
||||||
@@ -44,8 +43,7 @@ impl ToString for Transition {
|
|||||||
Transition::SlideLeft => " FX slide_l",
|
Transition::SlideLeft => " FX slide_l",
|
||||||
Transition::SlideRight => " FX slide_r",
|
Transition::SlideRight => " FX slide_r",
|
||||||
Transition::None => "",
|
Transition::None => "",
|
||||||
}
|
})
|
||||||
.to_string()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,24 +56,21 @@ pub struct Exit {
|
|||||||
pub effect: Transition,
|
pub effect: Transition,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for Exit {}
|
impl Exit {
|
||||||
|
pub fn from_str(s: &str) -> Result<Self, crate::Error> {
|
||||||
|
let parts: Vec<&str> = s.split_whitespace().collect();
|
||||||
|
|
||||||
impl FromStr for Exit {
|
if parts.len() < 2 {
|
||||||
type Err = String;
|
return Err(crate::Error::Exit);
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
let mut parts = s.split_whitespace();
|
|
||||||
let room_id = parts.next().unwrap().to_string();
|
|
||||||
let position = Position::from_str(parts.next().unwrap());
|
|
||||||
|
|
||||||
if position.is_err() {
|
|
||||||
return Err("Invalid position for exit".to_string());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let position = position.unwrap();
|
let mut parts = parts.iter();
|
||||||
|
|
||||||
|
let room_id = parts.next().unwrap().to_string();
|
||||||
|
let position = Position::from_str(parts.next().unwrap())?;
|
||||||
|
|
||||||
let effect = if parts.next().is_some() {
|
let effect = if parts.next().is_some() {
|
||||||
Transition::from(parts.next().unwrap())
|
Transition::from_str(parts.next().unwrap())?
|
||||||
} else {
|
} else {
|
||||||
Transition::None
|
Transition::None
|
||||||
};
|
};
|
||||||
@@ -98,9 +93,7 @@ impl fmt::Display for Exit {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::exit::{Transition, Exit};
|
use crate::{Transition, Exit, Position};
|
||||||
use crate::position::Position;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exit_from_string() {
|
fn exit_from_string() {
|
||||||
|
|||||||
477
src/game.rs
477
src/game.rs
@@ -1,9 +1,15 @@
|
|||||||
use crate::{Dialogue, Ending, Font, Item, Palette, Room, Sprite, TextDirection, Tile, Variable, transform_line_endings, segments_from_string, new_unique_id, try_id, Instance};
|
use crate::{
|
||||||
|
Blip, Dialogue, Ending, Font, Image, Item, Palette,
|
||||||
|
Room, Sprite, TextDirection, Tile, Tune, Variable, Instance, Error,
|
||||||
|
transform_line_endings, new_unique_id, try_id
|
||||||
|
};
|
||||||
|
use crate::error::NotFound;
|
||||||
|
|
||||||
use loe::TransformMode;
|
use loe::TransformMode;
|
||||||
use std::str::FromStr;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::borrow::BorrowMut;
|
use std::borrow::BorrowMut;
|
||||||
use crate::image::Image;
|
use std::fmt;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
/// in very early versions of Bitsy, room tiles were defined as single alphanumeric characters -
|
/// in very early versions of Bitsy, room tiles were defined as single alphanumeric characters -
|
||||||
/// so there was a maximum of 36 unique tiles. later versions are comma-separated.
|
/// so there was a maximum of 36 unique tiles. later versions are comma-separated.
|
||||||
@@ -22,12 +28,14 @@ impl RoomFormat {
|
|||||||
_ => Err(InvalidRoomFormat),
|
_ => Err(InvalidRoomFormat),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn to_string(&self) -> String {
|
impl Display for RoomFormat {
|
||||||
match &self {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
RoomFormat::Contiguous => "0",
|
write!(f, "{}", match &self {
|
||||||
RoomFormat::CommaSeparated => "1",
|
RoomFormat::Contiguous => 0,
|
||||||
}.to_string()
|
RoomFormat::CommaSeparated => 1,
|
||||||
|
}.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,12 +43,13 @@ impl RoomFormat {
|
|||||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||||
pub enum RoomType {Room, Set}
|
pub enum RoomType {Room, Set}
|
||||||
|
|
||||||
impl ToString for RoomType {
|
impl Display for RoomType {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match &self {
|
let str = match &self {
|
||||||
RoomType::Set => "SET",
|
RoomType::Set => "SET",
|
||||||
RoomType::Room => "ROOM",
|
RoomType::Room => "ROOM",
|
||||||
}.to_string()
|
}.to_string();
|
||||||
|
write!(f, "{}", str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,38 +60,56 @@ pub struct Version {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InvalidVersion;
|
pub enum VersionError {
|
||||||
|
MissingParts,
|
||||||
|
ExtraneousParts,
|
||||||
|
MalformedInteger,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for VersionError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", match self {
|
||||||
|
VersionError::MissingParts => "Not enough parts supplied for version",
|
||||||
|
VersionError::ExtraneousParts => "Too many parts supplied for version",
|
||||||
|
VersionError::MalformedInteger => "Version did not contain valid integers",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for VersionError {}
|
||||||
|
|
||||||
impl Version {
|
impl Version {
|
||||||
fn from(str: &str) -> Result<Version, InvalidVersion> {
|
fn from(str: &str) -> Result<Version, VersionError> {
|
||||||
let parts: Vec<&str> = str.split(".").collect();
|
let parts: Vec<&str> = str.split('.').collect();
|
||||||
if parts.len() == 2 {
|
|
||||||
Ok(Version {
|
|
||||||
major: parts[0].parse().unwrap(),
|
|
||||||
minor: parts[1].parse().unwrap(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Err (InvalidVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
if parts.len() < 2 {
|
||||||
pub enum NotFound {
|
Err(VersionError::MissingParts)
|
||||||
Avatar,
|
} else if parts.len() > 2 {
|
||||||
Room,
|
Err(VersionError::ExtraneousParts)
|
||||||
Sprite,
|
} else if let (Ok(major), Ok(minor)) = (parts[0].parse(), parts[1].parse()) {
|
||||||
Tile,
|
Ok(Version { major, minor })
|
||||||
|
} else {
|
||||||
|
Err(VersionError::MalformedInteger)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub version: Option<Version>,
|
pub version: Option<Version>,
|
||||||
|
/// it's a bit weird that we have the version twice now, but whatever. only in 8.0+
|
||||||
|
pub version_major: Option<u8>,
|
||||||
|
pub version_minor: Option<u8>,
|
||||||
pub room_format: Option<RoomFormat>,
|
pub room_format: Option<RoomFormat>,
|
||||||
|
/// not sure what this does, could be either a boolean or an int
|
||||||
|
pub dialogue_compatibility: Option<usize>,
|
||||||
|
/// not sure what this does, could be either a boolean or an int
|
||||||
|
pub text_mode: Option<usize>,
|
||||||
pub(crate) room_type: RoomType,
|
pub(crate) room_type: RoomType,
|
||||||
pub font: Font,
|
pub font: Font,
|
||||||
pub custom_font: Option<String>, // used if font is Font::Custom
|
/// used if font is `Font::Custom`
|
||||||
|
pub custom_font: Option<String>,
|
||||||
pub text_direction: TextDirection,
|
pub text_direction: TextDirection,
|
||||||
pub palettes: Vec<Palette>,
|
pub palettes: Vec<Palette>,
|
||||||
pub rooms: Vec<Room>,
|
pub rooms: Vec<Room>,
|
||||||
@@ -92,24 +119,30 @@ pub struct Game {
|
|||||||
pub dialogues: Vec<Dialogue>,
|
pub dialogues: Vec<Dialogue>,
|
||||||
pub endings: Vec<Ending>,
|
pub endings: Vec<Ending>,
|
||||||
pub variables: Vec<Variable>,
|
pub variables: Vec<Variable>,
|
||||||
|
pub tunes: Vec<Tune>,
|
||||||
|
pub blips: Vec<Blip>,
|
||||||
pub font_data: Option<String>, // todo make this an actual struct for parsing
|
pub font_data: Option<String>, // todo make this an actual struct for parsing
|
||||||
pub(crate) line_endings_crlf: bool, // otherwise lf (unix/mac)
|
/// true if CRLF (Windows), otherwise LF (unix/mac)
|
||||||
|
/// todo use the enum?
|
||||||
|
pub(crate) line_endings_crlf: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct GameHasNoAvatar;
|
|
||||||
// todo no tiles? no rooms? no palettes? turn this into an enum?
|
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
pub fn from(string: String) -> Result<Game, NotFound> {
|
pub fn from(string: String) -> Result<(Game, Vec<Error>), NotFound> {
|
||||||
|
if string.trim() == "" {
|
||||||
|
return Err(NotFound::Anything);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut warnings = Vec::new();
|
||||||
|
|
||||||
let line_endings_crlf = string.contains("\r\n");
|
let line_endings_crlf = string.contains("\r\n");
|
||||||
let mut string = string;
|
let mut string = string;
|
||||||
if line_endings_crlf {
|
if line_endings_crlf {
|
||||||
string = transform_line_endings(string, TransformMode::LF)
|
string = transform_line_endings(string, TransformMode::Lf)
|
||||||
}
|
}
|
||||||
|
|
||||||
let string = string.trim_start_matches("\n").to_string();
|
let string = string.trim_start_matches('\n').to_string();
|
||||||
let mut segments = segments_from_string(string);
|
let mut segments = crate::segments_from_str(&string);
|
||||||
|
|
||||||
let mut name = "".to_string();
|
let mut name = "".to_string();
|
||||||
|
|
||||||
@@ -145,7 +178,11 @@ impl Game {
|
|||||||
let mut font_data: Option<String> = None;
|
let mut font_data: Option<String> = None;
|
||||||
|
|
||||||
let mut version = None;
|
let mut version = None;
|
||||||
|
let mut version_major = None;
|
||||||
|
let mut version_minor = None;
|
||||||
let mut room_format = None;
|
let mut room_format = None;
|
||||||
|
let mut dialogue_compatibility = None;
|
||||||
|
let mut text_mode = None;
|
||||||
let mut room_type = RoomType::Room;
|
let mut room_type = RoomType::Room;
|
||||||
let mut font = Font::AsciiSmall;
|
let mut font = Font::AsciiSmall;
|
||||||
let mut custom_font = None;
|
let mut custom_font = None;
|
||||||
@@ -157,18 +194,55 @@ impl Game {
|
|||||||
let mut items: Vec<Item> = Vec::new();
|
let mut items: Vec<Item> = Vec::new();
|
||||||
let mut avatar_exists = false;
|
let mut avatar_exists = false;
|
||||||
|
|
||||||
|
// todo can we use multithreading here?
|
||||||
for segment in segments {
|
for segment in segments {
|
||||||
if segment.starts_with("# BITSY VERSION") {
|
if segment.starts_with("# BITSY VERSION") {
|
||||||
let segment = segment.replace("# BITSY VERSION ", "");
|
let segment = segment.replace("# BITSY VERSION ", "");
|
||||||
let segment = Version::from(&segment);
|
let result = Version::from(&segment);
|
||||||
if segment.is_ok() {
|
|
||||||
version = Some(segment.unwrap());
|
if let Ok(v) = result {
|
||||||
|
version = Some(v);
|
||||||
|
} else {
|
||||||
|
warnings.push(Error::Version);
|
||||||
}
|
}
|
||||||
} else if segment.starts_with("! ROOM_FORMAT") {
|
} else if segment.starts_with("! ") {
|
||||||
let segment = segment.replace("! ROOM_FORMAT ", "");
|
// this is (potentially?) an entire block,
|
||||||
room_format = Some(
|
// so we need to split it into lines and deal with the lines individually
|
||||||
RoomFormat::from(&segment).unwrap_or(RoomFormat::CommaSeparated)
|
for line in segment.lines() {
|
||||||
|
if line.starts_with("! VER_MAJ") {
|
||||||
|
let line = line.replace("! VER_MAJ ", "");
|
||||||
|
|
||||||
|
version_major = Some(
|
||||||
|
line.parse().expect("Couldn't parse major version")
|
||||||
);
|
);
|
||||||
|
} else if line.starts_with("! VER_MIN") {
|
||||||
|
let line = line.replace("! VER_MIN ", "");
|
||||||
|
|
||||||
|
version_minor = Some(
|
||||||
|
line.parse().expect("Couldn't parse minor version")
|
||||||
|
);
|
||||||
|
} else if line.starts_with("! ROOM_FORMAT") {
|
||||||
|
let line = line.replace("! ROOM_FORMAT ", "");
|
||||||
|
|
||||||
|
room_format = Some(
|
||||||
|
RoomFormat::from(&line).unwrap_or(RoomFormat::CommaSeparated)
|
||||||
|
);
|
||||||
|
} else if line.starts_with("! DLG_COMPAT") {
|
||||||
|
let line = line.replace("! DLG_COMPAT ", "");
|
||||||
|
|
||||||
|
// not sure if this is supposed to be a boolean or a version number
|
||||||
|
dialogue_compatibility = Some(
|
||||||
|
line.parse().expect("Couldn't parse dialogue compatibility")
|
||||||
|
);
|
||||||
|
} else if line.starts_with("! TXT_MODE") {
|
||||||
|
let line = line.replace("! TXT_MODE ", "");
|
||||||
|
|
||||||
|
// not sure if this is supposed to be a boolean or a version number
|
||||||
|
text_mode = Some(
|
||||||
|
line.parse().expect("Couldn't parse text mode")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if segment.starts_with("DEFAULT_FONT") {
|
} else if segment.starts_with("DEFAULT_FONT") {
|
||||||
let segment = segment.replace("DEFAULT_FONT ", "");
|
let segment = segment.replace("DEFAULT_FONT ", "");
|
||||||
|
|
||||||
@@ -177,10 +251,16 @@ impl Game {
|
|||||||
if font == Font::Custom {
|
if font == Font::Custom {
|
||||||
custom_font = Some(segment.to_string());
|
custom_font = Some(segment.to_string());
|
||||||
}
|
}
|
||||||
} else if segment.trim() == "TEXT_DIRECTION RTL".to_string() {
|
} else if segment.trim() == "TEXT_DIRECTION RTL" {
|
||||||
text_direction = TextDirection::RightToLeft;
|
text_direction = TextDirection::RightToLeft;
|
||||||
} else if segment.starts_with("PAL ") {
|
} else if segment.starts_with("PAL ") {
|
||||||
palettes.push(Palette::from(segment));
|
let result = Palette::from_str(&segment);
|
||||||
|
if let Ok((palette, mut errors)) = result {
|
||||||
|
palettes.push(palette);
|
||||||
|
warnings.append(&mut errors);
|
||||||
|
} else {
|
||||||
|
warnings.push(result.unwrap_err());
|
||||||
|
}
|
||||||
} else if segment.starts_with("ROOM ") || segment.starts_with("SET ") {
|
} else if segment.starts_with("ROOM ") || segment.starts_with("SET ") {
|
||||||
if segment.starts_with("SET ") {
|
if segment.starts_with("SET ") {
|
||||||
room_type = RoomType::Set;
|
room_type = RoomType::Set;
|
||||||
@@ -189,22 +269,39 @@ impl Game {
|
|||||||
} else if segment.starts_with("TIL ") {
|
} else if segment.starts_with("TIL ") {
|
||||||
tiles.push(Tile::from(segment));
|
tiles.push(Tile::from(segment));
|
||||||
} else if segment.starts_with("SPR ") {
|
} else if segment.starts_with("SPR ") {
|
||||||
let sprite = Sprite::from(segment);
|
let result = Sprite::from_str(&segment);
|
||||||
if sprite.is_ok() {
|
|
||||||
let sprite = sprite.unwrap();
|
if let Ok(sprite) = result {
|
||||||
if ! avatar_exists && sprite.id == "A".to_string() {
|
avatar_exists |= sprite.id == "A";
|
||||||
avatar_exists = true;
|
|
||||||
}
|
|
||||||
sprites.push(sprite);
|
sprites.push(sprite);
|
||||||
|
} else {
|
||||||
|
warnings.push(result.unwrap_err());
|
||||||
}
|
}
|
||||||
} else if segment.starts_with("ITM ") {
|
} else if segment.starts_with("ITM ") {
|
||||||
items.push(Item::from(segment));
|
let result = Item::from_str(&segment);
|
||||||
|
|
||||||
|
if let Ok((item, mut item_warnings)) = result {
|
||||||
|
items.push(item);
|
||||||
|
warnings.append(&mut item_warnings);
|
||||||
|
} else {
|
||||||
|
warnings.push(result.unwrap_err());
|
||||||
|
}
|
||||||
} else if segment.starts_with("DLG ") {
|
} else if segment.starts_with("DLG ") {
|
||||||
dialogues.push(Dialogue::from(segment));
|
let result = Dialogue::from_str(&segment);
|
||||||
|
|
||||||
|
if let Ok(dialogue) = result {
|
||||||
|
dialogues.push(dialogue);
|
||||||
|
} else {
|
||||||
|
warnings.push(result.unwrap_err());
|
||||||
|
}
|
||||||
} else if segment.starts_with("END ") {
|
} else if segment.starts_with("END ") {
|
||||||
let ending = Ending::from_str(&segment);
|
let result = Ending::from_str(&segment);
|
||||||
if ending.is_ok() {
|
|
||||||
endings.push(ending.unwrap());
|
if let Ok(ending) = result {
|
||||||
|
endings.push(ending);
|
||||||
|
} else {
|
||||||
|
warnings.push(result.unwrap_err());
|
||||||
}
|
}
|
||||||
} else if segment.starts_with("VAR ") {
|
} else if segment.starts_with("VAR ") {
|
||||||
variables.push(Variable::from(segment));
|
variables.push(Variable::from(segment));
|
||||||
@@ -214,14 +311,19 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ! avatar_exists {
|
if ! avatar_exists {
|
||||||
return Err(NotFound::Avatar);
|
warnings.push(Error::Game { missing: NotFound::Avatar });
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(
|
Ok(
|
||||||
|
(
|
||||||
Game {
|
Game {
|
||||||
name,
|
name,
|
||||||
version,
|
version,
|
||||||
|
version_major,
|
||||||
|
version_minor,
|
||||||
room_format,
|
room_format,
|
||||||
|
dialogue_compatibility,
|
||||||
|
text_mode,
|
||||||
room_type,
|
room_type,
|
||||||
font,
|
font,
|
||||||
custom_font,
|
custom_font,
|
||||||
@@ -234,9 +336,13 @@ impl Game {
|
|||||||
dialogues,
|
dialogues,
|
||||||
endings,
|
endings,
|
||||||
variables,
|
variables,
|
||||||
|
tunes: vec![],
|
||||||
|
blips: vec![],
|
||||||
font_data,
|
font_data,
|
||||||
line_endings_crlf,
|
line_endings_crlf,
|
||||||
}
|
},
|
||||||
|
warnings
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,10 +352,9 @@ impl Game {
|
|||||||
|sprite| sprite.id == id
|
|sprite| sprite.id == id
|
||||||
);
|
);
|
||||||
|
|
||||||
if index.is_some() {
|
match index {
|
||||||
Ok(&self.sprites[index.unwrap()])
|
Some(index) => Ok(&self.sprites[index]),
|
||||||
} else {
|
None => Err(NotFound::Sprite),
|
||||||
Err(NotFound::Sprite)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,10 +363,9 @@ impl Game {
|
|||||||
|tile| tile.id == id
|
|tile| tile.id == id
|
||||||
);
|
);
|
||||||
|
|
||||||
if index.is_some() {
|
match index {
|
||||||
Ok(&self.tiles[index.unwrap()])
|
Some(index) => Ok(&self.tiles[index]),
|
||||||
} else {
|
None => Err(NotFound::Tile),
|
||||||
Err(NotFound::Tile)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,10 +374,9 @@ impl Game {
|
|||||||
|room| room.id == id
|
|room| room.id == id
|
||||||
);
|
);
|
||||||
|
|
||||||
if index.is_some() {
|
match index {
|
||||||
Ok(&self.rooms[index.unwrap()])
|
Some(index) => Ok(&self.rooms[index]),
|
||||||
} else {
|
None => Err(NotFound::Room),
|
||||||
Err(NotFound::Room)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,9 +389,8 @@ impl Game {
|
|||||||
let mut tiles: Vec<&Tile> = Vec::new();
|
let mut tiles: Vec<&Tile> = Vec::new();
|
||||||
|
|
||||||
for id in ids {
|
for id in ids {
|
||||||
let tile = self.get_tile_by_id(id);
|
if let Ok(tile) = self.get_tile_by_id(id) {
|
||||||
if tile.is_ok() {
|
tiles.push(tile);
|
||||||
tiles.push(tile.unwrap());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,25 +398,22 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tiles_for_room(&self, id: String) -> Result<Vec<&Tile>, NotFound> {
|
pub fn get_tiles_for_room(&self, id: String) -> Result<Vec<&Tile>, NotFound> {
|
||||||
let room = self.get_room_by_id(id);
|
let room = self.get_room_by_id(id)?;
|
||||||
if room.is_err() {
|
let mut tile_ids = room.tiles.clone();
|
||||||
return Err(NotFound::Room);
|
|
||||||
}
|
|
||||||
let mut tile_ids = room.unwrap().tiles.clone();
|
|
||||||
tile_ids.sort();
|
tile_ids.sort();
|
||||||
tile_ids.dedup();
|
tile_ids.dedup();
|
||||||
// remove 0 as this isn't a real tile
|
|
||||||
let zero_index = tile_ids.iter()
|
// remove "0" as this isn't a real tile
|
||||||
.position(|i| i == &"0".to_string());
|
if let Some(zero_index) = tile_ids.iter().position(|i| i == "0") {
|
||||||
if zero_index.is_some() {
|
tile_ids.remove(zero_index);
|
||||||
tile_ids.remove(zero_index.unwrap());
|
|
||||||
}
|
}
|
||||||
// remove Ok once this function returns a result
|
|
||||||
|
// todo remove Ok once get_tiles_by_ids returns a Result
|
||||||
Ok(self.get_tiles_by_ids(tile_ids))
|
Ok(self.get_tiles_by_ids(tile_ids))
|
||||||
}
|
}
|
||||||
|
|
||||||
// return? array of changes made? error/ok?
|
// return? array of changes made? error/ok?
|
||||||
pub fn merge(&mut self, game: Game) {
|
pub fn merge(&mut self, game: &Game) {
|
||||||
// ignore title, version, room format, room type, font, text direction
|
// ignore title, version, room format, room type, font, text direction
|
||||||
|
|
||||||
let mut palette_id_changes: HashMap<String, String> = HashMap::new();
|
let mut palette_id_changes: HashMap<String, String> = HashMap::new();
|
||||||
@@ -402,11 +501,9 @@ impl Game {
|
|||||||
item.id = item_id_changes[&item.id].clone();
|
item.id = item_id_changes[&item.id].clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
if item.dialogue_id.is_some() {
|
if let Some(key) = item.dialogue_id.clone() {
|
||||||
let key = item.dialogue_id.clone().unwrap();
|
if let Some(change) = dialogue_id_changes.get(&key) {
|
||||||
let change = dialogue_id_changes.get(&key);
|
item.dialogue_id = Some(change.clone());
|
||||||
if change.is_some() {
|
|
||||||
item.dialogue_id = Some(change.unwrap().clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,7 +514,7 @@ impl Game {
|
|||||||
// to insert any new room, we need to know the new IDs of every room
|
// to insert any new room, we need to know the new IDs of every room
|
||||||
// to maintain the integrity of exits and endings
|
// to maintain the integrity of exits and endings
|
||||||
|
|
||||||
let mut all_room_ids = self.room_ids().clone();
|
let mut all_room_ids = self.room_ids();
|
||||||
|
|
||||||
for room in &game.rooms {
|
for room in &game.rooms {
|
||||||
let old = room.id.clone();
|
let old = room.id.clone();
|
||||||
@@ -431,16 +528,13 @@ impl Game {
|
|||||||
for room in &game.rooms {
|
for room in &game.rooms {
|
||||||
let mut room = room.clone();
|
let mut room = room.clone();
|
||||||
|
|
||||||
let room_id_change = room_id_changes.get(&room.id);
|
if let Some(room_id_change) = room_id_changes.get(&room.id) {
|
||||||
if room_id_change.is_some() {
|
room.id = room_id_change.clone();
|
||||||
room.id = room_id_change.unwrap().clone();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if room.palette_id.is_some() {
|
if let Some(key) = room.palette_id.clone() {
|
||||||
let key = room.palette_id.clone().unwrap();
|
if let Some(change) = palette_id_changes.get(&key) {
|
||||||
let change = palette_id_changes.get(&key);
|
room.palette_id = Some(change.clone());
|
||||||
if change.is_some() {
|
|
||||||
room.palette_id = Some(change.unwrap().clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,16 +555,14 @@ impl Game {
|
|||||||
let mut exit = exit.clone();
|
let mut exit = exit.clone();
|
||||||
|
|
||||||
let key = exit.exit.room_id.clone();
|
let key = exit.exit.room_id.clone();
|
||||||
let change = room_id_changes.get(&key);
|
|
||||||
if change.is_some() {
|
if let Some(change) = room_id_changes.get(&key) {
|
||||||
exit.exit.room_id = change.unwrap().clone();
|
exit.exit.room_id = change.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
if exit.dialogue_id.is_some() {
|
if let Some(key) = exit.dialogue_id.clone() {
|
||||||
let key = exit.dialogue_id.clone().unwrap();
|
if let Some(dialogue_change) = dialogue_id_changes.get(&key) {
|
||||||
let dialogue_change = dialogue_id_changes.get(&key);
|
exit.dialogue_id = Some(dialogue_change.clone());
|
||||||
if dialogue_change.is_some() {
|
|
||||||
exit.dialogue_id = Some(dialogue_change.unwrap().clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,37 +572,35 @@ impl Game {
|
|||||||
room.endings = room.endings.iter().map(|ending| {
|
room.endings = room.endings.iter().map(|ending| {
|
||||||
let mut ending = ending.clone();
|
let mut ending = ending.clone();
|
||||||
let key = ending.id.clone();
|
let key = ending.id.clone();
|
||||||
let change = ending_id_changes.get(&key);
|
|
||||||
if change.is_some() {
|
if let Some(change) = ending_id_changes.get(&key) {
|
||||||
ending.id = change.unwrap().clone();
|
ending.id = change.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
ending
|
ending
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
self.add_room(room);
|
self.add_room(room);
|
||||||
}
|
}
|
||||||
|
|
||||||
// a sprite has a dialogue ID, so we need to handle these after dialogues
|
// a sprite has a dialogue ID, so we need to handle sprites after dialogues
|
||||||
// a sprite has a position in a room, so we need to handle these after the rooms
|
// a sprite has a position in a room, so we need to handle sprites after rooms
|
||||||
for sprite in &game.sprites {
|
for sprite in &game.sprites {
|
||||||
let mut sprite = sprite.clone();
|
let mut sprite = sprite.clone();
|
||||||
// avoid having two avatars
|
// avoid having two avatars
|
||||||
if sprite.id == "A".to_string() {
|
if sprite.id == "A" {
|
||||||
sprite.id = "0".to_string(); // just a default value for replacement
|
sprite.id = "0".to_string(); // just a default value for later replacement
|
||||||
}
|
}
|
||||||
|
|
||||||
if sprite.dialogue_id.is_some() {
|
if let Some(key) = sprite.dialogue_id.clone() {
|
||||||
let key = sprite.dialogue_id.clone().unwrap();
|
|
||||||
if dialogue_id_changes.contains_key(&key) {
|
if dialogue_id_changes.contains_key(&key) {
|
||||||
sprite.dialogue_id = Some(dialogue_id_changes[&key].clone());
|
sprite.dialogue_id = Some(dialogue_id_changes[&key].clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sprite.room_id.is_some() {
|
if let Some(key) = sprite.room_id.clone() {
|
||||||
let key = sprite.room_id.clone().unwrap();
|
if let Some(change) = room_id_changes.get(&key) {
|
||||||
let change = room_id_changes.get(&key);
|
sprite.room_id = Some(change.clone());
|
||||||
if change.is_some() {
|
|
||||||
sprite.room_id = Some(change.unwrap().clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,8 +611,8 @@ impl Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Game {
|
impl Display for Game {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let mut segments: Vec<String> = Vec::new();
|
let mut segments: Vec<String> = Vec::new();
|
||||||
|
|
||||||
// todo refactor
|
// todo refactor
|
||||||
@@ -548,7 +638,9 @@ impl ToString for Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for dialogue in &self.dialogues {
|
for dialogue in &self.dialogues {
|
||||||
// this replacement is silly but see segments_from_string() for explanation
|
// some dialogues are multiline (starting/ending with `"""`) but have no contents
|
||||||
|
// and this kinda messes things up when trying to export unmodified dialogues
|
||||||
|
// in their original format for testing purposes
|
||||||
segments.push(dialogue.to_string().replace("\"\"\"\n\"\"\"", ""));
|
segments.push(dialogue.to_string().replace("\"\"\"\n\"\"\"", ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,18 +656,23 @@ impl ToString for Game {
|
|||||||
segments.push(self.font_data.to_owned().unwrap())
|
segments.push(self.font_data.to_owned().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
transform_line_endings(
|
let str = transform_line_endings(
|
||||||
format!(
|
format!(
|
||||||
"{}{}{}{}{}\n\n{}\n\n",
|
"{}{}{}{}{}{}{}{}{}\n\n{}\n\n",
|
||||||
&self.name,
|
&self.name,
|
||||||
&self.version_line(),
|
&self.version_line(),
|
||||||
&self.room_format_line(),
|
&self.version_major_line(),
|
||||||
|
&self.version_minor_line(),
|
||||||
|
&self.dialogue_compatibility_line(),
|
||||||
|
&self.text_mode_line(),
|
||||||
|
&self.version_minor_line(),
|
||||||
&self.font_line(),
|
&self.font_line(),
|
||||||
&self.text_direction_line(),
|
&self.text_direction_line(),
|
||||||
segments.join("\n\n"),
|
segments.join("\n\n"),
|
||||||
),
|
),
|
||||||
if self.line_endings_crlf {TransformMode::CRLF} else {TransformMode::LF}
|
if self.line_endings_crlf { TransformMode::Crlf } else { TransformMode::Lf }
|
||||||
)
|
);
|
||||||
|
write!(f, "{}", str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,6 +689,7 @@ impl Game {
|
|||||||
pub fn sprite_ids(&self) -> Vec<String> {
|
pub fn sprite_ids(&self) -> Vec<String> {
|
||||||
self.sprites.iter().map(|sprite| sprite.id.clone()).collect()
|
self.sprites.iter().map(|sprite| sprite.id.clone()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn room_ids(&self) -> Vec<String> {
|
pub fn room_ids(&self) -> Vec<String> {
|
||||||
self.rooms.iter().map(|room| room.id.clone()).collect()
|
self.rooms.iter().map(|room| room.id.clone()).collect()
|
||||||
}
|
}
|
||||||
@@ -652,6 +750,10 @@ impl Game {
|
|||||||
new_unique_id(self.variable_ids())
|
new_unique_id(self.variable_ids())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_palette(&self, id: &str) -> Option<&Palette> {
|
||||||
|
self.palettes.iter().find(|palette| palette.id == id)
|
||||||
|
}
|
||||||
|
|
||||||
/// todo refactor?
|
/// todo refactor?
|
||||||
pub fn get_tile_id(&self, matching_tile: &Tile) -> Option<String> {
|
pub fn get_tile_id(&self, matching_tile: &Tile) -> Option<String> {
|
||||||
for tile in &self.tiles {
|
for tile in &self.tiles {
|
||||||
@@ -663,8 +765,8 @@ impl Game {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_tile_with_animation(&self, animation: &Vec<Image>) -> Option<&Tile> {
|
pub fn find_tile_with_animation(&self, animation: &[Image]) -> Option<&Tile> {
|
||||||
self.tiles.iter().find(|&tile| &tile.animation_frames == animation)
|
self.tiles.iter().find(|&tile| tile.animation_frames.as_slice() == animation)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// adds a palette safely and returns the ID
|
/// adds a palette safely and returns the ID
|
||||||
@@ -679,12 +781,13 @@ impl Game {
|
|||||||
|
|
||||||
/// adds a tile safely and returns the ID
|
/// adds a tile safely and returns the ID
|
||||||
pub fn add_tile(&mut self, mut tile: Tile) -> String {
|
pub fn add_tile(&mut self, mut tile: Tile) -> String {
|
||||||
if tile.id == "0".to_string() || self.tile_ids().contains(&tile.id) {
|
if tile.id == "0" || self.tile_ids().contains(&tile.id) {
|
||||||
let new_id = self.new_tile_id();
|
let new_id = self.new_tile_id();
|
||||||
if new_id != tile.id {
|
if new_id != tile.id {
|
||||||
tile.id = new_id;
|
tile.id = new_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = tile.id.clone();
|
let id = tile.id.clone();
|
||||||
self.tiles.push(tile);
|
self.tiles.push(tile);
|
||||||
id
|
id
|
||||||
@@ -758,7 +861,7 @@ impl Game {
|
|||||||
let mut unique_tiles: Vec<Tile> = Vec::new();
|
let mut unique_tiles: Vec<Tile> = Vec::new();
|
||||||
let mut tile_id_changes: HashMap<String, String> = HashMap::new();
|
let mut tile_id_changes: HashMap<String, String> = HashMap::new();
|
||||||
|
|
||||||
while tiles_temp.len() > 0 {
|
while !tiles_temp.is_empty() {
|
||||||
let tile = tiles_temp.pop().unwrap();
|
let tile = tiles_temp.pop().unwrap();
|
||||||
|
|
||||||
if tile == crate::mock::tile_background() {
|
if tile == crate::mock::tile_background() {
|
||||||
@@ -786,38 +889,66 @@ impl Game {
|
|||||||
if self.version.is_some() {
|
if self.version.is_some() {
|
||||||
format!(
|
format!(
|
||||||
"\n\n# BITSY VERSION {}.{}",
|
"\n\n# BITSY VERSION {}.{}",
|
||||||
self.version.as_ref().unwrap().major, self.version.as_ref().unwrap().minor
|
self.version.as_ref().unwrap().major.to_string(),
|
||||||
|
self.version.as_ref().unwrap().minor.to_string()
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn version_major_line(&self) -> String {
|
||||||
|
if self.version_major.is_some() {
|
||||||
|
format!("\n! VER_MAJ {}", self.version_major.unwrap().to_string())
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version_minor_line(&self) -> String {
|
||||||
|
if self.version_minor.is_some() {
|
||||||
|
format!("\n! VER_MIN {}", self.version_minor.unwrap().to_string())
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn room_format_line(&self) -> String {
|
fn room_format_line(&self) -> String {
|
||||||
if self.room_format.is_some() {
|
if self.room_format.is_some() {
|
||||||
format!("\n\n! ROOM_FORMAT {}", self.room_format.unwrap().to_string())
|
format!("\n! ROOM_FORMAT {}", self.room_format.unwrap().to_string())
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dialogue_compatibility_line(&self) -> String {
|
||||||
|
if self.dialogue_compatibility.is_some() {
|
||||||
|
format!("\n! DLG_COMPAT {}", self.dialogue_compatibility.unwrap().to_string())
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text_mode_line(&self) -> String {
|
||||||
|
if self.text_mode.is_some() {
|
||||||
|
format!("\n! TXT_MODE {}", self.text_mode.unwrap().to_string())
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn font_line(&self) -> String {
|
fn font_line(&self) -> String {
|
||||||
if self.font == Font::AsciiSmall {
|
match self.font {
|
||||||
"".to_string()
|
Font::AsciiSmall => "".to_string(),
|
||||||
} else {
|
Font::Custom => format!("\n\nDEFAULT_FONT {}", self.custom_font.as_ref().unwrap()),
|
||||||
if self.font == Font::Custom {
|
_ => format!("\n\nDEFAULT_FONT {}", self.font.to_string().unwrap()),
|
||||||
format!("\n\nDEFAULT_FONT {}", self.custom_font.as_ref().unwrap())
|
|
||||||
} else {
|
|
||||||
format!("\n\nDEFAULT_FONT {}", self.font.to_string().unwrap())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_direction_line(&self) -> &str {
|
fn text_direction_line(&self) -> &str {
|
||||||
if self.text_direction == TextDirection::RightToLeft {
|
match self.text_direction {
|
||||||
"\n\nTEXT_DIRECTION RTL"
|
TextDirection::RightToLeft => "\n\nTEXT_DIRECTION RTL",
|
||||||
} else {
|
_ => "",
|
||||||
""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -834,14 +965,14 @@ impl Game {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::game::{Version, Game};
|
use crate::{TextDirection, Font, Version, Game, Tile, Image, Palette, Colour};
|
||||||
use crate::text::{TextDirection, Font};
|
|
||||||
use crate::tile::Tile;
|
|
||||||
use crate::image::Image;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn game_from_string() {
|
fn game_from_string() {
|
||||||
let output = Game::from(include_str!["test-resources/default.bitsy"].to_string()).unwrap();
|
let (output, _error) = Game::from(
|
||||||
|
include_str!["test-resources/default.bitsy"].to_string()
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
let expected = crate::mock::game_default();
|
let expected = crate::mock::game_default();
|
||||||
|
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
@@ -873,7 +1004,7 @@ mod test {
|
|||||||
for n in 1..10 {
|
for n in 1..10 {
|
||||||
if n != 4 {
|
if n != 4 {
|
||||||
let mut new_tile = crate::mock::tile_default();
|
let mut new_tile = crate::mock::tile_default();
|
||||||
new_tile.id = format!("{}", n).to_string();
|
new_tile.id = format!("{}", n.to_string()).to_string();
|
||||||
tiles.push(new_tile);
|
tiles.push(new_tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -904,7 +1035,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn arabic() {
|
fn arabic() {
|
||||||
let game = Game::from(include_str!("test-resources/arabic.bitsy").to_string()).unwrap();
|
let (game, _) = Game::from(include_str!("test-resources/arabic.bitsy").to_string()).unwrap();
|
||||||
|
|
||||||
assert_eq!(game.font, Font::Arabic);
|
assert_eq!(game.font, Font::Arabic);
|
||||||
assert_eq!(game.text_direction, TextDirection::RightToLeft);
|
assert_eq!(game.text_direction, TextDirection::RightToLeft);
|
||||||
@@ -942,7 +1073,7 @@ mod test {
|
|||||||
fn merge() {
|
fn merge() {
|
||||||
// try merging two default games
|
// try merging two default games
|
||||||
let mut game = crate::mock::game_default();
|
let mut game = crate::mock::game_default();
|
||||||
game.merge(crate::mock::game_default());
|
game.merge(&crate::mock::game_default());
|
||||||
|
|
||||||
assert_eq!(game.room_ids(), vec!["0".to_string(), "1".to_string()]);
|
assert_eq!(game.room_ids(), vec!["0".to_string(), "1".to_string()]);
|
||||||
assert_eq!(game.tile_ids(), vec!["a".to_string(), "1".to_string()]); // 0 is reserved
|
assert_eq!(game.tile_ids(), vec!["a".to_string(), "1".to_string()]); // 0 is reserved
|
||||||
@@ -981,7 +1112,7 @@ mod test {
|
|||||||
room.id = room_id.clone();
|
room.id = room_id.clone();
|
||||||
sprite.room_id = Some(room_id.clone());
|
sprite.room_id = Some(room_id.clone());
|
||||||
game_b.add_sprite(sprite);
|
game_b.add_sprite(sprite);
|
||||||
game_a.merge(game_b);
|
game_a.merge(&game_b);
|
||||||
assert_eq!(game_a.get_sprite_by_id("2".to_string()).unwrap().room_id, Some(room_id));
|
assert_eq!(game_a.get_sprite_by_id("2".to_string()).unwrap().room_id, Some(room_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1059,4 +1190,28 @@ mod test {
|
|||||||
let expected = Some(&game.tiles[0]);
|
let expected = Some(&game.tiles[0]);
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_game_data_throws_error() {
|
||||||
|
assert_eq!(Game::from("".to_string() ).unwrap_err(), crate::error::NotFound::Anything);
|
||||||
|
assert_eq!(Game::from(" \n \r\n".to_string()).unwrap_err(), crate::error::NotFound::Anything);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_palette() {
|
||||||
|
let mut game = crate::mock::game_default();
|
||||||
|
let new_palette = Palette {
|
||||||
|
id: "1".to_string(),
|
||||||
|
name: Some("sadness".to_string()),
|
||||||
|
colours: vec![
|
||||||
|
Colour { red: 133, green: 131, blue: 111 },
|
||||||
|
Colour { red: 105, green: 93, blue: 104 },
|
||||||
|
Colour { red: 62, green: 74, blue: 76 },
|
||||||
|
]
|
||||||
|
};
|
||||||
|
game.add_palette(new_palette.clone());
|
||||||
|
assert_eq!(game.get_palette("0").unwrap(), &crate::mock::game_default().palettes[0]);
|
||||||
|
assert_eq!(game.get_palette("1").unwrap(), &new_palette);
|
||||||
|
assert_eq!(game.get_palette("2"), None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
90
src/image.rs
90
src/image.rs
@@ -1,3 +1,7 @@
|
|||||||
|
use std::fmt;
|
||||||
|
use crate::Error;
|
||||||
|
use crate::error::ImageError;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Image {
|
pub struct Image {
|
||||||
pub pixels: Vec<u8>, // 64 for SD, 256 for HD
|
pub pixels: Vec<u8>, // 64 for SD, 256 for HD
|
||||||
@@ -49,12 +53,16 @@ impl Image {
|
|||||||
|
|
||||||
self.pixels = pixels;
|
self.pixels = pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn from_str(str: &str) -> Result<(Image, Vec<crate::Error>), crate::Error> {
|
||||||
|
let mut warnings = Vec::new();
|
||||||
|
|
||||||
|
if str.contains("NaN") {
|
||||||
|
warnings.push(crate::Error::Image { err: ImageError::MalformedPixel });
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for Image {
|
let string = str.trim().replace("NaN", "0");
|
||||||
fn from(string: String) -> Image {
|
|
||||||
let string = string.replace("NaN", "0");
|
|
||||||
let string = string.trim();
|
|
||||||
let lines: Vec<&str> = string.lines().collect();
|
let lines: Vec<&str> = string.lines().collect();
|
||||||
let dimension = lines.len();
|
let dimension = lines.len();
|
||||||
let mut pixels: Vec<u8> = Vec::new();
|
let mut pixels: Vec<u8> = Vec::new();
|
||||||
@@ -62,16 +70,30 @@ impl From<String> for Image {
|
|||||||
for line in lines {
|
for line in lines {
|
||||||
let line = &line[..dimension];
|
let line = &line[..dimension];
|
||||||
for char in line.chars().into_iter() {
|
for char in line.chars().into_iter() {
|
||||||
pixels.push(match char {'1' => 1, _ => 0});
|
pixels.push(match char {
|
||||||
|
'0' => 0,
|
||||||
|
'1' => 1,
|
||||||
|
_ => {
|
||||||
|
warnings.push(
|
||||||
|
crate::Error::Image { err: ImageError::MalformedPixel }
|
||||||
|
);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Image { pixels }
|
// 8×8 (normal) or 16×16 (Bitsy HD)
|
||||||
|
if [64, 256].contains(&pixels.len()) {
|
||||||
|
Ok((Image { pixels }, warnings))
|
||||||
|
} else {
|
||||||
|
Err(Error::Image { err: ImageError::WrongSize })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Image {
|
impl fmt::Display for Image {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let mut string = String::new();
|
let mut string = String::new();
|
||||||
|
|
||||||
let sqrt = (self.pixels.len() as f64).sqrt() as usize; // 8 for SD, 16 for HD
|
let sqrt = (self.pixels.len() as f64).sqrt() as usize; // 8 for SD, 16 for HD
|
||||||
@@ -84,26 +106,52 @@ impl ToString for Image {
|
|||||||
|
|
||||||
string.pop(); // remove trailing newline
|
string.pop(); // remove trailing newline
|
||||||
|
|
||||||
string
|
write!(f, "{}", string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn animation_frames_from_string(string: String) -> Vec<Image> {
|
/// todo return Result<(Vec<Image>, Vec<crate::Error>), crate::Error>
|
||||||
let frames: Vec<&str> = string.split(">").collect();
|
pub fn animation_frames_from_str(str: &str) -> Result<(Vec<Image>, Vec<crate::Error>), crate::Error> {
|
||||||
|
let mut warnings: Vec<Error> = Vec::new();
|
||||||
|
|
||||||
frames.iter().map(|&frame| Image::from(frame.to_string())).collect()
|
let results: Vec<Result<Image, crate::Error>> = str
|
||||||
|
.split('>')
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.iter()
|
||||||
|
.map(|&frame| {
|
||||||
|
match Image::from_str(frame) {
|
||||||
|
Ok((frame, mut frame_warnings)) => {
|
||||||
|
warnings.append(&mut frame_warnings);
|
||||||
|
Ok(frame)
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
warnings.push(e.clone());
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// this is a pretty stupid way of filtering the results
|
||||||
|
let mut ok_results = Vec::new();
|
||||||
|
|
||||||
|
for result in results {
|
||||||
|
if let Ok(image) = result {
|
||||||
|
ok_results.push(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((ok_results, warnings))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::image::{Image, animation_frames_from_string};
|
use crate::image::{Image, animation_frames_from_str};
|
||||||
use crate::mock;
|
use crate::mock;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn image_from_string() {
|
fn image_from_string() {
|
||||||
let output = Image::from(
|
let (output, _) = Image::from_str(include_str!("test-resources/image")).unwrap();
|
||||||
include_str!("test-resources/image").to_string()
|
|
||||||
);
|
|
||||||
|
|
||||||
let expected = Image {
|
let expected = Image {
|
||||||
pixels: vec![
|
pixels: vec![
|
||||||
@@ -130,9 +178,9 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_animation_frames_from_string() {
|
fn test_animation_frames_from_string() {
|
||||||
let output = animation_frames_from_string(
|
let output = animation_frames_from_str(
|
||||||
include_str!("test-resources/animation_frames").to_string()
|
include_str!("test-resources/animation_frames")
|
||||||
);
|
).unwrap().0;
|
||||||
|
|
||||||
let expected = mock::image::animation_frames();
|
let expected = mock::image::animation_frames();
|
||||||
|
|
||||||
@@ -143,9 +191,7 @@ mod test {
|
|||||||
/// check that these extraneous pixels are stripped out
|
/// check that these extraneous pixels are stripped out
|
||||||
#[test]
|
#[test]
|
||||||
fn image_out_of_bounds() {
|
fn image_out_of_bounds() {
|
||||||
let output = Image::from(
|
let (output, _) = Image::from_str(include_str!("test-resources/image-oob")).unwrap();
|
||||||
include_str!("test-resources/image-oob").to_string()
|
|
||||||
);
|
|
||||||
|
|
||||||
let expected = Image {
|
let expected = Image {
|
||||||
pixels: vec![
|
pixels: vec![
|
||||||
|
|||||||
54
src/item.rs
54
src/item.rs
@@ -1,5 +1,6 @@
|
|||||||
use crate::{optional_data_line, AnimationFrames, Image};
|
use crate::{optional_data_line, AnimationFrames, Image};
|
||||||
use crate::image::animation_frames_from_string;
|
use crate::image::animation_frames_from_str;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
@@ -8,6 +9,7 @@ pub struct Item {
|
|||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub dialogue_id: Option<String>,
|
pub dialogue_id: Option<String>,
|
||||||
pub colour_id: Option<u64>,
|
pub colour_id: Option<u64>,
|
||||||
|
pub blip: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item {
|
impl Item {
|
||||||
@@ -22,21 +24,32 @@ impl Item {
|
|||||||
fn colour_line(&self) -> String {
|
fn colour_line(&self) -> String {
|
||||||
optional_data_line("COL", self.colour_id.as_ref())
|
optional_data_line("COL", self.colour_id.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn blip_line(&self) -> String {
|
||||||
|
optional_data_line("BLIP", self.blip.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for Item {
|
pub fn from_str(str: &str) -> Result<(Item, Vec<crate::Error>), crate::Error> {
|
||||||
fn from(string: String) -> Item {
|
let mut lines: Vec<&str> = str.lines().collect();
|
||||||
let mut lines: Vec<&str> = string.lines().collect();
|
|
||||||
|
if lines.is_empty() || !lines[0].starts_with("ITM ") {
|
||||||
|
return Err(crate::Error::Item);
|
||||||
|
}
|
||||||
|
|
||||||
let id = lines[0].replace("ITM ", "");
|
let id = lines[0].replace("ITM ", "");
|
||||||
let mut name = None;
|
let mut name = None;
|
||||||
let mut dialogue_id = None;
|
let mut dialogue_id = None;
|
||||||
let mut colour_id: Option<u64> = None;
|
let mut colour_id: Option<u64> = None;
|
||||||
|
let mut blip = None;
|
||||||
|
|
||||||
|
let mut warnings = Vec::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let last_line = lines.pop().unwrap();
|
let last_line = lines.pop().unwrap();
|
||||||
|
|
||||||
if last_line.starts_with("NAME") {
|
if last_line.starts_with("BLIP") {
|
||||||
|
blip = Some(last_line.replace("BLIP ", "").to_string());
|
||||||
|
} else if last_line.starts_with("NAME") {
|
||||||
name = Some(last_line.replace("NAME ", "").to_string());
|
name = Some(last_line.replace("NAME ", "").to_string());
|
||||||
} else if last_line.starts_with("DLG") {
|
} else if last_line.starts_with("DLG") {
|
||||||
dialogue_id = Some(last_line.replace("DLG ", "").to_string());
|
dialogue_id = Some(last_line.replace("DLG ", "").to_string());
|
||||||
@@ -48,41 +61,38 @@ impl From<String> for Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let animation_frames = animation_frames_from_string(
|
let (animation_frames, mut animation_warnings) = animation_frames_from_str(
|
||||||
lines[1..].join("\n")
|
&lines[1..].join("\n")
|
||||||
);
|
).unwrap();
|
||||||
|
|
||||||
Item {
|
warnings.append(&mut animation_warnings);
|
||||||
id,
|
|
||||||
name,
|
Ok((Item { id, name, animation_frames, dialogue_id, colour_id, blip }, warnings))
|
||||||
animation_frames,
|
|
||||||
dialogue_id,
|
|
||||||
colour_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Item {
|
impl fmt::Display for Item {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
format!(
|
write!(
|
||||||
"ITM {}\n{}{}{}{}",
|
f,
|
||||||
|
"ITM {}\n{}{}{}{}{}",
|
||||||
self.id,
|
self.id,
|
||||||
self.animation_frames.to_string(),
|
self.animation_frames.to_string(),
|
||||||
self.name_line(),
|
self.name_line(),
|
||||||
self.dialogue_line(),
|
self.dialogue_line(),
|
||||||
self.colour_line(),
|
self.colour_line(),
|
||||||
|
self.blip_line(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::item::Item;
|
use crate::{Item, mock};
|
||||||
use crate::mock;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn item_from_string() {
|
fn item_from_string() {
|
||||||
let output = Item::from(include_str!("test-resources/item").to_string());
|
let (output, _err) = Item::from_str(include_str!("test-resources/item")).unwrap();
|
||||||
let expected = mock::item();
|
let expected = mock::item();
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
}
|
}
|
||||||
|
|||||||
70
src/lib.rs
70
src/lib.rs
@@ -1,12 +1,16 @@
|
|||||||
extern crate loe;
|
extern crate core;
|
||||||
|
|
||||||
|
use std::fmt::Display;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use radix_fmt::radix_36;
|
use radix_fmt::radix_36;
|
||||||
use loe::{process, Config, TransformMode};
|
use loe::{process, Config, TransformMode};
|
||||||
|
|
||||||
|
pub mod blip;
|
||||||
pub mod colour;
|
pub mod colour;
|
||||||
pub mod dialogue;
|
pub mod dialogue;
|
||||||
pub mod ending;
|
pub mod ending;
|
||||||
|
pub mod error;
|
||||||
pub mod exit;
|
pub mod exit;
|
||||||
pub mod game;
|
pub mod game;
|
||||||
pub mod image;
|
pub mod image;
|
||||||
@@ -19,24 +23,27 @@ pub mod sprite;
|
|||||||
pub mod text;
|
pub mod text;
|
||||||
pub mod tile;
|
pub mod tile;
|
||||||
pub mod variable;
|
pub mod variable;
|
||||||
|
pub mod note;
|
||||||
|
pub mod tune;
|
||||||
|
pub mod test_omnibus;
|
||||||
|
|
||||||
// pub mod test_omnibus;
|
pub use blip::Blip;
|
||||||
|
pub use colour::Colour;
|
||||||
use colour::Colour;
|
pub use dialogue::Dialogue;
|
||||||
use dialogue::Dialogue;
|
pub use ending::Ending;
|
||||||
use ending::Ending;
|
pub use error::Error;
|
||||||
use exit::{Exit, Transition};
|
pub use exit::*;
|
||||||
use game::{Game, Version};
|
pub use game::*;
|
||||||
use image::Image;
|
pub use image::Image;
|
||||||
use item::Item;
|
pub use item::Item;
|
||||||
use palette::Palette;
|
pub use palette::Palette;
|
||||||
use position::Position;
|
pub use position::Position;
|
||||||
use room::Room;
|
pub use room::Room;
|
||||||
use sprite::Sprite;
|
pub use sprite::Sprite;
|
||||||
use std::fmt::Display;
|
pub use text::*;
|
||||||
use text::{Font, TextDirection};
|
pub use tile::Tile;
|
||||||
use tile::Tile;
|
pub use tune::Tune;
|
||||||
use variable::Variable;
|
pub use variable::Variable;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
@@ -46,6 +53,7 @@ pub struct Instance {
|
|||||||
|
|
||||||
/// a Room can have many Exits in different positions,
|
/// a Room can have many Exits in different positions,
|
||||||
/// optionally with a transition and dialogue
|
/// optionally with a transition and dialogue
|
||||||
|
/// todo make a from_str() function for this
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct ExitInstance {
|
pub struct ExitInstance {
|
||||||
position: Position,
|
position: Position,
|
||||||
@@ -63,7 +71,7 @@ impl AnimationFrames for Vec<Image> {
|
|||||||
let mut string = String::new();
|
let mut string = String::new();
|
||||||
let last_frame = self.len() - 1;
|
let last_frame = self.len() - 1;
|
||||||
|
|
||||||
for (i, frame) in self.into_iter().enumerate() {
|
for (i, frame) in self.iter().enumerate() {
|
||||||
string.push_str(&frame.to_string());
|
string.push_str(&frame.to_string());
|
||||||
|
|
||||||
if i < last_frame {
|
if i < last_frame {
|
||||||
@@ -107,11 +115,11 @@ fn transform_line_endings(input: String, mode: TransformMode) -> String {
|
|||||||
String::from_utf8(output.into_inner()).unwrap()
|
String::from_utf8(output.into_inner()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn segments_from_string(string: String) -> Vec<String> {
|
fn segments_from_str(str: &str) -> Vec<String> {
|
||||||
// this is pretty weird but a dialogue can just have an empty line followed by a name
|
// this is pretty weird but a dialogue can just have an empty line followed by a name
|
||||||
// however, on entering two empty lines, dialogue will be wrapped in triple quotation marks
|
// however, on entering two empty lines, dialogue will be wrapped in triple quotation marks
|
||||||
// so, handle this here
|
// so, handle this here
|
||||||
let string = string.replace("\n\nNAME", "\n\"\"\"\n\"\"\"\nNAME");
|
let string = str.replace("\n\nNAME", "\n\"\"\"\n\"\"\"\nNAME");
|
||||||
|
|
||||||
let mut output:Vec<String> = Vec::new();
|
let mut output:Vec<String> = Vec::new();
|
||||||
// are we inside `"""\n...\n"""`? if so, ignore empty lines
|
// are we inside `"""\n...\n"""`? if so, ignore empty lines
|
||||||
@@ -161,7 +169,7 @@ fn new_unique_id(ids: Vec<String>) -> String {
|
|||||||
new_id += 1;
|
new_id += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return to_base36(new_id);
|
to_base36(new_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Quote {
|
pub trait Quote {
|
||||||
@@ -170,7 +178,7 @@ pub trait Quote {
|
|||||||
|
|
||||||
impl Quote for String {
|
impl Quote for String {
|
||||||
fn quote(&self) -> String {
|
fn quote(&self) -> String {
|
||||||
format!("\"\"\"\n{}\n\"\"\"", self).to_string()
|
format!("\"\"\"\n{}\n\"\"\"", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +194,7 @@ impl Unquote for String {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::{ToBase36, optional_data_line, mock, segments_from_string, Quote, Unquote, new_unique_id, try_id};
|
use crate::{ToBase36, optional_data_line, mock, segments_from_str, Quote, Unquote, new_unique_id, try_id};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn to_base36() {
|
fn to_base36() {
|
||||||
@@ -196,14 +204,12 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_optional_data_line() {
|
fn test_optional_data_line() {
|
||||||
let output = optional_data_line("NAME", mock::item().name);
|
let output = optional_data_line("NAME", mock::item().name);
|
||||||
assert_eq!(output, "\nNAME door".to_string());
|
assert_eq!(output, "\nNAME door");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn string_to_segments() {
|
fn string_to_segments() {
|
||||||
let output = segments_from_string(
|
let output = segments_from_str(include_str!("./test-resources/segments"));
|
||||||
include_str!("./test-resources/segments").to_string()
|
|
||||||
);
|
|
||||||
|
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
"\"\"\"\nthe first segment is a long bit of text\n\n\nit contains empty lines\n\n\"\"\"".to_string(),
|
"\"\"\"\nthe first segment is a long bit of text\n\n\nit contains empty lines\n\n\"\"\"".to_string(),
|
||||||
@@ -218,14 +224,14 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn quote() {
|
fn quote() {
|
||||||
let output = "this is a string.\nIt has 2 lines".to_string().quote();
|
let output = "this is a string.\nIt has 2 lines".to_string().quote();
|
||||||
let expected = "\"\"\"\nthis is a string.\nIt has 2 lines\n\"\"\"".to_string();
|
let expected = "\"\"\"\nthis is a string.\nIt has 2 lines\n\"\"\"";
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unquote() {
|
fn unquote() {
|
||||||
let output = "\"\"\"\nwho the fuck is scraeming \"LOG OFF\" at my house.\nshow yourself, coward.\ni will never log off\n\"\"\"".to_string().unquote();
|
let output = "\"\"\"\nwho the fuck is scraeming \"LOG OFF\" at my house.\nshow yourself, coward.\ni will never log off\n\"\"\"".to_string().unquote();
|
||||||
let expected = "who the fuck is scraeming \"LOG OFF\" at my house.\nshow yourself, coward.\ni will never log off".to_string();
|
let expected = "who the fuck is scraeming \"LOG OFF\" at my house.\nshow yourself, coward.\ni will never log off";
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,12 +240,12 @@ mod test {
|
|||||||
// does a conflict generate a new ID?
|
// does a conflict generate a new ID?
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
try_id(&vec!["0".to_string(), "1".to_string()], &"1".to_string()),
|
try_id(&vec!["0".to_string(), "1".to_string()], &"1".to_string()),
|
||||||
"2".to_string()
|
"2"
|
||||||
);
|
);
|
||||||
// with no conflict, does the ID remain the same?
|
// with no conflict, does the ID remain the same?
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
try_id(&vec!["0".to_string(), "1".to_string()], &"3".to_string()),
|
try_id(&vec!["0".to_string(), "1".to_string()], &"3".to_string()),
|
||||||
"3".to_string()
|
"3"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
24
src/mock.rs
24
src/mock.rs
@@ -185,8 +185,7 @@ pub fn sprite() -> Sprite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod item {
|
pub mod item {
|
||||||
use crate::item::Item;
|
use crate::{Image, Item};
|
||||||
use crate::image::Image;
|
|
||||||
|
|
||||||
pub fn key() -> Item {
|
pub fn key() -> Item {
|
||||||
Item {
|
Item {
|
||||||
@@ -205,7 +204,8 @@ pub mod item {
|
|||||||
],
|
],
|
||||||
name: Some("key".to_string()),
|
name: Some("key".to_string()),
|
||||||
dialogue_id: Some("2".to_string()),
|
dialogue_id: Some("2".to_string()),
|
||||||
colour_id: None
|
colour_id: None,
|
||||||
|
blip: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,6 +228,7 @@ pub fn item() -> Item {
|
|||||||
name: Some("door".to_string()),
|
name: Some("door".to_string()),
|
||||||
dialogue_id: Some("2".to_string()),
|
dialogue_id: Some("2".to_string()),
|
||||||
colour_id: None,
|
colour_id: None,
|
||||||
|
blip: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,15 +531,20 @@ pub fn room() -> Room {
|
|||||||
position: Position { x: 8, y: 7 },
|
position: Position { x: 8, y: 7 },
|
||||||
id: "undefined".to_string(),
|
id: "undefined".to_string(),
|
||||||
}],
|
}],
|
||||||
walls: vec![],
|
walls: None,
|
||||||
|
tune: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn game_default() -> Game {
|
pub fn game_default() -> Game {
|
||||||
Game {
|
Game {
|
||||||
name: "Write your game's title here".to_string(),
|
name: "Write your game's title here".to_string(),
|
||||||
version: Some(Version { major: 7, minor: 1 }),
|
version: Some(Version { major: 8, minor: 4 }),
|
||||||
|
version_major: Some(8),
|
||||||
|
version_minor: Some(12),
|
||||||
room_format: Some(RoomFormat::CommaSeparated),
|
room_format: Some(RoomFormat::CommaSeparated),
|
||||||
|
dialogue_compatibility: Some(0),
|
||||||
|
text_mode: Some(0),
|
||||||
room_type: RoomType::Room,
|
room_type: RoomType::Room,
|
||||||
font: Font::AsciiSmall,
|
font: Font::AsciiSmall,
|
||||||
custom_font: None,
|
custom_font: None,
|
||||||
@@ -829,9 +835,10 @@ pub fn game_default() -> Game {
|
|||||||
items: vec![],
|
items: vec![],
|
||||||
exits: vec![],
|
exits: vec![],
|
||||||
endings: vec![],
|
endings: vec![],
|
||||||
walls: vec![],
|
walls: None,
|
||||||
|
tune: None,
|
||||||
}],
|
}],
|
||||||
tiles: vec![self::tile_default()],
|
tiles: vec![tile_default()],
|
||||||
sprites: vec![
|
sprites: vec![
|
||||||
Sprite {
|
Sprite {
|
||||||
id: "A".to_string(),
|
id: "A".to_string(),
|
||||||
@@ -879,6 +886,7 @@ pub fn game_default() -> Game {
|
|||||||
name: Some("tea".to_string()),
|
name: Some("tea".to_string()),
|
||||||
dialogue_id: Some("1".to_string()),
|
dialogue_id: Some("1".to_string()),
|
||||||
colour_id: None,
|
colour_id: None,
|
||||||
|
blip: None,
|
||||||
},
|
},
|
||||||
item::key()
|
item::key()
|
||||||
],
|
],
|
||||||
@@ -904,6 +912,8 @@ pub fn game_default() -> Game {
|
|||||||
id: "a".to_string(),
|
id: "a".to_string(),
|
||||||
initial_value: "42".to_string(),
|
initial_value: "42".to_string(),
|
||||||
}],
|
}],
|
||||||
|
tunes: vec![],
|
||||||
|
blips: vec![],
|
||||||
font_data: None,
|
font_data: None,
|
||||||
line_endings_crlf: false
|
line_endings_crlf: false
|
||||||
}
|
}
|
||||||
|
|||||||
109
src/note.rs
Normal file
109
src/note.rs
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
use core::fmt;
|
||||||
|
use std::fmt::Formatter;
|
||||||
|
use crate::Error;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum RelativeNote {
|
||||||
|
C,
|
||||||
|
CSharp,
|
||||||
|
D,
|
||||||
|
DSharp,
|
||||||
|
E,
|
||||||
|
F,
|
||||||
|
FSharp,
|
||||||
|
G,
|
||||||
|
GSharp,
|
||||||
|
A,
|
||||||
|
ASharp,
|
||||||
|
B,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Note {
|
||||||
|
relative: RelativeNote,
|
||||||
|
octave: u8, // upper limit? 8?
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Note {
|
||||||
|
fn from(str: &str) -> Result<Self, Error> {
|
||||||
|
let mut chars: Vec<char> = str.chars().collect();
|
||||||
|
|
||||||
|
// last char may or may not be present / may or may not be an octave number
|
||||||
|
let octave = chars.pop().unwrap_or('4').to_string().parse().unwrap_or(4);
|
||||||
|
|
||||||
|
let chars: String = chars.into_iter().collect();
|
||||||
|
|
||||||
|
let relative = match chars.as_ref() {
|
||||||
|
"C" => RelativeNote::C,
|
||||||
|
"C#" => RelativeNote::CSharp,
|
||||||
|
"D" => RelativeNote::D,
|
||||||
|
"D#" => RelativeNote::DSharp,
|
||||||
|
"E" => RelativeNote::E,
|
||||||
|
"F" => RelativeNote::F,
|
||||||
|
"F#" => RelativeNote::FSharp,
|
||||||
|
"G" => RelativeNote::G,
|
||||||
|
"G#" => RelativeNote::GSharp,
|
||||||
|
"A" => RelativeNote::A,
|
||||||
|
"A#" => RelativeNote::ASharp,
|
||||||
|
"B" => RelativeNote::B,
|
||||||
|
_ => { return Err(Error::RelativeNote); }
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Note { relative, octave })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Note {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}{}",
|
||||||
|
match self.relative {
|
||||||
|
RelativeNote::C => "C",
|
||||||
|
RelativeNote::CSharp => "C#",
|
||||||
|
RelativeNote::D => "D",
|
||||||
|
RelativeNote::DSharp => "D#",
|
||||||
|
RelativeNote::E => "E",
|
||||||
|
RelativeNote::F => "F",
|
||||||
|
RelativeNote::FSharp => "F#",
|
||||||
|
RelativeNote::G => "G",
|
||||||
|
RelativeNote::GSharp => "G#",
|
||||||
|
RelativeNote::A => "A",
|
||||||
|
RelativeNote::ASharp => "A#",
|
||||||
|
RelativeNote::B => "B",
|
||||||
|
},
|
||||||
|
self.octave
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::note::{Note, RelativeNote};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn c4() {
|
||||||
|
assert_eq!(Note { relative: RelativeNote::C, octave: 4 }.to_string(), "C4");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_sharp_0() {
|
||||||
|
assert_eq!(Note { relative: RelativeNote::ASharp, octave: 0 }.to_string(), "A#0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn c_sharp_3_from_str() {
|
||||||
|
assert_eq!(
|
||||||
|
Note::from("C#3").unwrap(),
|
||||||
|
Note { relative: RelativeNote::CSharp, octave: 3 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn b_0_from_str() {
|
||||||
|
assert_eq!(
|
||||||
|
Note::from("B0").unwrap(),
|
||||||
|
Note { relative: RelativeNote::B, octave: 0 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::colour::Colour;
|
use crate::Colour;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Palette {
|
pub struct Palette {
|
||||||
@@ -7,25 +7,39 @@ pub struct Palette {
|
|||||||
pub colours: Vec<Colour>,
|
pub colours: Vec<Colour>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for Palette {
|
impl Palette {
|
||||||
fn from(string: String) -> Palette {
|
pub fn from_str(s: &str) -> Result<(Palette, Vec<crate::Error>), crate::Error> {
|
||||||
let lines: Vec<&str> = string.lines().collect();
|
let mut lines: Vec<&str> = s.lines().collect();
|
||||||
|
|
||||||
let id = lines[0].replace("PAL ", "");
|
if lines.is_empty() {
|
||||||
|
return Err(crate::Error::Palette);
|
||||||
|
}
|
||||||
|
|
||||||
let name = match lines[1].starts_with("NAME") {
|
let mut id = String::new();
|
||||||
true => Some(lines[1].replace("NAME ", "").to_string()),
|
let mut name = None;
|
||||||
false => None,
|
let mut colours = Vec::new();
|
||||||
};
|
let mut warnings = Vec::new();
|
||||||
|
|
||||||
let colour_start_index = if name.is_some() { 2 } else { 1 };
|
while !lines.is_empty() {
|
||||||
|
let line = lines.pop().unwrap();
|
||||||
|
|
||||||
let colours = lines[colour_start_index..]
|
if line.starts_with("PAL ") {
|
||||||
.iter()
|
id = line.replace("PAL ", "");
|
||||||
.map(|&line| Colour::from(line).unwrap())
|
} else if line.starts_with("NAME ") {
|
||||||
.collect();
|
name = Some(line.replace("NAME ", ""));
|
||||||
|
} else {
|
||||||
|
let result = Colour::from(line);
|
||||||
|
if let Ok(colour) = result {
|
||||||
|
colours.push(colour)
|
||||||
|
} else {
|
||||||
|
warnings.push(result.unwrap_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Palette { id, name, colours }
|
colours.reverse();
|
||||||
|
|
||||||
|
Ok((Palette { id, name, colours }, warnings))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,12 +63,11 @@ impl ToString for Palette {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::colour::Colour;
|
use crate::{Colour, Palette};
|
||||||
use crate::palette::Palette;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn palette_from_string() {
|
fn palette_from_string() {
|
||||||
let output = Palette::from("PAL 1\nNAME lamplight\n45,45,59\n66,60,39\n140,94,1".to_string());
|
let (output, _) = Palette::from_str("PAL 1\nNAME lamplight\n45,45,59\n66,60,39\n140,94,1").unwrap();
|
||||||
|
|
||||||
let expected = Palette {
|
let expected = Palette {
|
||||||
id: "1".to_string(),
|
id: "1".to_string(),
|
||||||
@@ -83,7 +96,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn palette_from_string_no_name() {
|
fn palette_from_string_no_name() {
|
||||||
let output = Palette::from("PAL 9\n45,45,59\n66,60,39\n140,94,1".to_string());
|
let (output, _) = Palette::from_str("PAL 9\n45,45,59\n66,60,39\n140,94,1").unwrap();
|
||||||
|
|
||||||
let expected = Palette {
|
let expected = Palette {
|
||||||
id: "9".to_string(),
|
id: "9".to_string(),
|
||||||
@@ -132,9 +145,9 @@ mod test {
|
|||||||
blue: 128,
|
blue: 128,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}.to_string();
|
||||||
.to_string();
|
|
||||||
let expected = "PAL g\nNAME moss\n1,2,3\n255,254,253\n126,127,128".to_string();
|
let expected = "PAL g\nNAME moss\n1,2,3\n255,254,253\n126,127,128";
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
use std::error::Error;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Position {
|
pub struct Position {
|
||||||
@@ -8,24 +6,17 @@ pub struct Position {
|
|||||||
pub y: u8,
|
pub y: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for Position {}
|
impl Position {
|
||||||
|
pub fn from_str(s: &str) -> Result<Self, crate::Error> {
|
||||||
impl FromStr for Position {
|
|
||||||
type Err = String;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
let mut parts = s.split(',');
|
let mut parts = s.split(',');
|
||||||
let x = parts.next().unwrap().parse();
|
|
||||||
let y = parts.next().unwrap().parse();
|
|
||||||
|
|
||||||
if x.is_err() {
|
let x = parts.next().unwrap();
|
||||||
Err("bad x supplied for position".to_string())
|
let y = parts.next().unwrap();
|
||||||
} else if y.is_err() {
|
|
||||||
Err("bad y supplied for position".to_string())
|
if let (Ok(x), Ok(y)) = (x.parse(), y.parse()) {
|
||||||
} else {
|
|
||||||
let x = x.unwrap();
|
|
||||||
let y = y.unwrap();
|
|
||||||
Ok(Position { x, y })
|
Ok(Position { x, y })
|
||||||
|
} else {
|
||||||
|
Err(crate::Error::Position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,17 +29,21 @@ impl fmt::Display for Position {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::position::Position;
|
use crate::Position;
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn position_from_str() {
|
fn position_from_str() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Position::from_str(&"4,12").unwrap(),
|
Position::from_str("4,12").unwrap(),
|
||||||
Position { x: 4, y: 12 }
|
Position { x: 4, y: 12 }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn position_from_malformed_str() {
|
||||||
|
assert!(Position::from_str("14,-1").is_err())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn position_to_string() {
|
fn position_to_string() {
|
||||||
assert_eq!(Position { x: 4, y: 12 }.to_string(), "4,12".to_string())
|
assert_eq!(Position { x: 4, y: 12 }.to_string(), "4,12".to_string())
|
||||||
|
|||||||
90
src/room.rs
90
src/room.rs
@@ -1,7 +1,14 @@
|
|||||||
use crate::{optional_data_line, Exit, ExitInstance, Instance, Position};
|
use crate::{
|
||||||
use crate::game::{RoomType, RoomFormat};
|
optional_data_line,
|
||||||
use crate::exit::Transition;
|
Exit,
|
||||||
use std::str::FromStr;
|
ExitInstance,
|
||||||
|
Instance,
|
||||||
|
Position,
|
||||||
|
RoomType,
|
||||||
|
RoomFormat,
|
||||||
|
Transition
|
||||||
|
};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
@@ -16,7 +23,8 @@ pub struct Room {
|
|||||||
pub exits: Vec<ExitInstance>,
|
pub exits: Vec<ExitInstance>,
|
||||||
pub endings: Vec<Instance>,
|
pub endings: Vec<Instance>,
|
||||||
/// old method of handling walls - a comma-separated list of tile IDs
|
/// old method of handling walls - a comma-separated list of tile IDs
|
||||||
pub walls: Vec<String>,
|
pub walls: Option<Vec<String>>,
|
||||||
|
pub tune: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Room {
|
impl Room {
|
||||||
@@ -25,18 +33,24 @@ impl Room {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn wall_line(&self) -> String {
|
fn wall_line(&self) -> String {
|
||||||
if self.walls.len() > 0 {
|
if let Some(walls) = &self.walls {
|
||||||
optional_data_line("WAL", Some(self.walls.join(",")))
|
optional_data_line("WAL", Some(walls.join(",")))
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn palette_line(&self) -> String {
|
fn palette_line(&self) -> String {
|
||||||
if self.palette_id.is_some() {
|
match &self.palette_id {
|
||||||
optional_data_line("PAL", Some(self.palette_id.as_ref().unwrap()))
|
Some(id) => optional_data_line("PAL", Some(id.clone())),
|
||||||
} else {
|
None => "".to_string(),
|
||||||
"".to_string()
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tune_line(&self) -> String {
|
||||||
|
match &self.tune {
|
||||||
|
Some(id) => optional_data_line("TUNE", Some(id.clone())),
|
||||||
|
None => "".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,15 +66,18 @@ impl From<String> for Room {
|
|||||||
let mut items: Vec<Instance> = Vec::new();
|
let mut items: Vec<Instance> = Vec::new();
|
||||||
let mut exits: Vec<ExitInstance> = Vec::new();
|
let mut exits: Vec<ExitInstance> = Vec::new();
|
||||||
let mut endings: Vec<Instance> = Vec::new();
|
let mut endings: Vec<Instance> = Vec::new();
|
||||||
let mut walls: Vec<String> = Vec::new();
|
let mut walls = None;
|
||||||
|
let mut tune = None;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let last_line = lines.pop().unwrap();
|
let last_line = lines.pop().unwrap();
|
||||||
|
|
||||||
if last_line.starts_with("WAL") {
|
if last_line.starts_with("TUNE") {
|
||||||
|
tune = Some(last_line.replace("TUNE ", ""));
|
||||||
|
} else if last_line.starts_with("WAL") {
|
||||||
let last_line = last_line.replace("WAL ", "");
|
let last_line = last_line.replace("WAL ", "");
|
||||||
let ids: Vec<&str> = last_line.split(",").collect();
|
let ids: Vec<&str> = last_line.split(',').collect();
|
||||||
walls = ids.iter().map(|&id| id.to_string()).collect();
|
walls = Some(ids.iter().map(|&id| id.to_string()).collect());
|
||||||
} else if last_line.starts_with("NAME") {
|
} else if last_line.starts_with("NAME") {
|
||||||
name = Some(last_line.replace("NAME ", "").to_string());
|
name = Some(last_line.replace("NAME ", "").to_string());
|
||||||
} else if last_line.starts_with("PAL") {
|
} else if last_line.starts_with("PAL") {
|
||||||
@@ -70,10 +87,8 @@ impl From<String> for Room {
|
|||||||
let item_position: Vec<&str> = last_line.split(' ').collect();
|
let item_position: Vec<&str> = last_line.split(' ').collect();
|
||||||
let item_id = item_position[0];
|
let item_id = item_position[0];
|
||||||
let position = item_position[1];
|
let position = item_position[1];
|
||||||
let position = Position::from_str(position);
|
|
||||||
|
|
||||||
if position.is_ok() {
|
if let Ok(position) = Position::from_str(position) {
|
||||||
let position = position.unwrap();
|
|
||||||
items.push(Instance { position, id: item_id.to_string() });
|
items.push(Instance { position, id: item_id.to_string() });
|
||||||
}
|
}
|
||||||
} else if last_line.starts_with("EXT") {
|
} else if last_line.starts_with("EXT") {
|
||||||
@@ -81,24 +96,25 @@ impl From<String> for Room {
|
|||||||
let parts: Vec<&str> = last_line.split(' ').collect();
|
let parts: Vec<&str> = last_line.split(' ').collect();
|
||||||
let position = Position::from_str(parts[0]);
|
let position = Position::from_str(parts[0]);
|
||||||
|
|
||||||
if position.is_ok() {
|
if let Ok(position) = position {
|
||||||
let position = position.unwrap();
|
|
||||||
let exit = Exit::from_str(
|
let exit = Exit::from_str(
|
||||||
&format!("{} {}", parts[1], parts[2])
|
&format!("{} {}", parts[1], parts[2])
|
||||||
);
|
);
|
||||||
|
|
||||||
if exit.is_ok() {
|
if let Ok(exit) = exit {
|
||||||
let exit = exit.unwrap();
|
|
||||||
let mut transition = None;
|
let mut transition = None;
|
||||||
let mut dialogue_id = None;
|
let mut dialogue_id = None;
|
||||||
|
|
||||||
let chunks = parts[3..].chunks(2);
|
let chunks = parts[3..].chunks(2);
|
||||||
|
|
||||||
for chunk in chunks {
|
for chunk in chunks {
|
||||||
if chunk[0] == "FX" {
|
if chunk[0] == "FX" {
|
||||||
transition = Some(Transition::from(chunk[1]));
|
transition = Some(Transition::from_str(chunk[1]).unwrap());
|
||||||
} else if chunk[0] == "DLG" {
|
} else if chunk[0] == "DLG" {
|
||||||
dialogue_id = Some(chunk[1].to_string());
|
dialogue_id = Some(chunk[1].to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exits.push(ExitInstance { position, exit, transition, dialogue_id });
|
exits.push(ExitInstance { position, exit, transition, dialogue_id });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,8 +125,7 @@ impl From<String> for Room {
|
|||||||
let position = ending_position[1];
|
let position = ending_position[1];
|
||||||
let position = Position::from_str(position);
|
let position = Position::from_str(position);
|
||||||
|
|
||||||
if position.is_ok() {
|
if let Ok(position) = position {
|
||||||
let position = position.unwrap();
|
|
||||||
endings.push(Instance { position, id: ending });
|
endings.push(Instance { position, id: ending });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -123,8 +138,8 @@ impl From<String> for Room {
|
|||||||
let dimension = lines.len(); // x or y, e.g. `16` for 16x16
|
let dimension = lines.len(); // x or y, e.g. `16` for 16x16
|
||||||
let mut tiles: Vec<String> = Vec::new();
|
let mut tiles: Vec<String> = Vec::new();
|
||||||
|
|
||||||
for line in lines.into_iter() {
|
for line in lines.iter() {
|
||||||
let comma_separated = line.contains(","); // old room format?
|
let comma_separated = line.contains(','); // old room format?
|
||||||
let mut line: Vec<&str> = line
|
let mut line: Vec<&str> = line
|
||||||
.split(if comma_separated {","} else {""})
|
.split(if comma_separated {","} else {""})
|
||||||
.collect();
|
.collect();
|
||||||
@@ -150,6 +165,7 @@ impl From<String> for Room {
|
|||||||
exits,
|
exits,
|
||||||
endings,
|
endings,
|
||||||
walls,
|
walls,
|
||||||
|
tune,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,8 +189,9 @@ impl Room {
|
|||||||
tiles.pop(); // remove trailing comma
|
tiles.pop(); // remove trailing comma
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles.push_str("\n");
|
tiles.push('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles.pop(); // remove trailing newline
|
tiles.pop(); // remove trailing newline
|
||||||
|
|
||||||
for instance in &self.items {
|
for instance in &self.items {
|
||||||
@@ -190,9 +207,10 @@ impl Room {
|
|||||||
"\nEXT {} {}{}{}{}",
|
"\nEXT {} {}{}{}{}",
|
||||||
instance.position.to_string(),
|
instance.position.to_string(),
|
||||||
instance.exit.to_string(),
|
instance.exit.to_string(),
|
||||||
if instance.transition.is_some() {
|
match &instance.transition {
|
||||||
instance.transition.as_ref().unwrap().to_string()
|
Some(transition) => transition,
|
||||||
} else {"".to_string()},
|
None => &Transition::None,
|
||||||
|
}.to_string(),
|
||||||
if instance.dialogue_id.is_some() {" DLG "} else {""},
|
if instance.dialogue_id.is_some() {" DLG "} else {""},
|
||||||
instance.dialogue_id.as_ref().unwrap_or(&"".to_string()),
|
instance.dialogue_id.as_ref().unwrap_or(&"".to_string()),
|
||||||
));
|
));
|
||||||
@@ -207,7 +225,7 @@ impl Room {
|
|||||||
}
|
}
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
"{} {}\n{}{}{}{}{}{}{}",
|
"{} {}\n{}{}{}{}{}{}{}{}",
|
||||||
room_type.to_string(),
|
room_type.to_string(),
|
||||||
self.id,
|
self.id,
|
||||||
tiles,
|
tiles,
|
||||||
@@ -216,7 +234,8 @@ impl Room {
|
|||||||
items,
|
items,
|
||||||
exits,
|
exits,
|
||||||
endings,
|
endings,
|
||||||
self.palette_line()
|
self.palette_line(),
|
||||||
|
self.tune_line(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,8 +249,7 @@ impl Room {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::room::Room;
|
use crate::{Room, RoomType, RoomFormat};
|
||||||
use crate::game::{RoomType, RoomFormat};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn room_from_string() {
|
fn room_from_string() {
|
||||||
@@ -253,6 +271,6 @@ mod test {
|
|||||||
fn room_walls_array() {
|
fn room_walls_array() {
|
||||||
let output = Room::from(include_str!("test-resources/room-with-walls").to_string());
|
let output = Room::from(include_str!("test-resources/room-with-walls").to_string());
|
||||||
|
|
||||||
assert_eq!(output.walls, vec!["a".to_string(), "f".to_string()]);
|
assert_eq!(output.walls, Some(vec!["a".to_string(), "f".to_string()]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::{optional_data_line, AnimationFrames, Image, Position};
|
use crate::{optional_data_line, AnimationFrames, Image, Position};
|
||||||
use crate::image::animation_frames_from_string;
|
use crate::image::animation_frames_from_str;
|
||||||
use std::str::FromStr;
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Sprite {
|
pub struct Sprite {
|
||||||
@@ -40,23 +41,24 @@ impl Sprite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn item_lines(&self) -> String {
|
fn item_lines(&self) -> String {
|
||||||
if self.items.len() == 0 {
|
if self.items.is_empty() {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
} else {
|
} else {
|
||||||
let lines: Vec<String> = self.items.iter().map(|item| format!("ITM {}", item)).collect();
|
let lines: Vec<String> = self.items.iter().map(
|
||||||
|
|item| format!("ITM {}", item)
|
||||||
|
).collect();
|
||||||
|
|
||||||
format!("\n{}", lines.join("\n"))
|
format!("\n{}", lines.join("\n"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_str(str: &str) -> Result<Sprite, crate::Error> {
|
||||||
|
let mut lines: Vec<&str> = str.lines().collect();
|
||||||
|
|
||||||
|
if lines.is_empty() || !lines[0].starts_with("SPR ") {
|
||||||
|
return Err(crate::Error::Sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SpriteMissingRoomPosition;
|
|
||||||
// todo "malformed sprite ID" or something
|
|
||||||
|
|
||||||
impl Sprite {
|
|
||||||
pub(crate) fn from(string: String) -> Result<Sprite, SpriteMissingRoomPosition> {
|
|
||||||
let mut lines: Vec<&str> = string.lines().collect();
|
|
||||||
|
|
||||||
let id = lines[0].replace("SPR ", "");
|
let id = lines[0].replace("SPR ", "");
|
||||||
let mut name = None;
|
let mut name = None;
|
||||||
let mut dialogue_id: Option<String> = None;
|
let mut dialogue_id: Option<String> = None;
|
||||||
@@ -78,10 +80,14 @@ impl Sprite {
|
|||||||
room_id = Some(room_position[0].to_string());
|
room_id = Some(room_position[0].to_string());
|
||||||
|
|
||||||
if room_position.len() < 2 {
|
if room_position.len() < 2 {
|
||||||
return Err(SpriteMissingRoomPosition);
|
return Err(crate::Error::Sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
position = Some(Position::from_str(room_position[1]).unwrap());
|
if let Ok(pos) = Position::from_str(room_position[1]) {
|
||||||
|
position = Some(pos);
|
||||||
|
} else {
|
||||||
|
return Err(crate::Error::Sprite);
|
||||||
|
}
|
||||||
} else if last_line.starts_with("COL") {
|
} else if last_line.starts_with("COL") {
|
||||||
colour_id = Some(last_line.replace("COL ", "").parse().unwrap());
|
colour_id = Some(last_line.replace("COL ", "").parse().unwrap());
|
||||||
} else if last_line.starts_with("ITM") {
|
} else if last_line.starts_with("ITM") {
|
||||||
@@ -94,9 +100,14 @@ impl Sprite {
|
|||||||
|
|
||||||
items.reverse();
|
items.reverse();
|
||||||
|
|
||||||
let animation_frames = animation_frames_from_string(
|
let animation_frames = match animation_frames_from_str(&lines[1..].join("\n")) {
|
||||||
lines[1..].join("\n")
|
Ok((frames, _warnings)) => {
|
||||||
);
|
frames
|
||||||
|
},
|
||||||
|
Err(_e) => {
|
||||||
|
Vec::new()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Sprite {
|
Ok(Sprite {
|
||||||
id,
|
id,
|
||||||
@@ -111,9 +122,10 @@ impl Sprite {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Sprite {
|
impl fmt::Display for Sprite {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
format!(
|
write!(
|
||||||
|
f,
|
||||||
"SPR {}\n{}{}{}{}{}{}",
|
"SPR {}\n{}{}{}{}{}{}",
|
||||||
self.id,
|
self.id,
|
||||||
self.animation_frames.to_string(),
|
self.animation_frames.to_string(),
|
||||||
@@ -128,13 +140,11 @@ impl ToString for Sprite {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::mock;
|
use crate::{mock, Sprite};
|
||||||
use crate::sprite::Sprite;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sprite_from_string() {
|
fn sprite_from_string() {
|
||||||
let string = include_str!("test-resources/sprite").to_string();
|
let output = Sprite::from_str(include_str!("test-resources/sprite")).unwrap();
|
||||||
let output = Sprite::from(string).unwrap();
|
|
||||||
let expected = mock::sprite();
|
let expected = mock::sprite();
|
||||||
|
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
@@ -142,6 +152,6 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sprite_to_string() {
|
fn sprite_to_string() {
|
||||||
assert_eq!(mock::sprite().to_string(), include_str!("test-resources/sprite").to_string());
|
assert_eq!(mock::sprite().to_string(), include_str!("test-resources/sprite"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
Write your game's title here
|
Write your game's title here
|
||||||
|
|
||||||
# BITSY VERSION 7.1
|
# BITSY VERSION 8.12
|
||||||
|
|
||||||
|
! VER_MAJ 8
|
||||||
|
! VER_MIN 12
|
||||||
! ROOM_FORMAT 1
|
! ROOM_FORMAT 1
|
||||||
|
! DLG_COMPAT 0
|
||||||
|
! TXT_MODE 0
|
||||||
|
|
||||||
PAL 0
|
PAL 0
|
||||||
NAME blueprint
|
|
||||||
0,82,204
|
0,82,204
|
||||||
128,159,255
|
128,159,255
|
||||||
255,255,255
|
255,255,255
|
||||||
|
NAME blueprint
|
||||||
|
|
||||||
ROOM 0
|
ROOM 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,0,0,0,0,0,0
|
||||||
@@ -29,6 +33,7 @@ ROOM 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,0,0,0,0,0,0
|
||||||
NAME example room
|
NAME example room
|
||||||
PAL 0
|
PAL 0
|
||||||
|
TUNE 2
|
||||||
|
|
||||||
TIL a
|
TIL a
|
||||||
11111111
|
11111111
|
||||||
@@ -64,6 +69,7 @@ SPR a
|
|||||||
NAME cat
|
NAME cat
|
||||||
DLG 0
|
DLG 0
|
||||||
POS 0 8,12
|
POS 0 8,12
|
||||||
|
BLIP 1
|
||||||
|
|
||||||
ITM 0
|
ITM 0
|
||||||
00000000
|
00000000
|
||||||
@@ -88,6 +94,7 @@ ITM 1
|
|||||||
00011000
|
00011000
|
||||||
NAME key
|
NAME key
|
||||||
DLG 2
|
DLG 2
|
||||||
|
BLIP 2
|
||||||
|
|
||||||
DLG 0
|
DLG 0
|
||||||
I'm a cat
|
I'm a cat
|
||||||
@@ -104,3 +111,91 @@ NAME key dialog
|
|||||||
VAR a
|
VAR a
|
||||||
42
|
42
|
||||||
|
|
||||||
|
TUNE 1
|
||||||
|
3d,0,0,0,3d5,0,0,0,3l,0,0,0,3s,0,0,0
|
||||||
|
16d2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
>
|
||||||
|
4l,0,0,0,s,0,3l,0,0,0,2s,0,2m,0,2r,0
|
||||||
|
16m2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
>
|
||||||
|
3d,0,0,0,3d5,0,0,0,3l,0,0,0,3s,0,0,0
|
||||||
|
16l2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
>
|
||||||
|
3l,0,0,0,s,0,4m,0,0,0,4r,0,0,0,0,0
|
||||||
|
16s2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
NAME finale fanfare
|
||||||
|
KEY C,D,E,F,G,A,B d,r,m,s,l
|
||||||
|
TMP XFST
|
||||||
|
SQR P2 P8
|
||||||
|
ARP INT8
|
||||||
|
|
||||||
|
TUNE 2
|
||||||
|
0,0,2G,0,A,0,B,0,2C5,0,B,A,G,0,2G,0
|
||||||
|
G3,0,D,0,G3,0,D,0,2A3,0,E,0,C,0,E,0
|
||||||
|
>
|
||||||
|
2F#,0,G,0,A,0,F#,0,2E,0,F#,E,4D,0,0,0
|
||||||
|
2D,0,E,0,F#,0,D,0,2C,0,2G3,0,2F#3,0,D2,0
|
||||||
|
>
|
||||||
|
0,0,2G,0,A,0,B,0,2C5,0,B,A,G,0,G,0
|
||||||
|
2G2,0,D,D5,G3,G,D,0,2C2,0,E,E5,C3,C,E5,0
|
||||||
|
>
|
||||||
|
2D,0,C5,B,A,0,A,0,4A,0,0,0,F#,0,0,0
|
||||||
|
A2,0,E3,0,C3,0,E3,0,D3,0,A3,0,D,0,0,0
|
||||||
|
>
|
||||||
|
2E5,0,2G,0,2G5,0,2G,0,2F#5,0,2E5,0,2D5,0,2C5,0
|
||||||
|
2C3,0,2E,0,2E5,0,2C,0,2A3,0,2C,0,2F#,0,2E,0
|
||||||
|
>
|
||||||
|
3B,0,0,0,2E5,0,D5,0,4A,0,0,0,G,0,0,0
|
||||||
|
2G3,0,B3,0,2D,0,D3,0,2C3,0,G3,0,D#,0,0,0
|
||||||
|
>
|
||||||
|
0,0,2G,0,A,0,2B,0,C5,0,B,C5,A,0,G,0
|
||||||
|
A2,0,A3,0,C,0,2D,0,D#,0,D,E,C,0,C3,0
|
||||||
|
>
|
||||||
|
8B,0,0,0,0,0,0,0,A,0,2F#,0,E,0,D,0
|
||||||
|
D3,0,A3,0,F#,0,D,0,C,0,2D3,0,C3,0,F#3,0
|
||||||
|
NAME tuneful town
|
||||||
|
TMP FST
|
||||||
|
SQR P4 P2
|
||||||
|
|
||||||
|
TUNE 3
|
||||||
|
3F5,0,0,A#,0,2C#5,0,A#,3F5,0,0,F#5,0,0,2F5,0
|
||||||
|
A#3,C#,F,0,0,F,C#,F,A#3,C#,F,A#,0,A#,C#,F
|
||||||
|
>
|
||||||
|
3F5,0,0,A,0,2C#5,0,A,3F5,0,0,2A#5,0,A#,D#5,0
|
||||||
|
A3,C#,F,A3,0,F,C#,F,A,C#,F,0,D#,0,C#5,0
|
||||||
|
>
|
||||||
|
4F5,0,0,0,G#,2C#5,0,G#,3F5,0,0,D#5,0,F5,2C#5,0
|
||||||
|
G#3,C#,F,3F#,0,0,2F,0,G#3,C#,F,F#,B,A,F,D#
|
||||||
|
>
|
||||||
|
4D#5,0,0,0,0,0,2A#,0,4A#,0,0,0,0,0,A#,C5
|
||||||
|
G3,D#,F,G,0,D#,F,G,G3,D#,G,F,0,F,D#,C#3
|
||||||
|
>
|
||||||
|
4C#5,0,0,0,0,0,2C#5,0,3C#5,0,0,D#5,0,0,2C#5,0
|
||||||
|
F#2,C#,F#3,A#3,0,F#3,C#3,F#3,F#2,A,F#3,C#,0,F#3,A3,F#3
|
||||||
|
>
|
||||||
|
3C#5,0,0,F,3C5,0,0,C,3C5,0,0,D#,3A#,0,0,0
|
||||||
|
F2,D#3,A3,0,0,F3,C#,0,F#2,A#3,D#3,0,0,F#3,C#,C
|
||||||
|
>
|
||||||
|
3A#,0,0,0,C5,0,C#5,0,A#,0,C#,D#,G#,G#3,0,C#3
|
||||||
|
C3,A#3,C,E,A,0,A#,0,0,B2,B3,0,2F,0,0,0
|
||||||
|
>
|
||||||
|
A#,0,A#3,0,C#,0,F,0,A#,0,0,0,0,0,0,0
|
||||||
|
A#2,0,C#3,0,F3,0,A#3,0,D,0,0,0,0,F#3,0,F3
|
||||||
|
NAME rhythmic ruins
|
||||||
|
TMP MED
|
||||||
|
SQR P4 P4
|
||||||
|
|
||||||
|
BLIP 1
|
||||||
|
E5,B5,B5
|
||||||
|
NAME meow
|
||||||
|
ENV 40 99 4 185 138
|
||||||
|
BEAT 61 115
|
||||||
|
SQR P2
|
||||||
|
|
||||||
|
BLIP 2
|
||||||
|
D5,E5,D5
|
||||||
|
NAME pick up key
|
||||||
|
ENV 99 65 6 96 152
|
||||||
|
BEAT 95 0
|
||||||
|
SQR P4
|
||||||
|
|
||||||
|
|||||||
1
src/test-resources/omnibus
Submodule
1
src/test-resources/omnibus
Submodule
Submodule src/test-resources/omnibus added at c3834a9c21
525
src/test_omnibus.rs
Normal file
525
src/test_omnibus.rs
Normal file
@@ -0,0 +1,525 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::game::Game;
|
||||||
|
|
||||||
|
/// bitsy-parser will parse these games correctly
|
||||||
|
/// but the output does not match the input, due to game data errors.
|
||||||
|
const ACCEPTED_FAILURES: [&str; 32] = [
|
||||||
|
// position out of bounds e.g. "5, -1"
|
||||||
|
"CFE62F11", // "SweetPea Village",
|
||||||
|
"013B3CDE", // "Sunset Shore",
|
||||||
|
"65C2B499", // "==GIRLS OWN THE VOID=={br}a faux platformer",
|
||||||
|
"74E0F6EF", // this one has no name. the files is huge so the test hangs, but it does parse ok apart from a bad item position.
|
||||||
|
// extra tiles in room (this was an old editor bug)
|
||||||
|
"07836D6F", // "I can't run anymore. They won't give up. I need water.",
|
||||||
|
"12490381", // "Picnic at Castle Island",
|
||||||
|
"14C48FA0", // "whatever you were doing ran later than expected and now it's",
|
||||||
|
"26A717C8", // "Goodfishas",
|
||||||
|
"2A1D0AF0", // "Dont Go South",
|
||||||
|
"2A5FDAE9", // "stars",
|
||||||
|
"5F836D20", // "We live in an increasingly connected world where we are incentivised to share every visual stimulus and emotional trigger that we encounter. ",
|
||||||
|
"C5CF3FDA", // "No Snow",
|
||||||
|
"D2A4D690", // "Cryptid Hunt feat. Mothman",
|
||||||
|
"ED62FAC9", // "SCREEECH! THUNK.",
|
||||||
|
"F3E61FC1", // "Vitreous",
|
||||||
|
"45EF9604",
|
||||||
|
// extraneous character at end of file
|
||||||
|
"D1FB278A", // "I Dream of Pixels",
|
||||||
|
"755DA50E", // "You arrive at a party.",
|
||||||
|
// extraneous whitespace
|
||||||
|
"49F56F40", // "sun machine",
|
||||||
|
"A5816C9C", // "THE BITSY MYSTERY DUNGEON{br}A game by everyone",
|
||||||
|
"F31CA90B", // "THE UNSEEN LIGHT{br}For Gothic Novel Jam 2018",
|
||||||
|
// extra pixels in image (another old editor bug)
|
||||||
|
"36DB0432",
|
||||||
|
"801AE85A", // "Write your game's title hevery blind (just without glasses but look my eyesight is very my eye sight is not good ok) (also i had a drink but am barely even tipsy but whatever)",
|
||||||
|
"86CC164A", // "Dog Walking, Dog Running, and Dog Still.",
|
||||||
|
"8831A581", // "startup sequence...",
|
||||||
|
"9484FD34", // "A Bit of Reverie",
|
||||||
|
"94943E5C", // "I am lost on this planet Alone, yet crowded by thoughts",
|
||||||
|
"C1DC0328", // "Four Corners",
|
||||||
|
"F79D5368", // "the fox and the moon",
|
||||||
|
// unexpected ordering of game data
|
||||||
|
"C673EA1B", // "here are my cats",
|
||||||
|
// NaN instead of pixels/etc.
|
||||||
|
"DA88C287",
|
||||||
|
"C2EF387A", // {clr2}{scramble}skeletal dos dreams skeletal dos dreams{scramble} skeletal dos dreams{clr2}
|
||||||
|
];
|
||||||
|
|
||||||
|
fn str(s: &str, id: &str) {
|
||||||
|
let result = Game::from(s.to_string());
|
||||||
|
|
||||||
|
if result.is_err() {
|
||||||
|
print!("{:?}", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
let (game, _) = result.expect("failed to parse game");
|
||||||
|
|
||||||
|
if ACCEPTED_FAILURES.contains(&id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
game.to_string().trim_matches('\n'),
|
||||||
|
s.to_string().trim_matches('\n'),
|
||||||
|
"output does not match input"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test] fn test_the_rest_of_your_life() {str(include_str!("test-resources/omnibus/the-rest-of-your-life.bitsy.txt"), "the-rest-of-your-life");}
|
||||||
|
#[test] fn test_0053b32f() {str(include_str!("test-resources/omnibus/0053B32F.bitsy.txt"), "0053B32F");}
|
||||||
|
#[test] fn test_00e45dc5() {str(include_str!("test-resources/omnibus/00E45DC5.bitsy.txt"), "00E45DC5");}
|
||||||
|
#[test] fn test_010beb39() {str(include_str!("test-resources/omnibus/010BEB39.bitsy.txt"), "010BEB39");}
|
||||||
|
#[test] fn test_013b3cde() {str(include_str!("test-resources/omnibus/013B3CDE.bitsy.txt"), "013B3CDE");}
|
||||||
|
#[test] fn test_0145f050() {str(include_str!("test-resources/omnibus/0145F050.bitsy.txt"), "0145F050");}
|
||||||
|
#[test] fn test_031faa8a() {str(include_str!("test-resources/omnibus/031FAA8A.bitsy.txt"), "031FAA8A");}
|
||||||
|
#[test] fn test_0365960a() {str(include_str!("test-resources/omnibus/0365960A.bitsy.txt"), "0365960A");}
|
||||||
|
#[test] fn test_04716e2a() {str(include_str!("test-resources/omnibus/04716E2A.bitsy.txt"), "04716E2A");}
|
||||||
|
#[test] fn test_058b6cc2() {str(include_str!("test-resources/omnibus/058B6CC2.bitsy.txt"), "058B6CC2");}
|
||||||
|
#[test] fn test_0727ffab() {str(include_str!("test-resources/omnibus/0727FFAB.bitsy.txt"), "0727FFAB");}
|
||||||
|
#[test] fn test_07836d6f() {str(include_str!("test-resources/omnibus/07836D6F.bitsy.txt"), "07836D6F");}
|
||||||
|
#[test] fn test_0944c6fc() {str(include_str!("test-resources/omnibus/0944C6FC.bitsy.txt"), "0944C6FC");}
|
||||||
|
#[test] fn test_09463227() {str(include_str!("test-resources/omnibus/09463227.bitsy.txt"), "09463227");}
|
||||||
|
#[test] fn test_09b9f805() {str(include_str!("test-resources/omnibus/09B9F805.bitsy.txt"), "09B9F805");}
|
||||||
|
#[test] fn test_0a5b0213() {str(include_str!("test-resources/omnibus/0A5B0213.bitsy.txt"), "0A5B0213");}
|
||||||
|
#[test] fn test_0b05d95e() {str(include_str!("test-resources/omnibus/0B05D95E.bitsy.txt"), "0B05D95E");}
|
||||||
|
#[test] fn test_0bdf73f8() {str(include_str!("test-resources/omnibus/0BDF73F8.bitsy.txt"), "0BDF73F8");}
|
||||||
|
#[test] fn test_0ca8ccc9() {str(include_str!("test-resources/omnibus/0CA8CCC9.bitsy.txt"), "0CA8CCC9");}
|
||||||
|
#[test] fn test_0cbaa229() {str(include_str!("test-resources/omnibus/0CBAA229.bitsy.txt"), "0CBAA229");}
|
||||||
|
#[test] fn test_0d045f5f() {str(include_str!("test-resources/omnibus/0D045F5F.bitsy.txt"), "0D045F5F");}
|
||||||
|
#[test] fn test_0d5f9f11() {str(include_str!("test-resources/omnibus/0D5F9F11.bitsy.txt"), "0D5F9F11");}
|
||||||
|
#[test] fn test_0daebe2d() {str(include_str!("test-resources/omnibus/0DAEBE2D.bitsy.txt"), "0DAEBE2D");}
|
||||||
|
#[test] fn test_0dc609d8() {str(include_str!("test-resources/omnibus/0DC609D8.bitsy.txt"), "0DC609D8");}
|
||||||
|
#[test] fn test_0ddead71() {str(include_str!("test-resources/omnibus/0DDEAD71.bitsy.txt"), "0DDEAD71");}
|
||||||
|
#[test] fn test_0f3f62ba() {str(include_str!("test-resources/omnibus/0F3F62BA.bitsy.txt"), "0F3F62BA");}
|
||||||
|
#[test] fn test_0fabc625() {str(include_str!("test-resources/omnibus/0FABC625.bitsy.txt"), "0FABC625");}
|
||||||
|
#[test] fn test_0fba2397() {str(include_str!("test-resources/omnibus/0FBA2397.bitsy.txt"), "0FBA2397");}
|
||||||
|
#[test] fn test_0ff04b41() {str(include_str!("test-resources/omnibus/0FF04B41.bitsy.txt"), "0FF04B41");}
|
||||||
|
#[test] fn test_103cee9f() {str(include_str!("test-resources/omnibus/103CEE9F.bitsy.txt"), "103CEE9F");}
|
||||||
|
#[test] fn test_1057e4b3() {str(include_str!("test-resources/omnibus/1057E4B3.bitsy.txt"), "1057E4B3");}
|
||||||
|
#[test] fn test_107b236b() {str(include_str!("test-resources/omnibus/107B236B.bitsy.txt"), "107B236B");}
|
||||||
|
#[test] fn test_111183bd() {str(include_str!("test-resources/omnibus/111183BD.bitsy.txt"), "111183BD");}
|
||||||
|
#[test] fn test_12201174() {str(include_str!("test-resources/omnibus/12201174.bitsy.txt"), "12201174");}
|
||||||
|
#[test] fn test_12490381() {str(include_str!("test-resources/omnibus/12490381.bitsy.txt"), "12490381");}
|
||||||
|
#[test] fn test_127e4635() {str(include_str!("test-resources/omnibus/127E4635.bitsy.txt"), "127E4635");}
|
||||||
|
#[test] fn test_13882e3b() {str(include_str!("test-resources/omnibus/13882E3B.bitsy.txt"), "13882E3B");}
|
||||||
|
#[test] fn test_138a5257() {str(include_str!("test-resources/omnibus/138A5257.bitsy.txt"), "138A5257");}
|
||||||
|
#[test] fn test_13935f38() {str(include_str!("test-resources/omnibus/13935F38.bitsy.txt"), "13935F38");}
|
||||||
|
#[test] fn test_14926703() {str(include_str!("test-resources/omnibus/14926703.bitsy.txt"), "14926703");}
|
||||||
|
#[test] fn test_14c48fa0() {str(include_str!("test-resources/omnibus/14C48FA0.bitsy.txt"), "14C48FA0");}
|
||||||
|
#[test] fn test_163df269() {str(include_str!("test-resources/omnibus/163DF269.bitsy.txt"), "163DF269");}
|
||||||
|
#[test] fn test_1663a765() {str(include_str!("test-resources/omnibus/1663A765.bitsy.txt"), "1663A765");}
|
||||||
|
#[test] fn test_17c6de40() {str(include_str!("test-resources/omnibus/17C6DE40.bitsy.txt"), "17C6DE40");}
|
||||||
|
#[test] fn test_17f6799b() {str(include_str!("test-resources/omnibus/17F6799B.bitsy.txt"), "17F6799B");}
|
||||||
|
#[test] fn test_18647f85() {str(include_str!("test-resources/omnibus/18647F85.bitsy.txt"), "18647F85");}
|
||||||
|
#[test] fn test_18a82fc7() {str(include_str!("test-resources/omnibus/18A82FC7.bitsy.txt"), "18A82FC7");}
|
||||||
|
#[test] fn test_19217ac5() {str(include_str!("test-resources/omnibus/19217AC5.bitsy.txt"), "19217AC5");}
|
||||||
|
#[test] fn test_196c5cfe() {str(include_str!("test-resources/omnibus/196C5CFE.bitsy.txt"), "196C5CFE");}
|
||||||
|
#[test] fn test_1998508e() {str(include_str!("test-resources/omnibus/1998508E.bitsy.txt"), "1998508E");}
|
||||||
|
#[test] fn test_19adfd75() {str(include_str!("test-resources/omnibus/19ADFD75.bitsy.txt"), "19ADFD75");}
|
||||||
|
#[test] fn test_19f30e9d() {str(include_str!("test-resources/omnibus/19F30E9D.bitsy.txt"), "19F30E9D");}
|
||||||
|
#[test] fn test_1a2279eb() {str(include_str!("test-resources/omnibus/1A2279EB.bitsy.txt"), "1A2279EB");}
|
||||||
|
#[test] fn test_1a595207() {str(include_str!("test-resources/omnibus/1A595207.bitsy.txt"), "1A595207");}
|
||||||
|
#[test] fn test_1b10d2fe() {str(include_str!("test-resources/omnibus/1B10D2FE.bitsy.txt"), "1B10D2FE");}
|
||||||
|
#[test] fn test_1c54c16d() {str(include_str!("test-resources/omnibus/1C54C16D.bitsy.txt"), "1C54C16D");}
|
||||||
|
#[test] fn test_1e2742e0() {str(include_str!("test-resources/omnibus/1E2742E0.bitsy.txt"), "1E2742E0");}
|
||||||
|
#[test] fn test_1e339dba() {str(include_str!("test-resources/omnibus/1E339DBA.bitsy.txt"), "1E339DBA");}
|
||||||
|
#[test] fn test_1f6683a4() {str(include_str!("test-resources/omnibus/1F6683A4.bitsy.txt"), "1F6683A4");}
|
||||||
|
#[test] fn test_1f8db6b8() {str(include_str!("test-resources/omnibus/1F8DB6B8.bitsy.txt"), "1F8DB6B8");}
|
||||||
|
#[test] fn test_209b9517() {str(include_str!("test-resources/omnibus/209B9517.bitsy.txt"), "209B9517");}
|
||||||
|
#[test] fn test_20b08319() {str(include_str!("test-resources/omnibus/20B08319.bitsy.txt"), "20B08319");}
|
||||||
|
#[test] fn test_21e26b92() {str(include_str!("test-resources/omnibus/21E26B92.bitsy.txt"), "21E26B92");}
|
||||||
|
#[test] fn test_22ab996a() {str(include_str!("test-resources/omnibus/22AB996A.bitsy.txt"), "22AB996A");}
|
||||||
|
#[test] fn test_22cef657() {str(include_str!("test-resources/omnibus/22CEF657.bitsy.txt"), "22CEF657");}
|
||||||
|
#[test] fn test_23a22678() {str(include_str!("test-resources/omnibus/23A22678.bitsy.txt"), "23A22678");}
|
||||||
|
#[test] fn test_23c95b44() {str(include_str!("test-resources/omnibus/23C95B44.bitsy.txt"), "23C95B44");}
|
||||||
|
#[test] fn test_245ee1c6() {str(include_str!("test-resources/omnibus/245EE1C6.bitsy.txt"), "245EE1C6");}
|
||||||
|
#[test] fn test_24ac79ff() {str(include_str!("test-resources/omnibus/24AC79FF.bitsy.txt"), "24AC79FF");}
|
||||||
|
#[test] fn test_24c74f49() {str(include_str!("test-resources/omnibus/24C74F49.bitsy.txt"), "24C74F49");}
|
||||||
|
#[test] fn test_252182b5() {str(include_str!("test-resources/omnibus/252182B5.bitsy.txt"), "252182B5");}
|
||||||
|
#[test] fn test_26a20c22() {str(include_str!("test-resources/omnibus/26A20C22.bitsy.txt"), "26A20C22");}
|
||||||
|
#[test] fn test_26a717c8() {str(include_str!("test-resources/omnibus/26A717C8.bitsy.txt"), "26A717C8");}
|
||||||
|
#[test] fn test_27b5cddf() {str(include_str!("test-resources/omnibus/27B5CDDF.bitsy.txt"), "27B5CDDF");}
|
||||||
|
#[test] fn test_27dfc976() {str(include_str!("test-resources/omnibus/27DFC976.bitsy.txt"), "27DFC976");}
|
||||||
|
#[test] fn test_2805c4e9() {str(include_str!("test-resources/omnibus/2805C4E9.bitsy.txt"), "2805C4E9");}
|
||||||
|
#[test] fn test_282c85b4() {str(include_str!("test-resources/omnibus/282C85B4.bitsy.txt"), "282C85B4");}
|
||||||
|
#[test] fn test_2839d1ae() {str(include_str!("test-resources/omnibus/2839D1AE.bitsy.txt"), "2839D1AE");}
|
||||||
|
#[test] fn test_284796eb() {str(include_str!("test-resources/omnibus/284796EB.bitsy.txt"), "284796EB");}
|
||||||
|
#[test] fn test_284d2078() {str(include_str!("test-resources/omnibus/284D2078.bitsy.txt"), "284D2078");}
|
||||||
|
#[test] fn test_29e7379a() {str(include_str!("test-resources/omnibus/29E7379A.bitsy.txt"), "29E7379A");}
|
||||||
|
#[test] fn test_2a1d0af0() {str(include_str!("test-resources/omnibus/2A1D0AF0.bitsy.txt"), "2A1D0AF0");}
|
||||||
|
#[test] fn test_2a5fdae9() {str(include_str!("test-resources/omnibus/2A5FDAE9.bitsy.txt"), "2A5FDAE9");}
|
||||||
|
#[test] fn test_2a879a66() {str(include_str!("test-resources/omnibus/2A879A66.bitsy.txt"), "2A879A66");}
|
||||||
|
#[test] fn test_2ae3f2f7() {str(include_str!("test-resources/omnibus/2AE3F2F7.bitsy.txt"), "2AE3F2F7");}
|
||||||
|
#[test] fn test_2ae5b41f() {str(include_str!("test-resources/omnibus/2AE5B41F.bitsy.txt"), "2AE5B41F");}
|
||||||
|
#[test] fn test_2b22c193() {str(include_str!("test-resources/omnibus/2B22C193.bitsy.txt"), "2B22C193");}
|
||||||
|
#[test] fn test_2d2b56b6() {str(include_str!("test-resources/omnibus/2D2B56B6.bitsy.txt"), "2D2B56B6");}
|
||||||
|
#[test] fn test_2d533752() {str(include_str!("test-resources/omnibus/2D533752.bitsy.txt"), "2D533752");}
|
||||||
|
#[test] fn test_2d678f83() {str(include_str!("test-resources/omnibus/2D678F83.bitsy.txt"), "2D678F83");}
|
||||||
|
#[test] fn test_2dedac14() {str(include_str!("test-resources/omnibus/2DEDAC14.bitsy.txt"), "2DEDAC14");}
|
||||||
|
#[test] fn test_2e2987d0() {str(include_str!("test-resources/omnibus/2E2987D0.bitsy.txt"), "2E2987D0");}
|
||||||
|
#[test] fn test_2e60f4c3() {str(include_str!("test-resources/omnibus/2E60F4C3.bitsy.txt"), "2E60F4C3");}
|
||||||
|
#[test] fn test_30960393() {str(include_str!("test-resources/omnibus/30960393.bitsy.txt"), "30960393");}
|
||||||
|
#[test] fn test_31102002() {str(include_str!("test-resources/omnibus/31102002.bitsy.txt"), "31102002");}
|
||||||
|
/// todo fix this - a triple-quoted dialogue becomes empty
|
||||||
|
#[test] fn test_313d1314() {str(include_str!("test-resources/omnibus/313D1314.bitsy.txt"), "313D1314");}
|
||||||
|
#[test] fn test_317415f3() {str(include_str!("test-resources/omnibus/317415F3.bitsy.txt"), "317415F3");}
|
||||||
|
#[test] fn test_31c0d44b() {str(include_str!("test-resources/omnibus/31C0D44B.bitsy.txt"), "31C0D44B");}
|
||||||
|
#[test] fn test_32051452() {str(include_str!("test-resources/omnibus/32051452.bitsy.txt"), "32051452");}
|
||||||
|
#[test] fn test_333db34a() {str(include_str!("test-resources/omnibus/333DB34A.bitsy.txt"), "333DB34A");}
|
||||||
|
#[test] fn test_3388d883() {str(include_str!("test-resources/omnibus/3388D883.bitsy.txt"), "3388D883");}
|
||||||
|
#[test] fn test_34e2323e() {str(include_str!("test-resources/omnibus/34E2323E.bitsy.txt"), "34E2323E");}
|
||||||
|
#[test] fn test_3595b459() {str(include_str!("test-resources/omnibus/3595B459.bitsy.txt"), "3595B459");}
|
||||||
|
#[test] fn test_35c079d5() {str(include_str!("test-resources/omnibus/35C079D5.bitsy.txt"), "35C079D5");}
|
||||||
|
#[test] fn test_362c9f8e() {str(include_str!("test-resources/omnibus/362C9F8E.bitsy.txt"), "362C9F8E");}
|
||||||
|
#[test] fn test_362f1e1d() {str(include_str!("test-resources/omnibus/362F1E1D.bitsy.txt"), "362F1E1D");}
|
||||||
|
#[test] fn test_3664c1b9() {str(include_str!("test-resources/omnibus/3664C1B9.bitsy.txt"), "3664C1B9");}
|
||||||
|
#[test] fn test_36db0432() {str(include_str!("test-resources/omnibus/36DB0432.bitsy.txt"), "36DB0432");}
|
||||||
|
#[test] fn test_3895271d() {str(include_str!("test-resources/omnibus/3895271D.bitsy.txt"), "3895271D");}
|
||||||
|
#[test] fn test_38bedab0() {str(include_str!("test-resources/omnibus/38BEDAB0.bitsy.txt"), "38BEDAB0");}
|
||||||
|
#[test] fn test_38d19484() {str(include_str!("test-resources/omnibus/38D19484.bitsy.txt"), "38D19484");}
|
||||||
|
#[test] fn test_39eff3d0() {str(include_str!("test-resources/omnibus/39EFF3D0.bitsy.txt"), "39EFF3D0");}
|
||||||
|
#[test] fn test_3a3e8773() {str(include_str!("test-resources/omnibus/3A3E8773.bitsy.txt"), "3A3E8773");}
|
||||||
|
#[test] fn test_3a68df96() {str(include_str!("test-resources/omnibus/3A68DF96.bitsy.txt"), "3A68DF96");}
|
||||||
|
#[test] fn test_3a6a0fee() {str(include_str!("test-resources/omnibus/3A6A0FEE.bitsy.txt"), "3A6A0FEE");}
|
||||||
|
#[test] fn test_3ad39018() {str(include_str!("test-resources/omnibus/3AD39018.bitsy.txt"), "3AD39018");}
|
||||||
|
#[test] fn test_3adc3b2b() {str(include_str!("test-resources/omnibus/3ADC3B2B.bitsy.txt"), "3ADC3B2B");}
|
||||||
|
#[test] fn test_3b376b08() {str(include_str!("test-resources/omnibus/3B376B08.bitsy.txt"), "3B376B08");}
|
||||||
|
#[test] fn test_3bdc8a5e() {str(include_str!("test-resources/omnibus/3BDC8A5E.bitsy.txt"), "3BDC8A5E");}
|
||||||
|
#[test] fn test_3c2225e3() {str(include_str!("test-resources/omnibus/3C2225E3.bitsy.txt"), "3C2225E3");}
|
||||||
|
#[test] fn test_3c5ba8f0() {str(include_str!("test-resources/omnibus/3C5BA8F0.bitsy.txt"), "3C5BA8F0");}
|
||||||
|
#[test] fn test_3c712f1b() {str(include_str!("test-resources/omnibus/3C712F1B.bitsy.txt"), "3C712F1B");}
|
||||||
|
#[test] fn test_3c814196() {str(include_str!("test-resources/omnibus/3C814196.bitsy.txt"), "3C814196");}
|
||||||
|
#[test] fn test_3c8c19dd() {str(include_str!("test-resources/omnibus/3C8C19DD.bitsy.txt"), "3C8C19DD");}
|
||||||
|
#[test] fn test_3e8c3022() {str(include_str!("test-resources/omnibus/3E8C3022.bitsy.txt"), "3E8C3022");}
|
||||||
|
#[test] fn test_3f6eaaeb() {str(include_str!("test-resources/omnibus/3F6EAAEB.bitsy.txt"), "3F6EAAEB");}
|
||||||
|
#[test] fn test_3fc83ee6() {str(include_str!("test-resources/omnibus/3FC83EE6.bitsy.txt"), "3FC83EE6");}
|
||||||
|
#[test] fn test_400a3a88() {str(include_str!("test-resources/omnibus/400A3A88.bitsy.txt"), "400A3A88");}
|
||||||
|
#[test] fn test_40610fb3() {str(include_str!("test-resources/omnibus/40610FB3.bitsy.txt"), "40610FB3");}
|
||||||
|
#[test] fn test_40e58b03() {str(include_str!("test-resources/omnibus/40E58B03.bitsy.txt"), "40E58B03");}
|
||||||
|
#[test] fn test_41b01b3a() {str(include_str!("test-resources/omnibus/41B01B3A.bitsy.txt"), "41B01B3A");}
|
||||||
|
#[test] fn test_41c30128() {str(include_str!("test-resources/omnibus/41C30128.bitsy.txt"), "41C30128");}
|
||||||
|
#[test] fn test_42492af1() {str(include_str!("test-resources/omnibus/42492AF1.bitsy.txt"), "42492AF1");}
|
||||||
|
#[test] fn test_428d89c7() {str(include_str!("test-resources/omnibus/428D89C7.bitsy.txt"), "428D89C7");}
|
||||||
|
#[test] fn test_42c251ea() {str(include_str!("test-resources/omnibus/42C251EA.bitsy.txt"), "42C251EA");}
|
||||||
|
#[test] fn test_439ba1a5() {str(include_str!("test-resources/omnibus/439BA1A5.bitsy.txt"), "439BA1A5");}
|
||||||
|
#[test] fn test_43abaffd() {str(include_str!("test-resources/omnibus/43ABAFFD.bitsy.txt"), "43ABAFFD");}
|
||||||
|
#[test] fn test_43d24c5a() {str(include_str!("test-resources/omnibus/43D24C5A.bitsy.txt"), "43D24C5A");}
|
||||||
|
#[test] fn test_4483029c() {str(include_str!("test-resources/omnibus/4483029C.bitsy.txt"), "4483029C");}
|
||||||
|
#[test] fn test_4527a047() {str(include_str!("test-resources/omnibus/4527A047.bitsy.txt"), "4527A047");}
|
||||||
|
#[test] fn test_45ef9604() {str(include_str!("test-resources/omnibus/45EF9604.bitsy.txt"), "45EF9604");}
|
||||||
|
#[test] fn test_45f1225d() {str(include_str!("test-resources/omnibus/45F1225D.bitsy.txt"), "45F1225D");}
|
||||||
|
#[test] fn test_46062786() {str(include_str!("test-resources/omnibus/46062786.bitsy.txt"), "46062786");}
|
||||||
|
#[test] fn test_465efaa2() {str(include_str!("test-resources/omnibus/465EFAA2.bitsy.txt"), "465EFAA2");}
|
||||||
|
#[test] fn test_46a699a5() {str(include_str!("test-resources/omnibus/46A699A5.bitsy.txt"), "46A699A5");}
|
||||||
|
#[test] fn test_46eddcc6() {str(include_str!("test-resources/omnibus/46EDDCC6.bitsy.txt"), "46EDDCC6");}
|
||||||
|
#[test] fn test_4759957f() {str(include_str!("test-resources/omnibus/4759957F.bitsy.txt"), "4759957F");}
|
||||||
|
#[test] fn test_477a3731() {str(include_str!("test-resources/omnibus/477A3731.bitsy.txt"), "477A3731");}
|
||||||
|
#[test] fn test_4782f065() {str(include_str!("test-resources/omnibus/4782F065.bitsy.txt"), "4782F065");}
|
||||||
|
#[test] fn test_479de864() {str(include_str!("test-resources/omnibus/479DE864.bitsy.txt"), "479DE864");}
|
||||||
|
#[test] fn test_4941e947() {str(include_str!("test-resources/omnibus/4941E947.bitsy.txt"), "4941E947");}
|
||||||
|
#[test] fn test_49f56f40() {str(include_str!("test-resources/omnibus/49F56F40.bitsy.txt"), "49F56F40");}
|
||||||
|
#[test] fn test_4ab34220() {str(include_str!("test-resources/omnibus/4AB34220.bitsy.txt"), "4AB34220");}
|
||||||
|
#[test] fn test_4ac058fe() {str(include_str!("test-resources/omnibus/4AC058FE.bitsy.txt"), "4AC058FE");}
|
||||||
|
#[test] fn test_4b1e6a14() {str(include_str!("test-resources/omnibus/4B1E6A14.bitsy.txt"), "4B1E6A14");}
|
||||||
|
#[test] fn test_4c8ad705() {str(include_str!("test-resources/omnibus/4C8AD705.bitsy.txt"), "4C8AD705");}
|
||||||
|
#[test] fn test_4ddd9930() {str(include_str!("test-resources/omnibus/4DDD9930.bitsy.txt"), "4DDD9930");}
|
||||||
|
#[test] fn test_4ec3ae6f() {str(include_str!("test-resources/omnibus/4EC3AE6F.bitsy.txt"), "4EC3AE6F");}
|
||||||
|
#[test] fn test_50830651() {str(include_str!("test-resources/omnibus/50830651.bitsy.txt"), "50830651");}
|
||||||
|
#[test] fn test_512739f5() {str(include_str!("test-resources/omnibus/512739F5.bitsy.txt"), "512739F5");}
|
||||||
|
#[test] fn test_51dd0198() {str(include_str!("test-resources/omnibus/51DD0198.bitsy.txt"), "51DD0198");}
|
||||||
|
#[test] fn test_52629e0f() {str(include_str!("test-resources/omnibus/52629E0F.bitsy.txt"), "52629E0F");}
|
||||||
|
#[test] fn test_5295f9e7() {str(include_str!("test-resources/omnibus/5295F9E7.bitsy.txt"), "5295F9E7");}
|
||||||
|
#[test] fn test_52ad1de7() {str(include_str!("test-resources/omnibus/52AD1DE7.bitsy.txt"), "52AD1DE7");}
|
||||||
|
#[test] fn test_53b2a153() {str(include_str!("test-resources/omnibus/53B2A153.bitsy.txt"), "53B2A153");}
|
||||||
|
#[test] fn test_54bc2ac4() {str(include_str!("test-resources/omnibus/54BC2AC4.bitsy.txt"), "54BC2AC4");}
|
||||||
|
#[test] fn test_553ecb46() {str(include_str!("test-resources/omnibus/553ECB46.bitsy.txt"), "553ECB46");}
|
||||||
|
#[test] fn test_555e198c() {str(include_str!("test-resources/omnibus/555E198C.bitsy.txt"), "555E198C");}
|
||||||
|
#[test] fn test_55eb6535() {str(include_str!("test-resources/omnibus/55EB6535.bitsy.txt"), "55EB6535");}
|
||||||
|
#[test] fn test_5784dfef() {str(include_str!("test-resources/omnibus/5784DFEF.bitsy.txt"), "5784DFEF");}
|
||||||
|
#[test] fn test_5951f457() {str(include_str!("test-resources/omnibus/5951F457.bitsy.txt"), "5951F457");}
|
||||||
|
#[test] fn test_59b42152() {str(include_str!("test-resources/omnibus/59B42152.bitsy.txt"), "59B42152");}
|
||||||
|
#[test] fn test_59cfbdf2() {str(include_str!("test-resources/omnibus/59CFBDF2.bitsy.txt"), "59CFBDF2");}
|
||||||
|
#[test] fn test_59ea005d() {str(include_str!("test-resources/omnibus/59EA005D.bitsy.txt"), "59EA005D");}
|
||||||
|
#[test] fn test_5b337d40() {str(include_str!("test-resources/omnibus/5B337D40.bitsy.txt"), "5B337D40");}
|
||||||
|
#[test] fn test_5ba59ab1() {str(include_str!("test-resources/omnibus/5BA59AB1.bitsy.txt"), "5BA59AB1");}
|
||||||
|
#[test] fn test_5bcfd3b5() {str(include_str!("test-resources/omnibus/5BCFD3B5.bitsy.txt"), "5BCFD3B5");}
|
||||||
|
#[test] fn test_5d01e40d() {str(include_str!("test-resources/omnibus/5D01E40D.bitsy.txt"), "5D01E40D");}
|
||||||
|
#[test] fn test_5d0b4ec3() {str(include_str!("test-resources/omnibus/5D0B4EC3.bitsy.txt"), "5D0B4EC3");}
|
||||||
|
#[test] fn test_5d2b55a9() {str(include_str!("test-resources/omnibus/5D2B55A9.bitsy.txt"), "5D2B55A9");}
|
||||||
|
#[test] fn test_5d8aa0e5() {str(include_str!("test-resources/omnibus/5D8AA0E5.bitsy.txt"), "5D8AA0E5");}
|
||||||
|
#[test] fn test_5f836d20() {str(include_str!("test-resources/omnibus/5F836D20.bitsy.txt"), "5F836D20");}
|
||||||
|
#[test] fn test_5f977747() {str(include_str!("test-resources/omnibus/5F977747.bitsy.txt"), "5F977747");}
|
||||||
|
#[test] fn test_5fd6fa60() {str(include_str!("test-resources/omnibus/5FD6FA60.bitsy.txt"), "5FD6FA60");}
|
||||||
|
#[test] fn test_60289d2b() {str(include_str!("test-resources/omnibus/60289D2B.bitsy.txt"), "60289D2B");}
|
||||||
|
#[test] fn test_604ed83b() {str(include_str!("test-resources/omnibus/604ED83B.bitsy.txt"), "604ED83B");}
|
||||||
|
#[test] fn test_605e57d3() {str(include_str!("test-resources/omnibus/605E57D3.bitsy.txt"), "605E57D3");}
|
||||||
|
#[test] fn test_60a5c704() {str(include_str!("test-resources/omnibus/60A5C704.bitsy.txt"), "60A5C704");}
|
||||||
|
#[test] fn test_610930d7() {str(include_str!("test-resources/omnibus/610930D7.bitsy.txt"), "610930D7");}
|
||||||
|
#[test] fn test_61d4df26() {str(include_str!("test-resources/omnibus/61D4DF26.bitsy.txt"), "61D4DF26");}
|
||||||
|
#[test] fn test_6227c33b() {str(include_str!("test-resources/omnibus/6227C33B.bitsy.txt"), "6227C33B");}
|
||||||
|
#[test] fn test_629744da() {str(include_str!("test-resources/omnibus/629744DA.bitsy.txt"), "629744DA");}
|
||||||
|
#[test] fn test_640b5e37() {str(include_str!("test-resources/omnibus/640B5E37.bitsy.txt"), "640B5E37");}
|
||||||
|
#[test] fn test_643e26e7() {str(include_str!("test-resources/omnibus/643E26E7.bitsy.txt"), "643E26E7");}
|
||||||
|
#[test] fn test_657029d2() {str(include_str!("test-resources/omnibus/657029D2.bitsy.txt"), "657029D2");}
|
||||||
|
#[test] fn test_65821da2() {str(include_str!("test-resources/omnibus/65821DA2.bitsy.txt"), "65821DA2");}
|
||||||
|
#[test] fn test_65c2b499() {str(include_str!("test-resources/omnibus/65C2B499.bitsy.txt"), "65C2B499");}
|
||||||
|
#[test] fn test_66888415() {str(include_str!("test-resources/omnibus/66888415.bitsy.txt"), "66888415");}
|
||||||
|
#[test] fn test_68005325() {str(include_str!("test-resources/omnibus/68005325.bitsy.txt"), "68005325");}
|
||||||
|
#[test] fn test_682993ac() {str(include_str!("test-resources/omnibus/682993AC.bitsy.txt"), "682993AC");}
|
||||||
|
#[test] fn test_69e5adde() {str(include_str!("test-resources/omnibus/69E5ADDE.bitsy.txt"), "69E5ADDE");}
|
||||||
|
#[test] fn test_6a3083f8() {str(include_str!("test-resources/omnibus/6A3083F8.bitsy.txt"), "6A3083F8");}
|
||||||
|
#[test] fn test_6a934776() {str(include_str!("test-resources/omnibus/6A934776.bitsy.txt"), "6A934776");}
|
||||||
|
#[test] fn test_6c3d076c() {str(include_str!("test-resources/omnibus/6C3D076C.bitsy.txt"), "6C3D076C");}
|
||||||
|
#[test] fn test_6c491749() {str(include_str!("test-resources/omnibus/6C491749.bitsy.txt"), "6C491749");}
|
||||||
|
#[test] fn test_6cf290c7() {str(include_str!("test-resources/omnibus/6CF290C7.bitsy.txt"), "6CF290C7");}
|
||||||
|
#[test] fn test_6d9a411a() {str(include_str!("test-resources/omnibus/6D9A411A.bitsy.txt"), "6D9A411A");}
|
||||||
|
#[test] fn test_6e835b7d() {str(include_str!("test-resources/omnibus/6E835B7D.bitsy.txt"), "6E835B7D");}
|
||||||
|
#[test] fn test_6f136b0b() {str(include_str!("test-resources/omnibus/6F136B0B.bitsy.txt"), "6F136B0B");}
|
||||||
|
#[test] fn test_70e9483e() {str(include_str!("test-resources/omnibus/70E9483E.bitsy.txt"), "70E9483E");}
|
||||||
|
#[test] fn test_70ea1ca6() {str(include_str!("test-resources/omnibus/70EA1CA6.bitsy.txt"), "70EA1CA6");}
|
||||||
|
#[test] fn test_710f4731() {str(include_str!("test-resources/omnibus/710F4731.bitsy.txt"), "710F4731");}
|
||||||
|
#[test] fn test_7129037b() {str(include_str!("test-resources/omnibus/7129037B.bitsy.txt"), "7129037B");}
|
||||||
|
#[test] fn test_725b9251() {str(include_str!("test-resources/omnibus/725B9251.bitsy.txt"), "725B9251");}
|
||||||
|
#[test] fn test_73d4bbde() {str(include_str!("test-resources/omnibus/73D4BBDE.bitsy.txt"), "73D4BBDE");}
|
||||||
|
#[test] fn test_74685d79() {str(include_str!("test-resources/omnibus/74685D79.bitsy.txt"), "74685D79");}
|
||||||
|
#[test] fn test_74802fe3() {str(include_str!("test-resources/omnibus/74802FE3.bitsy.txt"), "74802FE3");}
|
||||||
|
#[test] fn test_748ea164() {str(include_str!("test-resources/omnibus/748EA164.bitsy.txt"), "748EA164");}
|
||||||
|
#[test] fn test_748f77b5() {str(include_str!("test-resources/omnibus/748F77B5.bitsy.txt"), "748F77B5");}
|
||||||
|
#[test] fn test_74e0f6ef() {str(include_str!("test-resources/omnibus/74E0F6EF.bitsy.txt"), "74E0F6EF");}
|
||||||
|
#[test] fn test_750d339d() {str(include_str!("test-resources/omnibus/750D339D.bitsy.txt"), "750D339D");}
|
||||||
|
#[test] fn test_755da50e() {str(include_str!("test-resources/omnibus/755DA50E.bitsy.txt"), "755DA50E");}
|
||||||
|
#[test] fn test_75b61d2b() {str(include_str!("test-resources/omnibus/75B61D2B.bitsy.txt"), "75B61D2B");}
|
||||||
|
#[test] fn test_75e04506() {str(include_str!("test-resources/omnibus/75E04506.bitsy.txt"), "75E04506");}
|
||||||
|
#[test] fn test_7698b32e() {str(include_str!("test-resources/omnibus/7698B32E.bitsy.txt"), "7698B32E");}
|
||||||
|
#[test] fn test_7769825b() {str(include_str!("test-resources/omnibus/7769825B.bitsy.txt"), "7769825B");}
|
||||||
|
#[test] fn test_77c2a64a() {str(include_str!("test-resources/omnibus/77C2A64A.bitsy.txt"), "77C2A64A");}
|
||||||
|
#[test] fn test_78a27fa0() {str(include_str!("test-resources/omnibus/78A27FA0.bitsy.txt"), "78A27FA0");}
|
||||||
|
#[test] fn test_79ff4e48() {str(include_str!("test-resources/omnibus/79FF4E48.bitsy.txt"), "79FF4E48");}
|
||||||
|
#[test] fn test_7ac4008f() {str(include_str!("test-resources/omnibus/7AC4008F.bitsy.txt"), "7AC4008F");}
|
||||||
|
#[test] fn test_7adf3924() {str(include_str!("test-resources/omnibus/7ADF3924.bitsy.txt"), "7ADF3924");}
|
||||||
|
#[test] fn test_7bc643cf() {str(include_str!("test-resources/omnibus/7BC643CF.bitsy.txt"), "7BC643CF");}
|
||||||
|
#[test] fn test_7bd4c1e0() {str(include_str!("test-resources/omnibus/7BD4C1E0.bitsy.txt"), "7BD4C1E0");}
|
||||||
|
#[test] fn test_7c0211e8() {str(include_str!("test-resources/omnibus/7C0211E8.bitsy.txt"), "7C0211E8");}
|
||||||
|
#[test] fn test_7c57e56e() {str(include_str!("test-resources/omnibus/7C57E56E.bitsy.txt"), "7C57E56E");}
|
||||||
|
#[test] fn test_7ca8eff9() {str(include_str!("test-resources/omnibus/7CA8EFF9.bitsy.txt"), "7CA8EFF9");}
|
||||||
|
#[test] fn test_7cb22bec() {str(include_str!("test-resources/omnibus/7CB22BEC.bitsy.txt"), "7CB22BEC");}
|
||||||
|
#[test] fn test_7cc82262() {str(include_str!("test-resources/omnibus/7CC82262.bitsy.txt"), "7CC82262");}
|
||||||
|
#[test] fn test_7dc64c62() {str(include_str!("test-resources/omnibus/7DC64C62.bitsy.txt"), "7DC64C62");}
|
||||||
|
#[test] fn test_7df36da4() {str(include_str!("test-resources/omnibus/7DF36DA4.bitsy.txt"), "7DF36DA4");}
|
||||||
|
#[test] fn test_7f1599d1() {str(include_str!("test-resources/omnibus/7F1599D1.bitsy.txt"), "7F1599D1");}
|
||||||
|
#[test] fn test_7f607cfa() {str(include_str!("test-resources/omnibus/7F607CFA.bitsy.txt"), "7F607CFA");}
|
||||||
|
#[test] fn test_7fbbc26e() {str(include_str!("test-resources/omnibus/7FBBC26E.bitsy.txt"), "7FBBC26E");}
|
||||||
|
#[test] fn test_7fcf6d96() {str(include_str!("test-resources/omnibus/7FCF6D96.bitsy.txt"), "7FCF6D96");}
|
||||||
|
#[test] fn test_801ae85a() {str(include_str!("test-resources/omnibus/801AE85A.bitsy.txt"), "801AE85A");}
|
||||||
|
#[test] fn test_8025521d() {str(include_str!("test-resources/omnibus/8025521D.bitsy.txt"), "8025521D");}
|
||||||
|
#[test] fn test_8059564a() {str(include_str!("test-resources/omnibus/8059564A.bitsy.txt"), "8059564A");}
|
||||||
|
#[test] fn test_807805cc() {str(include_str!("test-resources/omnibus/807805CC.bitsy.txt"), "807805CC");}
|
||||||
|
#[test] fn test_808ea54b() {str(include_str!("test-resources/omnibus/808EA54B.bitsy.txt"), "808EA54B");}
|
||||||
|
#[test] fn test_81875aec() {str(include_str!("test-resources/omnibus/81875AEC.bitsy.txt"), "81875AEC");}
|
||||||
|
#[test] fn test_82dde16f() {str(include_str!("test-resources/omnibus/82DDE16F.bitsy.txt"), "82DDE16F");}
|
||||||
|
#[test] fn test_83402ede() {str(include_str!("test-resources/omnibus/83402EDE.bitsy.txt"), "83402EDE");}
|
||||||
|
#[test] fn test_83db1fec() {str(include_str!("test-resources/omnibus/83DB1FEC.bitsy.txt"), "83DB1FEC");}
|
||||||
|
#[test] fn test_84ee182e() {str(include_str!("test-resources/omnibus/84EE182E.bitsy.txt"), "84EE182E");}
|
||||||
|
#[test] fn test_85319efc() {str(include_str!("test-resources/omnibus/85319EFC.bitsy.txt"), "85319EFC");}
|
||||||
|
#[test] fn test_85d7ae4c() {str(include_str!("test-resources/omnibus/85D7AE4C.bitsy.txt"), "85D7AE4C");}
|
||||||
|
#[test] fn test_865d97a2() {str(include_str!("test-resources/omnibus/865D97A2.bitsy.txt"), "865D97A2");}
|
||||||
|
#[test] fn test_86cc164a() {str(include_str!("test-resources/omnibus/86CC164A.bitsy.txt"), "86CC164A");}
|
||||||
|
#[test] fn test_8749dd6f() {str(include_str!("test-resources/omnibus/8749DD6F.bitsy.txt"), "8749DD6F");}
|
||||||
|
#[test] fn test_874b5bd3() {str(include_str!("test-resources/omnibus/874B5BD3.bitsy.txt"), "874B5BD3");}
|
||||||
|
#[test] fn test_87d1fe22() {str(include_str!("test-resources/omnibus/87D1FE22.bitsy.txt"), "87D1FE22");}
|
||||||
|
#[test] fn test_8831a581() {str(include_str!("test-resources/omnibus/8831A581.bitsy.txt"), "8831A581");}
|
||||||
|
#[test] fn test_88465670() {str(include_str!("test-resources/omnibus/88465670.bitsy.txt"), "88465670");}
|
||||||
|
#[test] fn test_88599170() {str(include_str!("test-resources/omnibus/88599170.bitsy.txt"), "88599170");}
|
||||||
|
#[test] fn test_89551e9a() {str(include_str!("test-resources/omnibus/89551E9A.bitsy.txt"), "89551E9A");}
|
||||||
|
#[test] fn test_89711e3e() {str(include_str!("test-resources/omnibus/89711E3E.bitsy.txt"), "89711E3E");}
|
||||||
|
#[test] fn test_89c6ed6a() {str(include_str!("test-resources/omnibus/89C6ED6A.bitsy.txt"), "89C6ED6A");}
|
||||||
|
#[test] fn test_8c057b81() {str(include_str!("test-resources/omnibus/8C057B81.bitsy.txt"), "8C057B81");}
|
||||||
|
#[test] fn test_8cabe4c9() {str(include_str!("test-resources/omnibus/8CABE4C9.bitsy.txt"), "8CABE4C9");}
|
||||||
|
#[test] fn test_8d020129() {str(include_str!("test-resources/omnibus/8D020129.bitsy.txt"), "8D020129");}
|
||||||
|
#[test] fn test_8da05131() {str(include_str!("test-resources/omnibus/8DA05131.bitsy.txt"), "8DA05131");}
|
||||||
|
#[test] fn test_8db7cf07() {str(include_str!("test-resources/omnibus/8DB7CF07.bitsy.txt"), "8DB7CF07");}
|
||||||
|
#[test] fn test_8e4187fd() {str(include_str!("test-resources/omnibus/8E4187FD.bitsy.txt"), "8E4187FD");}
|
||||||
|
#[test] fn test_8ef8319b() {str(include_str!("test-resources/omnibus/8EF8319B.bitsy.txt"), "8EF8319B");}
|
||||||
|
#[test] fn test_8f7a6fb5() {str(include_str!("test-resources/omnibus/8F7A6FB5.bitsy.txt"), "8F7A6FB5");}
|
||||||
|
#[test] fn test_8fedb06b() {str(include_str!("test-resources/omnibus/8FEDB06B.bitsy.txt"), "8FEDB06B");}
|
||||||
|
#[test] fn test_9074c1cd() {str(include_str!("test-resources/omnibus/9074C1CD.bitsy.txt"), "9074C1CD");}
|
||||||
|
#[test] fn test_924d038f() {str(include_str!("test-resources/omnibus/924D038F.bitsy.txt"), "924D038F");}
|
||||||
|
#[test] fn test_926a622e() {str(include_str!("test-resources/omnibus/926A622E.bitsy.txt"), "926A622E");}
|
||||||
|
#[test] fn test_92d589b9() {str(include_str!("test-resources/omnibus/92D589B9.bitsy.txt"), "92D589B9");}
|
||||||
|
#[test] fn test_9372ade8() {str(include_str!("test-resources/omnibus/9372ADE8.bitsy.txt"), "9372ADE8");}
|
||||||
|
#[test] fn test_938468ba() {str(include_str!("test-resources/omnibus/938468BA.bitsy.txt"), "938468BA");}
|
||||||
|
#[test] fn test_94612f67() {str(include_str!("test-resources/omnibus/94612F67.bitsy.txt"), "94612F67");}
|
||||||
|
#[test] fn test_946e85b3() {str(include_str!("test-resources/omnibus/946E85B3.bitsy.txt"), "946E85B3");}
|
||||||
|
#[test] fn test_947c7544() {str(include_str!("test-resources/omnibus/947C7544.bitsy.txt"), "947C7544");}
|
||||||
|
#[test] fn test_9484fd34() {str(include_str!("test-resources/omnibus/9484FD34.bitsy.txt"), "9484FD34");}
|
||||||
|
#[test] fn test_94943e5c() {str(include_str!("test-resources/omnibus/94943E5C.bitsy.txt"), "94943E5C");}
|
||||||
|
#[test] fn test_94fd6705() {str(include_str!("test-resources/omnibus/94FD6705.bitsy.txt"), "94FD6705");}
|
||||||
|
#[test] fn test_955b75c9() {str(include_str!("test-resources/omnibus/955B75C9.bitsy.txt"), "955B75C9");}
|
||||||
|
#[test] fn test_967dfe88() {str(include_str!("test-resources/omnibus/967DFE88.bitsy.txt"), "967DFE88");}
|
||||||
|
#[test] fn test_9724bf5e() {str(include_str!("test-resources/omnibus/9724BF5E.bitsy.txt"), "9724BF5E");}
|
||||||
|
#[test] fn test_974aa125() {str(include_str!("test-resources/omnibus/974AA125.bitsy.txt"), "974AA125");}
|
||||||
|
#[test] fn test_976e1d47() {str(include_str!("test-resources/omnibus/976E1D47.bitsy.txt"), "976E1D47");}
|
||||||
|
#[test] fn test_97812dac() {str(include_str!("test-resources/omnibus/97812DAC.bitsy.txt"), "97812DAC");}
|
||||||
|
#[test] fn test_98509df4() {str(include_str!("test-resources/omnibus/98509DF4.bitsy.txt"), "98509DF4");}
|
||||||
|
#[test] fn test_98b2b460() {str(include_str!("test-resources/omnibus/98B2B460.bitsy.txt"), "98B2B460");}
|
||||||
|
#[test] fn test_9927728d() {str(include_str!("test-resources/omnibus/9927728D.bitsy.txt"), "9927728D");}
|
||||||
|
#[test] fn test_99d3df43() {str(include_str!("test-resources/omnibus/99D3DF43.bitsy.txt"), "99D3DF43");}
|
||||||
|
#[test] fn test_99ea5769() {str(include_str!("test-resources/omnibus/99EA5769.bitsy.txt"), "99EA5769");}
|
||||||
|
#[test] fn test_9acccd68() {str(include_str!("test-resources/omnibus/9ACCCD68.bitsy.txt"), "9ACCCD68");}
|
||||||
|
#[test] fn test_9ad2a574() {str(include_str!("test-resources/omnibus/9AD2A574.bitsy.txt"), "9AD2A574");}
|
||||||
|
#[test] fn test_9b411e31() {str(include_str!("test-resources/omnibus/9B411E31.bitsy.txt"), "9B411E31");}
|
||||||
|
#[test] fn test_9c8ecf36() {str(include_str!("test-resources/omnibus/9C8ECF36.bitsy.txt"), "9C8ECF36");}
|
||||||
|
#[test] fn test_9da3b70d() {str(include_str!("test-resources/omnibus/9DA3B70D.bitsy.txt"), "9DA3B70D");}
|
||||||
|
#[test] fn test_9dad710d() {str(include_str!("test-resources/omnibus/9DAD710D.bitsy.txt"), "9DAD710D");}
|
||||||
|
#[test] fn test_9de4c3ba() {str(include_str!("test-resources/omnibus/9DE4C3BA.bitsy.txt"), "9DE4C3BA");}
|
||||||
|
#[test] fn test_9f39737d() {str(include_str!("test-resources/omnibus/9F39737D.bitsy.txt"), "9F39737D");}
|
||||||
|
#[test] fn test_9fcfddbc() {str(include_str!("test-resources/omnibus/9FCFDDBC.bitsy.txt"), "9FCFDDBC");}
|
||||||
|
#[test] fn test_a09d5907() {str(include_str!("test-resources/omnibus/A09D5907.bitsy.txt"), "A09D5907");}
|
||||||
|
#[test] fn test_a19f89f1() {str(include_str!("test-resources/omnibus/A19F89F1.bitsy.txt"), "A19F89F1");}
|
||||||
|
#[test] fn test_a1ae038d() {str(include_str!("test-resources/omnibus/A1AE038D.bitsy.txt"), "A1AE038D");}
|
||||||
|
#[test] fn test_a1b12872() {str(include_str!("test-resources/omnibus/A1B12872.bitsy.txt"), "A1B12872");}
|
||||||
|
#[test] fn test_a3b29805() {str(include_str!("test-resources/omnibus/A3B29805.bitsy.txt"), "A3B29805");}
|
||||||
|
#[test] fn test_a418d2ab() {str(include_str!("test-resources/omnibus/A418D2AB.bitsy.txt"), "A418D2AB");}
|
||||||
|
#[test] fn test_a5816c9c() {str(include_str!("test-resources/omnibus/A5816C9C.bitsy.txt"), "A5816C9C");}
|
||||||
|
#[test] fn test_a5cfeed6() {str(include_str!("test-resources/omnibus/A5CFEED6.bitsy.txt"), "A5CFEED6");}
|
||||||
|
#[test] fn test_a7183583() {str(include_str!("test-resources/omnibus/A7183583.bitsy.txt"), "A7183583");}
|
||||||
|
#[test] fn test_a7df882e() {str(include_str!("test-resources/omnibus/A7DF882E.bitsy.txt"), "A7DF882E");}
|
||||||
|
#[test] fn test_a7f51ae4() {str(include_str!("test-resources/omnibus/A7F51AE4.bitsy.txt"), "A7F51AE4");}
|
||||||
|
#[test] fn test_a82f4321() {str(include_str!("test-resources/omnibus/A82F4321.bitsy.txt"), "A82F4321");}
|
||||||
|
#[test] fn test_a8d107b2() {str(include_str!("test-resources/omnibus/A8D107B2.bitsy.txt"), "A8D107B2");}
|
||||||
|
#[test] fn test_aa007e54() {str(include_str!("test-resources/omnibus/AA007E54.bitsy.txt"), "AA007E54");}
|
||||||
|
#[test] fn test_ab368cec() {str(include_str!("test-resources/omnibus/AB368CEC.bitsy.txt"), "AB368CEC");}
|
||||||
|
#[test] fn test_ac7e9f07() {str(include_str!("test-resources/omnibus/AC7E9F07.bitsy.txt"), "AC7E9F07");}
|
||||||
|
#[test] fn test_ad97fbc3() {str(include_str!("test-resources/omnibus/AD97FBC3.bitsy.txt"), "AD97FBC3");}
|
||||||
|
#[test] fn test_adb7c913() {str(include_str!("test-resources/omnibus/ADB7C913.bitsy.txt"), "ADB7C913");}
|
||||||
|
#[test] fn test_afa24079() {str(include_str!("test-resources/omnibus/AFA24079.bitsy.txt"), "AFA24079");}
|
||||||
|
#[test] fn test_b16974f7() {str(include_str!("test-resources/omnibus/B16974F7.bitsy.txt"), "B16974F7");}
|
||||||
|
#[test] fn test_b34f07d5() {str(include_str!("test-resources/omnibus/B34F07D5.bitsy.txt"), "B34F07D5");}
|
||||||
|
#[test] fn test_b53d6e92() {str(include_str!("test-resources/omnibus/B53D6E92.bitsy.txt"), "B53D6E92");}
|
||||||
|
#[test] fn test_b545feac() {str(include_str!("test-resources/omnibus/B545FEAC.bitsy.txt"), "B545FEAC");}
|
||||||
|
#[test] fn test_b6370aff() {str(include_str!("test-resources/omnibus/B6370AFF.bitsy.txt"), "B6370AFF");}
|
||||||
|
#[test] fn test_b74f7f7a() {str(include_str!("test-resources/omnibus/B74F7F7A.bitsy.txt"), "B74F7F7A");}
|
||||||
|
#[test] fn test_b7b61117() {str(include_str!("test-resources/omnibus/B7B61117.bitsy.txt"), "B7B61117");}
|
||||||
|
#[test] fn test_b831fb24() {str(include_str!("test-resources/omnibus/B831FB24.bitsy.txt"), "B831FB24");}
|
||||||
|
#[test] fn test_b8e10418() {str(include_str!("test-resources/omnibus/B8E10418.bitsy.txt"), "B8E10418");}
|
||||||
|
#[test] fn test_b9e61bc6() {str(include_str!("test-resources/omnibus/B9E61BC6.bitsy.txt"), "B9E61BC6");}
|
||||||
|
#[test] fn test_ba102197() {str(include_str!("test-resources/omnibus/BA102197.bitsy.txt"), "BA102197");}
|
||||||
|
#[test] fn test_bb5d0d6c() {str(include_str!("test-resources/omnibus/BB5D0D6C.bitsy.txt"), "BB5D0D6C");}
|
||||||
|
#[test] fn test_bbb98596() {str(include_str!("test-resources/omnibus/BBB98596.bitsy.txt"), "BBB98596");}
|
||||||
|
#[test] fn test_bc0dce5c() {str(include_str!("test-resources/omnibus/BC0DCE5C.bitsy.txt"), "BC0DCE5C");}
|
||||||
|
#[test] fn test_bc8b3e64() {str(include_str!("test-resources/omnibus/BC8B3E64.bitsy.txt"), "BC8B3E64");}
|
||||||
|
#[test] fn test_bcc99eb5() {str(include_str!("test-resources/omnibus/BCC99EB5.bitsy.txt"), "BCC99EB5");}
|
||||||
|
#[test] fn test_bd621b6d() {str(include_str!("test-resources/omnibus/BD621B6D.bitsy.txt"), "BD621B6D");}
|
||||||
|
#[test] fn test_bdd57b7d() {str(include_str!("test-resources/omnibus/BDD57B7D.bitsy.txt"), "BDD57B7D");}
|
||||||
|
#[test] fn test_bebd5115() {str(include_str!("test-resources/omnibus/BEBD5115.bitsy.txt"), "BEBD5115");}
|
||||||
|
#[test] fn test_bf15da66() {str(include_str!("test-resources/omnibus/BF15DA66.bitsy.txt"), "BF15DA66");}
|
||||||
|
#[test] fn test_c03befc8() {str(include_str!("test-resources/omnibus/C03BEFC8.bitsy.txt"), "C03BEFC8");}
|
||||||
|
#[test] fn test_c0be7f65() {str(include_str!("test-resources/omnibus/C0BE7F65.bitsy.txt"), "C0BE7F65");}
|
||||||
|
#[test] fn test_c1dc0328() {str(include_str!("test-resources/omnibus/C1DC0328.bitsy.txt"), "C1DC0328");}
|
||||||
|
#[test] fn test_c2493877() {str(include_str!("test-resources/omnibus/C2493877.bitsy.txt"), "C2493877");}
|
||||||
|
#[test] fn test_c2ef387a() {str(include_str!("test-resources/omnibus/C2EF387A.bitsy.txt"), "C2EF387A");}
|
||||||
|
#[test] fn test_c353f7cf() {str(include_str!("test-resources/omnibus/C353F7CF.bitsy.txt"), "C353F7CF");}
|
||||||
|
#[test] fn test_c49c625e() {str(include_str!("test-resources/omnibus/C49C625E.bitsy.txt"), "C49C625E");}
|
||||||
|
#[test] fn test_c50eb781() {str(include_str!("test-resources/omnibus/C50EB781.bitsy.txt"), "C50EB781");}
|
||||||
|
#[test] fn test_c5cf3fda() {str(include_str!("test-resources/omnibus/C5CF3FDA.bitsy.txt"), "C5CF3FDA");}
|
||||||
|
#[test] fn test_c6617fa2() {str(include_str!("test-resources/omnibus/C6617FA2.bitsy.txt"), "C6617FA2");}
|
||||||
|
#[test] fn test_c673ea1b() {str(include_str!("test-resources/omnibus/C673EA1B.bitsy.txt"), "C673EA1B");}
|
||||||
|
#[test] fn test_c6e7831c() {str(include_str!("test-resources/omnibus/C6E7831C.bitsy.txt"), "C6E7831C");}
|
||||||
|
#[test] fn test_c8421383() {str(include_str!("test-resources/omnibus/C8421383.bitsy.txt"), "C8421383");}
|
||||||
|
#[test] fn test_c872d239() {str(include_str!("test-resources/omnibus/C872D239.bitsy.txt"), "C872D239");}
|
||||||
|
#[test] fn test_c87e0b9f() {str(include_str!("test-resources/omnibus/C87E0B9F.bitsy.txt"), "C87E0B9F");}
|
||||||
|
#[test] fn test_c8c0d6bd() {str(include_str!("test-resources/omnibus/C8C0D6BD.bitsy.txt"), "C8C0D6BD");}
|
||||||
|
#[test] fn test_c9ad2be0() {str(include_str!("test-resources/omnibus/C9AD2BE0.bitsy.txt"), "C9AD2BE0");}
|
||||||
|
#[test] fn test_cb70cded() {str(include_str!("test-resources/omnibus/CB70CDED.bitsy.txt"), "CB70CDED");}
|
||||||
|
#[test] fn test_cbb105d7() {str(include_str!("test-resources/omnibus/CBB105D7.bitsy.txt"), "CBB105D7");}
|
||||||
|
#[test] fn test_cbbfb107() {str(include_str!("test-resources/omnibus/CBBFB107.bitsy.txt"), "CBBFB107");}
|
||||||
|
#[test] fn test_cbf9a0c0() {str(include_str!("test-resources/omnibus/CBF9A0C0.bitsy.txt"), "CBF9A0C0");}
|
||||||
|
#[test] fn test_cc34457e() {str(include_str!("test-resources/omnibus/CC34457E.bitsy.txt"), "CC34457E");}
|
||||||
|
#[test] fn test_cd609e8e() {str(include_str!("test-resources/omnibus/CD609E8E.bitsy.txt"), "CD609E8E");}
|
||||||
|
#[test] fn test_ce0512b2() {str(include_str!("test-resources/omnibus/CE0512B2.bitsy.txt"), "CE0512B2");}
|
||||||
|
#[test] fn test_ce59a086() {str(include_str!("test-resources/omnibus/CE59A086.bitsy.txt"), "CE59A086");}
|
||||||
|
#[test] fn test_cf890145() {str(include_str!("test-resources/omnibus/CF890145.bitsy.txt"), "CF890145");}
|
||||||
|
#[test] fn test_cf89e555() {str(include_str!("test-resources/omnibus/CF89E555.bitsy.txt"), "CF89E555");}
|
||||||
|
#[test] fn test_cfbe5bdf() {str(include_str!("test-resources/omnibus/CFBE5BDF.bitsy.txt"), "CFBE5BDF");}
|
||||||
|
#[test] fn test_cfe62f11() {str(include_str!("test-resources/omnibus/CFE62F11.bitsy.txt"), "CFE62F11");}
|
||||||
|
#[test] fn test_cff98f1a() {str(include_str!("test-resources/omnibus/CFF98F1A.bitsy.txt"), "CFF98F1A");}
|
||||||
|
#[test] fn test_d07caf2a() {str(include_str!("test-resources/omnibus/D07CAF2A.bitsy.txt"), "D07CAF2A");}
|
||||||
|
#[test] fn test_d173c9c5() {str(include_str!("test-resources/omnibus/D173C9C5.bitsy.txt"), "D173C9C5");}
|
||||||
|
#[test] fn test_d1be479b() {str(include_str!("test-resources/omnibus/D1BE479B.bitsy.txt"), "D1BE479B");}
|
||||||
|
#[test] fn test_d1fb278a() {str(include_str!("test-resources/omnibus/D1FB278A.bitsy.txt"), "D1FB278A");}
|
||||||
|
#[test] fn test_d2a4d690() {str(include_str!("test-resources/omnibus/D2A4D690.bitsy.txt"), "D2A4D690");}
|
||||||
|
#[test] fn test_d336f626() {str(include_str!("test-resources/omnibus/D336F626.bitsy.txt"), "D336F626");}
|
||||||
|
#[test] fn test_d35b2e27() {str(include_str!("test-resources/omnibus/D35B2E27.bitsy.txt"), "D35B2E27");}
|
||||||
|
#[test] fn test_d373f018() {str(include_str!("test-resources/omnibus/D373F018.bitsy.txt"), "D373F018");}
|
||||||
|
#[test] fn test_d3a5c1d7() {str(include_str!("test-resources/omnibus/D3A5C1D7.bitsy.txt"), "D3A5C1D7");}
|
||||||
|
#[test] fn test_d498eefa() {str(include_str!("test-resources/omnibus/D498EEFA.bitsy.txt"), "D498EEFA");}
|
||||||
|
#[test] fn test_d53b7c03() {str(include_str!("test-resources/omnibus/D53B7C03.bitsy.txt"), "D53B7C03");}
|
||||||
|
#[test] fn test_d60e6d7f() {str(include_str!("test-resources/omnibus/D60E6D7F.bitsy.txt"), "D60E6D7F");}
|
||||||
|
#[test] fn test_d8480dc7() {str(include_str!("test-resources/omnibus/D8480DC7.bitsy.txt"), "D8480DC7");}
|
||||||
|
#[test] fn test_d84cbfff() {str(include_str!("test-resources/omnibus/D84CBFFF.bitsy.txt"), "D84CBFFF");}
|
||||||
|
#[test] fn test_d903b657() {str(include_str!("test-resources/omnibus/D903B657.bitsy.txt"), "D903B657");}
|
||||||
|
#[test] fn test_da70c62c() {str(include_str!("test-resources/omnibus/DA70C62C.bitsy.txt"), "DA70C62C");}
|
||||||
|
#[test] fn test_da88c287() {str(include_str!("test-resources/omnibus/DA88C287.bitsy.txt"), "DA88C287");}
|
||||||
|
#[test] fn test_dabc1b16() {str(include_str!("test-resources/omnibus/DABC1B16.bitsy.txt"), "DABC1B16");}
|
||||||
|
#[test] fn test_db59a848() {str(include_str!("test-resources/omnibus/DB59A848.bitsy.txt"), "DB59A848");}
|
||||||
|
#[test] fn test_db74abe2() {str(include_str!("test-resources/omnibus/DB74ABE2.bitsy.txt"), "DB74ABE2");}
|
||||||
|
#[test] fn test_dbd5d375() {str(include_str!("test-resources/omnibus/DBD5D375.bitsy.txt"), "DBD5D375");}
|
||||||
|
#[test] fn test_dc053b1a() {str(include_str!("test-resources/omnibus/DC053B1A.bitsy.txt"), "DC053B1A");}
|
||||||
|
#[test] fn test_dcdd7569() {str(include_str!("test-resources/omnibus/DCDD7569.bitsy.txt"), "DCDD7569");}
|
||||||
|
#[test] fn test_dd5be55b() {str(include_str!("test-resources/omnibus/DD5BE55B.bitsy.txt"), "DD5BE55B");}
|
||||||
|
#[test] fn test_de25b125() {str(include_str!("test-resources/omnibus/DE25B125.bitsy.txt"), "DE25B125");}
|
||||||
|
#[test] fn test_ded097eb() {str(include_str!("test-resources/omnibus/DED097EB.bitsy.txt"), "DED097EB");}
|
||||||
|
#[test] fn test_df0ba198() {str(include_str!("test-resources/omnibus/DF0BA198.bitsy.txt"), "DF0BA198");}
|
||||||
|
#[test] fn test_df7f0379() {str(include_str!("test-resources/omnibus/DF7F0379.bitsy.txt"), "DF7F0379");}
|
||||||
|
#[test] fn test_e058a61f() {str(include_str!("test-resources/omnibus/E058A61F.bitsy.txt"), "E058A61F");}
|
||||||
|
#[test] fn test_e1c8834b() {str(include_str!("test-resources/omnibus/E1C8834B.bitsy.txt"), "E1C8834B");}
|
||||||
|
#[test] fn test_e1cd8743() {str(include_str!("test-resources/omnibus/E1CD8743.bitsy.txt"), "E1CD8743");}
|
||||||
|
#[test] fn test_e1f19987() {str(include_str!("test-resources/omnibus/E1F19987.bitsy.txt"), "E1F19987");}
|
||||||
|
#[test] fn test_e2417e83() {str(include_str!("test-resources/omnibus/E2417E83.bitsy.txt"), "E2417E83");}
|
||||||
|
#[test] fn test_e363f335() {str(include_str!("test-resources/omnibus/E363F335.bitsy.txt"), "E363F335");}
|
||||||
|
#[test] fn test_e46023b3() {str(include_str!("test-resources/omnibus/E46023B3.bitsy.txt"), "E46023B3");}
|
||||||
|
#[test] fn test_e48dccdb() {str(include_str!("test-resources/omnibus/E48DCCDB.bitsy.txt"), "E48DCCDB");}
|
||||||
|
#[test] fn test_e4a85876() {str(include_str!("test-resources/omnibus/E4A85876.bitsy.txt"), "E4A85876");}
|
||||||
|
#[test] fn test_e5d4285e() {str(include_str!("test-resources/omnibus/E5D4285E.bitsy.txt"), "E5D4285E");}
|
||||||
|
#[test] fn test_e6030df0() {str(include_str!("test-resources/omnibus/E6030DF0.bitsy.txt"), "E6030DF0");}
|
||||||
|
#[test] fn test_e69239ef() {str(include_str!("test-resources/omnibus/E69239EF.bitsy.txt"), "E69239EF");}
|
||||||
|
#[test] fn test_e971b9fd() {str(include_str!("test-resources/omnibus/E971B9FD.bitsy.txt"), "E971B9FD");}
|
||||||
|
#[test] fn test_e9bd845a() {str(include_str!("test-resources/omnibus/E9BD845A.bitsy.txt"), "E9BD845A");}
|
||||||
|
#[test] fn test_eadd856d() {str(include_str!("test-resources/omnibus/EADD856D.bitsy.txt"), "EADD856D");}
|
||||||
|
#[test] fn test_eb09383e() {str(include_str!("test-resources/omnibus/EB09383E.bitsy.txt"), "EB09383E");}
|
||||||
|
#[test] fn test_ec269334() {str(include_str!("test-resources/omnibus/EC269334.bitsy.txt"), "EC269334");}
|
||||||
|
#[test] fn test_ec8e4594() {str(include_str!("test-resources/omnibus/EC8E4594.bitsy.txt"), "EC8E4594");}
|
||||||
|
#[test] fn test_ecd56a4f() {str(include_str!("test-resources/omnibus/ECD56A4F.bitsy.txt"), "ECD56A4F");}
|
||||||
|
#[test] fn test_ed47e5ed() {str(include_str!("test-resources/omnibus/ED47E5ED.bitsy.txt"), "ED47E5ED");}
|
||||||
|
#[test] fn test_ed62fac9() {str(include_str!("test-resources/omnibus/ED62FAC9.bitsy.txt"), "ED62FAC9");}
|
||||||
|
#[test] fn test_edb03d05() {str(include_str!("test-resources/omnibus/EDB03D05.bitsy.txt"), "EDB03D05");}
|
||||||
|
#[test] fn test_ee642f55() {str(include_str!("test-resources/omnibus/EE642F55.bitsy.txt"), "EE642F55");}
|
||||||
|
#[test] fn test_ef26697e() {str(include_str!("test-resources/omnibus/EF26697E.bitsy.txt"), "EF26697E");}
|
||||||
|
#[test] fn test_ef763825() {str(include_str!("test-resources/omnibus/EF763825.bitsy.txt"), "EF763825");}
|
||||||
|
#[test] fn test_f02bd788() {str(include_str!("test-resources/omnibus/F02BD788.bitsy.txt"), "F02BD788");}
|
||||||
|
#[test] fn test_f22c1fa2() {str(include_str!("test-resources/omnibus/F22C1FA2.bitsy.txt"), "F22C1FA2");}
|
||||||
|
#[test] fn test_f31ca90b() {str(include_str!("test-resources/omnibus/F31CA90B.bitsy.txt"), "F31CA90B");}
|
||||||
|
#[test] fn test_f38c5522() {str(include_str!("test-resources/omnibus/F38C5522.bitsy.txt"), "F38C5522");}
|
||||||
|
#[test] fn test_f3af62e7() {str(include_str!("test-resources/omnibus/F3AF62E7.bitsy.txt"), "F3AF62E7");}
|
||||||
|
#[test] fn test_f3e61fc1() {str(include_str!("test-resources/omnibus/F3E61FC1.bitsy.txt"), "F3E61FC1");}
|
||||||
|
#[test] fn test_f52b510f() {str(include_str!("test-resources/omnibus/F52B510F.bitsy.txt"), "F52B510F");}
|
||||||
|
#[test] fn test_f60a4b5f() {str(include_str!("test-resources/omnibus/F60A4B5F.bitsy.txt"), "F60A4B5F");}
|
||||||
|
#[test] fn test_f64d8936() {str(include_str!("test-resources/omnibus/F64D8936.bitsy.txt"), "F64D8936");}
|
||||||
|
#[test] fn test_f673def5() {str(include_str!("test-resources/omnibus/F673DEF5.bitsy.txt"), "F673DEF5");}
|
||||||
|
#[test] fn test_f6f5e3fb() {str(include_str!("test-resources/omnibus/F6F5E3FB.bitsy.txt"), "F6F5E3FB");}
|
||||||
|
#[test] fn test_f712f2f3() {str(include_str!("test-resources/omnibus/F712F2F3.bitsy.txt"), "F712F2F3");}
|
||||||
|
#[test] fn test_f79d5368() {str(include_str!("test-resources/omnibus/F79D5368.bitsy.txt"), "F79D5368");}
|
||||||
|
#[test] fn test_f8d7930c() {str(include_str!("test-resources/omnibus/F8D7930C.bitsy.txt"), "F8D7930C");}
|
||||||
|
#[test] fn test_f9b6e61f() {str(include_str!("test-resources/omnibus/F9B6E61F.bitsy.txt"), "F9B6E61F");}
|
||||||
|
#[test] fn test_fa4eb7c6() {str(include_str!("test-resources/omnibus/FA4EB7C6.bitsy.txt"), "FA4EB7C6");}
|
||||||
|
#[test] fn test_fc8a7441() {str(include_str!("test-resources/omnibus/FC8A7441.bitsy.txt"), "FC8A7441");}
|
||||||
|
#[test] fn test_fcd95029() {str(include_str!("test-resources/omnibus/FCD95029.bitsy.txt"), "FCD95029");}
|
||||||
|
#[test] fn test_fe53ef82() {str(include_str!("test-resources/omnibus/FE53EF82.bitsy.txt"), "FE53EF82");}
|
||||||
|
#[test] fn test_fe6547de() {str(include_str!("test-resources/omnibus/FE6547DE.bitsy.txt"), "FE6547DE");}
|
||||||
|
#[test] fn test_ff3857ae() {str(include_str!("test-resources/omnibus/FF3857AE.bitsy.txt"), "FF3857AE");}
|
||||||
|
#[test] fn test_ff7bcf9c() {str(include_str!("test-resources/omnibus/FF7BCF9C.bitsy.txt"), "FF7BCF9C");}
|
||||||
|
#[test] fn test_goodbyes() {str(include_str!("test-resources/goodbye_summer.bitsy"), "goodbye_summer");}
|
||||||
|
}
|
||||||
@@ -19,13 +19,13 @@ impl Font {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn to_string(&self) -> Result<String, &'static str> {
|
pub(crate) fn to_string(&self) -> Result<String, crate::Error> {
|
||||||
match &self {
|
match &self {
|
||||||
Font::UnicodeEuropeanSmall => Ok("unicode_european_small".to_string()),
|
Font::UnicodeEuropeanSmall => Ok("unicode_european_small".to_string()),
|
||||||
Font::UnicodeEuropeanLarge => Ok("unicode_european_large".to_string()),
|
Font::UnicodeEuropeanLarge => Ok("unicode_european_large".to_string()),
|
||||||
Font::UnicodeAsian => Ok("unicode_asian".to_string()),
|
Font::UnicodeAsian => Ok("unicode_asian".to_string()),
|
||||||
Font::Arabic => Ok("arabic".to_string()),
|
Font::Arabic => Ok("arabic".to_string()),
|
||||||
_ => Err("No string available for this Font"),
|
_ => Err(crate::Error::Font),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
30
src/tile.rs
30
src/tile.rs
@@ -1,16 +1,23 @@
|
|||||||
use crate::{optional_data_line, AnimationFrames, Image};
|
use crate::{optional_data_line, AnimationFrames, Image};
|
||||||
use crate::image::animation_frames_from_string;
|
use crate::image::animation_frames_from_str;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq)]
|
#[derive(Clone, Debug, Eq)]
|
||||||
pub struct Tile {
|
pub struct Tile {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub wall: Option<bool>, // this is "optional" in that a tile can have `WAL true|false` or neither
|
/// Can the player move over this tile?
|
||||||
|
/// This is "optional" in that a tile can have `WAL true`, `WAL false` or neither.
|
||||||
|
/// obviously Some(false) is functionally the same as None
|
||||||
|
/// but we want to preserve the original formatting where possible.
|
||||||
|
pub wall: Option<bool>,
|
||||||
pub animation_frames: Vec<Image>,
|
pub animation_frames: Vec<Image>,
|
||||||
|
/// Bitsy has an undocumented feature where a tile can be rendered
|
||||||
|
/// in a specific colour (`COL n`) from the current palette.
|
||||||
pub colour_id: Option<u64>,
|
pub colour_id: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Tile {
|
impl PartialEq for Tile {
|
||||||
|
/// ignore id and name.
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.wall == other.wall
|
self.wall == other.wall
|
||||||
&&
|
&&
|
||||||
@@ -42,6 +49,7 @@ impl Tile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// todo refactor
|
// todo refactor
|
||||||
|
// can we do map_in_place or something?
|
||||||
|
|
||||||
pub fn invert(&mut self) {
|
pub fn invert(&mut self) {
|
||||||
self.animation_frames = self.animation_frames.iter().map(|frame: &Image| {
|
self.animation_frames = self.animation_frames.iter().map(|frame: &Image| {
|
||||||
@@ -101,9 +109,14 @@ impl From<String> for Tile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let animation_frames = animation_frames_from_string(
|
let animation_frames = match animation_frames_from_str(&lines[1..].join("\n")) {
|
||||||
lines[1..].join("\n")
|
Ok((animation_frames, _warnings)) => {
|
||||||
);
|
animation_frames
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
Vec::new()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
Tile {
|
Tile {
|
||||||
id,
|
id,
|
||||||
@@ -130,9 +143,7 @@ impl ToString for Tile {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::tile::Tile;
|
use crate::{Image, Tile, mock};
|
||||||
use crate::image::Image;
|
|
||||||
use crate::mock;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tile_from_string() {
|
fn tile_from_string() {
|
||||||
@@ -162,8 +173,7 @@ mod test {
|
|||||||
mock::image::chequers_2(),
|
mock::image::chequers_2(),
|
||||||
],
|
],
|
||||||
colour_id: None,
|
colour_id: None,
|
||||||
}
|
}.to_string();
|
||||||
.to_string();
|
|
||||||
|
|
||||||
let expected = include_str!("test-resources/tile-chequers").to_string();
|
let expected = include_str!("test-resources/tile-chequers").to_string();
|
||||||
|
|
||||||
|
|||||||
41
src/tune.rs
Normal file
41
src/tune.rs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
use std::fmt;
|
||||||
|
use std::fmt::{Formatter};
|
||||||
|
use crate::note::Note;
|
||||||
|
|
||||||
|
/// this seems to be complete as of 23/10/2022. there's no ExtraSlow or whatever
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum Tempo {
|
||||||
|
Slow,
|
||||||
|
Medium,
|
||||||
|
Fast,
|
||||||
|
ExtraFast,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Tempo {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", match self {
|
||||||
|
Tempo::Slow => "SLW",
|
||||||
|
Tempo::Medium => "MED",
|
||||||
|
Tempo::Fast => "FST",
|
||||||
|
Tempo::ExtraFast => "XFST",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Measure {
|
||||||
|
notes: [Note; 32],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Tune {
|
||||||
|
id: String,
|
||||||
|
// how many measures? should this be a slice? default game data tunes always have 8 measures
|
||||||
|
measures: Vec<Measure>,
|
||||||
|
name: Option<String>,
|
||||||
|
// todo key (this seems confusing, maybe just implement as a non-parsed string for now?)
|
||||||
|
tempo: Tempo,
|
||||||
|
// but what's the contents? enum?
|
||||||
|
arpeggio: Option<String>,
|
||||||
|
// todo sqr (waveform? not sure. maybe just implement as a non-parsed string for now?)
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ pub struct Variable {
|
|||||||
impl From<String> for Variable {
|
impl From<String> for Variable {
|
||||||
fn from(string: String) -> Variable {
|
fn from(string: String) -> Variable {
|
||||||
let id_value: Vec<&str> = string.lines().collect();
|
let id_value: Vec<&str> = string.lines().collect();
|
||||||
let id = id_value[0].replace("VAR ", "").to_string();
|
let id = id_value[0].replace("VAR ", "");
|
||||||
|
|
||||||
let initial_value = if id_value.len() == 1 {
|
let initial_value = if id_value.len() == 1 {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
@@ -27,7 +27,7 @@ impl ToString for Variable {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::variable::Variable;
|
use crate::Variable;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn variable_from_string() {
|
fn variable_from_string() {
|
||||||
|
|||||||
Reference in New Issue
Block a user