Randoloot/scripts/planets/surface_scenery.gd
2026-10-18 14:46:34 +02:00

82 lines
3.9 KiB
GDScript

extends RefCounted
const BUILDING_SCALE := 0.65
const KINDS := ["ruined_house","warehouse","radar","airstrip","fuel_depot","solar_farm","scrapyard"]
const WIDTHS := {"ruined_house":135.0,"warehouse":180.0,"radar":130.0,"airstrip":290.0,"fuel_depot":150.0,"solar_farm":180.0,"scrapyard":160.0,"engineer_camp":130.0}
static func generate(data: Dictionary, rng: RandomNumberGenerator) -> void:
data.structures = []
data.events = []
for index in rng.randi_range(2,5):
var kind: String = KINDS[rng.randi_range(0,KINDS.size()-1)]
var width: float = WIDTHS[kind]*BUILDING_SCALE*rng.randf_range(0.85,1.15)
var position := find_site(data,rng,width*0.55)
if position == Vector2.INF:
continue
data.structures.append({"kind":kind,"position":position,"size":width,"rotation":rng.randf_range(-PI,PI)})
var event_rng := RandomNumberGenerator.new()
event_rng.seed = int(data.seed) ^ 0x45564e54
var position := find_event_site(data,event_rng)
var kinds: Array = preload("res://scripts/planets/surface_events.gd").KINDS
data.events.append({"kind":kinds[event_rng.randi_range(0,kinds.size()-1)],"position":position,"seed":event_rng.randi(),"complete":false,"discovered":false})
data.trees = data.trees.filter(func(prop): return prop.position.distance_to(position) > 90+float(prop.size)*0.3)
data.mountains = data.mountains.filter(func(prop): return prop.position.distance_to(position) > 90+float(prop.size)*0.7)
data.rocks = data.rocks.filter(func(prop): return prop.position.distance_to(position) > 80)
var clearings: Array = data.structures.duplicate()
for clearing in clearings:
data.trees = data.trees.filter(func(prop): return prop.position.distance_to(clearing.position) > float(clearing.size)*0.6+float(prop.size)*0.3)
data.rocks = data.rocks.filter(func(prop): return prop.position.distance_to(clearing.position) > float(clearing.size)*0.6+float(prop.size)*0.3)
static func find_site(data: Dictionary, rng: RandomNumberGenerator, radius: float) -> Vector2:
for attempt in 300:
var point := Vector2(rng.randf_range(-1600,1600),rng.randf_range(-1600,1600))
if point.length() < radius+250:
continue
var good := true
var minimum := 1.0
var maximum := 0.0
for offset in [Vector2.ZERO,Vector2.LEFT,Vector2.RIGHT,Vector2.UP,Vector2.DOWN,Vector2(-0.7,-0.7),Vector2(0.7,0.7),Vector2(-0.7,0.7),Vector2(0.7,-0.7)]:
var at: Vector2 = point+offset*radius
var x := clampi(int((at.x+1920)/40),0,95)
var y := clampi(int((at.y+1920)/40),0,95)
var h: float = data.heights[y*96+x]
minimum = minf(minimum,h)
maximum = maxf(maximum,h)
if minimum < 0.32 or maximum > 0.76 or maximum-minimum > 0.16:
continue
for mountain in data.mountains:
if point.distance_to(mountain.position) < radius+float(mountain.size)*0.7:
good = false
break
for poi in data.pois:
if point.distance_to(poi.position) < radius+150:
good = false
break
for structure in data.structures:
if point.distance_to(structure.position) < radius+float(structure.size)*0.65+60:
good = false
break
if good:
return point
return Vector2.INF
static func find_event_site(data: Dictionary, rng: RandomNumberGenerator) -> Vector2:
var preferred := find_site(data,rng,60)
if preferred != Vector2.INF: return preferred
# Lander movement supports every terrain. Guarantee one encounter even on
# maps without flat ground, away from the landing pad and other locations.
var chosen := Vector2(1200,1200)
var best_clearance := -INF
for y in range(-1600,1601,160):
for x in range(-1600,1601,160):
var point := Vector2(x,y)
if point.length() < 400: continue
var clearance := point.length()-310
for poi in data.pois:
clearance = minf(clearance,point.distance_to(poi.position)-210)
for structure in data.structures:
clearance = minf(clearance,point.distance_to(structure.position)-float(structure.size)*0.65-120)
if clearance > best_clearance:
best_clearance = clearance
chosen = point
return chosen