diff --git a/assets/world/style/colors.ron b/assets/world/style/colors.ron index 1db85c0f91..ecbc2e017c 100644 --- a/assets/world/style/colors.ron +++ b/assets/world/style/colors.ron @@ -18,7 +18,7 @@ GreenSludge: None, // Leaves all actually get interpolated. TemperateLeaves: [ - (start: (0, 100, 50), end: (105, 175, 0)), + (start: (20, 100, 40), end: (60, 120, 0)), //(start: (178, 216, 0), end: (255, 185, 63)), //(start: (142, 164, 0), end: (142, 164, 0)), //(start: (168, 81, 0), end: (54, 150, 31)), @@ -26,9 +26,11 @@ PineLeaves: [(start: (0, 60, 50), end: (30, 80, 10))], PalmLeavesInner: [(start: (70, 140, 43), end: (55, 140, 32))], PalmLeavesOuter: [(start: (60, 130, 38), end: (30, 130, 65))], - Acacia: [(start: (30, 100, 0), end: (90, 110, 20))], + Acacia: [(start: (35, 70, 0), end: (100, 120, 30))], Liana: [(start: (0, 125, 107), end: (0, 155, 129))], - Mangrove: [(start: (15, 80, 10), end: (20, 120, 47))], + Mangrove: [(start: (20, 60, 0), end: (40, 90, 30))], + Chestnut: [(start: (30, 80, 0), end: (50, 120, 0))], + Baobab: [(start: (50, 100, 40), end: (50, 90, 0))], ) // Water blocks ignore color now so this isn't used, but just in case this color was worth diff --git a/common/src/terrain/structure.rs b/common/src/terrain/structure.rs index f017b582ff..d0dfefbfdb 100644 --- a/common/src/terrain/structure.rs +++ b/common/src/terrain/structure.rs @@ -34,6 +34,8 @@ make_case_elim!( Log = 16, Filled(kind: BlockKind, color: Rgb) = 17, Sprite(kind: SpriteKind) = 18, + Chestnut = 19, + Baobab = 20, } ); diff --git a/world/src/all.rs b/world/src/all.rs index 030952d731..561409898f 100644 --- a/world/src/all.rs +++ b/world/src/all.rs @@ -9,6 +9,8 @@ pub enum ForestKind { Acacia, Baobab, Oak, + Chestnut, + Cedar, Pine, Birch, Mangrove, @@ -29,6 +31,8 @@ impl ForestKind { ForestKind::Acacia => 0.05..0.55, ForestKind::Baobab => 0.2..0.6, ForestKind::Oak => 0.35..1.5, + ForestKind::Chestnut => 0.35..1.5, + ForestKind::Cedar => 0.275..1.45, ForestKind::Pine => 0.2..1.4, ForestKind::Birch => 0.0..0.6, ForestKind::Mangrove => 0.65..1.3, @@ -42,7 +46,9 @@ impl ForestKind { ForestKind::Palm => 0.4..1.6, ForestKind::Acacia => 0.3..1.6, ForestKind::Baobab => 0.4..0.9, - ForestKind::Oak => -0.35..0.6, + ForestKind::Oak => -0.35..0.45, + ForestKind::Chestnut => -0.35..0.45, + ForestKind::Cedar => -1.0..0.1, ForestKind::Pine => -1.8..-0.2, ForestKind::Birch => -0.7..0.25, ForestKind::Mangrove => 0.4..1.6, @@ -66,9 +72,11 @@ impl ForestKind { ForestKind::Acacia => 0.6, ForestKind::Baobab => 0.2, ForestKind::Oak => 1.0, + ForestKind::Chestnut => 0.3, + ForestKind::Cedar => 0.3, ForestKind::Pine => 1.0, ForestKind::Birch => 0.65, - ForestKind::Mangrove => 1.0, + ForestKind::Mangrove => 2.0, ForestKind::Swamp => 1.0, _ => 0.0, } diff --git a/world/src/block/mod.rs b/world/src/block/mod.rs index 1c702e9e42..0f243192ac 100644 --- a/world/src/block/mod.rs +++ b/world/src/block/mod.rs @@ -289,7 +289,9 @@ pub fn block_from_structure( | StructureBlock::PalmLeavesInner | StructureBlock::PalmLeavesOuter | StructureBlock::Acacia - | StructureBlock::Mangrove => { + | StructureBlock::Mangrove + | StructureBlock::Chestnut + | StructureBlock::Baobab => { let ranges = sblock .elim_case_pure(&index.colors.block.structure_blocks) .as_ref() diff --git a/world/src/layer/tree.rs b/world/src/layer/tree.rs index 1bdb28cee2..8a7c563c2b 100644 --- a/world/src/layer/tree.rs +++ b/world/src/layer/tree.rs @@ -95,8 +95,26 @@ pub fn apply_trees_to(canvas: &mut Canvas, dynamic_rng: &mut impl Rng) { *FRUIT_TREES }, ForestKind::Palm => *PALMS, - ForestKind::Acacia => *ACACIAS, - ForestKind::Baobab => *BAOBABS, + ForestKind::Acacia => { + break 'model TreeModel::Procedural( + ProceduralTree::generate( + TreeConfig::acacia(&mut RandomPerm::new(seed), scale), + &mut RandomPerm::new(seed), + ), + StructureBlock::Acacia, + ); + }, + // ForestKind::Acacia => *ACACIAS, + ForestKind::Baobab => { + break 'model TreeModel::Procedural( + ProceduralTree::generate( + TreeConfig::baobab(&mut RandomPerm::new(seed), scale), + &mut RandomPerm::new(seed), + ), + StructureBlock::Baobab, + ); + }, + // ForestKind::Baobab => *BAOBABS, // ForestKind::Oak => *OAKS, ForestKind::Oak => { break 'model TreeModel::Procedural( @@ -107,6 +125,15 @@ pub fn apply_trees_to(canvas: &mut Canvas, dynamic_rng: &mut impl Rng) { StructureBlock::TemperateLeaves, ); }, + ForestKind::Chestnut => { + break 'model TreeModel::Procedural( + ProceduralTree::generate( + TreeConfig::chestnut(&mut RandomPerm::new(seed), scale), + &mut RandomPerm::new(seed), + ), + StructureBlock::Chestnut, + ); + }, //ForestKind::Pine => *PINES, ForestKind::Pine => { break 'model TreeModel::Procedural( @@ -117,8 +144,26 @@ pub fn apply_trees_to(canvas: &mut Canvas, dynamic_rng: &mut impl Rng) { StructureBlock::PineLeaves, ); }, + ForestKind::Cedar => { + break 'model TreeModel::Procedural( + ProceduralTree::generate( + TreeConfig::cedar(&mut RandomPerm::new(seed), scale), + &mut RandomPerm::new(seed), + ), + StructureBlock::PineLeaves, + ); + }, ForestKind::Birch => *BIRCHES, - ForestKind::Mangrove => *MANGROVE_TREES, + // ForestKind::Mangrove => *MANGROVE_TREES, + ForestKind::Mangrove => { + break 'model TreeModel::Procedural( + ProceduralTree::generate( + TreeConfig::jungle(&mut RandomPerm::new(seed), scale), + &mut RandomPerm::new(seed), + ), + StructureBlock::Mangrove, + ); + }, ForestKind::Swamp => *SWAMP_TREES, ForestKind::Giant => { break 'model TreeModel::Procedural( @@ -164,6 +209,11 @@ pub fn apply_trees_to(canvas: &mut Canvas, dynamic_rng: &mut impl Rng) { continue; } + let hanging_sprites = match &tree.model { + TreeModel::Structure(_) => &[(0.0004, SpriteKind::Beehive)], + TreeModel::Procedural(t, _) => t.config.hanging_sprites, + }; + let mut is_top = true; let mut is_leaf_top = true; let mut last_block = Block::empty(); @@ -228,8 +278,13 @@ pub fn apply_trees_to(canvas: &mut Canvas, dynamic_rng: &mut impl Rng) { last_block = block; }) .unwrap_or_else(|| { - if last_block.kind() == BlockKind::Wood && dynamic_rng.gen_range(0..2048) == 0 { - canvas.set(wpos, Block::air(SpriteKind::Beehive)); + // Hanging sprites + if last_block.is_filled() { + for (chance, sprite) in hanging_sprites { + if dynamic_rng.gen_bool(*chance as f64) { + canvas.map(wpos, |block| block.with_sprite(*sprite)); + } + } } is_leaf_top = true; @@ -282,11 +337,12 @@ pub struct TreeConfig { pub proportionality: f32, /// Whether the tree is inhabited (adds various features and effects) pub inhabited: bool, + pub hanging_sprites: &'static [(f32, SpriteKind)], } impl TreeConfig { pub fn oak(rng: &mut impl Rng, scale: f32) -> Self { - let scale = scale * (0.8 + rng.gen::().powi(4) * 0.75); + let scale = scale * (0.8 + rng.gen::().powi(2) * 0.5); let log_scale = 1.0 + scale.log2().max(0.0); Self { @@ -305,6 +361,127 @@ impl TreeConfig { leaf_vertical_scale: 1.0, proportionality: 0.0, inhabited: false, + hanging_sprites: &[(0.0005, SpriteKind::Beehive)], + } + } + + pub fn jungle(rng: &mut impl Rng, scale: f32) -> Self { + let scale = scale * (0.9 + rng.gen::().powi(4) * 1.0); + let log_scale = 1.0 + scale.log2().max(0.0); + + Self { + trunk_len: 44.0 * scale, + trunk_radius: 2.25 * scale, + branch_child_len: 0.35, + branch_child_radius: 0.5, + branch_child_radius_lerp: true, + leaf_radius: 4.0 * log_scale..4.5 * log_scale, + leaf_radius_scaled: 0.0, + straightness: 0.2, + max_depth: 2, + splits: 7.5..8.5, + split_range: 0.3..1.25, + branch_len_bias: 0.5, + leaf_vertical_scale: 0.4, + proportionality: 0.8, + inhabited: false, + hanging_sprites: &[(0.00015, SpriteKind::Beehive), (0.015, SpriteKind::Liana)], + } + } + + pub fn baobab(rng: &mut impl Rng, scale: f32) -> Self { + let scale = scale * (0.5 + rng.gen::().powi(4) * 1.0); + let log_scale = 1.0 + scale.log2().max(0.0); + + Self { + trunk_len: 24.0 * scale, + trunk_radius: 7.0 * scale, + branch_child_len: 0.55, + branch_child_radius: 0.3, + branch_child_radius_lerp: true, + leaf_radius: 2.5 * log_scale..3.0 * log_scale, + leaf_radius_scaled: 0.0, + straightness: 0.5, + max_depth: 4, + splits: 3.0..3.5, + split_range: 0.95..1.0, + branch_len_bias: 0.0, + leaf_vertical_scale: 0.2, + proportionality: 1.0, + inhabited: false, + hanging_sprites: &[(0.0005, SpriteKind::Beehive)], + } + } + + pub fn cedar(rng: &mut impl Rng, scale: f32) -> Self { + let scale = scale * (0.8 + rng.gen::().powi(2) * 0.5); + let log_scale = 1.0 + scale.log2().max(0.0); + + Self { + trunk_len: 9.0 * scale, + trunk_radius: 2.0 * scale, + branch_child_len: 0.9, + branch_child_radius: 0.75, + branch_child_radius_lerp: true, + leaf_radius: 4.0 * log_scale..5.0 * log_scale, + leaf_radius_scaled: 0.0, + straightness: 0.55, + max_depth: 4, + splits: 1.75..2.0, + split_range: 0.75..1.5, + branch_len_bias: 0.0, + leaf_vertical_scale: 0.2, + proportionality: 0.0, + inhabited: false, + hanging_sprites: &[(0.0005, SpriteKind::Beehive)], + } + } + + pub fn acacia(rng: &mut impl Rng, scale: f32) -> Self { + let scale = scale * (0.9 + rng.gen::().powi(4) * 0.3); + let log_scale = 1.0 + scale.log2().max(0.0); + + Self { + trunk_len: 12.0 * scale, + trunk_radius: 1.5 * scale, + branch_child_len: 0.75, + branch_child_radius: 0.75, + branch_child_radius_lerp: true, + leaf_radius: 6.0 * log_scale..7.0 * log_scale, + leaf_radius_scaled: 0.0, + straightness: 0.3, + max_depth: 5, + splits: 1.75..2.25, + split_range: 1.0..1.25, + branch_len_bias: 0.0, + leaf_vertical_scale: 0.15, + proportionality: 1.0, + inhabited: false, + hanging_sprites: &[(0.0005, SpriteKind::Beehive)], + } + } + + pub fn chestnut(rng: &mut impl Rng, scale: f32) -> Self { + let scale = scale * (0.85 + rng.gen::().powi(4) * 0.3); + let log_scale = 1.0 + scale.log2().max(0.0); + + Self { + trunk_len: 13.0 * scale, + trunk_radius: 1.5 * scale, + branch_child_len: 0.75, + branch_child_radius: 0.75, + branch_child_radius_lerp: true, + leaf_radius: 2.5 * log_scale..2.6 * log_scale, + leaf_radius_scaled: 0.0, + straightness: 0.4, + max_depth: 5, + splits: 3.0..3.5, + split_range: 0.5..1.25, + branch_len_bias: 0.0, + leaf_vertical_scale: 0.35, + proportionality: 0.5, + inhabited: false, + hanging_sprites: &[(0.0005, SpriteKind::Beehive)], } } @@ -328,6 +505,7 @@ impl TreeConfig { leaf_vertical_scale: 0.3, proportionality: 1.0, inhabited: false, + hanging_sprites: &[(0.0005, SpriteKind::Beehive)], } } @@ -350,6 +528,7 @@ impl TreeConfig { leaf_vertical_scale: 0.6, proportionality: 0.0, inhabited, + hanging_sprites: &[(0.0005, SpriteKind::Beehive)], } } } @@ -466,7 +645,7 @@ impl ProceduralTree { // Now, interpolate between the target direction and the parent branch's // direction to find a direction let branch_dir = - Lerp::lerp(tgt - branch_start, dir, config.straightness).normalized(); + Lerp::lerp_unclamped(tgt - branch_start, dir, config.straightness).normalized(); let (branch_idx, branch_aabb) = self.add_branch( config,