extends RefCounted const POI := preload("res://scripts/levels/exploration_poi.gd") static func spawn(game: Node2D, data: Dictionary, player: CharacterBody2D) -> void: var rng := RandomNumberGenerator.new() rng.seed = GameState.system_seed ^ 0x504f49 var occupied: Array[Vector2] = [] var wreck_count := rng.randi_range(2, 4) for index in wreck_count + rng.randi_range(6, 10): var kind := "wreck" if index < wreck_count else "asteroid" var candidate := Vector2.ZERO var found := false for attempt in 200: candidate = Vector2(rng.randf_range(-2300, 2300), rng.randf_range(-1500, 1500)) if candidate.length() < 650 or candidate.distance_to(player.position) < 450: continue var clear := true for planet in data["planets"]: if candidate.distance_to(planet["position"]) < float(planet["radius"]) + 220: clear = false for point in occupied: if candidate.distance_to(point) < 180: clear = false if clear: found = true break if found: occupied.append(candidate) _add(game, player, kind, candidate, index, rng.randi()) # Rare per system, at most one ruin on an uninhabited planet. if rng.randf() < 0.08: var candidates: Array[int] = [] for index in data["planets"].size(): if not data["planets"][index]["protected"]: candidates.append(index) if not candidates.is_empty(): var index := candidates[rng.randi_range(0, candidates.size() - 1)] var planet := game.get_node("CelestialBodies/Planet%d" % (index + 1)) _add(game, player, "ruin", planet.position, 100, rng.randi(), float(planet.get("radius")) + 100.0) static func _add(game: Node2D, player: CharacterBody2D, kind: String, position: Vector2, index: int, reward_seed: int, approach_radius: float = 115.0) -> void: var id := "%d:%d" % [GameState.system_seed, index] if GameState.explored_pois.has(id): return var poi := StaticBody2D.new() poi.set_script(POI) poi.set("kind", kind) poi.set("poi_id", id) poi.set("reward_seed", reward_seed) poi.set("player", player) poi.set("approach_radius", approach_radius) poi.position = position game.add_child(poi)