extends Node2D const PLANET_DEFINITIONS = preload("res://planets/PlanetDefinitions.gd") # A landable world-object - unlike regular Asteroid.gd, planets are # stationary ("Big Stable Asteroid" - stable means it doesn't drift or # destroy ships on touch). Whether the fleet counts as "landed" is decided # by PlanetField comparing the fleet's CENTROID distance to landing_radius, # not per-ship Area2D collision - a single stable number, immune to the # constant minor jostling of individual ships holding formation, which # used to make the "enter atmosphere" prompt flicker on/off as ships # drifted in and out of the boundary independently of each other even # while the fleet as a whole was clearly sitting on the planet. @export var planet_name: String = "" @export var planet_id: String = "" @export var definition_id: String = PLANET_DEFINITIONS.DEFAULT_DEFINITION_ID @export var landing_radius: float = 140.0 # Set by whoever spawns this planet (PlanetField, seeded from the chunk's # own coordinates) so the outline shape is stable across respawns of the # same chunk, instead of reading as a "different" planet every time. @export var shape_seed: int = 0 var definition: Resource var visual: Node2D var resource_type: String: get: return String(definition.resource_id) if definition != null else "ore" var surface_profile_id: String: get: return String(definition.surface_profile_id) if definition != null else "rocky" var shape_points: PackedVector2Array: get: if visual != null and "shape_points" in visual: return visual.shape_points return PackedVector2Array() var gas_phase: float: get: if visual != null and "gas_phase" in visual: return float(visual.gas_phase) return 0.0 # An extractor is built down on this planet's SURFACE, in a different scene # the player is no longer looking at, so from space nothing distinguished a # planet already being mined from an untouched one - you had to land to find # out. This is a derrick planted on the rim: the same amber the world map # uses for its extractor badge, so the two read as the same fact. const EXTRACTOR_MARKER_COLOR: Color = Color(1.0, 0.85, 0.3) const DERRICK_HEIGHT: float = 44.0 const DERRICK_HALF_WIDTH: float = 16.0 # Kept in step with GameState.extractor_added rather than polled per frame. # An extractor is built from SPACE (BuildController._planet_under_fleet(), # with the fleet parked on the planet), so this node is already in the tree # with its _ready() long since run when the answer changes - resolving it # only at _ready() left the planet looking untouched until it happened to # despawn and respawn. var shows_extractor: bool = false func _ready() -> void: add_to_group("planets") z_index = -1 definition = PLANET_DEFINITIONS.get_definition(definition_id) visual = definition.visual_scene.instantiate() visual.configure(shape_seed) get_node("VisualHost").add_child(visual) if planet_id == "": planet_id = planet_name shows_extractor = GameState.has_extractor_at(planet_id) GameState.extractor_added.connect(_on_extractor_added) queue_redraw() func _on_extractor_added(built_on: String) -> void: # Only the planet it was actually built on, and only a redraw when the # answer really changed - every other planet in range gets this too. if built_on != planet_id or shows_extractor: return shows_extractor = true queue_redraw() func extractor_derrick_anchor() -> Vector2: if visual != null and visual.has_method("extractor_anchor"): return visual.extractor_anchor() return Vector2(0.0, -100.0) func extractor_derrick_tip() -> Vector2: # Exposed separately from the polygon because "does the derrick clear the # planet's outline" is a question about the TIP alone. The base corners # sit a half-width off to either side, so they are sqrt(|base|^2 + w^2) # from the centre and can clear the rim on their own even when the tower # points straight into the ground. var base: Vector2 = extractor_derrick_anchor() var out: Vector2 = base.normalized() if out == Vector2.ZERO: out = Vector2.UP return base + out * DERRICK_HEIGHT func extractor_derrick_points() -> PackedVector2Array: var base: Vector2 = extractor_derrick_anchor() var out: Vector2 = base.normalized() if out == Vector2.ZERO: out = Vector2.UP var side: Vector2 = Vector2(-out.y, out.x) var tip: Vector2 = extractor_derrick_tip() return PackedVector2Array([ base - side * DERRICK_HALF_WIDTH, tip - side * (DERRICK_HALF_WIDTH * 0.35), tip + side * (DERRICK_HALF_WIDTH * 0.35), base + side * DERRICK_HALF_WIDTH, ]) func _draw() -> void: if shows_extractor: NeonDraw.draw_glowing_polygon(self, extractor_derrick_points(), EXTRACTOR_MARKER_COLOR, 1.0)