turn room format and room type into enums; transform line endings

This commit is contained in:
Max Bradbury 2020-04-24 18:06:17 +01:00
parent f4b82c3a67
commit 1c6e3eb515
5 changed files with 87 additions and 13 deletions

View File

@ -13,3 +13,4 @@ keywords = ["gamedev"]
[dependencies] [dependencies]
radix_fmt = "1.0.0" radix_fmt = "1.0.0"
loe = "0.2.0"

View File

@ -1,8 +1,51 @@
use crate::{ use crate::{Avatar, Dialogue, Ending, Font, Item, Palette, Room, Sprite, TextDirection, Tile, ToBase36, Variable, transform_line_endings};
optional_data_line, Avatar, Dialogue, Ending, Font, Item, Palette, Room, Sprite, TextDirection,
Tile, ToBase36, Variable,
};
use std::error::Error; use std::error::Error;
use loe::TransformMode;
/// in very early versions of Bitsy, room tiles were defined as single characters
/// so, only 36 tiles total. later versions are comma-separated
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum RoomFormat {Contiguous, CommaSeparated}
impl RoomFormat {
fn from(str: &str) -> Result<RoomFormat, &'static dyn Error> {
match str {
"0" => Ok(RoomFormat::Contiguous),
"1" => Ok(RoomFormat::CommaSeparated),
_ => panic!(format!("Invalid room format: {}", str)),
}
}
fn to_string(&self) -> String {
match &self {
RoomFormat::Contiguous => "0",
RoomFormat::CommaSeparated => "1",
}.to_string()
}
}
/// in very early versions of Bitsy, a room was called a "set"
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum RoomType {Room, Set}
impl From<&str> for RoomType {
fn from(string: &str) -> RoomType {
match string {
"ROOM" => RoomType::Room,
"SET" => RoomType::Set,
_ => panic!("Unrecognised room type"),
}
}
}
impl ToString for RoomType {
fn to_string(&self) -> String {
match &self {
RoomType::Set => "SET",
RoomType::Room => "ROOM",
}.to_string()
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone)] #[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub struct Version { pub struct Version {
@ -25,7 +68,8 @@ impl Version {
pub struct Game { pub struct Game {
pub name: String, pub name: String,
pub version: Option<Version>, pub version: Option<Version>,
pub room_format: u8, // this is "0 = non-comma separated, 1 = comma separated" apparently pub room_format: Option<RoomFormat>,
pub(crate) room_type: RoomType,
pub font: Font, pub font: Font,
pub custom_font: Option<String>, // used if font is Font::Custom pub custom_font: Option<String>, // used if font is Font::Custom
pub text_direction: TextDirection, pub text_direction: TextDirection,
@ -44,6 +88,12 @@ pub struct Game {
impl Game { impl Game {
pub fn from(string: String) -> Result<Game, &'static dyn Error> { pub fn from(string: String) -> Result<Game, &'static dyn Error> {
let line_endings_crlf = string.contains("\r\n");
let mut string = string;
if line_endings_crlf {
string = transform_line_endings(string, TransformMode::LF)
}
let mut string = format!("{}\n\n", string.trim_matches('\n')); let mut string = format!("{}\n\n", string.trim_matches('\n'));
if string.starts_with("# BITSY VERSION") { if string.starts_with("# BITSY VERSION") {
@ -105,7 +155,8 @@ impl Game {
let name = segments[0].to_string(); let name = segments[0].to_string();
let mut version = None; let mut version = None;
let mut room_format: u8 = 1; let mut room_format = None;
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;
let mut text_direction = TextDirection::LeftToRight; let mut text_direction = TextDirection::LeftToRight;
@ -123,7 +174,8 @@ impl Game {
let segment = segment.replace("# BITSY VERSION ", ""); let segment = segment.replace("# BITSY VERSION ", "");
version = Some(Version::from(&segment)); version = Some(Version::from(&segment));
} else if segment.starts_with("! ROOM_FORMAT") { } else if segment.starts_with("! ROOM_FORMAT") {
room_format = segment.replace("! ROOM_FORMAT ", "").parse().unwrap(); let segment = segment.replace("! ROOM_FORMAT ", "");
room_format = Some(RoomFormat::from(&segment).unwrap());
} 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 ", "");
@ -137,6 +189,9 @@ impl Game {
} else if segment.starts_with("PAL") { } else if segment.starts_with("PAL") {
palettes.push(Palette::from(segment)); palettes.push(Palette::from(segment));
} 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") {
room_type = RoomType::Set;
}
rooms.push(Room::from(segment)); rooms.push(Room::from(segment));
} else if segment.starts_with("TIL") { } else if segment.starts_with("TIL") {
tiles.push(Tile::from(segment)); tiles.push(Tile::from(segment));
@ -156,6 +211,7 @@ impl Game {
name, name,
version, version,
room_format, room_format,
room_type,
font, font,
custom_font, custom_font,
text_direction, text_direction,
@ -169,7 +225,7 @@ impl Game {
endings, endings,
variables, variables,
font_data, font_data,
line_endings_crlf: false line_endings_crlf
}) })
} }
} }

View File

@ -1,4 +1,8 @@
extern crate loe;
use std::io::Cursor;
use radix_fmt::radix_36; use radix_fmt::radix_36;
use loe::{process, Config, TransformMode};
pub mod avatar; pub mod avatar;
pub mod colour; pub mod colour;
@ -96,6 +100,14 @@ fn optional_data_line<T: Display>(label: &str, item: Option<T>) -> String {
} }
} }
fn transform_line_endings(input: String, mode: TransformMode) -> String {
let mut input = Cursor::new(input);
let mut output = Cursor::new(Vec::new());
process(&mut input, &mut output, Config::default().transform(mode)).unwrap();
String::from_utf8(output.into_inner()).unwrap()
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::{from_base36, ToBase36, optional_data_line, mock}; use crate::{from_base36, ToBase36, optional_data_line, mock};

View File

@ -1,4 +1,5 @@
use crate::*; use crate::*;
use crate::game::{RoomType, RoomFormat};
pub mod image { pub mod image {
use crate::Image; use crate::Image;
@ -404,7 +405,8 @@ 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: 6, minor: 5 }), version: Some(Version { major: 6, minor: 5 }),
room_format: 1, room_format: Some(RoomFormat::CommaSeparated),
room_type: RoomType::Room,
font: Font::AsciiSmall, font: Font::AsciiSmall,
custom_font: None, custom_font: None,
text_direction: TextDirection::LeftToRight, text_direction: TextDirection::LeftToRight,

View File

@ -1,4 +1,5 @@
use crate::{from_base36, optional_data_line, Exit, ExitInstance, Instance, Position, ToBase36}; use crate::{from_base36, optional_data_line, Exit, ExitInstance, Instance, Position, ToBase36};
use crate::game::{RoomType, RoomFormat};
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Room { pub struct Room {
@ -125,8 +126,8 @@ impl From<String> for Room {
} }
} }
impl ToString for Room { impl Room {
fn to_string(&self) -> String { pub fn to_string(&self, room_format: RoomFormat, room_type: RoomType) -> String {
let mut tiles = String::new(); let mut tiles = String::new();
let mut items = String::new(); let mut items = String::new();
let mut exits = String::new(); let mut exits = String::new();
@ -167,7 +168,8 @@ impl ToString for Room {
} }
format!( format!(
"ROOM {}\n{}{}{}{}{}{}{}", "{} {}\n{}{}{}{}{}{}{}",
room_type.to_string(),
self.id.to_base36(), self.id.to_base36(),
tiles, tiles,
self.name_line(), self.name_line(),
@ -183,6 +185,7 @@ impl ToString for Room {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::room::Room; use crate::room::Room;
use crate::game::{RoomType, RoomFormat};
#[test] #[test]
fn test_room_from_string() { fn test_room_from_string() {
@ -195,7 +198,7 @@ mod test {
#[test] #[test]
fn test_room_to_string() { fn test_room_to_string() {
assert_eq!( assert_eq!(
crate::mock::room().to_string(), crate::mock::room().to_string(RoomFormat::CommaSeparated, RoomType::Room),
include_str!("test-resources/room").to_string() include_str!("test-resources/room").to_string()
); );
} }