mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Town hazards
This commit is contained in:
parent
7d1c95eae7
commit
123651e0a6
@ -109,8 +109,8 @@ impl Civs {
|
|||||||
attempt(5, || {
|
attempt(5, || {
|
||||||
let (kind, size) = match ctx.rng.gen_range(0..8) {
|
let (kind, size) = match ctx.rng.gen_range(0..8) {
|
||||||
0 => (SiteKind::Castle, 3),
|
0 => (SiteKind::Castle, 3),
|
||||||
1 => (SiteKind::Refactor, 5),
|
1 => (SiteKind::Dungeon, 0),
|
||||||
_ => (SiteKind::Dungeon, 0),
|
_ => (SiteKind::Refactor, 5),
|
||||||
};
|
};
|
||||||
let loc = find_site_loc(&mut ctx, None, size)?;
|
let loc = find_site_loc(&mut ctx, None, size)?;
|
||||||
this.establish_site(&mut ctx.reseed(), loc, |place| Site {
|
this.establish_site(&mut ctx.reseed(), loc, |place| Site {
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
use crate::sim;
|
use crate::sim;
|
||||||
|
use common::{
|
||||||
|
terrain::TerrainChunkSize,
|
||||||
|
vol::RectVolSize,
|
||||||
|
};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
/// A wrapper type that may contain a reference to a generated world. If not, default values will be provided.
|
/// A wrapper type that may contain a reference to a generated world. If not, default values will be provided.
|
||||||
@ -18,4 +22,14 @@ impl<'a> Land<'a> {
|
|||||||
pub fn get_alt_approx(&self, wpos: Vec2<i32>) -> f32 {
|
pub fn get_alt_approx(&self, wpos: Vec2<i32>) -> f32 {
|
||||||
self.sim.and_then(|sim| sim.get_alt_approx(wpos)).unwrap_or(0.0)
|
self.sim.and_then(|sim| sim.get_alt_approx(wpos)).unwrap_or(0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_gradient_approx(&self, wpos: Vec2<i32>) -> f32 {
|
||||||
|
self.sim
|
||||||
|
.and_then(|sim| sim.get_gradient_approx(wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e.div_euclid(sz as i32))))
|
||||||
|
.unwrap_or(0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_chunk_at(&self, wpos: Vec2<i32>) -> Option<&sim::SimChunk> {
|
||||||
|
self.sim.and_then(|sim| sim.get_wpos(wpos))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,21 @@ mod tile;
|
|||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
plot::{Plot, PlotKind},
|
plot::{Plot, PlotKind},
|
||||||
tile::{TileGrid, Tile, TileKind, TILE_SIZE},
|
tile::{TileGrid, Tile, TileKind, HazardKind, TILE_SIZE},
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
site::SpawnRules,
|
site::SpawnRules,
|
||||||
util::{Grid, attempt, CARDINALS, SQUARE_9},
|
util::{Grid, attempt, CARDINALS, SQUARE_4, SQUARE_9},
|
||||||
Canvas,
|
Canvas,
|
||||||
Land,
|
Land,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
terrain::{Block, BlockKind, SpriteKind},
|
terrain::{Block, BlockKind, SpriteKind, TerrainChunkSize},
|
||||||
|
vol::RectVolSize,
|
||||||
store::{Id, Store},
|
store::{Id, Store},
|
||||||
astar::Astar,
|
astar::Astar,
|
||||||
lottery::Lottery,
|
lottery::Lottery,
|
||||||
|
spiral::Spiral2d,
|
||||||
};
|
};
|
||||||
use hashbrown::hash_map::DefaultHashBuilder;
|
use hashbrown::hash_map::DefaultHashBuilder;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
@ -33,7 +35,8 @@ pub struct Site {
|
|||||||
|
|
||||||
impl Site {
|
impl Site {
|
||||||
pub fn radius(&self) -> f32 {
|
pub fn radius(&self) -> f32 {
|
||||||
(tile::MAX_BLOCK_RADIUS.pow(2) as f32 * 2.0).sqrt()
|
((self.tiles.bounds.min.map(|e| e.abs()).reduce_max()
|
||||||
|
.max(self.tiles.bounds.max.map(|e| e.abs()).reduce_max()) + 1) * tile::TILE_SIZE as i32) as f32
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_rules(&self, wpos: Vec2<i32>) -> SpawnRules {
|
pub fn spawn_rules(&self, wpos: Vec2<i32>) -> SpawnRules {
|
||||||
@ -46,10 +49,10 @@ impl Site {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn bounds(&self) -> Aabr<i32> {
|
pub fn bounds(&self) -> Aabr<i32> {
|
||||||
let radius = tile::MAX_BLOCK_RADIUS;
|
let border = 1;
|
||||||
Aabr {
|
Aabr {
|
||||||
min: -Vec2::broadcast(radius as i32),
|
min: self.origin + self.tile_wpos(self.tiles.bounds.min - border),
|
||||||
max: Vec2::broadcast(radius as i32),
|
max: self.origin + self.tile_wpos(self.tiles.bounds.max + 1 + border),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +76,7 @@ impl Site {
|
|||||||
for y in 0..w {
|
for y in 0..w {
|
||||||
for x in 0..w {
|
for x in 0..w {
|
||||||
if self.tiles.get(*tile + Vec2::new(x, y)).is_obstacle() {
|
if self.tiles.get(*tile + Vec2::new(x, y)).is_obstacle() {
|
||||||
return 100.0;
|
return 1000.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,6 +148,7 @@ impl Site {
|
|||||||
self.plazas
|
self.plazas
|
||||||
.choose(rng)
|
.choose(rng)
|
||||||
.map(|&p| self.plot(p).root_tile + (Vec2::new(rng.gen_range(-1.0..1.0), rng.gen_range(-1.0..1.0)).normalized() * 24.0).map(|e| e as i32))
|
.map(|&p| self.plot(p).root_tile + (Vec2::new(rng.gen_range(-1.0..1.0), rng.gen_range(-1.0..1.0)).normalized() * 24.0).map(|e| e as i32))
|
||||||
|
.filter(|tile| !self.tiles.get(*tile).is_obstacle())
|
||||||
.filter(|&tile| self
|
.filter(|&tile| self
|
||||||
.plazas
|
.plazas
|
||||||
.iter()
|
.iter()
|
||||||
@ -185,19 +189,37 @@ impl Site {
|
|||||||
plaza
|
plaza
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn demarcate_obstacles(&mut self, land: &Land) {
|
||||||
|
const SEARCH_RADIUS: u32 = 96;
|
||||||
|
|
||||||
|
Spiral2d::new()
|
||||||
|
.take((SEARCH_RADIUS * 2 + 1).pow(2) as usize)
|
||||||
|
.for_each(|tile| {
|
||||||
|
if let Some(kind) = wpos_is_hazard(land, self.tile_wpos(tile)) {
|
||||||
|
for &rpos in &SQUARE_4 {
|
||||||
|
// `get_mut` doesn't increase generation bounds
|
||||||
|
self.tiles.get_mut(tile - rpos - 1).map(|tile| tile.kind = TileKind::Hazard(kind));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generate(land: &Land, rng: &mut impl Rng, origin: Vec2<i32>) -> Self {
|
pub fn generate(land: &Land, rng: &mut impl Rng, origin: Vec2<i32>) -> Self {
|
||||||
let mut site = Site {
|
let mut site = Site {
|
||||||
origin,
|
origin,
|
||||||
..Site::default()
|
..Site::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
site.demarcate_obstacles(land);
|
||||||
|
|
||||||
site.make_plaza(land, rng);
|
site.make_plaza(land, rng);
|
||||||
|
|
||||||
let build_chance = Lottery::from(vec![
|
let build_chance = Lottery::from(vec![
|
||||||
(1.0, 0),
|
(1.0, 0),
|
||||||
(48.0, 1),
|
(48.0, 1),
|
||||||
(5.0, 2),
|
(5.0, 2),
|
||||||
(1.0, 3),
|
(20.0, 3),
|
||||||
|
(1.0, 4),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mut castles = 0;
|
let mut castles = 0;
|
||||||
@ -247,6 +269,38 @@ impl Site {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// Field
|
||||||
|
3 => {
|
||||||
|
attempt(10, || {
|
||||||
|
let search_pos = attempt(16, || {
|
||||||
|
let tile = (Vec2::new(
|
||||||
|
rng.gen_range(-1.0..1.0),
|
||||||
|
rng.gen_range(-1.0..1.0),
|
||||||
|
).normalized() * rng.gen_range(32.0..48.0)).map(|e| e as i32);
|
||||||
|
|
||||||
|
if site
|
||||||
|
.plazas
|
||||||
|
.iter()
|
||||||
|
.all(|&p| site.plot(p).root_tile.distance_squared(tile) > 20i32.pow(2))
|
||||||
|
&& rng.gen_range(0..48) > tile.map(|e| e.abs()).reduce_max()
|
||||||
|
{
|
||||||
|
Some(tile)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or_else(Vec2::zero);
|
||||||
|
site.tiles.find_near(
|
||||||
|
search_pos,
|
||||||
|
|center, _| site.tiles.grow_aabr(center, 9..25, Extent2::new(3, 3)).ok())
|
||||||
|
})
|
||||||
|
.map(|(aabr, _)| {
|
||||||
|
site.blit_aabr(aabr, Tile {
|
||||||
|
kind: TileKind::Field,
|
||||||
|
plot: None,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
// Castle
|
// Castle
|
||||||
_ if castles < 1 => {
|
_ if castles < 1 => {
|
||||||
if let Some((aabr, _)) = attempt(10, || site.find_roadside_aabr(rng, 16 * 16..18 * 18, Extent2::new(16, 16))) {
|
if let Some((aabr, _)) = attempt(10, || site.find_roadside_aabr(rng, 16 * 16..18 * 18, Extent2::new(16, 16))) {
|
||||||
@ -295,21 +349,60 @@ impl Site {
|
|||||||
site
|
site
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn wpos_tile_pos(&self, wpos2d: Vec2<i32>) -> Vec2<i32> {
|
||||||
|
(wpos2d - self.origin).map(|e| e.div_euclid(TILE_SIZE as i32))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn wpos_tile(&self, wpos2d: Vec2<i32>) -> &Tile {
|
pub fn wpos_tile(&self, wpos2d: Vec2<i32>) -> &Tile {
|
||||||
self.tiles.get((wpos2d - self.origin).map(|e| e.div_euclid(TILE_SIZE as i32)))
|
self.tiles.get(self.wpos_tile_pos(wpos2d))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tile_wpos(&self, tile: Vec2<i32>) -> Vec2<i32> {
|
||||||
|
self.origin + tile * tile::TILE_SIZE as i32
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tile_center_wpos(&self, tile: Vec2<i32>) -> Vec2<i32> {
|
pub fn tile_center_wpos(&self, tile: Vec2<i32>) -> Vec2<i32> {
|
||||||
self.origin + tile * tile::TILE_SIZE as i32 + tile::TILE_SIZE as i32 / 2
|
self.origin + tile * tile::TILE_SIZE as i32 + tile::TILE_SIZE as i32 / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(&self, canvas: &mut Canvas, dynamic_rng: &mut impl Rng) {
|
pub fn render_tile(&self, canvas: &mut Canvas, dynamic_rng: &mut impl Rng, tpos: Vec2<i32>) {
|
||||||
canvas.foreach_col(|canvas, wpos2d, col| {
|
let tile = self.tiles.get(tpos);
|
||||||
let tile = self.wpos_tile(wpos2d);
|
let twpos = self.tile_wpos(tpos);
|
||||||
let seed = tile.plot.map_or(0, |p| self.plot(p).seed);
|
let cols = (-(TILE_SIZE as i32)..TILE_SIZE as i32 * 2).map(|y| (-(TILE_SIZE as i32)..TILE_SIZE as i32 * 2).map(move |x| (twpos + Vec2::new(x, y), Vec2::new(x, y)))).flatten();
|
||||||
match tile.kind {
|
|
||||||
TileKind::Field | TileKind::Road => (-4..5).for_each(|z| canvas.map(
|
match &tile.kind {
|
||||||
Vec3::new(wpos2d.x, wpos2d.y, col.alt as i32 + z),
|
TileKind::Empty | TileKind::Hazard(_) => {},
|
||||||
|
TileKind::Road => cols.for_each(|(wpos2d, offs)| {
|
||||||
|
let tpos = self.tile_wpos(wpos2d);
|
||||||
|
|
||||||
|
let is_x = [
|
||||||
|
self.tiles.get(tpos - Vec2::unit_x()) == tile,
|
||||||
|
self.tiles.get(tpos) == tile,
|
||||||
|
self.tiles.get(tpos + Vec2::unit_x()) == tile,
|
||||||
|
];
|
||||||
|
|
||||||
|
let dist_x = [
|
||||||
|
if is_x[0] ^ is_x[1] { Some((offs.x % tile::TILE_SIZE as i32) * if is_x[1] { -1 } else { 1 }) } else { None },
|
||||||
|
if is_x[1] ^ is_x[2] { Some((tile::TILE_SIZE as i32 - offs.x % tile::TILE_SIZE as i32) * if is_x[1] { -1 } else { 1 }) } else { None },
|
||||||
|
].iter().filter_map(|x| *x).min();
|
||||||
|
|
||||||
|
let is_y = [
|
||||||
|
self.tiles.get(tpos - Vec2::unit_y()) == tile,
|
||||||
|
self.tiles.get(tpos) == tile,
|
||||||
|
self.tiles.get(tpos + Vec2::unit_y()) == tile,
|
||||||
|
];
|
||||||
|
|
||||||
|
let dist_y = [
|
||||||
|
if is_y[0] ^ is_y[1] { Some((offs.y % tile::TILE_SIZE as i32) * if is_y[1] { -1 } else { 1 }) } else { None },
|
||||||
|
if is_y[1] ^ is_y[2] { Some((tile::TILE_SIZE as i32 - offs.y % tile::TILE_SIZE as i32) * if is_y[1] { -1 } else { 1 }) } else { None },
|
||||||
|
].iter().filter_map(|x| *x).min();
|
||||||
|
|
||||||
|
let dist = dist_x.unwrap_or(-(tile::TILE_SIZE as i32)).min(dist_y.unwrap_or(-(tile::TILE_SIZE as i32)));
|
||||||
|
|
||||||
|
if dist > 4 {
|
||||||
|
let alt = canvas.col(wpos2d).map_or(0, |c| c.alt as i32);
|
||||||
|
(-4..5).for_each(|z| canvas.map(
|
||||||
|
Vec3::new(wpos2d.x, wpos2d.y, alt + z),
|
||||||
|b| if [
|
|b| if [
|
||||||
BlockKind::Grass,
|
BlockKind::Grass,
|
||||||
BlockKind::Earth,
|
BlockKind::Earth,
|
||||||
@ -318,41 +411,91 @@ impl Site {
|
|||||||
BlockKind::Rock,
|
BlockKind::Rock,
|
||||||
]
|
]
|
||||||
.contains(&b.kind()) {
|
.contains(&b.kind()) {
|
||||||
match tile.kind {
|
Block::new(BlockKind::Rock, Rgb::new(55, 45, 65))
|
||||||
TileKind::Field => Block::new(BlockKind::Earth, Rgb::new(40, 5 + (seed % 32) as u8, 0)),
|
|
||||||
TileKind::Road => Block::new(BlockKind::Rock, Rgb::new(55, 45, 65)),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
b.with_sprite(SpriteKind::Empty)
|
b.with_sprite(SpriteKind::Empty)
|
||||||
},
|
},
|
||||||
)),
|
));
|
||||||
TileKind::Building { levels } => {
|
|
||||||
let base_alt = tile.plot.map(|p| self.plot(p)).map_or(col.alt as i32, |p| p.base_alt);
|
|
||||||
for z in base_alt - 12..base_alt + 4 + 6 * levels as i32 {
|
|
||||||
canvas.set(
|
|
||||||
Vec3::new(wpos2d.x, wpos2d.y, z),
|
|
||||||
Block::new(BlockKind::Wood, Rgb::new(180, 90 + (seed % 64) as u8, 120))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
}),
|
||||||
TileKind::Castle | TileKind::Wall => {
|
|
||||||
let base_alt = tile.plot.map(|p| self.plot(p)).map_or(col.alt as i32, |p| p.base_alt);
|
|
||||||
for z in base_alt - 12..base_alt + if tile.kind == TileKind::Wall { 24 } else { 40 } {
|
|
||||||
canvas.set(
|
|
||||||
Vec3::new(wpos2d.x, wpos2d.y, z),
|
|
||||||
Block::new(BlockKind::Wood, Rgb::new(40, 40, 55))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
pub fn render(&self, canvas: &mut Canvas, dynamic_rng: &mut impl Rng) {
|
||||||
|
let tile_aabr = Aabr {
|
||||||
|
min: self.wpos_tile_pos(canvas.wpos()) - 1,
|
||||||
|
max: self.wpos_tile_pos(canvas.wpos() + TerrainChunkSize::RECT_SIZE.map(|e| e as i32) + 2) + 3, // Round up, uninclusive, border
|
||||||
|
};
|
||||||
|
|
||||||
|
for y in tile_aabr.min.y..tile_aabr.max.y {
|
||||||
|
for x in tile_aabr.min.x..tile_aabr.max.x {
|
||||||
|
self.render_tile(canvas, dynamic_rng, Vec2::new(x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// canvas.foreach_col(|canvas, wpos2d, col| {
|
||||||
|
// let tile = self.wpos_tile(wpos2d);
|
||||||
|
// let seed = tile.plot.map_or(0, |p| self.plot(p).seed);
|
||||||
|
// match tile.kind {
|
||||||
|
// TileKind::Field | TileKind::Road => (-4..5).for_each(|z| canvas.map(
|
||||||
|
// Vec3::new(wpos2d.x, wpos2d.y, col.alt as i32 + z),
|
||||||
|
// |b| if [
|
||||||
|
// BlockKind::Grass,
|
||||||
|
// BlockKind::Earth,
|
||||||
|
// BlockKind::Sand,
|
||||||
|
// BlockKind::Snow,
|
||||||
|
// BlockKind::Rock,
|
||||||
|
// ]
|
||||||
|
// .contains(&b.kind()) {
|
||||||
|
// match tile.kind {
|
||||||
|
// TileKind::Field => Block::new(BlockKind::Earth, Rgb::new(40, 5 + (seed % 32) as u8, 0)),
|
||||||
|
// TileKind::Road => Block::new(BlockKind::Rock, Rgb::new(55, 45, 65)),
|
||||||
|
// _ => unreachable!(),
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// b.with_sprite(SpriteKind::Empty)
|
||||||
|
// },
|
||||||
|
// )),
|
||||||
|
// TileKind::Building { levels } => {
|
||||||
|
// let base_alt = tile.plot.map(|p| self.plot(p)).map_or(col.alt as i32, |p| p.base_alt);
|
||||||
|
// for z in base_alt - 12..base_alt + 4 + 6 * levels as i32 {
|
||||||
|
// canvas.set(
|
||||||
|
// Vec3::new(wpos2d.x, wpos2d.y, z),
|
||||||
|
// Block::new(BlockKind::Wood, Rgb::new(180, 90 + (seed % 64) as u8, 120))
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// TileKind::Castle | TileKind::Wall => {
|
||||||
|
// let base_alt = tile.plot.map(|p| self.plot(p)).map_or(col.alt as i32, |p| p.base_alt);
|
||||||
|
// for z in base_alt - 12..base_alt + if tile.kind == TileKind::Wall { 24 } else { 40 } {
|
||||||
|
// canvas.set(
|
||||||
|
// Vec3::new(wpos2d.x, wpos2d.y, z),
|
||||||
|
// Block::new(BlockKind::Wood, Rgb::new(40, 40, 55))
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// _ => {},
|
||||||
|
// }
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_site() -> Site { Site::generate(&Land::empty(), &mut thread_rng(), Vec2::zero()) }
|
pub fn test_site() -> Site { Site::generate(&Land::empty(), &mut thread_rng(), Vec2::zero()) }
|
||||||
|
|
||||||
|
fn wpos_is_hazard(land: &Land, wpos: Vec2<i32>) -> Option<HazardKind> {
|
||||||
|
if land
|
||||||
|
.get_chunk_at(wpos)
|
||||||
|
.map_or(true, |c| c.river.near_water())
|
||||||
|
{
|
||||||
|
Some(HazardKind::Water)
|
||||||
|
} else if let Some(gradient) = Some(land.get_gradient_approx(wpos)).filter(|g| *g > 0.8) {
|
||||||
|
Some(HazardKind::Hill { gradient })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn aabr_tiles(aabr: Aabr<i32>) -> impl Iterator<Item=Vec2<i32>> {
|
pub fn aabr_tiles(aabr: Aabr<i32>) -> impl Iterator<Item=Vec2<i32>> {
|
||||||
(0..aabr.size().h)
|
(0..aabr.size().h)
|
||||||
.map(move |y| (0..aabr.size().w)
|
.map(move |y| (0..aabr.size().w)
|
||||||
|
@ -9,12 +9,14 @@ pub const TILE_RADIUS: u32 = ZONE_SIZE * ZONE_RADIUS;
|
|||||||
pub const MAX_BLOCK_RADIUS: u32 = TILE_SIZE * TILE_RADIUS;
|
pub const MAX_BLOCK_RADIUS: u32 = TILE_SIZE * TILE_RADIUS;
|
||||||
|
|
||||||
pub struct TileGrid {
|
pub struct TileGrid {
|
||||||
|
pub(crate) bounds: Aabr<i32>, // Inclusive
|
||||||
zones: Grid<Option<Grid<Option<Tile>>>>,
|
zones: Grid<Option<Grid<Option<Tile>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TileGrid {
|
impl Default for TileGrid {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
bounds: Aabr::new_empty(Vec2::zero()),
|
||||||
zones: Grid::populate_from(Vec2::broadcast(ZONE_RADIUS as i32 * 2 + 1), |_| None),
|
zones: Grid::populate_from(Vec2::broadcast(ZONE_RADIUS as i32 * 2 + 1), |_| None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -35,6 +37,7 @@ impl TileGrid {
|
|||||||
.unwrap_or(&EMPTY)
|
.unwrap_or(&EMPTY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WILL NOT EXPAND BOUNDS!
|
||||||
pub fn get_mut(&mut self, tpos: Vec2<i32>) -> Option<&mut Tile> {
|
pub fn get_mut(&mut self, tpos: Vec2<i32>) -> Option<&mut Tile> {
|
||||||
let tpos = tpos + TILE_RADIUS as i32;
|
let tpos = tpos + TILE_RADIUS as i32;
|
||||||
self.zones.get_mut(tpos.map(|e| e.div_euclid(ZONE_SIZE as i32))).and_then(|zone| {
|
self.zones.get_mut(tpos.map(|e| e.div_euclid(ZONE_SIZE as i32))).and_then(|zone| {
|
||||||
@ -47,6 +50,7 @@ impl TileGrid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, tpos: Vec2<i32>, tile: Tile) -> Option<Tile> {
|
pub fn set(&mut self, tpos: Vec2<i32>, tile: Tile) -> Option<Tile> {
|
||||||
|
self.bounds.expand_to_contain_point(tpos);
|
||||||
self.get_mut(tpos).map(|t| std::mem::replace(t, tile))
|
self.get_mut(tpos).map(|t| std::mem::replace(t, tile))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +114,7 @@ impl TileGrid {
|
|||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum TileKind {
|
pub enum TileKind {
|
||||||
Empty,
|
Empty,
|
||||||
|
Hazard(HazardKind),
|
||||||
Field,
|
Field,
|
||||||
Road,
|
Road,
|
||||||
Building { levels: u32 },
|
Building { levels: u32 },
|
||||||
@ -117,7 +122,7 @@ pub enum TileKind {
|
|||||||
Wall,
|
Wall,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct Tile {
|
pub struct Tile {
|
||||||
pub(crate) kind: TileKind,
|
pub(crate) kind: TileKind,
|
||||||
pub(crate) plot: Option<Id<Plot>>,
|
pub(crate) plot: Option<Id<Plot>>,
|
||||||
@ -144,9 +149,16 @@ impl Tile {
|
|||||||
pub fn is_obstacle(&self) -> bool {
|
pub fn is_obstacle(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self.kind,
|
self.kind,
|
||||||
TileKind::Building { .. }
|
TileKind::Hazard(_)
|
||||||
|
| TileKind::Building { .. }
|
||||||
| TileKind::Castle
|
| TileKind::Castle
|
||||||
| TileKind::Wall
|
| TileKind::Wall
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
pub enum HazardKind {
|
||||||
|
Water,
|
||||||
|
Hill { gradient: f32 },
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user