extends Node2D # 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_type: String = "big_stable_asteroid" @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 shape_points: PackedVector2Array = PackedVector2Array() # 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 var rng: RandomNumberGenerator = RandomNumberGenerator.new() rng.seed = shape_seed var point_count: int = 10 for i in range(point_count): var angle: float = (float(i) / point_count) * TAU var radius: float = rng.randf_range(70.0, 100.0) shape_points.append(Vector2(cos(angle), sin(angle)) * radius) shows_extractor = GameState.has_extractor_at(planet_name) 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_name or shows_extractor: return shows_extractor = true queue_redraw() func extractor_derrick_anchor() -> Vector2: # The rim vertex the derrick stands on: the shape's own topmost point, # rather than a fixed radius, so it sits ON the outline whatever lumpy # shape the seed drew instead of floating off it or sinking inside it. var base: Vector2 = Vector2(0.0, -100.0) for p in shape_points: if p.y < base.y: base = p return base 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: NeonDraw.draw_glowing_polygon(self, shape_points, Color(0.6, 0.55, 0.5), 1.0) if shows_extractor: NeonDraw.draw_glowing_polygon(self, extractor_derrick_points(), EXTRACTOR_MARKER_COLOR, 1.0)