Randoloot/scripts/planets/surface_landmarks.gd
2026-10-18 08:43:54 +02:00

47 lines
2.3 KiB
GDScript

extends RefCounted
## Rare visual landmarks use a random stream independent of expedition rewards.
const SPECS := [
{"kind":"fissure", "chance":0.55, "count":3, "min_size":90.0, "max_size":155.0},
{"kind":"meteor_crater", "chance":0.14, "count":1, "min_size":160.0, "max_size":220.0},
{"kind":"abandoned_hamlet", "chance":0.06, "count":1, "min_size":155.0, "max_size":185.0},
{"kind":"weathered_stones", "chance":0.12, "count":1, "min_size":70.0, "max_size":100.0},
{"kind":"dry_hollow", "chance":0.30, "count":1, "min_size":95.0, "max_size":140.0}
]
static func generate(data: Dictionary) -> void:
var rng := RandomNumberGenerator.new()
rng.seed = int(data.seed) ^ 0x4c414e44
data.landmarks = []
for spec in SPECS:
var chance := float(spec.chance)
if spec.kind == "dry_hollow" and int(data.landscape.index) < 3:
chance *= 0.4
if rng.randf() >= chance:
continue
for index in rng.randi_range(1, int(spec.count)):
var width := rng.randf_range(float(spec.min_size), float(spec.max_size))
var position := _find_site(data, rng, width*0.55)
if position == Vector2.INF:
continue
data.landmarks.append({"kind":spec.kind, "position":position, "size":width, "rotation":rng.randf_range(-PI, PI)})
# A crater rim and ruined roofs should remain visible through the vegetation.
for landmark in data.landmarks:
data.trees = data.trees.filter(func(prop): return prop.position.distance_to(landmark.position) > float(landmark.size)*0.48+float(prop.size)*0.4)
data.rocks = data.rocks.filter(func(prop): return prop.position.distance_to(landmark.position) > float(landmark.size)*0.5+float(prop.size)*0.5)
static func _find_site(data: Dictionary, rng: RandomNumberGenerator, radius: float) -> Vector2:
for attempt in 120:
var point := Vector2(rng.randf_range(-1650, 1650), rng.randf_range(-1650, 1650))
if not preload("res://scripts/planets/surface_details.gd")._clear_site(data, point, radius):
continue
# Check interior cells as well as the perimeter so small ponds stay clear.
var good := true
for y in range(-ceili(radius), ceili(radius)+1, 30):
for x in range(-ceili(radius), ceili(radius)+1, 30):
var h := preload("res://scripts/planets/surface_details.gd")._height(data, point+Vector2(x,y))
if h < 0.33 or h > 0.66:
good = false
if good:
return point
return Vector2.INF