simple-game-utils 0.5.3

Utilities for simple games
Documentation
use std::collections::HashMap;
use std::rc::Rc;

use ici_files::prelude::*;
use serde::{Deserialize, Serialize};

use crate::prelude::*;

#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct IciTileset {
    pub name: String,
    tile_size: (u8, u8),
    palette: Vec<Color>,
    tiles: HashMap<String, Vec<u8>>,
}

impl IciTileset {
    pub fn new(
        name: String,
        tile_size: (u8, u8),
        palette: Vec<Color>,
        tiles: HashMap<String, Vec<u8>>,
    ) -> Self {
        Self {
            name,
            tile_size,
            palette,
            tiles,
        }
    }
}

impl IciTileset {
    pub fn add_image(&mut self, name: &str, image: &IndexedImage) {
        if image.get_palette() == self.palette {
            self.tiles
                .insert(name.to_string(), image.get_pixels().to_vec());
        } else {
            panic!("Image has invalid palette");
        }
    }

    pub fn tile_size(&self) -> (u8, u8) {
        self.tile_size
    }

    pub fn palette(&self) -> &Vec<Color> {
        &self.palette
    }

    pub fn tiles(&self) -> &HashMap<String, Vec<u8>> {
        &self.tiles
    }
}

impl IciTileset {
    pub fn into_tileset(self) -> Result<Tileset<IndexedImage>, String> {
        let mut images = vec![];
        let mut names = vec![];

        let palette = self.palette;

        for (name, pixels) in self.tiles {
            names.push(name);
            images.push(Rc::new(
                IndexedImage::new(self.tile_size.0, self.tile_size.1, palette.clone(), pixels)
                    .map_err(|e| e.to_string())?,
            ));
        }

        Ok(Tileset::new(
            images,
            names,
            (self.tile_size.0 as u32, self.tile_size.1 as u32),
        ))
    }
}

#[cfg(test)]
mod test {
    use super::*;

    const SAMPLE_RON: &str = r#"(
        name: "sample",
        tile_size: (3,3),
        palette: [0,4278190335,16711935,65535],
        tiles: {
            "trans": [0,0,0,0,0,0,0,0,0],
            "red":   [1,1,1,1,1,1,1,1,1],
            "green": [2,2,2,2,2,2,2,2,2],
            "blue":  [3,3,3,3,3,3,3,3,3],
        }
    )
    "#;

    #[test]
    fn serde() {
        let tileset: IciTileset = ron::from_str(SAMPLE_RON).unwrap();
        assert_eq!(tileset.name, String::from("sample"));
        assert_eq!(tileset.palette, vec![TRANSPARENT, RED, GREEN, BLUE]);
        assert_eq!(tileset.tile_size, (3, 3));
        assert_eq!(
            tileset.tiles,
            HashMap::from([
                ("trans".to_string(), vec![0; 9]),
                ("red".to_string(), vec![1; 9]),
                ("green".to_string(), vec![2; 9]),
                ("blue".to_string(), vec![3; 9]),
            ])
        );
    }

    #[test]
    fn converting() {
        let tileset: Tileset<IndexedImage> = ron::from_str::<IciTileset>(SAMPLE_RON)
            .unwrap()
            .into_tileset()
            .unwrap();
        assert_eq!(tileset.tilesize(), (3, 3));
        assert_eq!(tileset.images().len(), 4);
        assert_eq!(tileset.find_by_name("red").unwrap().get_palette()[3], BLUE);
        assert_eq!(tileset.find_by_name("blue").unwrap().get_palette()[1], RED);
        assert!(tileset
            .find_by_name("trans")
            .unwrap()
            .get_pixels()
            .iter()
            .all(|&p| p == 0));
        assert!(tileset
            .find_by_name("green")
            .unwrap()
            .get_pixels()
            .iter()
            .all(|&p| p == 2));
    }
}