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