Tune tree density/spacing and fix trail distance to use segments
- nearest_trail_distance2 now measures point-to-segment distance to each trail edge instead of only to stored points, with a single-point fallback. - Tree height scaling keeps canopy proportions; maturity adds subtle variation instead of shrinking young trees to bare poles. - Raise forest spawn probability and tighten spacing for denser, more coherent stands; redwoods cluster a bit closer. - Cabins near trails favor a wooded setback off the centerline; the spur still connects. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
@@ -2000,7 +2000,9 @@ static void generate_tree(worldgen_ctx *ctx, const tree_archetype *arch, int x,
|
|||||||
double maturity, rng_state *rng, block_list *out) {
|
double maturity, rng_state *rng, block_list *out) {
|
||||||
if (!arch) return;
|
if (!arch) return;
|
||||||
int height = rng_range_inclusive(rng, arch->min_height, arch->max_height);
|
int height = rng_range_inclusive(rng, arch->min_height, arch->max_height);
|
||||||
double height_scale = 0.62 + clamp01(maturity) * 0.38;
|
/* Preserve the proportions expected by each canopy builder; maturity now
|
||||||
|
* adds subtle height variation without reducing young trees to bare poles. */
|
||||||
|
double height_scale = 0.86 + clamp01(maturity) * 0.14;
|
||||||
height = (int)llround((double)height * height_scale);
|
height = (int)llround((double)height * height_scale);
|
||||||
if (height < 4) height = 4;
|
if (height < 4) height = 4;
|
||||||
if (!can_place_tree(ctx, x, y, z, height, arch->space_radius, arch->canopy_extra)) {
|
if (!can_place_tree(ctx, x, y, z, height, arch->space_radius, arch->canopy_extra)) {
|
||||||
@@ -2972,10 +2974,10 @@ static void generate_chunk_cabins(worldgen_ctx *ctx, int chunk_x, int chunk_z, c
|
|||||||
double dist2 = nearest_trail_distance2(ctx, world_cx, world_cz, 1.0e12);
|
double dist2 = nearest_trail_distance2(ctx, world_cx, world_cz, 1.0e12);
|
||||||
double bonus = 0.0;
|
double bonus = 0.0;
|
||||||
double dist = sqrt(dist2);
|
double dist = sqrt(dist2);
|
||||||
if (dist < 640.0) {
|
/* Favor a wooded setback instead of putting the building footprint
|
||||||
double t = clamp01(1.0 - dist / 640.0);
|
* directly on the centerline. The spur still handles the connection. */
|
||||||
bonus += 0.45 * t;
|
if (dist < 8.0) bonus -= (8.0 - dist) * 0.9;
|
||||||
}
|
else if (dist < 96.0) bonus += 0.45 * clamp01(1.0 - fabs(dist - 20.0) / 76.0);
|
||||||
score += bonus;
|
score += bonus;
|
||||||
}
|
}
|
||||||
if (score > best_score) {
|
if (score > best_score) {
|
||||||
@@ -3304,14 +3306,14 @@ static void generate_chunk_trees(worldgen_ctx *ctx, int chunk_x, int chunk_z, ch
|
|||||||
}
|
}
|
||||||
/* Openings retain a few isolated field trees, while forest interiors
|
/* Openings retain a few isolated field trees, while forest interiors
|
||||||
* become substantially denser than their regenerating edges. */
|
* become substantially denser than their regenerating edges. */
|
||||||
spawn_prob = (0.035 + density * 0.78) * altitude_factor;
|
spawn_prob = (0.08 + density * 0.9) * altitude_factor;
|
||||||
if (is_old_growth) {
|
if (is_old_growth) {
|
||||||
spawn_prob = clamp01(0.25 + grove_mask * 0.7) * altitude_factor;
|
spawn_prob = clamp01(0.25 + grove_mask * 0.7) * altitude_factor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rng_next_f64(&rng) > spawn_prob) continue;
|
if (rng_next_f64(&rng) > spawn_prob) continue;
|
||||||
double spacing = is_redwood ? (10.0 + (1.0 - stand_density) * 4.0)
|
double spacing = is_redwood ? (8.0 + (1.0 - stand_density) * 3.0)
|
||||||
: (4.5 + (1.0 - cover) * 4.5 + maturity * 1.5);
|
: (3.5 + (1.0 - cover) * 2.5 + maturity * 0.75);
|
||||||
if (!tree_wins_spacing(ctx, gx, gz, grid, candidate_x, candidate_z, spacing)) continue;
|
if (!tree_wins_spacing(ctx, gx, gz, grid, candidate_x, candidate_z, spacing)) continue;
|
||||||
|
|
||||||
block_list tmp;
|
block_list tmp;
|
||||||
@@ -3582,11 +3584,15 @@ static double nearest_trail_distance2(worldgen_ctx *ctx, int x, int z, double fa
|
|||||||
for (size_t i = 0; i < ctx->trail_segment_count; ++i) {
|
for (size_t i = 0; i < ctx->trail_segment_count; ++i) {
|
||||||
trail_segment *seg = &ctx->trail_segments[i];
|
trail_segment *seg = &ctx->trail_segments[i];
|
||||||
if (!seg || seg->count < 1 || !seg->points) continue;
|
if (!seg || seg->count < 1 || !seg->points) continue;
|
||||||
for (int p = 0; p < seg->count; ++p) {
|
for (int p = 0; p < seg->count - 1; ++p) {
|
||||||
int tx = seg->points[p * 2];
|
double d2 = point_segment_distance2((double)x, (double)z,
|
||||||
int tz = seg->points[p * 2 + 1];
|
(double)seg->points[p * 2], (double)seg->points[p * 2 + 1],
|
||||||
double dx = (double)(tx - x);
|
(double)seg->points[(p + 1) * 2], (double)seg->points[(p + 1) * 2 + 1]);
|
||||||
double dz = (double)(tz - z);
|
if (d2 < best) best = d2;
|
||||||
|
}
|
||||||
|
if (seg->count == 1) {
|
||||||
|
double dx = (double)(seg->points[0] - x);
|
||||||
|
double dz = (double)(seg->points[1] - z);
|
||||||
double d2 = dx * dx + dz * dz;
|
double d2 = dx * dx + dz * dz;
|
||||||
if (d2 < best) best = d2;
|
if (d2 < best) best = d2;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user