~comcloudway/little_town

3d081decfc3ae2d59b828d23411e7a9fb87eba10 — Jakob Meier 1 year, 8 months ago 5be7d20
Added blocks from Sketch Town Expansion pack
7 files changed, 306 insertions(+), 321 deletions(-)

M Cargo.lock
M Cargo.toml
M README.md
M src/game/blocks.rs
M src/game/world.rs
M src/screens/build.rs
M src/textures.rs
M Cargo.lock => Cargo.lock +1 -1
@@ 1619,7 1619,7 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"

[[package]]
name = "little_town"
version = "0.2.0"
version = "0.2.1"
dependencies = [
 "async-std",
 "directories-next",

M Cargo.toml => Cargo.toml +1 -1
@@ 1,7 1,7 @@
[package]
name = "little_town"
description = "Build a small isometric town"
version = "0.2.0"
version = "0.2.1"
edition = "2021"
authors = [ "Jakob Meier <comcloudway@ccw.icu>" ]
readme = "README.org"

M README.md => README.md +1 -1
@@ 35,7 35,7 @@ launch the game and the world should appear in the world list
- [ ] Settings menu (i.e for Keybindings)
- [ ] Game music?
- [ ] Add more assets
  - [ ] SketchTown Expansion pack
  - [x] SketchTown Expansion pack
  - [ ] (MAYBE) [Sketch Desert](https://kenney.nl/assets/sketch-desert)

## Keymap

M src/game/blocks.rs => src/game/blocks.rs +268 -310
@@ 9,7 9,6 @@ use crate::screens::build::{
    TEXTURE_INNER_HEIGHT
};

static mut CACHE: Option<HashMap<Block, DirectionalTexture>> = None;

/// A block's face
///   /'\


@@ 79,321 78,213 @@ impl Face {
    }
}

#[derive(Eq, Hash, Clone, PartialEq, SerJson, DeJson)]
pub enum Block {
    Bridge,

    BuildingCenter,
    BuildingCenterBeige,
    BuildingCorner,
    BuildingCornerBeige,
    BuildingDoor,
    BuildingDoorBeige,
    BuildingDoorWindows,
    BuildingDoorWindowsBeige,
    BuildingWindow,
    BuildingWindowBeige,
    BuildingWindows,
    BuildingWindowsBeige,

    CastleBend,
    CastleCenter,
    CastleCorner,
    CastleGate,
    CastleGateOpen,
    CastleSlope,
    CastleTower,
    CastleTowerBeige,
    CastleTowerBrown,
    CastleTowerGreen,
    CastleTowerPurple,
    CastleWall,
    CastleWindow,

    DirtCenter,
    DirtLow,

    GrassCenter,
    GrassCorner,
    GrassPath,
    GrassPathBend,
    GrassPathCorner,
    GrassPathCrossing,
    GrassPathEnd,
    GrassPathEndSquare,
    GrassPathSlope,
    GrassPathSplit,
    GrassRiver,
    GrassRiverBend,
    GrassRiverBridge,
    GrassRiverCorner,
    GrassRiverCrossing,
    GrassRiverEnd,
    GrassRiverEndSquare,
    GrassRiverSlope,
    GrassRiverSplit,
    GrassSlope,
    GrassSlopeConcave,
    GrassSlopeConvex,
    GrassWater,
    GrassWaterConcave,
    GrassWaterConvex,
    GrassWaterRiver,

    RocksDirt,
    RocksGrass,

    RoofChurchBeige,
    RoofChuchBrown,
    RoofChurchGreen,
    RoofChurchPurple,
    RoofGableBeige,
    RoofGableBrown,
    RoofGableGreen,
    RoofGablePurple,
    RoofPointBeige,
    RoofPointBrown,
    RoofPointGreen,
    RoofPointPurple,
    RoofRoundBeige,
    RoofRoundBrown,
    RoofRoundGreen,
    RoofRoundPurple,
    RoofRoundedBeige,
    RoofRoundedBrown,
    RoofRoundedGreen,
    RoofRoundedPurple,
    RoofSlantBeige,
    RoofSlantBrown,
    RoofSlantGreen,
    RoofSlantPurple,

    StructureArch,
    StructureHigh,
    StructureLow,

    /// tree_multiple_
    Trees,
    /// tree_single_
    Tree,

    WaterCenter,
    WaterFall
}
impl Block {
    /// returns the texture for the block
    pub async fn get_texture(&self) -> DirectionalTexture {
/// rust macro to autogenerate the Block enum
/// and the texture maps from a set of variant names and paths
macro_rules! auto_gen_blocks {
    ( $(($name:ident, $file:literal)),* ) => {
        static mut CACHE: Option<HashMap<Block, DirectionalTexture>> = None;

        unsafe {
            if CACHE.is_none() {
                CACHE = Some(HashMap::new());
        #[derive(Eq, Hash, Clone, PartialEq, SerJson, DeJson)]
        pub enum Block {
            $($name),*
        }
        impl Block {
            pub fn all() -> Vec<Self> {
                vec![
                    $(Self::$name),*
                ]
            }
            if let Some(map) = &CACHE {
                if let Some(dt) = map.get(self) {
                    return dt.clone();

            pub async fn get_texture(&self) -> DirectionalTexture {

                unsafe {
                    if CACHE.is_none() {
                        CACHE = Some(HashMap::new());
                    }
                    if let Some(map) = &CACHE {
                        if let Some(dt) = map.get(self) {
                            return dt.clone();
                        }
                    }
                }

                let dt = match self {
                    $(Self::$name => include_tile!($file)),*
                };


                unsafe {
                    if let Some(map) = &mut CACHE {
                        map.insert(self.clone(), dt.clone());
                    }
                }
            }
        }

        let dt = match self {
            Block::Bridge => include_base_tile!("bridge"),
            Block::BuildingCenter => include_base_tile!("building_center"),
            Block::BuildingCenterBeige => include_base_tile!("building_centerBeige"),
            Block::BuildingCorner => include_base_tile!("building_corner"),
            Block::BuildingCornerBeige => include_base_tile!("building_cornerBeige"),
            Block::BuildingDoor => include_base_tile!("building_door"),
            Block::BuildingDoorBeige => include_base_tile!("building_doorBeige"),
            Block::BuildingDoorWindows => include_base_tile!("building_doorWindows"),
            Block::BuildingDoorWindowsBeige => include_base_tile!("building_doorWindowsBeige"),
            Block::BuildingWindow => include_base_tile!("building_window"),
            Block::BuildingWindowBeige => include_base_tile!("building_windowBeige"),
            Block::BuildingWindows => include_base_tile!("building_windows"),
            Block::BuildingWindowsBeige => include_base_tile!("building_windowsBeige"),

            Block::CastleBend => include_base_tile!("castle_bend"),
            Block::CastleCenter => include_base_tile!("castle_center"),
            Block::CastleCorner => include_base_tile!("castle_corner"),
            Block::CastleGate => include_base_tile!("castle_gate"),
            Block::CastleGateOpen => include_base_tile!("castle_gateOpen"),
            Block::CastleSlope => include_base_tile!("castle_slope"),
            Block::CastleTower => include_base_tile!("castle_tower"),
            Block::CastleTowerBeige => include_base_tile!("castle_towerBeige"),
            Block::CastleTowerBrown => include_base_tile!("castle_towerBrown"),
            Block::CastleTowerGreen => include_base_tile!("castle_towerGreen"),
            Block::CastleTowerPurple => include_base_tile!("castle_towerPurple"),
            Block::CastleWall => include_base_tile!("castle_wall"),
            Block::CastleWindow => include_base_tile!("castle_window"),

            Block::DirtCenter => include_base_tile!("dirt_center"),
            Block::DirtLow => include_base_tile!("dirt_low"),

            Block::GrassCenter => include_base_tile!("grass_center"),
            Block::GrassCorner => include_base_tile!("grass_corner"),
            Block::GrassPath => include_base_tile!("grass_path"),
            Block::GrassPathBend => include_base_tile!("grass_pathBend"),
            Block::GrassPathCorner => include_base_tile!("grass_pathCorner"),
            Block::GrassPathCrossing => include_base_tile!("grass_pathCrossing"),
            Block::GrassPathEnd => include_base_tile!("grass_pathEnd"),
            Block::GrassPathEndSquare => include_base_tile!("grass_pathEndSquare"),
            Block::GrassPathSlope => include_base_tile!("grass_pathSlope"),
            Block::GrassPathSplit => include_base_tile!("grass_pathSplit"),
            Block::GrassRiver => include_base_tile!("grass_river"),
            Block::GrassRiverBend => include_base_tile!("grass_riverBend"),
            Block::GrassRiverBridge => include_base_tile!("grass_riverBridge"),
            Block::GrassRiverCorner => include_base_tile!("grass_riverCorner"),
            Block::GrassRiverCrossing => include_base_tile!("grass_riverCrossing"),
            Block::GrassRiverEnd => include_base_tile!("grass_riverEnd"),
            Block::GrassRiverEndSquare => include_base_tile!("grass_riverEndSquare"),
            Block::GrassRiverSlope => include_base_tile!("grass_riverSlope"),
            Block::GrassRiverSplit => include_base_tile!("grass_riverSplit"),
            Block::GrassSlope => include_base_tile!("grass_slope"),
            Block::GrassSlopeConcave => include_base_tile!("grass_slopeConcave"),
            Block::GrassSlopeConvex => include_base_tile!("grass_slopeConvex"),
            Block::GrassWater => include_base_tile!("grass_water"),
            Block::GrassWaterConcave => include_base_tile!("grass_waterConcave"),
            Block::GrassWaterConvex => include_base_tile!("grass_waterConvex"),
            Block::GrassWaterRiver => include_base_tile!("grass_waterRiver"),

            Block::RocksDirt => include_base_tile!("rocks_dirt"),
            Block::RocksGrass => include_base_tile!("rocks_grass"),

            Block::RoofChurchBeige => include_base_tile!("roof_churchBeige"),
            Block::RoofChuchBrown => include_base_tile!("roof_churchBrown"),
            Block::RoofChurchGreen => include_base_tile!("roof_churchGreen"),
            Block::RoofChurchPurple => include_base_tile!("roof_churchPurple"),
            Block::RoofGableBeige => include_base_tile!("roof_gableBeige"),
            Block::RoofGableBrown => include_base_tile!("roof_gableBrown"),
            Block::RoofGableGreen => include_base_tile!("roof_gableGreen"),
            Block::RoofGablePurple => include_base_tile!("roof_gablePurple"),
            Block::RoofPointBeige => include_base_tile!("roof_pointBeige"),
            Block::RoofPointBrown => include_base_tile!("roof_pointBrown"),
            Block::RoofPointGreen => include_base_tile!("roof_pointGreen"),
            Block::RoofPointPurple => include_base_tile!("roof_pointPurple"),
            Block::RoofRoundBeige => include_base_tile!("roof_roundBeige"),
            Block::RoofRoundBrown => include_base_tile!("roof_roundBrown"),
            Block::RoofRoundGreen => include_base_tile!("roof_roundGreen"),
            Block::RoofRoundPurple => include_base_tile!("roof_roundPurple"),
            Block::RoofRoundedBeige => include_base_tile!("roof_roundedBeige"),
            Block::RoofRoundedBrown => include_base_tile!("roof_roundedBrown"),
            Block::RoofRoundedGreen => include_base_tile!("roof_roundedGreen"),
            Block::RoofRoundedPurple => include_base_tile!("roof_roundedPurple"),
            Block::RoofSlantBeige => include_base_tile!("roof_slantBeige"),
            Block::RoofSlantBrown => include_base_tile!("roof_slantBrown"),
            Block::RoofSlantGreen => include_base_tile!("roof_slantGreen"),
            Block::RoofSlantPurple => include_base_tile!("roof_slantPurple"),

            Block::StructureArch => include_base_tile!("structure_arch"),
            Block::StructureHigh => include_base_tile!("structure_high"),
            Block::StructureLow => include_base_tile!("structure_low"),

            Block::Trees => include_base_tile!("tree_multiple"),
            Block::Tree => include_base_tile!("tree_single"),

            Block::WaterCenter => include_base_tile!("water_center"),
            Block::WaterFall => include_base_tile!("water_fall")
        };

        unsafe {
            if let Some(map) = &mut CACHE {
                map.insert(self.clone(), dt.clone());
                return dt;
            }
        }

        return dt;
    }
    /// returns a list of all blocks
    pub fn all() -> Vec<Block> {
        vec![
            Block::Bridge,
            Block::BuildingCenter,
            Block::BuildingCenterBeige,
            Block::BuildingCorner,
            Block::BuildingCornerBeige,
            Block::BuildingDoor,
            Block::BuildingDoorBeige,
            Block::BuildingDoorWindows,
            Block::BuildingDoorWindowsBeige,
            Block::BuildingWindow,
            Block::BuildingWindowBeige,
            Block::BuildingWindows,
            Block::BuildingWindowsBeige,
            Block::CastleBend,
            Block::CastleCenter,
            Block::CastleCorner,
            Block::CastleGate,
            Block::CastleGateOpen,
            Block::CastleSlope,
            Block::CastleTower,
            Block::CastleTowerBeige,
            Block::CastleTowerBrown,
            Block::CastleTowerGreen,
            Block::CastleTowerPurple,
            Block::CastleWall,
            Block::CastleWindow,
            Block::DirtCenter,
            Block::DirtLow,
            Block::GrassCenter,
            Block::GrassCorner,
            Block::GrassPath,
            Block::GrassPathBend,
            Block::GrassPathCorner,
            Block::GrassPathCrossing,
            Block::GrassPathEnd,
            Block::GrassPathEndSquare,
            Block::GrassPathSlope,
            Block::GrassPathSplit,
            Block::GrassRiver,
            Block::GrassRiverBend,
            Block::GrassRiverBridge,
            Block::GrassRiverCorner,
            Block::GrassRiverCrossing,
            Block::GrassRiverEnd,
            Block::GrassRiverEndSquare,
            Block::GrassRiverSlope,
            Block::GrassRiverSplit,
            Block::GrassSlope,
            Block::GrassSlopeConcave,
            Block::GrassSlopeConvex,
            Block::GrassWater,
            Block::GrassWaterConcave,
            Block::GrassWaterConvex,
            Block::GrassWaterRiver,
            Block::RocksDirt,
            Block::RocksGrass,
            Block::RoofChurchBeige,
            Block::RoofChuchBrown,
            Block::RoofChurchGreen,
            Block::RoofChurchPurple,
            Block::RoofGableBeige,
            Block::RoofGableBrown,
            Block::RoofGableGreen,
            Block::RoofGablePurple,
            Block::RoofPointBeige,
            Block::RoofPointBrown,
            Block::RoofPointGreen,
            Block::RoofPointPurple,
            Block::RoofRoundBeige,
            Block::RoofRoundBrown,
            Block::RoofRoundGreen,
            Block::RoofRoundPurple,
            Block::RoofRoundedBeige,
            Block::RoofRoundedBrown,
            Block::RoofRoundedGreen,
            Block::RoofRoundedPurple,
            Block::RoofSlantBeige,
            Block::RoofSlantBrown,
            Block::RoofSlantGreen,
            Block::RoofSlantPurple,
            Block::StructureArch,
            Block::StructureHigh,
            Block::StructureLow,
            Block::Trees,
            Block::Tree,
            Block::WaterCenter,
            Block::WaterFall
        ]
    }
}

auto_gen_blocks!(
    ( BalconyStone, "exp/Tiles/balcony_stone" ),
    ( BalconyWood, "exp/Tiles/balcony_wood" ),
    ( Bridge, "base/Tiles/bridge" ),
    ( BuildingCenter, "base/Tiles/building_center" ),
    ( BuildingCenterBeige, "base/Tiles/building_centerBeige" ),
    ( BuildingCorner, "base/Tiles/building_corner" ),
    ( BuildingCornerBeige, "base/Tiles/building_cornerBeige" ),
    ( BuildingDoor, "base/Tiles/building_door" ),
    ( BuildingDoorBeige, "base/Tiles/building_doorBeige" ),
    ( BuildingDoorWindows, "base/Tiles/building_doorWindows" ),
    ( BuildingDoorWindowsBeige, "base/Tiles/building_doorWindowsBeige" ),
    ( BuildingWindow, "base/Tiles/building_window" ),
    ( BuildingWindowBeige, "base/Tiles/building_windowBeige" ),
    ( BuildingWindows, "base/Tiles/building_windows" ),
    ( BuildingWindowsBeige, "base/Tiles/building_windowsBeige" ),
    ( BuildingStack, "exp/Tiles/building_stack" ),
    ( BuildingStackBeige, "exp/Tiles/building_stackBeige" ),
    ( BuildingStackCorner, "exp/Tiles/building_stackCorner" ),
    ( BuildingStackCornerBeige, "exp/Tiles/building_stackCornerBeige" ),

    ( CastleBend, "base/Tiles/castle_bend" ),
    ( CastleCenter, "base/Tiles/castle_center" ),
    ( CastleCorner, "base/Tiles/castle_corner" ),
    ( CastleEnd, "exp/Tiles/castle_end" ),
    ( CastleEndRound, "exp/Tiles/castle_endRound" ),
    ( CastleEndRuined, "exp/Tiles/castle_endRuined" ),
    ( CastleGate, "base/Tiles/castle_gate" ),
    ( CastleGateOpen, "base/Tiles/castle_gateOpen" ),
    ( CastleSlope, "base/Tiles/castle_slope" ),
    ( CastleTower, "base/Tiles/castle_tower" ),
    ( CastleTowerCenter, "exp/Tiles/castle_towerCenter" ),
    ( CastleTowerBeige, "base/Tiles/castle_towerBeige" ),
    ( CastleTowerBeigeBase, "exp/Tiles/castle_towerBeigeBase" ),
    ( CastleTowerBeigeTop, "exp/Tiles/castle_towerBeigeTop" ),
    ( CastleTowerBrown, "base/Tiles/castle_towerBrown" ),
    ( CastleTowerBrownBase, "exp/Tiles/castle_towerBrownBase" ),
    ( CastleTowerBrownTop, "exp/Tiles/castle_towerBrownTop" ),
    ( CastleTowerGreen, "base/Tiles/castle_towerGreen" ),
    ( CastleTowerGreenBase, "exp/Tiles/castle_towerGreenBase" ),
    ( CastleTowerGreenTop, "exp/Tiles/castle_towerGreenTop" ),
    ( CastleTowerPurple, "base/Tiles/castle_towerPurple" ),
    ( CastleTowerPurpleBase, "exp/Tiles/castle_towerPurpleBase" ),
    ( CastleTowerPurpleTop, "exp/Tiles/castle_towerPurpleTop" ),
    ( CastleWall, "base/Tiles/castle_wall" ),
    ( CastleWindow, "base/Tiles/castle_window" ),

    ( Cliff, "exp/Tiles/cliff"),
    ( CliffCorner, "exp/Tiles/cliff"),
    ( CliffCornerInner, "exp/Tiles/cliff"),
    ( CliffEntrance, "exp/Tiles/cliff"),
    ( CliffTop, "exp/Tiles/cliff_top"),
    ( CliffTopEntrance, "exp/Tiles/cliff_topEntrance"),
    ( CliffTopCorner, "exp/Tiles/cliff_topCorner"),
    ( CliffTopCornerInner, "exp/Tiles/cliff_topCornerInner"),

    ( DirtCenter, "base/Tiles/dirt_center" ),
    ( DirtCorner, "exp/Tiles/dirt_corner" ),
    ( DirtLow, "base/Tiles/dirt_low" ),

    (Fence, "exp/Tiles/fence_wood"),
    (FenceCorner, "exp/Tiles/fence_woodCorner"),
    (FenceCurve, "exp/Tiles/fence_woodCurve"),
    (FenceEnd, "exp/Tiles/fence_woodEnd"),
    (FenceDouble, "exp/Tiles/fence_woodDouble"),
    (FenceDoubleCorner, "exp/Tiles/fence_woodDoubleCorner"),
    (FenceDoubleCurve, "exp/Tiles/fence_woodDoubleCurve"),
    (FenceDoubleEnd, "exp/Tiles/fence_woodDoubleEnd"),

    ( Furrow, "exp/Tiles/furrow" ),
    ( FurrowCropWheat, "exp/Tiles/furrow_cropWheat" ),
    ( FurrowCrop, "exp/Tiles/furrow_crop" ),
    ( FurrowEnd, "exp/Tiles/furrow_end" ),

    ( Grass, "exp/Tiles/grass_block" ),
    ( GrassCenter, "base/Tiles/grass_center" ),
    ( GrassCorner, "base/Tiles/grass_corner" ),
    ( GrassPath, "base/Tiles/grass_path" ),
    ( GrassPathBend, "base/Tiles/grass_pathBend" ),
    ( GrassPathCorner, "base/Tiles/grass_pathCorner" ),
    ( GrassPathCrossing, "base/Tiles/grass_pathCrossing" ),
    ( GrassPathEnd, "base/Tiles/grass_pathEnd" ),
    ( GrassPathEndSquare, "base/Tiles/grass_pathEndSquare" ),
    ( GrassPathSlope, "base/Tiles/grass_pathSlope" ),
    ( GrassPathSplit, "base/Tiles/grass_pathSplit" ),
    ( GrassRiver, "base/Tiles/grass_river" ),
    ( GrassRiverBend, "base/Tiles/grass_riverBend" ),
    ( GrassRiverBridge, "base/Tiles/grass_riverBridge" ),
    ( GrassRiverCorner, "base/Tiles/grass_riverCorner" ),
    ( GrassRiverCrossing, "base/Tiles/grass_riverCrossing" ),
    ( GrassRiverEnd, "base/Tiles/grass_riverEnd" ),
    ( GrassRiverEndSquare, "base/Tiles/grass_riverEndSquare" ),
    ( GrassRiverSlope, "base/Tiles/grass_riverSlope" ),
    ( GrassRiverSplit, "base/Tiles/grass_riverSplit" ),
    ( GrassSlope, "base/Tiles/grass_slope" ),
    ( GrassSlopeConcave, "base/Tiles/grass_slopeConcave" ),
    ( GrassSlopeConvex, "base/Tiles/grass_slopeConvex" ),
    ( GrassWater, "base/Tiles/grass_water" ),
    ( GrassWaterConcave, "base/Tiles/grass_waterConcave" ),
    ( GrassWaterConvex, "base/Tiles/grass_waterConvex" ),
    ( GrassWaterRiver, "base/Tiles/grass_waterRiver" ),

    ( RocksDirt, "base/Tiles/rocks_dirt" ),
    ( RocksGrass, "base/Tiles/rocks_grass" ),

    ( RoofChurchBeige, "base/Tiles/roof_churchBeige" ),
    ( RoofChuchBrown, "base/Tiles/roof_churchBrown" ),
    ( RoofChurchGreen, "base/Tiles/roof_churchGreen" ),
    ( RoofChurchPurple, "base/Tiles/roof_churchPurple" ),
    ( RoofGableBeige, "base/Tiles/roof_gableBeige" ),
    ( RoofGableCornerBeige, "exp/Tiles/roof_gableCornerBeige" ),
    ( RoofGableBrown, "base/Tiles/roof_gableBrown" ),
    ( RoofGableCornerBrown, "exp/Tiles/roof_gableCornerBrown" ),
    ( RoofGableGreen, "base/Tiles/roof_gableGreen" ),
    ( RoofGableCornerGreen, "exp/Tiles/roof_gableCornerGreen" ),
    ( RoofGablePurple, "base/Tiles/roof_gablePurple" ),
    ( RoofGableCornerPurple, "exp/Tiles/roof_gableCornerPurple" ),
    ( RoofPointBeige, "base/Tiles/roof_pointBeige" ),
    ( RoofPointBrown, "base/Tiles/roof_pointBrown" ),
    ( RoofPointGreen, "base/Tiles/roof_pointGreen" ),
    ( RoofPointPurple, "base/Tiles/roof_pointPurple" ),
    ( RoofRoundBeige, "base/Tiles/roof_roundBeige" ),
    ( RoofRoundCornerBeige, "exp/Tiles/roof_roundCornerBeige" ),
    ( RoofRoundBrown, "base/Tiles/roof_roundBrown" ),
    ( RoofRoundCornerBrown, "exp/Tiles/roof_roundCornerBrown" ),
    ( RoofRoundGreen, "base/Tiles/roof_roundGreen" ),
    ( RoofRoundCornerGreen, "exp/Tiles/roof_roundCornerGreen" ),
    ( RoofRoundPurple, "base/Tiles/roof_roundPurple" ),
    ( RoofRoundCornerPurple, "exp/Tiles/roof_roundCornerPurple" ),
    ( RoofRoundedBeige, "base/Tiles/roof_roundedBeige" ),
    ( RoofRoundedBrown, "base/Tiles/roof_roundedBrown" ),
    ( RoofRoundedGreen, "base/Tiles/roof_roundedGreen" ),
    ( RoofRoundedPurple, "base/Tiles/roof_roundedPurple" ),
    ( RoofSlantBeige, "base/Tiles/roof_slantBeige" ),
    ( RoofSlantCornerBeige, "exp/Tiles/roof_slantCornerBeige" ),
    ( RoofSlantCornerInnerBeige, "exp/Tiles/roof_slantCornerInnerBeige" ),
    ( RoofSlantBrown, "base/Tiles/roof_slantBrown" ),
    ( RoofSlantCornerBrown, "exp/Tiles/roof_slantCornerBrown" ),
    ( RoofSlantCornerInnerBrown, "exp/Tiles/roof_slantCornerInnerBrown" ),
    ( RoofSlantGreen, "base/Tiles/roof_slantGreen" ),
    ( RoofSlantCornerGreen, "exp/Tiles/roof_slantCornerGreen" ),
    ( RoofSlantCornerInnerGreen, "exp/Tiles/roof_slantCornerInnerGreen" ),
    ( RoofSlantPurple, "base/Tiles/roof_slantPurple" ),
    ( RoofSlantCornerPurple, "exp/Tiles/roof_slantCornerPurple" ),
    ( RoofSlantCornerInnerPurple, "exp/Tiles/roof_slantCornerInnerPurple" ),

    ( StructureArch, "base/Tiles/structure_arch" ),
    ( StructureHigh, "base/Tiles/structure_high" ),
    ( StructureLow, "base/Tiles/structure_low" ),

    ( Trees, "base/Tiles/tree_multiple" ),
    ( Tree, "base/Tiles/tree_single" ),
    (Pine, "exp/Tiles/tree_pine"),
    (PineLarge, "exp/Tiles/tree_pineLarge"),

    ( WaterCenter, "base/Tiles/water_center" ),
    ( WaterFall, "base/Tiles/water_fall" ),
    (Well, "exp/Tiles/well")
);

impl Default for Block {
    fn default() -> Self {
        Block::StructureHigh


@@ 451,6 342,9 @@ impl Category {
    pub fn get_blocks(&self) -> Vec<Block> {
        match self {
            Category::Building => vec![
                Block::BalconyStone,
                Block::BalconyWood,
                Block::Bridge,
                Block::BuildingCenter,
                Block::BuildingCenterBeige,
                Block::BuildingCorner,


@@ 459,6 353,10 @@ impl Category {
                Block::BuildingDoorBeige,
                Block::BuildingDoorWindows,
                Block::BuildingDoorWindowsBeige,
                Block::BuildingStack,
                Block::BuildingStackBeige,
                Block::BuildingStackCorner,
                Block::BuildingStackCornerBeige,
                Block::BuildingWindow,
                Block::BuildingWindowBeige,
                Block::BuildingWindows,


@@ 466,14 364,26 @@ impl Category {
                Block::CastleBend,
                Block::CastleCenter,
                Block::CastleCorner,
                Block::CastleEnd,
                Block::CastleEndRound,
                Block::CastleEndRuined,
                Block::CastleGate,
                Block::CastleGateOpen,
                Block::CastleSlope,
                Block::CastleTower,
                Block::CastleTowerCenter,
                Block::CastleTowerBeige,
                Block::CastleTowerBeigeBase,
                Block::CastleTowerBeigeTop,
                Block::CastleTowerBrown,
                Block::CastleTowerBrownBase,
                Block::CastleTowerBrownTop,
                Block::CastleTowerGreen,
                Block::CastleTowerGreenBase,
                Block::CastleTowerGreenTop,
                Block::CastleTowerPurple,
                Block::CastleTowerPurpleBase,
                Block::CastleTowerPurpleTop,
                Block::CastleWall,
                Block::CastleWindow,
                Block::RoofChurchBeige,


@@ 481,29 391,46 @@ impl Category {
                Block::RoofChurchGreen,
                Block::RoofChurchPurple,
                Block::RoofGableBeige,
                Block::RoofGableCornerBeige,
                Block::RoofGableBrown,
                Block::RoofGableCornerBrown,
                Block::RoofGableGreen,
                Block::RoofGableCornerGreen,
                Block::RoofGablePurple,
                Block::RoofGableCornerPurple,
                Block::RoofPointBeige,
                Block::RoofPointBrown,
                Block::RoofPointGreen,
                Block::RoofPointPurple,
                Block::RoofRoundBeige,
                Block::RoofRoundCornerBeige,
                Block::RoofRoundBrown,
                Block::RoofRoundCornerBrown,
                Block::RoofRoundGreen,
                Block::RoofRoundCornerGreen,
                Block::RoofRoundPurple,
                Block::RoofRoundCornerPurple,
                Block::RoofRoundedBeige,
                Block::RoofRoundedBrown,
                Block::RoofRoundedGreen,
                Block::RoofRoundedPurple,
                Block::RoofSlantBeige,
                Block::RoofSlantCornerBeige,
                Block::RoofSlantCornerInnerBeige,
                Block::RoofSlantBrown,
                Block::RoofSlantCornerBrown,
                Block::RoofSlantCornerInnerBrown,
                Block::RoofSlantGreen,
                Block::RoofSlantCornerGreen,
                Block::RoofSlantCornerInnerGreen,
                Block::RoofSlantPurple,
                Block::RoofSlantCornerPurple,
                Block::RoofSlantCornerInnerPurple,
            ],
            Category::Blocks => vec![
                Block::DirtCenter,
                Block::DirtLow,
                Block::Grass,
                Block::GrassCenter,
                Block::GrassCorner,
                Block::GrassPath,


@@ 531,7 458,7 @@ impl Category {
                Block::GrassWaterConvex,
                Block::GrassWaterRiver,
                Block::WaterCenter,
                Block::WaterFall
                Block::WaterFall,
            ],
            Category::Roofs => vec![
                Block::RoofChurchBeige,


@@ 539,31 466,53 @@ impl Category {
                Block::RoofChurchGreen,
                Block::RoofChurchPurple,
                Block::RoofGableBeige,
                Block::RoofGableCornerBeige,
                Block::RoofGableBrown,
                Block::RoofGableCornerBrown,
                Block::RoofGableGreen,
                Block::RoofGableCornerGreen,
                Block::RoofGablePurple,
                Block::RoofGableCornerPurple,
                Block::RoofPointBeige,
                Block::RoofPointBrown,
                Block::RoofPointGreen,
                Block::RoofPointPurple,
                Block::RoofRoundBeige,
                Block::RoofRoundCornerBeige,
                Block::RoofRoundBrown,
                Block::RoofRoundCornerBrown,
                Block::RoofRoundGreen,
                Block::RoofRoundCornerGreen,
                Block::RoofRoundPurple,
                Block::RoofRoundCornerPurple,
                Block::RoofRoundedBeige,
                Block::RoofRoundedBrown,
                Block::RoofRoundedGreen,
                Block::RoofRoundedPurple,
                Block::RoofSlantBeige,
                Block::RoofSlantCornerBeige,
                Block::RoofSlantCornerInnerBeige,
                Block::RoofSlantBrown,
                Block::RoofSlantCornerBrown,
                Block::RoofSlantCornerInnerBrown,
                Block::RoofSlantGreen,
                Block::RoofSlantCornerGreen,
                Block::RoofSlantCornerInnerGreen,
                Block::RoofSlantPurple,
                Block::RoofSlantCornerPurple,
                Block::RoofSlantCornerInnerPurple,
            ],
            Category::Plants => vec![
                Block::RocksDirt,
                Block::RocksGrass,
                Block::Trees,
                Block::Tree,
                Block::Pine,
                Block::PineLarge,
                Block::Furrow,
                Block::FurrowCropWheat,
                Block::FurrowCrop,
                Block::FurrowEnd,
            ],
            Category::Water => vec![
                Block::GrassRiver,


@@ 580,13 529,22 @@ impl Category {
                Block::GrassWaterConvex,
                Block::GrassWaterRiver,
                Block::WaterCenter,
                Block::WaterFall
                Block::WaterFall,
                Block::Well
            ],
            Category::Wood => vec![
                Block::Bridge,
                Block::StructureArch,
                Block::StructureHigh,
                Block::StructureLow,
                Block::Fence,
                Block::FenceCorner,
                Block::FenceCurve,
                Block::FenceEnd,
                Block::FenceDouble,
                Block::FenceDoubleCorner,
                Block::FenceDoubleCurve,
                Block::FenceDoubleEnd,
            ],
            Category::All => Block::all()
        }

M src/game/world.rs => src/game/world.rs +13 -1
@@ 12,6 12,7 @@ use std::path::Path;
use std::fs::{
    File,
    OpenOptions,
    DirBuilder,
    read_dir
};
use std::io::{


@@ 93,6 94,11 @@ impl World {
            }
        }

        // place block even though it is not in inventory
        if self.sandbox {
                self.grid.insert(pos.clone(), (block, dir));
        }

        false
    }



@@ 149,11 155,17 @@ impl World {
        if let Some(dir) = get_data_dir() {
            let json = World::serialize_json(self);

            let path = Path::new(&dir).join(name);

            DirBuilder::new()
                .recursive(true)
                .create(&path);

            let mut file =  OpenOptions::new()
                .write(true)
                .create(true)
                .truncate(true)
                .open(Path::new(&dir).join(name));
                .open(path);

            if let Ok(file) = &mut file {
                if file.write_all(json.as_bytes()).is_err() {

M src/screens/build.rs => src/screens/build.rs +9 -1
@@ 64,9 64,14 @@ fn get_screen_coords(pos: &Pos3, scale: f32, center: (f32, f32)) -> (f32, f32) {
}

struct InventoryWidgets {
    /// widgets used to render pages
    widgets_slots: Vec<ItemFrame>,
    /// back button widget
    /// used to return to game
    widget_back: TextButton,
    /// button used to cycle through categories
    widget_categories: TextButton,
    /// text widget used to display page numbers
    widget_page_indicator: CenteredText,
    /// current page
    /// set to zero when closing inventory


@@ 106,6 111,9 @@ impl InventoryWidgets {
    }
    /// loads a new category
    fn load_category(&mut self, cat: Category, inv: &mut Inventory) {
        let page = if inv.category != cat {
            0
        } else { self.page };
        inv.category = cat;
        let title = inv.category.get_name();
        self.widget_categories.set_text(title);


@@ 114,7 122,7 @@ impl InventoryWidgets {
        self.widget_page_indicator.set_text(&format!("{}/{}", self.page+1, page_count));
        self.widget_categories.set_text(&format!("{}", title));

        self.load_page(0, inv);
        self.load_page(page, inv);
    }
    /// loads the entries of the given page in the current category
    fn load_page(&mut self, page: usize, inv: &mut Inventory) {

M src/textures.rs => src/textures.rs +13 -6
@@ 32,6 32,8 @@ impl DirectionalTexture {
        }
    }
}

/// macro used to include png assets
macro_rules! include_img_asset {
    ($name:literal) => {
        Texture2D::from_image(


@@ 42,24 44,29 @@ macro_rules! include_img_asset {
        )
    };
}
macro_rules! include_base_tile {

/// macro used to include .png tiles from an asset pack
macro_rules! include_tile {
    ($name:literal, $dir:literal) => {
        Texture2D::from_image(
            &Image::from_file_with_format(
                include_bytes!(concat!("../../assets/base/Tiles/", $name, "_", $dir, ".png")),
                include_bytes!(concat!("../../assets/", $name, "_", $dir, ".png")),
                Some(ImageFormat::Png)
            )
        )
    };
    ($name:literal) => {
        DirectionalTexture {
            north: include_base_tile!($name, "N"),
            south: include_base_tile!($name, "S"),
            east: include_base_tile!($name, "E"),
            west: include_base_tile!($name, "W"),
            north: include_tile!($name, "N"),
            south: include_tile!($name, "S"),
            east: include_tile!($name, "E"),
            west: include_tile!($name, "W"),
        }
    }
}

/// macro used to include ui elements
/// from the ui asset pack
macro_rules! include_ui_img {
    ($name:literal) => {
        Texture2D::from_image(