Files
peachy/src/lib.rs

332 lines
7.9 KiB
Rust
Raw Normal View History

2020-09-02 17:50:13 +01:00
use std::fs;
use std::path::PathBuf;
2020-09-02 17:50:13 +01:00
mod colour;
mod config;
2021-05-19 11:07:49 +01:00
mod entity;
mod image;
mod mock;
2021-05-18 00:05:39 +01:00
mod music;
mod palette;
2021-05-17 20:50:32 +01:00
mod scene;
2021-05-18 22:09:08 +01:00
mod tile;
2020-09-02 17:50:13 +01:00
pub use colour::Colour;
2021-05-18 00:05:39 +01:00
pub use config::Config;
2021-05-19 11:42:49 +01:00
pub use entity::Entity;
2021-05-18 21:33:03 +01:00
pub use crate::image::Image;
2021-05-18 00:05:39 +01:00
pub use music::Music;
pub use palette::Palette;
2021-05-17 20:50:32 +01:00
pub use scene::Scene;
2021-05-19 11:42:49 +01:00
pub use tile::Tile;
2020-09-02 17:50:13 +01:00
2021-05-17 20:50:32 +01:00
#[derive(Debug, Eq, Hash, PartialEq)]
2020-09-02 17:50:13 +01:00
pub struct Position {
x: u8,
y: u8,
}
2021-11-14 18:07:57 +00:00
impl Position {
pub fn to_index(&self, width: u8) -> u16 {
(self.y * width + self.x) as u16
}
}
2020-09-02 17:50:13 +01:00
// #[derive(Serialize, Deserialize)]
// pub enum DataType {
// Image,
// Integer,
// Palette,
// Room,
// Script,
// String,
// Thing,
// Variable,
// }
//
// /// todo refactor, this is stupid
// #[derive(Serialize, Deserialize)]
// pub struct Value {
// data_type: DataType,
// image: Option<String>,
// integer: Option<u64>,
// palette: Option<String>,
// room: Option<String>,
// script: Option<String>,
// string: Option<String>,
// thing: Option<String>,
// variable: Option<String>,
// }
//
// #[derive(Serialize, Deserialize)]
// pub struct Variable {
// name: String,
// data_type: DataType,
// default: Value,
// }
//
// #[derive(Serialize, Deserialize)]
// pub struct Parameter {
// name: String,
// data_type: DataType,
// default: Value,
// }
//
// #[derive(Serialize, Deserialize)]
// pub struct Script {
// name: Option<String>,
// params: Vec<Parameter>,
// script: String,
// }
//
// #[derive(Serialize, Deserialize)]
// pub struct ScriptInstance {
// script: String,
// params: HashMap<String, Value>,
// }
//
// #[derive(Serialize, Deserialize)]
// pub struct ScriptCollection {
// scripts: Vec<ScriptInstance>,
// /// as well as many named scripts, a trigger can have one anonymous script
// anonymous: Option<String>,
// }
//
// #[derive(Serialize, Deserialize)]
// pub struct Version {
// major: u8,
// minor: u8,
// }
//
// impl Version {
// pub fn default() -> Version {
// Version { major: 0, minor: 1 }
// }
// }
pub struct Game {
pub config: Config,
2021-11-14 18:07:57 +00:00
pub entities: Vec<Entity>,
pub images: Vec<Image>,
2021-11-14 18:07:57 +00:00
pub palettes: Vec<Palette>,
pub scenes: Vec<Scene>,
pub tiles: Vec<Tile>,
// pub variables: Vec<Variable>,
// pub triggers: HashMap<String, ScriptCollection>,
pub music: Vec<Music>,
2020-09-02 17:50:13 +01:00
}
#[derive(Debug)]
pub struct GameParseError;
2020-09-02 17:50:13 +01:00
impl Game {
2021-11-14 18:07:57 +00:00
pub fn new() -> Self {
Self {
config: Config {
name: None,
width: 16,
height: 9,
tick: 400,
starting_room: None,
version: (0, 1)
},
entities: vec![],
images: vec![],
palettes: vec![],
scenes: vec![],
tiles: vec![],
music: vec![]
}
}
2021-05-19 17:52:12 +01:00
pub fn from_dir(path: PathBuf) -> Result<Game, GameParseError> {
2021-05-18 21:33:03 +01:00
let mut images = Vec::new();
2021-05-19 11:42:49 +01:00
let mut tiles = Vec::new();
let mut entities = Vec::new();
2021-05-18 00:05:39 +01:00
let mut music = Vec::new();
let mut palettes = Vec::new();
2021-11-14 18:07:57 +00:00
let mut scenes = Vec::new();
2021-05-18 00:05:39 +01:00
let mut music_dir = path.clone();
music_dir.push("music");
let music_files = music_dir.read_dir();
if music_files.is_ok() {
for file in music_files.unwrap() {
let file = file.unwrap();
music.push(Music::from_file(file.path()));
}
}
let mut palettes_dir = path.clone();
palettes_dir.push("palettes");
2021-05-18 00:05:39 +01:00
let palette_files = palettes_dir.read_dir()
2021-05-18 00:05:39 +01:00
.expect("couldn't read palettes dir");
2020-09-02 17:50:13 +01:00
for file in palette_files {
let file = file.unwrap();
2021-05-18 00:05:39 +01:00
palettes.push(Palette::from_file(file.path()));
2020-09-02 17:50:13 +01:00
}
2021-05-18 21:33:03 +01:00
let mut images_dir = path.clone();
images_dir.push("images");
2021-05-18 21:33:03 +01:00
let image_files = images_dir.read_dir()
2021-05-19 11:42:49 +01:00
.expect("couldn't read image dir");
2021-05-18 21:33:03 +01:00
for file in image_files {
let file = file.unwrap();
images.push(Image::from_file(file.path()));
}
2021-05-19 11:42:49 +01:00
let mut tiles_dir = path.clone();
tiles_dir.push("tiles");
2021-05-19 11:42:49 +01:00
let tiles_files = tiles_dir.read_dir()
.expect("couldn't read tile dir");
for file in tiles_files {
let file = file.unwrap();
tiles.push(Tile::from_file(file.path()));
}
let mut entities_dir = path.clone();
entities_dir.push("entities");
2021-05-19 11:42:49 +01:00
let entities_files = entities_dir.read_dir()
.expect("couldn't read tile dir");
for file in entities_files {
let file = file.unwrap();
entities.push(Entity::from_file(file.path()));
}
2021-11-14 18:07:57 +00:00
let mut scenes_dir = path.clone();
scenes_dir.push("scenes");
let scenes_files = scenes_dir.read_dir()
.expect("couldn't read scene dir");
for file in scenes_files {
let file = file.unwrap();
scenes.push(Scene::from_file(file.path()));
}
let mut game_config = path.clone();
game_config.push("game.toml");
let config = fs::read_to_string(game_config)
.expect("Couldn't load game config");
let config: Config = toml::from_str(&config)
.expect("Couldn't parse game config");
2021-11-14 18:07:57 +00:00
Ok(Game { config, images, tiles, palettes, music, entities, scenes })
2020-09-02 17:50:13 +01:00
}
// todo Result<&Image>?
pub fn get_image_by_name(&self, name: String) -> Option<&Image> {
for image in self.images.iter() {
if image.name == name {
return Some(&image);
}
}
None
}
pub fn get_entities_by_tag(&self, tag: &String) -> Vec<&Entity> {
let mut entities = Vec::new();
for entity in self.entities.iter() {
if entity.tags.contains(tag) {
entities.push(entity);
}
}
entities
}
// todo Result<&Entity>?
pub fn get_entity_by_name(&self, name: String) -> Option<&Entity> {
for entity in self.entities.iter() {
if entity.name == name {
2021-11-14 18:07:57 +00:00
return Some(entity);
}
}
None
}
// todo Result<&Music>?
pub fn get_music_by_name(&self, name: String) -> Option<&Music> {
for music in self.music.iter() {
if music.name == name {
2021-11-14 18:07:57 +00:00
return Some(music);
}
}
None
}
// todo Result<&Palette>?
2021-11-14 18:07:57 +00:00
pub fn find_palette(&mut self, name: &str) -> Option<&mut Palette> {
for palette in self.palettes.iter_mut() {
if palette.name == name {
2021-11-14 18:07:57 +00:00
return Some(palette);
}
}
None
}
// todo Result<&Tile>?
pub fn get_tile_by_name(&self, name: String) -> Option<&Tile> {
for tile in self.tiles.iter() {
if tile.name == name {
2021-11-14 18:07:57 +00:00
return Some(tile);
}
}
None
}
pub fn get_scene_by_name(&mut self, name: String) -> Option<&mut Scene> {
for scene in self.scenes.iter_mut() {
if scene.name == name {
return Some(scene);
}
}
None
}
2021-11-14 18:07:57 +00:00
pub fn remove_entity(&mut self, scene_name: String, position: Position) {
let width = self.config.width.clone();
self.get_scene_by_name(scene_name).unwrap()
.foreground[position.to_index(width) as usize] = None;
}
}
#[cfg(test)]
mod test {
use crate::{Position, Game};
#[test]
fn position_to_index() {
assert_eq!(Position { x: 1, y: 5 }.to_index(8), 41);
assert_eq!(Position { x: 0, y: 0 }.to_index(8), 0);
}
#[test]
fn remove_entity() {
let mut game = Game::new();
game.scenes.push(crate::mock::scenes::zero());
game.remove_entity("zero".into(), Position { x: 1, y: 1 });
assert_eq!(game.scenes[0].foreground[9], None);
}
2020-09-02 17:50:13 +01:00
}