extends Node2D const GENERATOR_ATLAS_PATH := preload("res://scripts/planets/surface_details.gd").ATLAS_PATH const BUILDING_SCALE := preload("res://scripts/planets/surface_scenery.gd").BUILDING_SCALE const GENERATOR := preload("res://scripts/planets/surface_generator.gd") var data: Dictionary var terrain: ImageTexture var tree_canopy: Node2D var _nature: Array[AtlasTexture] = [] var _tree: Texture2D var _poi_sprites: Dictionary = {} var _poi_labels: Dictionary = {} var _event_nodes: Array[Dictionary] = [] func _ready() -> void: texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS terrain = GENERATOR.terrain_texture(data) var ground := Sprite2D.new() ground.name = "Terrain" ground.texture = data.height_texture ground.scale = Vector2.ONE * GENERATOR.WORLD_SIZE / ground.texture.get_width() ground.z_index = -5 var material := ShaderMaterial.new() material.shader = preload("res://resources/effects/planet_terrain.gdshader") material.set_shader_parameter("height_map",data.height_texture) material.set_shader_parameter("grass_detail",preload("res://assets/planets/grass.png")) for kind in ["soil","rock","sand","moss"]: material.set_shader_parameter(kind+"_detail",load("res://assets/planets/terrain/%s.png" % kind)) material.set_shader_parameter("biome_kind",int(data.landscape.index)) for key in ["low","high","sand","rock"]: material.set_shader_parameter(key+"_color",data.landscape[key]) material.set_shader_parameter("climate",float(data.profile.temperature)) material.set_shader_parameter("seed_offset",float(posmod(int(data.seed),10000))) ground.material = material add_child(ground) var atlas: Texture2D = load(GENERATOR_ATLAS_PATH) var atlas_scale := Vector2(atlas.get_size()) / 1280.0 # The painted sheet has uneven transparent gutters; avoid clipping canopies. var rows := [Vector2(0,360), Vector2(360,280), Vector2(640,310), Vector2(950,330)] for index in 16: var tile := AtlasTexture.new() tile.atlas = atlas var band: Vector2 = rows[index / 4] var region := Rect2(float(index % 4)*320.0, band.x, 320.0, band.y) if index == 12: region = Rect2(0,950,365,330) elif index == 13: region = Rect2(370,950,270,330) tile.region = Rect2(region.position*atlas_scale, region.size*atlas_scale) tile.filter_clip = true _nature.append(tile) _tree = load("res://assets/planets/tree.png") var mountains := Node2D.new() mountains.name = "Mountains" mountains.set_script(preload("res://scripts/planets/surface_mountains.gd")) mountains.data = data mountains.z_index = -1 add_child(mountains) tree_canopy = Node2D.new() tree_canopy.set_script(preload("res://scripts/planets/surface_tree_canopy.gd")) tree_canopy.world = self add_child(tree_canopy) for poi in data.pois: var sprite := Sprite2D.new() if poi.kind in ["deposit", "deep_deposit"]: sprite.set_script(preload("res://scripts/planets/surface_deposit.gd")) sprite.configure(data,poi) else: if poi.kind == "cave": sprite.set_script(preload("res://scripts/planets/surface_cave.gd")) sprite.configure(data,poi) else: var textures := {"ruins":"ruins", "warehouse":"props/warehouse", "village":"landmarks/abandoned_hamlet", "crew":"props/engineer_camp", "hermit":"props/hermit_cartographer", "time_engineer":"props/time_engineer"} sprite.texture = load("res://assets/planets/%s.png" % textures[poi.kind]) sprite.position = poi.position if sprite.texture != null and poi.kind != "cave": sprite.scale = Vector2.ONE * 125.0*BUILDING_SCALE / maxf(sprite.texture.get_width(), sprite.texture.get_height()) sprite.z_index = 10 if poi.kind == "crew" and sprite.texture != null: sprite.scale = Vector2.ONE * 170.0 / maxf(sprite.texture.get_width(),sprite.texture.get_height()) add_child(sprite) _poi_sprites[poi.id] = sprite var label := Label.new() label.position = poi.position + Vector2(-120, 46) label.size.x = 240 label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER label.add_theme_font_size_override("font_size", 13) label.add_theme_color_override("font_color", Color("f0d5a1")) label.add_theme_color_override("font_shadow_color", Color("061310")) label.add_theme_constant_override("shadow_outline_size", 5) label.z_index = 15 add_child(label) _poi_labels[poi.id] = label for landmark in data.get("landmarks", []): var prop := Sprite2D.new() prop.name = str(landmark.kind).to_pascal_case() prop.texture = load("res://assets/planets/landmarks/%s.png" % landmark.kind) prop.position = landmark.position prop.rotation = landmark.rotation prop.scale = Vector2.ONE * float(landmark.size) / maxf(prop.texture.get_width(), prop.texture.get_height()) prop.z_index = -2 add_child(prop) for structure in data.structures: var prop := Sprite2D.new() prop.name = str(structure.kind).to_pascal_case() prop.texture = load("res://assets/planets/props/%s.png" % structure.kind) prop.position = structure.position prop.rotation = structure.rotation prop.scale = Vector2.ONE * float(structure.size) / maxf(prop.texture.get_width(),prop.texture.get_height()) prop.z_index = 4 add_child(prop) for index in data.events.size(): var event: Dictionary = data.events[index] var marker := Label.new() marker.name = "EventMarker%d" % index marker.text = "?" marker.position = event.position+Vector2(-22,-28) marker.size = Vector2(44,55) marker.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER marker.add_theme_font_size_override("font_size",40) marker.add_theme_color_override("font_color",Color("f8d685")) marker.add_theme_color_override("font_outline_color",Color("17211b")) marker.add_theme_constant_override("outline_size",7) marker.z_index = 25 add_child(marker) _event_nodes.append({"marker":marker}) refresh_pois(Vector2.ZERO) func refresh_pois(lander_position: Vector2) -> void: for index in data.events.size(): var event: Dictionary = data.events[index] if lander_position.distance_to(event.position) < 600: event.discovered = true var nodes: Dictionary = _event_nodes[index] nodes.marker.visible = not event.complete for poi in data.pois: if lander_position.distance_to(poi.position) < 650: poi.discovered = true var sprite: Sprite2D = _poi_sprites[poi.id] sprite.visible = bool(poi.discovered) sprite.modulate = Color(0.5, 0.55, 0.5) if poi.complete else Color.WHITE var label: Label = _poi_labels[poi.id] label.visible = bool(poi.discovered) if poi.kind == "deep_deposit": var built: bool = GameState.captain.expedition.mining_stations.has(str(data.profile.id)) if built and not bool(sprite.get_meta("outpost", false)): sprite.texture = load("res://assets/planets/props/deuterium_outpost.png") sprite.material = null sprite.rotation = 0 sprite.scale = Vector2.ONE * 185.0 / maxf(sprite.texture.get_width(), sprite.texture.get_height()) sprite.set_meta("outpost", true) var network := preload("res://scripts/planets/mining_network.gd") var richness: int = network.station_richness(GameState.captain.expedition.mining_stations[str(data.profile.id)]) if built else network.deposit_richness(data.profile, int(data.profile.get("system_level", GameState.system_level))) label.text = ("%s · %d/100" % ["Placówka górnicza" if built else "Głębokie złoże deuteru", richness]) if lander_position.distance_to(poi.position) <= 150: label.text += "\n[F] Placówka" if built else "\n[F] Buduj" continue if poi.kind == "time_engineer": label.text = "Inżynier chronalny" + ("\n[F] Maksymalizuj addon" if lander_position.distance_to(poi.position) <= 150 else "") continue if poi.kind == "hermit": var owned: bool = GameState.captain.expedition.distant_maps.has(str(data.profile.id)+":distant_map") label.text = "Pustelnik / Kartograf" + (" · mapa kupiona" if owned else ("\n[F] Kup mapę" if lander_position.distance_to(poi.position) <= 150 else "")) continue if poi.kind == "crew": label.text = "Obóz specjalisty" + (" · zatrudniono" if poi.complete else ("\n[F] Porozmawiaj" if lander_position.distance_to(poi.position) <= 150 else "")) continue var title: String = preload("res://scripts/planets/poi_rules.gd").NAMES[poi.kind] label.text = title + ((" · zatrudniono" if poi.kind == "crew" else " · zbadano") if poi.complete else ("\n[F] Zbadaj" if lander_position.distance_to(poi.position) <= 150 else "")) func _draw() -> void: if terrain == null: return for detail in data.get("details", []): var shade := float(detail.shade) _draw_prop(_nature[int(detail.variant)], detail.position, detail.size, detail.rotation, Color(shade,shade,shade)) for rock in data.rocks: _draw_prop(_nature[int(rock.get("variant",4))],rock.position,rock.size,rock.rotation,Color.WHITE) # Small landing beacon. draw_circle(Vector2.ZERO, 50, Color(0.5, 0.85, 0.8, 0.12)) draw_arc(Vector2.ZERO, 48, 0, TAU, 48, Color("8cd9c2"), 2, true) func _draw_prop(texture: Texture2D, point: Vector2, width: float, angle: float, color: Color) -> void: draw_set_transform(point, angle) var size := Vector2(width, width*float(texture.get_height())/float(texture.get_width())) draw_texture_rect(texture, Rect2(-size*0.5, size), false, color) draw_set_transform(Vector2.ZERO)