From fc59880b803cca725af5294ecd0ccb4268a98145 Mon Sep 17 00:00:00 2001 From: Llywelwyn Date: Thu, 20 Jul 2023 17:21:32 +0100 Subject: [PATCH] initial wfc, and suppressing dead code warnings --- src/map.rs | 2 +- src/map_builders/common.rs | 1 + src/map_builders/dla.rs | 1 - src/map_builders/mod.rs | 47 +++--- src/map_builders/voronoi.rs | 1 + src/map_builders/wfc/common.rs | 110 ++++++++++++++ src/map_builders/wfc/constraints.rs | 95 ++++++++++++ src/map_builders/wfc/mod.rs | 97 +++++++++++- src/map_builders/wfc/solver.rs | 225 ++++++++++++++++++++++++++++ src/rex_assets.rs | 2 - 10 files changed, 551 insertions(+), 30 deletions(-) create mode 100644 src/map_builders/wfc/common.rs create mode 100644 src/map_builders/wfc/constraints.rs create mode 100644 src/map_builders/wfc/solver.rs diff --git a/src/map.rs b/src/map.rs index 7a61654..39621fe 100644 --- a/src/map.rs +++ b/src/map.rs @@ -4,7 +4,7 @@ use specs::prelude::*; use std::collections::HashSet; use std::ops::{Add, Mul}; -#[derive(PartialEq, Copy, Clone, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)] pub enum TileType { Wall, Floor, diff --git a/src/map_builders/common.rs b/src/map_builders/common.rs index 50b277d..1bc87c7 100644 --- a/src/map_builders/common.rs +++ b/src/map_builders/common.rs @@ -78,6 +78,7 @@ pub fn generate_voronoi_spawn_regions(map: &Map, rng: &mut rltk::RandomNumberGen return noise_areas; } +#[allow(dead_code)] #[derive(PartialEq, Copy, Clone)] pub enum Symmetry { None, diff --git a/src/map_builders/dla.rs b/src/map_builders/dla.rs index 2e61a92..627216a 100644 --- a/src/map_builders/dla.rs +++ b/src/map_builders/dla.rs @@ -222,7 +222,6 @@ impl DLABuilder { } paint(&mut self.map, self.symmetry, self.brush_size, prev_x, prev_y); } - _ => {} } self.take_snapshot(); floor_tile_count = self.map.tiles.iter().filter(|a| **a == TileType::Floor).count(); diff --git a/src/map_builders/mod.rs b/src/map_builders/mod.rs index e9845bd..abff66d 100644 --- a/src/map_builders/mod.rs +++ b/src/map_builders/mod.rs @@ -22,27 +22,34 @@ pub trait MapBuilder { fn take_snapshot(&mut self); } +#[rustfmt::skip] pub fn random_builder(new_depth: i32) -> Box { - /*let mut rng = rltk::RandomNumberGenerator::new(); + let mut rng = rltk::RandomNumberGenerator::new(); let builder = rng.roll_dice(1, 17); + let mut result : Box; match builder { - 1 => Box::new(bsp_dungeon::BspDungeonBuilder::new(new_depth)), - 2 => Box::new(bsp_interior::BspInteriorBuilder::new(new_depth)), - 3 => Box::new(cellular_automata::CellularAutomataBuilder::new(new_depth)), - 4 => Box::new(drunkard::DrunkardsWalkBuilder::open_area(new_depth)), - 5 => Box::new(drunkard::DrunkardsWalkBuilder::open_halls(new_depth)), - 6 => Box::new(drunkard::DrunkardsWalkBuilder::winding_passages(new_depth)), - 6 => Box::new(drunkard::DrunkardsWalkBuilder::fat_passages(new_depth)), - 6 => Box::new(drunkard::DrunkardsWalkBuilder::fearful_symmetry(new_depth)), - 7 => Box::new(maze::MazeBuilder::new(new_depth)), - 8 => Box::new(dla::DLABuilder::walk_inwards(new_depth)), - 9 => Box::new(dla::DLABuilder::walk_outwards(new_depth)), - 10 => Box::new(dla::DLABuilder::central_attractor(new_depth)), - 11 => Box::new(dla::DLABuilder::insectoid(new_depth)), - 12 => Box::new(voronoi::VoronoiBuilder::pythagoras(new_depth)), - 12 => Box::new(voronoi::VoronoiBuilder::manhattan(new_depth)), - 12 => Box::new(voronoi::VoronoiBuilder::chebyshev(new_depth)), - _ => Box::new(simple_map::SimpleMapBuilder::new(new_depth)), - }*/ - Box::new(wfc::WaveFunctionCollapseBuilder::new(new_depth)) + 1 => { result = Box::new(bsp_dungeon::BspDungeonBuilder::new(new_depth)); } + 2 => { result = Box::new(bsp_interior::BspInteriorBuilder::new(new_depth)); } + 3 => { result = Box::new(cellular_automata::CellularAutomataBuilder::new(new_depth)); } + 4 => { result = Box::new(drunkard::DrunkardsWalkBuilder::open_area(new_depth)); } + 5 => { result = Box::new(drunkard::DrunkardsWalkBuilder::open_halls(new_depth)); } + 6 => { result = Box::new(drunkard::DrunkardsWalkBuilder::winding_passages(new_depth)); } + 7 => { result = Box::new(drunkard::DrunkardsWalkBuilder::fat_passages(new_depth)); } + 8 => { result = Box::new(drunkard::DrunkardsWalkBuilder::fearful_symmetry(new_depth)); } + 9 => { result = Box::new(maze::MazeBuilder::new(new_depth)); } + 10 => { result = Box::new(dla::DLABuilder::walk_inwards(new_depth)); } + 11 => { result = Box::new(dla::DLABuilder::walk_outwards(new_depth)); } + 12 => { result = Box::new(dla::DLABuilder::central_attractor(new_depth)); } + 13 => { result = Box::new(dla::DLABuilder::insectoid(new_depth)); } + 14 => { result = Box::new(voronoi::VoronoiBuilder::pythagoras(new_depth)); } + 15 => { result = Box::new(voronoi::VoronoiBuilder::manhattan(new_depth)); } + 16 => { result = Box::new(wfc::WaveFunctionCollapseBuilder::test_map(new_depth)); } + _ => { result = Box::new(simple_map::SimpleMapBuilder::new(new_depth)); } + } + + if rng.roll_dice(1, 3)==1 { + result = Box::new(wfc::WaveFunctionCollapseBuilder::derived_map(new_depth, result)); + } + + result } diff --git a/src/map_builders/voronoi.rs b/src/map_builders/voronoi.rs index 3e04ff4..7bcfa42 100644 --- a/src/map_builders/voronoi.rs +++ b/src/map_builders/voronoi.rs @@ -77,6 +77,7 @@ impl VoronoiBuilder { distance_algorithm: DistanceAlgorithm::Manhattan, } } + #[allow(dead_code)] pub fn chebyshev(new_depth: i32) -> VoronoiBuilder { VoronoiBuilder { map: Map::new(new_depth), diff --git a/src/map_builders/wfc/common.rs b/src/map_builders/wfc/common.rs new file mode 100644 index 0000000..fb2bb62 --- /dev/null +++ b/src/map_builders/wfc/common.rs @@ -0,0 +1,110 @@ +use super::TileType; + +#[derive(PartialEq, Eq, Hash, Clone)] +pub struct MapChunk { + pub pattern: Vec, + pub exits: [Vec; 4], + pub has_exits: bool, + pub compatible_with: [Vec; 4], +} + +pub fn tile_idx_in_chunk(chunk_size: i32, x: i32, y: i32) -> usize { + ((y * chunk_size) + x) as usize +} + +pub fn patterns_to_constraints(patterns: Vec>, chunk_size: i32) -> Vec { + // Move patterns into constraints obj + let mut constraints: Vec = Vec::new(); + for pattern in patterns { + let mut new_chunk = MapChunk { + pattern: pattern, + exits: [Vec::new(), Vec::new(), Vec::new(), Vec::new()], + has_exits: true, + compatible_with: [Vec::new(), Vec::new(), Vec::new(), Vec::new()], + }; + for exit in new_chunk.exits.iter_mut() { + for _i in 0..chunk_size { + exit.push(false); + } + } + + let mut number_of_exits = 0; + for x in 0..chunk_size { + // Check north + let north_idx = tile_idx_in_chunk(chunk_size, x, 0); + if new_chunk.pattern[north_idx] == TileType::Floor { + new_chunk.exits[0][x as usize] = true; + number_of_exits += 1; + } + // Check south + let south_idx = tile_idx_in_chunk(chunk_size, x, chunk_size - 1); + if new_chunk.pattern[south_idx] == TileType::Floor { + new_chunk.exits[1][x as usize] = true; + number_of_exits += 1; + } + // Check west + let west_idx = tile_idx_in_chunk(chunk_size, 0, x); + if new_chunk.pattern[west_idx] == TileType::Floor { + new_chunk.exits[2][x as usize] = true; + number_of_exits += 1; + } + // Check east + let east_idx = tile_idx_in_chunk(chunk_size, chunk_size - 1, x); + if new_chunk.pattern[east_idx] == TileType::Floor { + new_chunk.exits[3][x as usize] = true; + number_of_exits += 1; + } + } + + if number_of_exits == 0 { + new_chunk.has_exits = false; + } + constraints.push(new_chunk); + } + + // Build compatibility matrix + let ch = constraints.clone(); + for constraint in constraints.iter_mut() { + for (j, potential) in ch.iter().enumerate() { + // If no exits at all, it's compatible + if !constraint.has_exits || !potential.has_exits { + for compatible in constraint.compatible_with.iter_mut() { + compatible.push(j); + } + } else { + // Evaluate compatibility by dir + for (direction, exit_list) in constraint.exits.iter_mut().enumerate() { + let opposite = match direction { + 0 => 1, // North-South + 1 => 0, // South-North + 2 => 3, // West-East + _ => 2, // East-West + }; + + let mut it_fits = false; + let mut has_any = false; + for (slot, can_enter) in exit_list.iter().enumerate() { + if *can_enter { + has_any = true; + if potential.exits[opposite][slot] { + it_fits = true; + } + } + } + if it_fits { + constraint.compatible_with[direction].push(j); + } + if !has_any { + // No exits, match only if other edge also has none + let matching_exit_count = potential.exits[opposite].iter().filter(|a| !**a).count(); + if matching_exit_count == 0 { + constraint.compatible_with[direction].push(j); + } + } + } + } + } + } + + return constraints; +} diff --git a/src/map_builders/wfc/constraints.rs b/src/map_builders/wfc/constraints.rs new file mode 100644 index 0000000..e9504a0 --- /dev/null +++ b/src/map_builders/wfc/constraints.rs @@ -0,0 +1,95 @@ +use super::{Map, MapChunk, TileType}; +use std::collections::HashSet; + +pub fn build_patterns(map: &Map, chunk_size: i32, include_flipping: bool, dedupe: bool) -> Vec> { + let chunks_x = map.width / chunk_size; + let chunks_y = map.height / chunk_size; + let mut patterns = Vec::new(); + + for cy in 0..chunks_y { + for cx in 0..chunks_x { + // Normal orientation + let mut pattern: Vec = Vec::new(); + let start_x = cx * chunk_size; + let end_x = (cx + 1) * chunk_size; + let start_y = cy * chunk_size; + let end_y = (cy + 1) * chunk_size; + + for y in start_y..end_y { + for x in start_x..end_x { + let idx = map.xy_idx(x, y); + pattern.push(map.tiles[idx]); + } + } + patterns.push(pattern); + + if include_flipping { + // Flip horizontal + pattern = Vec::new(); + for y in start_y..end_y { + for x in start_x..end_x { + let idx = map.xy_idx(end_x - (x + 1), y); + pattern.push(map.tiles[idx]); + } + } + patterns.push(pattern); + + // Flip vertical + pattern = Vec::new(); + for y in start_y..end_y { + for x in start_x..end_x { + let idx = map.xy_idx(x, end_y - (y + 1)); + pattern.push(map.tiles[idx]); + } + } + patterns.push(pattern); + } + } + } + + // Dedupe + if dedupe { + rltk::console::log(format!("Pre de-duplication, there are {} patterns.", patterns.len())); + let set: HashSet> = patterns.drain(..).collect(); // Dedupes + patterns.extend(set.into_iter()); + rltk::console::log(format!("There are {} patterns.", patterns.len())); + } + + return patterns; +} + +pub fn render_pattern_to_map(map: &mut Map, chunk: &MapChunk, chunk_size: i32, start_x: i32, start_y: i32) { + let mut i = 0usize; + for tile_y in 0..chunk_size { + for tile_x in 0..chunk_size { + let map_idx = map.xy_idx(start_x + tile_x, start_y + tile_y); + map.tiles[map_idx] = chunk.pattern[i]; + map.visible_tiles[map_idx] = true; + i += 1; + } + } + for (x, northbound) in chunk.exits[0].iter().enumerate() { + if *northbound { + let map_idx = map.xy_idx(start_x + x as i32, start_y); + map.tiles[map_idx] = TileType::DownStair; + } + } + for (x, southbound) in chunk.exits[1].iter().enumerate() { + if *southbound { + let map_idx = map.xy_idx(start_x + x as i32, start_y + chunk_size - 1); + map.tiles[map_idx] = TileType::DownStair; + } + } + for (x, westbound) in chunk.exits[2].iter().enumerate() { + if *westbound { + let map_idx = map.xy_idx(start_x, start_y + x as i32); + map.tiles[map_idx] = TileType::DownStair; + } + } + for (x, eastbound) in chunk.exits[3].iter().enumerate() { + if *eastbound { + let map_idx = map.xy_idx(start_x + chunk_size - 1, start_y + x as i32); + map.tiles[map_idx] = TileType::DownStair; + } + } +} diff --git a/src/map_builders/wfc/mod.rs b/src/map_builders/wfc/mod.rs index 20c8515..420e380 100644 --- a/src/map_builders/wfc/mod.rs +++ b/src/map_builders/wfc/mod.rs @@ -4,16 +4,29 @@ use super::{ }; mod image_loader; use image_loader::load_rex_map; +mod common; +use common::MapChunk; +mod constraints; +mod solver; use rltk::RandomNumberGenerator; +use solver::Solver; use specs::prelude::*; use std::collections::HashMap; +#[derive(PartialEq, Copy, Clone)] +pub enum WaveFunctionMode { + TestMap, + Derived, +} + pub struct WaveFunctionCollapseBuilder { map: Map, starting_position: Position, depth: i32, history: Vec, noise_areas: HashMap>, + mode: WaveFunctionMode, + derive_from: Option>, } impl MapBuilder for WaveFunctionCollapseBuilder { @@ -48,26 +61,72 @@ impl MapBuilder for WaveFunctionCollapseBuilder { } impl WaveFunctionCollapseBuilder { - pub fn new(new_depth: i32) -> WaveFunctionCollapseBuilder { + pub fn new( + new_depth: i32, + mode: WaveFunctionMode, + derive_from: Option>, + ) -> WaveFunctionCollapseBuilder { WaveFunctionCollapseBuilder { map: Map::new(new_depth), starting_position: Position { x: 0, y: 0 }, depth: new_depth, history: Vec::new(), noise_areas: HashMap::new(), + mode, + derive_from, } } + pub fn test_map(new_depth: i32) -> WaveFunctionCollapseBuilder { + WaveFunctionCollapseBuilder::new(new_depth, WaveFunctionMode::TestMap, None) + } + pub fn derived_map(new_depth: i32, builder: Box) -> WaveFunctionCollapseBuilder { + WaveFunctionCollapseBuilder::new(new_depth, WaveFunctionMode::Derived, Some(builder)) + } fn build(&mut self, rng: &mut RandomNumberGenerator) { - self.map = load_rex_map(self.depth, &rltk::rex::XpFile::from_resource("../resources/wfc-demo1.xp").unwrap()); + if self.mode == WaveFunctionMode::TestMap { + self.map = + load_rex_map(self.depth, &rltk::rex::XpFile::from_resource("../resources/wfc-demo1.xp").unwrap()); + self.take_snapshot(); + return; + } + + const CHUNK_SIZE: i32 = 8; + + let prebuilder = &mut self.derive_from.as_mut().unwrap(); + prebuilder.build_map(rng); + self.map = prebuilder.get_map(); + for t in self.map.tiles.iter_mut() { + if *t == TileType::DownStair { + *t = TileType::Floor; + } + } + self.take_snapshot(); + + let patterns = constraints::build_patterns(&self.map, CHUNK_SIZE, true, true); + let constraints = common::patterns_to_constraints(patterns, CHUNK_SIZE); + self.render_tile_gallery(&constraints, CHUNK_SIZE); + + // Call solver + self.map = Map::new(self.depth); + loop { + let mut solver = Solver::new(constraints.clone(), CHUNK_SIZE, &self.map); + while !solver.iteration(&mut self.map, rng) { + self.take_snapshot(); + } + self.take_snapshot(); + if solver.possible { + break; + } + } // Find a starting point; start at the middle and walk left until we find an open tile self.starting_position = Position { x: self.map.width / 2, y: self.map.height / 2 }; let mut start_idx = self.map.xy_idx(self.starting_position.x, self.starting_position.y); - //while self.map.tiles[start_idx] != TileType::Floor { - // self.starting_position.x -= 1; - // start_idx = self.map.xy_idx(self.starting_position.x, self.starting_position.y); - //} + while self.map.tiles[start_idx] != TileType::Floor { + self.starting_position.x -= 1; + start_idx = self.map.xy_idx(self.starting_position.x, self.starting_position.y); + } self.take_snapshot(); // Find all tiles we can reach from the starting point @@ -81,4 +140,30 @@ impl WaveFunctionCollapseBuilder { // Now we build a noise map for use in spawning entities later self.noise_areas = generate_voronoi_spawn_regions(&self.map, rng); } + + fn render_tile_gallery(&mut self, constraints: &Vec, chunk_size: i32) { + self.map = Map::new(0); + let mut counter = 0; + let mut x = 1; + let mut y = 1; + while counter < constraints.len() { + constraints::render_pattern_to_map(&mut self.map, &constraints[counter], chunk_size, x, y); + x += chunk_size + 1; + if x + chunk_size > self.map.width { + // Next row + x = 1; + y += chunk_size + 1; + + if y + chunk_size > self.map.height { + // Next page + self.take_snapshot(); + self.map = Map::new(0); + x = 1; + y = 1; + } + } + counter += 1; + } + self.take_snapshot(); + } } diff --git a/src/map_builders/wfc/solver.rs b/src/map_builders/wfc/solver.rs new file mode 100644 index 0000000..548f4df --- /dev/null +++ b/src/map_builders/wfc/solver.rs @@ -0,0 +1,225 @@ +use super::{Map, MapChunk}; +use std::collections::HashSet; + +pub struct Solver { + constraints: Vec, + chunk_size: i32, + chunks: Vec>, + chunks_x: usize, + chunks_y: usize, + remaining: Vec<(usize, i32)>, // (idx, number of neighbours) + pub possible: bool, +} + +impl Solver { + pub fn new(constraints: Vec, chunk_size: i32, map: &Map) -> Solver { + let chunks_x = (map.width / chunk_size) as usize; + let chunks_y = (map.height / chunk_size) as usize; + let mut remaining: Vec<(usize, i32)> = Vec::new(); + for i in 0..(chunks_x * chunks_y) { + remaining.push((i, 0)); + } + + Solver { + constraints, + chunk_size, + chunks: vec![None; chunks_x * chunks_y], + chunks_x, + chunks_y, + remaining, + possible: true, + } + } + + fn chunk_idx(&self, x: usize, y: usize) -> usize { + return ((y * self.chunks_x) + x) as usize; + } + + fn count_neighbours(&self, chunk_x: usize, chunk_y: usize) -> i32 { + let mut neighbours = 0; + + if chunk_x > 0 { + let left_idx = self.chunk_idx(chunk_x - 1, chunk_y); + match self.chunks[left_idx] { + None => {} + Some(_) => { + neighbours += 1; + } + } + } + if chunk_x > self.chunks_x - 1 { + let right_idx = self.chunk_idx(chunk_x + 1, chunk_y); + match self.chunks[right_idx] { + None => {} + Some(_) => { + neighbours += 1; + } + } + } + if chunk_y > 0 { + let up_idx = self.chunk_idx(chunk_x, chunk_y - 1); + match self.chunks[up_idx] { + None => {} + Some(_) => { + neighbours += 1; + } + } + } + if chunk_y > self.chunks_y - 1 { + let down_idx = self.chunk_idx(chunk_x, chunk_y + 1); + match self.chunks[down_idx] { + None => {} + Some(_) => { + neighbours += 1; + } + } + } + return neighbours; + } + + pub fn iteration(&mut self, map: &mut Map, rng: &mut super::RandomNumberGenerator) -> bool { + if self.remaining.is_empty() { + return true; + } + + // Populate the neighbor count of the remaining list + let mut remain_copy = self.remaining.clone(); + let mut neighbours_exist = false; + for r in remain_copy.iter_mut() { + let idx = r.0; + let chunk_x = idx % self.chunks_x; + let chunk_y = idx / self.chunks_x; + let neighbour_count = self.count_neighbours(chunk_x, chunk_y); + if neighbour_count > 0 { + neighbours_exist = true; + } + *r = (r.0, neighbour_count); + } + remain_copy.sort_by(|a, b| b.1.cmp(&a.1)); + self.remaining = remain_copy; + + // Pick a random chunk we haven't dealt with yet and get its index, remove from remaining list + let remaining_index = + if !neighbours_exist { (rng.roll_dice(1, self.remaining.len() as i32) - 1) as usize } else { 0usize }; + let chunk_index = self.remaining[remaining_index].0; + self.remaining.remove(remaining_index); + + let chunk_x = chunk_index % self.chunks_x; + let chunk_y = chunk_index / self.chunks_x; + + let mut neighbours = 0; + let mut options: Vec> = Vec::new(); + + if chunk_x > 0 { + let left_idx = self.chunk_idx(chunk_x - 1, chunk_y); + match self.chunks[left_idx] { + None => {} + Some(nt) => { + neighbours += 1; + options.push(self.constraints[nt].compatible_with[3].clone()); + } + } + } + + if chunk_x < self.chunks_x - 1 { + let right_idx = self.chunk_idx(chunk_x + 1, chunk_y); + match self.chunks[right_idx] { + None => {} + Some(nt) => { + neighbours += 1; + options.push(self.constraints[nt].compatible_with[2].clone()); + } + } + } + + if chunk_y > 0 { + let up_idx = self.chunk_idx(chunk_x, chunk_y - 1); + match self.chunks[up_idx] { + None => {} + Some(nt) => { + neighbours += 1; + options.push(self.constraints[nt].compatible_with[1].clone()); + } + } + } + + if chunk_y < self.chunks_y - 1 { + let down_idx = self.chunk_idx(chunk_x, chunk_y + 1); + match self.chunks[down_idx] { + None => {} + Some(nt) => { + neighbours += 1; + options.push(self.constraints[nt].compatible_with[0].clone()); + } + } + } + + if neighbours == 0 { + // There is nothing nearby, so we can have anything! + let new_chunk_idx = (rng.roll_dice(1, self.constraints.len() as i32) - 1) as usize; + self.chunks[chunk_index] = Some(new_chunk_idx); + let left_x = chunk_x as i32 * self.chunk_size as i32; + let right_x = (chunk_x as i32 + 1) * self.chunk_size as i32; + let top_y = chunk_y as i32 * self.chunk_size as i32; + let bottom_y = (chunk_y as i32 + 1) * self.chunk_size as i32; + + let mut i: usize = 0; + for y in top_y..bottom_y { + for x in left_x..right_x { + let mapidx = map.xy_idx(x, y); + let tile = self.constraints[new_chunk_idx].pattern[i]; + map.tiles[mapidx] = tile; + i += 1; + } + } + } else { + // There are neighbors, so we try to be compatible with them + let mut options_to_check: HashSet = HashSet::new(); + for o in options.iter() { + for i in o.iter() { + options_to_check.insert(*i); + } + } + + let mut possible_options: Vec = Vec::new(); + for new_chunk_idx in options_to_check.iter() { + let mut possible = true; + for o in options.iter() { + if !o.contains(new_chunk_idx) { + possible = false; + } + } + if possible { + possible_options.push(*new_chunk_idx); + } + } + + if possible_options.is_empty() { + rltk::console::log("Oh no! It's not possible!"); + self.possible = false; + return true; + } else { + let new_chunk_idx = + if possible_options.len() == 1 { 0 } else { rng.roll_dice(1, possible_options.len() as i32) - 1 }; + + self.chunks[chunk_index] = Some(new_chunk_idx as usize); + let left_x = chunk_x as i32 * self.chunk_size as i32; + let right_x = (chunk_x as i32 + 1) * self.chunk_size as i32; + let top_y = chunk_y as i32 * self.chunk_size as i32; + let bottom_y = (chunk_y as i32 + 1) * self.chunk_size as i32; + + let mut i: usize = 0; + for y in top_y..bottom_y { + for x in left_x..right_x { + let mapidx = map.xy_idx(x, y); + let tile = self.constraints[new_chunk_idx as usize].pattern[i]; + map.tiles[mapidx] = tile; + i += 1; + } + } + } + } + + false + } +} diff --git a/src/rex_assets.rs b/src/rex_assets.rs index d0f749c..0b0ab8f 100644 --- a/src/rex_assets.rs +++ b/src/rex_assets.rs @@ -2,7 +2,6 @@ use rltk::rex::XpFile; rltk::embedded_resource!(CAVE_TUNNEL, "../resources/cave_tunnel80x60.xp"); rltk::embedded_resource!(WFC_DEMO_IMAGE1, "../resources/wfc-demo1.xp"); -rltk::embedded_resource!(WFC_DEMO_IMAGE2, "../resources/wfc-demo2.xp"); pub struct RexAssets { pub menu: XpFile, @@ -13,7 +12,6 @@ impl RexAssets { pub fn new() -> RexAssets { rltk::link_resource!(CAVE_TUNNEL, "../resources/cave_tunnel80x60.xp"); rltk::link_resource!(WFC_DEMO_IMAGE1, "../resources/wfc-demo1.xp"); - rltk::link_resource!(WFC_DEMO_IMAGE2, "../resources/wfc-demo2.xp"); RexAssets { menu: XpFile::from_resource("../resources/cave_tunnel80x60.xp").unwrap() } }