From 7a72df7e27bdae39146845a81d6e32a84041f378 Mon Sep 17 00:00:00 2001 From: James Melkonian Date: Thu, 29 Jul 2021 18:20:53 -0700 Subject: [PATCH] Gable primitive and dungeon lava rooms --- common/src/terrain/block.rs | 8 ++++ world/src/site2/gen.rs | 28 ++++++++++++ world/src/site2/plot/dungeon.rs | 77 ++++++++++++++++++++++++++++++--- 3 files changed, 108 insertions(+), 5 deletions(-) diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index 71b0c861c4..d6420ec348 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -125,6 +125,14 @@ impl Block { } } + #[inline] + pub const fn lava(sprite: SpriteKind) -> Self { + Self { + kind: BlockKind::Lava, + attr: [sprite as u8, 0, 0], + } + } + #[inline] pub const fn empty() -> Self { Self::air(SpriteKind::Empty) } diff --git a/world/src/site2/gen.rs b/world/src/site2/gen.rs index 7db069d0de..1717dadb99 100644 --- a/world/src/site2/gen.rs +++ b/world/src/site2/gen.rs @@ -24,6 +24,12 @@ pub enum Primitive { aabb: Aabb, inset: i32, }, + Gable { + aabb: Aabb, + inset: i32, + // X axis parallel or Y axis parallel + dir: bool, + }, Cylinder(Aabb), Cone(Aabb), Sphere(Aabb), @@ -83,6 +89,27 @@ impl Fill { < 1.0 - ((pos.z - aabb.min.z) as f32 + 0.5) / (aabb.max.z - aabb.min.z) as f32 }, + Primitive::Gable { aabb, inset, dir } => { + let inset = (*inset).max(aabb.size().reduce_min()); + let inner = if *dir { + Aabr { + min: Vec2::new(aabb.min.x - 1 + inset, aabb.min.y), + max: Vec2::new(aabb.max.x - inset, aabb.max.y), + } + } else { + Aabr { + min: Vec2::new(aabb.min.x, aabb.min.y - 1 + inset), + max: Vec2::new(aabb.max.x, aabb.max.y - inset), + } + }; + aabb_contains(*aabb, pos) && + (inner.projected_point(pos.xy()) - pos.xy()) + .map(|e| e.abs()) + .reduce_max() as f32 + / (inset as f32) + < 1.0 + - ((pos.z - aabb.min.z) as f32 + 0.5) / (aabb.max.z - aabb.min.z) as f32 + } Primitive::Cylinder(aabb) => { (aabb.min.z..aabb.max.z).contains(&pos.z) && (pos @@ -200,6 +227,7 @@ impl Fill { Primitive::Empty => return None, Primitive::Aabb(aabb) => *aabb, Primitive::Pyramid { aabb, .. } => *aabb, + Primitive::Gable { aabb, .. } => *aabb, Primitive::Cylinder(aabb) => *aabb, Primitive::Cone(aabb) => *aabb, Primitive::Sphere(aabb) => *aabb, diff --git a/world/src/site2/plot/dungeon.rs b/world/src/site2/plot/dungeon.rs index 98bd8d4202..36a2a4f421 100644 --- a/world/src/site2/plot/dungeon.rs +++ b/world/src/site2/plot/dungeon.rs @@ -192,6 +192,7 @@ enum RoomKind { Fight, Boss, Miniboss, + LavaPlatforming, } pub struct Room { @@ -201,6 +202,7 @@ pub struct Room { area: Rect, height: i32, pillars: Option, // Pillars with the given separation + pits: Option, // Pits filled with lava difficulty: u32, } @@ -393,6 +395,7 @@ impl Floor { area: Rect::from((stair_tile - tile_offset - 1, Extent2::broadcast(3))), height: STAIR_ROOM_HEIGHT, pillars: None, + pits: None, difficulty, }); if final_level { @@ -407,6 +410,7 @@ impl Floor { )), height: height as i32, pillars: Some(2), + pits: None, difficulty, }); } else { @@ -418,6 +422,7 @@ impl Floor { area: Rect::from((new_stair_tile - tile_offset - 1, Extent2::broadcast(3))), height: STAIR_ROOM_HEIGHT, pillars: None, + pits: None, difficulty, }); this.tiles.set( @@ -506,6 +511,18 @@ impl Floor { area, height: ctx.rng.gen_range(15..20), pillars: Some(ctx.rng.gen_range(2..=4)), + pits: None, + difficulty: self.difficulty, + }), + // Lava platforming room + 1 => self.create_room(Room { + seed: ctx.rng.gen(), + loot_density: 0.0, + kind: RoomKind::LavaPlatforming, + area, + height: ctx.rng.gen_range(10..15), + pillars: None, + pits: Some(1), difficulty: self.difficulty, }), // Fight room with enemies in it @@ -520,6 +537,7 @@ impl Floor { } else { None }, + pits: None, difficulty: self.difficulty, }), }; @@ -631,7 +649,7 @@ impl Floor { RoomKind::Boss => { room.fill_boss_cell(supplement, tile_wcenter, wpos2d, tile_pos) }, - RoomKind::Peaceful => {}, + RoomKind::Peaceful | RoomKind::LavaPlatforming => {}, } } } @@ -1018,8 +1036,22 @@ impl Floor { }; let floor_prim = prim(Primitive::Aabb(floor_aabb)); + // This is copied from `src/layer/mod.rs`. It should be moved into + // a util file somewhere + let noisy_color = |color: Rgb, factor: u32| { + let nz = RandomField::new(0).get(Vec3::new(floor_corner.x, floor_corner.y, floor_z)); + color.map(|e| { + (e as u32 + nz % (factor * 2)) + .saturating_sub(factor) + .min(255) as u8 + }) + }; + // Declare the various kinds of blocks that will be used as fills let vacant = Block::air(SpriteKind::Empty); + // FIXME: Lava and stone color hardcoded here, it is available in colors.ron + // but that file is not accessed from site2 yet + let lava = Block::new(BlockKind::Lava, noisy_color(Rgb::new(184, 39, 0), 8)); let stone = Block::new(BlockKind::Rock, Rgb::new(150, 150, 175)); let stone_purple = Block::new(BlockKind::GlowingRock, Rgb::new(96, 0, 128)); @@ -1227,10 +1259,45 @@ impl Floor { })); chests = Some((chest_sprite, chest_sprite_fill)); - // If a room has pillars, the current tile aligns with - // the pillar spacing, and we're not too close to a wall - // (i.e. the adjacent tiles are rooms and not hallways/solid), - // place a pillar + if room.pits.is_some() { + // Make an air pit + let tile_pit = prim(Primitive::Aabb(aabr_with_z( + tile_aabr, + floor_z - 7..floor_z, + ))); + let tile_pit = prim(Primitive::Diff(tile_pit, wall_contours)); + fill(tile_pit, Fill::Block(vacant)); + + // Fill with lava + let tile_lava = prim(Primitive::Aabb(aabr_with_z( + tile_aabr, + floor_z - 7..floor_z - 5, + ))); + let tile_lava = prim(Primitive::Diff(tile_lava, wall_contours)); + //pits.push(tile_pit); + //pits.push(tile_lava); + fill(tile_lava, Fill::Block(lava)); + } + if room + .pits + .map(|pit_space| { + tile_pos + .map(|e| e.rem_euclid(pit_space) == 0) + .reduce_and() + }) + .unwrap_or(false) { + let platform = prim(Primitive::Aabb(Aabb { + min: (tile_center - Vec2::broadcast(pillar_thickness - 1)) + .with_z(floor_z - 7), + max: (tile_center + Vec2::broadcast(pillar_thickness)) + .with_z(floor_z), + })); + fill(platform, Fill::Block(stone)); + } + + // If a room has pillars, the current tile aligns with the pillar spacing, and + // we're not too close to a wall (i.e. the adjacent tiles are rooms and not + // hallways/solid), place a pillar if room .pillars .map(|pillar_space| {