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 bool(prop.get("cave_anchor",false)) or 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 mountain in data.mountains: if mountain.get("cave_anchor",false): clearance = minf(clearance,point.distance_to(mountain.position)-float(mountain.size)*0.7-90) 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