Stacje górnicze
BIN
artifacts/mining_built_outpost.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
40
artifacts/mining_built_outpost.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c7urmci7jx376"
|
||||
path="res://.godot/imported/mining_built_outpost.png-77e746170a9aec36f9fee12b78634737.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/mining_built_outpost.png"
|
||||
dest_files=["res://.godot/imported/mining_built_outpost.png-77e746170a9aec36f9fee12b78634737.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
artifacts/mining_cabin.png
Normal file
|
After Width: | Height: | Size: 900 KiB |
40
artifacts/mining_cabin.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://d1spksp3e0m2s"
|
||||
path="res://.godot/imported/mining_cabin.png-706b1ec26fcc87cd347620ae43590b0c.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/mining_cabin.png"
|
||||
dest_files=["res://.godot/imported/mining_cabin.png-706b1ec26fcc87cd347620ae43590b0c.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
artifacts/mining_command.png
Normal file
|
After Width: | Height: | Size: 870 KiB |
40
artifacts/mining_command.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dqvq68kdagb24"
|
||||
path="res://.godot/imported/mining_command.png-7caa01b95f77da3d680ffba6796dafb3.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/mining_command.png"
|
||||
dest_files=["res://.godot/imported/mining_command.png-7caa01b95f77da3d680ffba6796dafb3.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
artifacts/mining_construction.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
40
artifacts/mining_construction.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dr1rcr822mjvh"
|
||||
path="res://.godot/imported/mining_construction.png-91bcdc8e846b46c629cc595f3cbf4668.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/mining_construction.png"
|
||||
dest_files=["res://.godot/imported/mining_construction.png-91bcdc8e846b46c629cc595f3cbf4668.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
artifacts/mining_recruitment.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
40
artifacts/mining_recruitment.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://nanieob3htt"
|
||||
path="res://.godot/imported/mining_recruitment.png-bfd8a737935c7b3b4da967f155357ff7.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/mining_recruitment.png"
|
||||
dest_files=["res://.godot/imported/mining_recruitment.png-bfd8a737935c7b3b4da967f155357ff7.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
artifacts/mining_storage.png
Normal file
|
After Width: | Height: | Size: 877 KiB |
40
artifacts/mining_storage.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://j54irqsrl1fo"
|
||||
path="res://.godot/imported/mining_storage.png-d886989878e8d040e73eac66bd0fc46b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/mining_storage.png"
|
||||
dest_files=["res://.godot/imported/mining_storage.png-d886989878e8d040e73eac66bd0fc46b.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
1
assets/icons/resources/deuter.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><g fill="none" stroke="#81d9e9" stroke-width="2"><circle cx="24" cy="24" r="17" opacity=".25"/><ellipse cx="24" cy="24" rx="20" ry="8" transform="rotate(-35 24 24)"/><ellipse cx="24" cy="24" rx="20" ry="8" transform="rotate(35 24 24)"/></g><circle cx="21" cy="24" r="5" fill="#b6f4ff"/><circle cx="28" cy="24" r="5" fill="#4e9fce"/><circle cx="39" cy="13" r="3" fill="#e1ffff"/></svg>
|
||||
|
After Width: | Height: | Size: 468 B |
43
assets/icons/resources/deuter.svg.import
Normal file
@ -0,0 +1,43 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://h3b6hffd0r28"
|
||||
path="res://.godot/imported/deuter.svg-eb6e41c97050cdbb566835b47bc2c3cf.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/icons/resources/deuter.svg"
|
||||
dest_files=["res://.godot/imported/deuter.svg-eb6e41c97050cdbb566835b47bc2c3cf.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
1
assets/planets/props/deuterium_outpost.PROMPT.txt
Normal file
@ -0,0 +1 @@
|
||||
Use case: stylized-concept. Asset type: transparent game sprite for a planetary deuterium mining outpost in a top-down space survival RPG. Reference image is the existing planetary warehouse building, match its painted realistic hard-surface game-art style and camera angle. One compact complete modular deep-drilling mining facility: central robust drilling well with extraction derrick, attached low white-gray industrial control hut with orange stripes, two pale blue cylindrical deuterium tanks connected by visible steel pipes, small radiator and power equipment, work platform with hazard markings and service lights. Practical weathered off-world technology, recognizable silhouette at 160 pixels, detailed but uncluttered. Camera nearly overhead with slight view of front walls exactly like reference, isolated whole structure, no large terrain base. All parts connected as one game prop. Fully transparent background, small natural contact shadow only, no landscape, no sky, no people, no text, no letters, no logos. Entire building visible with generous transparent margin and no cropping.
|
||||
BIN
assets/planets/props/deuterium_outpost.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
40
assets/planets/props/deuterium_outpost.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cnpk68uwjsb35"
|
||||
path="res://.godot/imported/deuterium_outpost.png-8c0051818e09799eaa0a4237c6a5c8e9.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/planets/props/deuterium_outpost.png"
|
||||
dest_files=["res://.godot/imported/deuterium_outpost.png-8c0051818e09799eaa0a4237c6a5c8e9.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
@ -30,6 +30,7 @@ func _ready() -> void:
|
||||
GameState.system_level = clampi(GameState.system_level, 1, LEVEL_BALANCE.MAX_LEVEL)
|
||||
if GameState.system_seed == 0:
|
||||
GameState.system_seed = GameState.create_system_seed()
|
||||
GameState.remember_system()
|
||||
system_data = SYSTEM_GENERATOR.generate(GameState.system_level, GameState.system_seed)
|
||||
player.position = system_data["player_start"]
|
||||
var camera := player.get_node_or_null("Camera2D") as Camera2D
|
||||
@ -95,6 +96,11 @@ func _spawn_celestial_bodies() -> void:
|
||||
protected_planet = planet
|
||||
|
||||
func _spawn_enemies() -> void:
|
||||
if bool(GameState.cleared_systems.get(GameState.system_level, false)):
|
||||
system_cleared = true
|
||||
_boss_spawned = true
|
||||
protected_planet.call("set_safe", true)
|
||||
return
|
||||
for data in system_data["enemies"]:
|
||||
if int(data["tier"]) == 2:
|
||||
_pending_boss = data.duplicate()
|
||||
@ -159,6 +165,7 @@ func _physics_process(_delta: float) -> void:
|
||||
_spawn_boss()
|
||||
else:
|
||||
system_cleared = true
|
||||
GameState.cleared_systems[GameState.system_level] = true
|
||||
protected_planet.call("set_safe", true)
|
||||
if system_cleared and is_near_protected_planet():
|
||||
if not services_menu.visible:
|
||||
@ -218,7 +225,7 @@ func _load_next_level() -> void:
|
||||
var previous_seed := GameState.system_seed
|
||||
player.get_node("ShipInventory").call("preserve_for_restart")
|
||||
GameState.system_level += 1
|
||||
GameState.system_seed = GameState.create_system_seed()
|
||||
GameState.system_seed = GameState.seed_for_system(GameState.system_level)
|
||||
var error := get_tree().reload_current_scene()
|
||||
if error != OK:
|
||||
GameState.system_level = previous_level
|
||||
@ -228,3 +235,25 @@ func _load_next_level() -> void:
|
||||
if is_near_protected_planet():
|
||||
services_menu.call("show_services", false, true)
|
||||
push_error("Could not enter next system: %s" % error_string(error))
|
||||
|
||||
func travel_to_system(level: int) -> bool:
|
||||
if _transitioning or bool(player.get("_is_destroyed")) or level == GameState.system_level or not GameState.can_visit_system(level): return false
|
||||
_transitioning = true
|
||||
_load_known_system.call_deferred(level)
|
||||
return true
|
||||
|
||||
func _load_known_system(level: int) -> void:
|
||||
var previous_level := GameState.system_level
|
||||
var previous_seed := GameState.system_seed
|
||||
player.get_node("ShipInventory").preserve_for_restart()
|
||||
GameState.remember_system()
|
||||
GameState.system_level = level
|
||||
GameState.system_seed = GameState.seed_for_system(level)
|
||||
get_tree().paused = false
|
||||
var error := get_tree().reload_current_scene()
|
||||
if error != OK:
|
||||
GameState.system_level = previous_level
|
||||
GameState.system_seed = previous_seed
|
||||
GameState.restart_inventory.clear()
|
||||
_transitioning = false
|
||||
push_error("Nie udało się przenieść do układu: %s" % error_string(error))
|
||||
|
||||
@ -7,6 +7,10 @@ var selected_ship_path: String = ""
|
||||
var restart_inventory: Dictionary = {}
|
||||
var system_level: int = 1
|
||||
var system_seed: int = 0
|
||||
var highest_system := 1
|
||||
var system_seeds: Dictionary = {}
|
||||
var cleared_systems: Dictionary = {}
|
||||
var _production_signal_time := 0.0
|
||||
var explored_pois: Dictionary = {}
|
||||
var asteroid_retry_seeds: Dictionary = {}
|
||||
var exploration_wreck_bonuses: Dictionary = {}
|
||||
@ -32,6 +36,10 @@ func reset_current_system_exploration() -> void:
|
||||
func start_new_run() -> void:
|
||||
captain = CAPTAIN_PROGRESS.new()
|
||||
system_level = 1
|
||||
highest_system = 1
|
||||
system_seeds.clear()
|
||||
cleared_systems.clear()
|
||||
_production_signal_time = 0
|
||||
system_seed = create_system_seed()
|
||||
restart_inventory.clear()
|
||||
explored_pois.clear()
|
||||
@ -40,7 +48,35 @@ func start_new_run() -> void:
|
||||
hud_panel_state.clear()
|
||||
|
||||
func _ready() -> void:
|
||||
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
var game_window := get_tree().root
|
||||
game_window.content_scale_size = Vector2i(1280, 720)
|
||||
game_window.content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS
|
||||
game_window.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_EXPAND
|
||||
|
||||
func remember_system() -> void:
|
||||
highest_system = maxi(highest_system, system_level)
|
||||
system_seeds[system_level] = system_seed
|
||||
|
||||
func can_visit_system(level: int) -> bool:
|
||||
return level >= 1 and level <= highest_system and level <= 120
|
||||
|
||||
func seed_for_system(level: int) -> int:
|
||||
if not system_seeds.has(level): system_seeds[level] = create_system_seed()
|
||||
return int(system_seeds[level])
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
advance_play_time(delta, get_tree().current_scene)
|
||||
|
||||
func advance_play_time(delta: float, scene: Node) -> void:
|
||||
if scene == null or not scene.has_node("PlayerShip"): return
|
||||
if bool(scene.get_node("PlayerShip").get("_is_destroyed")): return
|
||||
var expedition := scene.get_node_or_null("PlanetExpeditions")
|
||||
var location_open := expedition != null and is_instance_valid(expedition.screen)
|
||||
if get_tree().paused and not location_open: return
|
||||
var network := preload("res://scripts/planets/mining_network.gd")
|
||||
if network.advance(captain.expedition, delta) <= 0: return
|
||||
_production_signal_time += delta
|
||||
if _production_signal_time >= 1.0:
|
||||
_production_signal_time = fmod(_production_signal_time, 1.0)
|
||||
captain.expedition.emit_changed()
|
||||
|
||||
@ -268,3 +268,9 @@ func _exit_tree() -> void:
|
||||
if is_instance_valid(screen):
|
||||
get_tree().paused = _previous_pause
|
||||
get_tree().auto_accept_quit = true
|
||||
|
||||
func request_system_travel(level: int) -> bool:
|
||||
if not is_instance_valid(screen) or GameState.captain.expedition.active or level == GameState.system_level or not GameState.can_visit_system(level): return false
|
||||
if not game.travel_to_system(level): return false
|
||||
_leave()
|
||||
return true
|
||||
|
||||
73
scripts/planets/freighter_command.gd
Normal file
@ -0,0 +1,73 @@
|
||||
extends RefCounted
|
||||
const MENU := preload("res://scripts/planets/freighter_menu.gd")
|
||||
const NETWORK := preload("res://scripts/planets/mining_network.gd")
|
||||
|
||||
static func build(screen: Control) -> void:
|
||||
var progress: Resource = screen.captain.expedition
|
||||
var navigation := MENU.card(screen._content)
|
||||
MENU.label(navigation, "NAWIGACJA / ODKRYTE UKŁADY", 14, MENU.GOLD)
|
||||
MENU.label(navigation, "Obecny: System %d · Najdalszy odkryty: %d" % [GameState.system_level, GameState.highest_system], 12)
|
||||
var row := MENU.row(navigation)
|
||||
var destination := OptionButton.new()
|
||||
destination.name = "SystemDestination"
|
||||
destination.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
destination.add_theme_font_size_override("font_size", 11)
|
||||
destination.add_theme_font_override("font", ThemeDB.fallback_font)
|
||||
for level in range(1, GameState.highest_system + 1):
|
||||
destination.add_item("System %d%s" % [level, " · HARD" if level > 60 else ""], level)
|
||||
destination.select(GameState.system_level - 1)
|
||||
row.add_child(destination)
|
||||
var travel := MENU.button(row, "LEĆ DO UKŁADU", func(): screen._travel_to_system(destination.get_selected_id()), true)
|
||||
travel.name = "TravelToSystem"
|
||||
travel.disabled = true
|
||||
destination.item_selected.connect(func(_index): travel.disabled = destination.get_selected_id() == GameState.system_level)
|
||||
MENU.label(navigation, "Nowe układy odblokujesz, przechodząc dalej przez tunel po pokonaniu przeciwników.", 11, MENU.MUTED)
|
||||
var summary := MENU.card(screen._content)
|
||||
MENU.label(summary, "SIEĆ WYDOBYWCZA", 14, MENU.GOLD)
|
||||
var stock := MENU.label(summary, "", 13, Color("95dce8"))
|
||||
screen._economy_labels["network"] = stock
|
||||
MENU.label(summary, "Obsadzona placówka: 1 deuter/min + punkty zarządzania. Dostawy automatyczne do magazynu.", 11, MENU.MUTED)
|
||||
MENU.label(summary, "Jeden załogant obsługuje jedną placówkę. Nowy przydział przenosi go z poprzedniej.", 11, MENU.MUTED)
|
||||
if progress.mining_stations.is_empty():
|
||||
MENU.label(summary, "Brak placówek. Szukaj głębokich złóż na planetach (szansa 60%). Budowa: 200 części.", 12)
|
||||
for station_id in progress.mining_stations:
|
||||
var station: Dictionary = progress.mining_stations[station_id]
|
||||
var card := MENU.card(screen._content)
|
||||
MENU.label(card, "%s · SYSTEM %d" % [station.planet_name, station.system], 13, MENU.GOLD)
|
||||
var member: Dictionary = progress.crew.get(str(station.get("crew_id", "")), {})
|
||||
MENU.label(card, "Czeka na załoganta" if member.is_empty() else "%s · zarządzanie %d/100 · %.0f deuteru/min" % [member.name, member.management, NETWORK.station_rate(progress, station)], 12)
|
||||
var assign_row := MENU.row(card)
|
||||
var option := OptionButton.new()
|
||||
option.name = "StationCrew_" + str(station_id).md5_text().substr(0, 8)
|
||||
option.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
option.fit_to_longest_item = false
|
||||
option.add_theme_font_size_override("font_size", 11)
|
||||
option.add_theme_font_override("font", ThemeDB.fallback_font)
|
||||
option.add_item("Bez przydziału")
|
||||
option.set_item_metadata(0, "")
|
||||
for crew_id in progress.crew:
|
||||
var person: Dictionary = progress.crew[crew_id]
|
||||
option.add_item("%s · %d/100" % [person.name, person.management])
|
||||
option.set_item_metadata(option.item_count - 1, crew_id)
|
||||
if str(station.get("crew_id", "")) == str(crew_id): option.select(option.item_count - 1)
|
||||
assign_row.add_child(option)
|
||||
var apply := MENU.button(assign_row, "PRZYDZIEL", screen._assign_station.bind(str(station_id), option))
|
||||
apply.disabled = progress.crew.is_empty() and member.is_empty()
|
||||
if progress.crew.is_empty(): MENU.label(screen._content, "Brak załogantów. Przygotuj kajutę i zatrudnij specjalistę spotkanego na planecie.", 12, MENU.MUTED)
|
||||
screen._refresh_live_labels()
|
||||
|
||||
static func cabin(screen: Control) -> void:
|
||||
var progress: Resource = screen.captain.expedition
|
||||
var member := NETWORK.cabin_crew(progress, screen._tab)
|
||||
var card := MENU.card(screen._content)
|
||||
if member.is_empty():
|
||||
MENU.label(card, "WOLNA KAJUTA", 14, MENU.GOLD)
|
||||
MENU.label(card, "Przygotowana dla jednego załoganta. Specjalistów możesz zatrudniać na planetach.", 12)
|
||||
return
|
||||
MENU.label(card, str(member.name), 15, MENU.GOLD)
|
||||
MENU.label(card, "Zarządzanie: %d / 100\nPremia do wydobycia: +%d deuteru/min\nPochodzenie: %s" % [member.management, member.management, member.planet_name], 12)
|
||||
var assignment := "Bez przydziału"
|
||||
for station in progress.mining_stations.values():
|
||||
if str(station.get("crew_id", "")) == str(member.id): assignment = "%s · System %d" % [station.planet_name, station.system]
|
||||
MENU.label(card, "Placówka: " + assignment, 12, Color("95dce8"))
|
||||
MENU.button(card, "ZWOLNIJ ZAŁOGANTA", screen._dismiss_crew.bind(str(member.id)))
|
||||
1
scripts/planets/freighter_command.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cl4wrga1rbm0p
|
||||
@ -3,7 +3,7 @@ signal section_selected(section: String)
|
||||
signal section_hovered(section: String)
|
||||
const DESIGN_SIZE := Vector2(1792,768)
|
||||
const ROOMS := [
|
||||
{"id":"command","title":"CENTRUM DOWODZENIA","status":"MOSTEK","rect":Rect2(25,165,315,435),"tag":Vector2(88,68),"active":false},
|
||||
{"id":"command","title":"CENTRUM DOWODZENIA","status":"NAWIGACJA / PLACÓWKI","rect":Rect2(25,165,315,435),"tag":Vector2(88,68),"active":false},
|
||||
{"id":"workshop","title":"WARSZTAT","status":"OPERACYJNY","rect":Rect2(360,120,255,205),"tag":Vector2(360,58),"active":true},
|
||||
{"id":"expansion_1","title":"SEKCJA 02","status":"W REMONCIE","rect":Rect2(632,120,200,205),"tag":Vector2(632,58),"active":false},
|
||||
{"id":"expansion_2","title":"SEKCJA 03","status":"W REMONCIE","rect":Rect2(848,120,214,205),"tag":Vector2(848,58),"active":false},
|
||||
@ -20,7 +20,7 @@ const ROOM_SCENE := preload("res://scenes/planets/freighter_room.tscn")
|
||||
const ROOM_PLANS := {
|
||||
"expansion_1":{"kind":"laboratory","title":"LABORATORIUM","description":"Stanowiska analityczne, aparatura i stół do doświadczeń."},
|
||||
"expansion_2":{"kind":"alien_research","title":"BADANIA OBCYCH","description":"Izolowane próbki i komora do badań obcych organizmów."},
|
||||
"expansion_3":{"kind":"module_storage","title":"SKŁAD MODUŁÓW","description":"Regały, pojemniki i stanowiska do przechowywania modułów."}
|
||||
"expansion_3":{"kind":"module_storage","title":"MAGAZYN","description":"Regały, pojemniki i stanowiska do przechowywania modułów."}
|
||||
}
|
||||
var room_states: Dictionary = {}
|
||||
var room_nodes: Dictionary = {}
|
||||
|
||||
@ -16,12 +16,15 @@ var _hint: Label
|
||||
var _owned_open := false
|
||||
var _storage_columns: GridContainer
|
||||
var _storage_notice := ""
|
||||
var _economy_labels: Dictionary = {}
|
||||
@onready var deck: Control = $Deck
|
||||
@onready var _audio: Node = $FreighterAudio
|
||||
|
||||
func _ready() -> void:
|
||||
if captain == null:
|
||||
captain = GameState.captain
|
||||
captain.expedition.freighter_rooms["expansion_3"] = "module_storage"
|
||||
captain.expedition.changed.connect(_refresh_live_labels)
|
||||
deck.sync_rooms(captain.expedition.freighter_rooms)
|
||||
deck.section_selected.connect(_select_section)
|
||||
deck.section_hovered.connect(_hover_section)
|
||||
@ -111,7 +114,7 @@ func _layout() -> void:
|
||||
var research: bool = _tab == "expansion_2" and deck.is_built(_tab)
|
||||
var width := minf(490 if research else (700 if storage else (440 if _tab == "hangar" else 490)),viewport_size.x-32)
|
||||
var construction: bool = deck.is_buildable(_tab) and not deck.is_built(_tab)
|
||||
var target_height := 390 if construction else 430 if research else 420 if _tab == "hangar" else (520 if _tab == "workshop" else (600 if storage else (300 if _tab == "command" else 260)))
|
||||
var target_height := 390 if construction else 430 if research else 420 if _tab == "hangar" else (520 if _tab == "workshop" else (600 if storage else (540 if _tab == "command" else (340 if _tab.begins_with("cabin_") else 260))))
|
||||
var height := minf(target_height,maxf(240,viewport_size.y-140))
|
||||
_drawer.position = Vector2(16 if _tab == "hangar" else viewport_size.x-width-16,maxf(90,(viewport_size.y-height)*0.5))
|
||||
_drawer.size = Vector2(width,height)
|
||||
@ -162,6 +165,7 @@ func _label(text: String, size_value := 14, color := Color("c5d3d7")) -> Label:
|
||||
return node
|
||||
|
||||
func _refresh() -> void:
|
||||
_economy_labels.clear()
|
||||
_storage_columns = null
|
||||
_audio.set_maintenance_needed(captain.expedition.lander_hp < 30)
|
||||
for child in _content.get_children():
|
||||
@ -199,6 +203,9 @@ func _build_room() -> void:
|
||||
if str(plan.kind) == "alien_research" and deck.is_built(_tab):
|
||||
_build_alien_research()
|
||||
return
|
||||
if _tab.begins_with("cabin_") and deck.is_built(_tab):
|
||||
preload("res://scripts/planets/freighter_command.gd").cabin(self)
|
||||
return
|
||||
_label("ZBUDOWANO" if deck.is_built(_tab) else "W REMONCIE",21,UI.CYAN if deck.is_built(_tab) else Color("e0b16a"))
|
||||
_label(str(plan.description))
|
||||
if deck.is_built(_tab):
|
||||
@ -359,6 +366,18 @@ func _unlock_ship_slot(kind: String) -> void:
|
||||
|
||||
func _build_storage() -> void:
|
||||
MENU.hero(_content,"storage","MAGAZYN / ZASOBY I WYPOSAŻENIE")
|
||||
var deuter_card := MENU.card(_content)
|
||||
var deuter_row := MENU.row(deuter_card)
|
||||
MENU.icon(deuter_row, load("res://assets/icons/resources/deuter.svg"), 26)
|
||||
var deuter_title := MENU.label(deuter_row, "DEUTER / PALIWO FREGATY", 13, Color("95dce8"))
|
||||
deuter_title.autowrap_mode = TextServer.AUTOWRAP_OFF
|
||||
deuter_title.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
var deuter_amount := MENU.label(deuter_row, "%.1f" % captain.expedition.deuter, 15, MENU.GOLD)
|
||||
deuter_amount.autowrap_mode = TextServer.AUTOWRAP_OFF
|
||||
deuter_amount.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||
deuter_amount.custom_minimum_size.x = 80
|
||||
_economy_labels["stock_header"] = deuter_amount
|
||||
MENU.label(deuter_card, "Automatyczne dostawy z obsadzonych placówek · %.0f / min" % preload("res://scripts/planets/mining_network.gd").total_rate(captain.expedition), 11, MENU.MUTED)
|
||||
if not deck.is_built("expansion_3"):
|
||||
_build_resource_overview()
|
||||
var construction := MENU.card(_content)
|
||||
@ -437,21 +456,23 @@ func _build_resource_overview() -> void:
|
||||
if is_instance_valid(inventory):
|
||||
for key in ["ammunition","missile","irradiated_ammunition","energy_bank"]: values[key] = inventory.get_crafted_stock(key)
|
||||
values.samples = captain.expedition.analysis_samples
|
||||
values.deuter = captain.expedition.deuter
|
||||
var names: Dictionary = RECIPES.NAMES.duplicate()
|
||||
names.merge(GEAR.MATERIAL_NAMES)
|
||||
names.merge({"credits":"Kredyty","parts":"Części","ammunition":"Amunicja","missile":"Rakiety","irradiated_ammunition":"Radiacyjna","energy_bank":"Powerbanki","samples":"Próbki"})
|
||||
names.merge({"credits":"Kredyty","parts":"Części","ammunition":"Amunicja","missile":"Rakiety","irradiated_ammunition":"Radiacyjna","energy_bank":"Powerbanki","samples":"Próbki","deuter":"Deuter"})
|
||||
for key in values:
|
||||
var tile := MENU.card(grid)
|
||||
tile.get_parent().name = "Stock_"+key
|
||||
var row := MENU.row(tile)
|
||||
var path := "res://assets/icons/resources/%s.%s" % [key,"svg" if key in ["credits","energy_bank"] else "png"]
|
||||
var path := "res://assets/icons/resources/%s.%s" % [key,"svg" if key in ["credits","energy_bank","deuter"] else "png"]
|
||||
if ResourceLoader.exists(path): MENU.icon(row,load(path),22)
|
||||
var labels := VBoxContainer.new()
|
||||
labels.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
row.add_child(labels)
|
||||
MENU.label(labels,str(names.get(key,key)),11,MENU.MUTED)
|
||||
MENU.label(labels,str(values[key]),13,MENU.GOLD)
|
||||
tile.get_parent().tooltip_text = "%s: %d" % [names.get(key,key),values[key]]
|
||||
var amount_label := MENU.label(labels,"%.1f" % values[key] if key == "deuter" else str(values[key]),13,MENU.GOLD)
|
||||
if key == "deuter": _economy_labels["stock"] = amount_label
|
||||
tile.get_parent().tooltip_text = "%s: %.1f" % [names.get(key,key),values[key]] if key == "deuter" else "%s: %d" % [names.get(key,key),values[key]]
|
||||
|
||||
func _transfer_all(retrieve: bool) -> void:
|
||||
if not is_instance_valid(inventory): return
|
||||
@ -547,17 +568,25 @@ func _build_workshop() -> void:
|
||||
button.disabled = equipped
|
||||
|
||||
func _build_command() -> void:
|
||||
var progress: Resource = captain.expedition
|
||||
_label("MOSTEK / SYSTEMY NAWIGACYJNE",13,Color("8bd9d0"))
|
||||
_label("Łączność z twoim statkiem jest stabilna. Fregata pozostaje gotowa do przejścia do kolejnego układu.")
|
||||
_label("Zeskanowane planety: %d" % progress.scans.size(),16)
|
||||
_label("Próbki do analizy w dziale badań obcych: %d" % progress.analysis_samples,15,UI.CYAN)
|
||||
_label("ODZYSKANE ARCHIWA",15,UI.CYAN)
|
||||
if progress.research_records.is_empty():
|
||||
_label("Brak odzyskanych zapisów.",13,Color("819ca5"))
|
||||
for key in progress.research_records:
|
||||
_label("%s ×%d" % [key,progress.research_records[key]],13)
|
||||
_label("Rozbudowa centrum dowodzenia oraz pozostałych sekcji będzie dostępna później.",13,Color("bc9e72"))
|
||||
preload("res://scripts/planets/freighter_command.gd").build(self)
|
||||
|
||||
func _travel_to_system(level: int) -> void:
|
||||
var controller := get_parent().get_parent()
|
||||
if controller.has_method("request_system_travel"): controller.request_system_travel(level)
|
||||
|
||||
func _assign_station(station_id: String, option: OptionButton) -> void:
|
||||
preload("res://scripts/planets/mining_network.gd").assign(captain.expedition, station_id, str(option.get_selected_metadata()))
|
||||
_refresh()
|
||||
|
||||
func _dismiss_crew(member_id: String) -> void:
|
||||
preload("res://scripts/planets/mining_network.gd").dismiss(captain.expedition, member_id)
|
||||
_refresh()
|
||||
|
||||
func _refresh_live_labels() -> void:
|
||||
for key in _economy_labels:
|
||||
var label: Label = _economy_labels[key]
|
||||
if not is_instance_valid(label): continue
|
||||
label.text = "Deuter: %.1f · Produkcja: %.0f/min" % [captain.expedition.deuter, preload("res://scripts/planets/mining_network.gd").total_rate(captain.expedition)] if key == "network" else "%.1f" % captain.expedition.deuter
|
||||
|
||||
func _craft(kind: String) -> void:
|
||||
if _tab != "workshop": return
|
||||
|
||||
92
scripts/planets/mining_network.gd
Normal file
@ -0,0 +1,92 @@
|
||||
extends RefCounted
|
||||
## The network belongs to expedition progress, so it survives visits and system travel.
|
||||
const BUILD_COST := 200
|
||||
const DEPOSIT_CHANCE := 0.60
|
||||
const CREW_CHANCE := 0.40
|
||||
const CABINS := ["cabin_1", "cabin_2", "cabin_3", "cabin_4", "cabin_5"]
|
||||
const FIRST_NAMES := ["Ada", "Mira", "Jan", "Leon", "Iga", "Oskar", "Nina", "Tomasz", "Sara", "Emil"]
|
||||
const LAST_NAMES := ["Nowak", "Voss", "Kowalski", "Orion", "Lis", "Ward", "Keller", "Wilk", "Stern", "Vale"]
|
||||
|
||||
static func planet_roll(profile: Dictionary, salt: int) -> RandomNumberGenerator:
|
||||
var rng := RandomNumberGenerator.new()
|
||||
rng.seed = int(profile.get("seed", 0)) ^ str(profile.get("id", "planet")).hash() ^ salt
|
||||
return rng
|
||||
|
||||
static func has_deep_deposit(profile: Dictionary) -> bool:
|
||||
return planet_roll(profile, 0x44454550).randf() < DEPOSIT_CHANCE
|
||||
|
||||
static func has_recruit(profile: Dictionary) -> bool:
|
||||
return planet_roll(profile, 0x43524557).randf() < CREW_CHANCE
|
||||
|
||||
static func recruit(profile: Dictionary) -> Dictionary:
|
||||
var rng := planet_roll(profile, 0x50455253)
|
||||
var rating := clampi(1 + roundi(clampf(float(profile.get("difficulty", 0)), 0, 1) * 80) + rng.randi_range(0, 19), 1, 100)
|
||||
return {"id":str(profile.id)+":crew", "name":FIRST_NAMES[rng.randi_range(0,9)]+" "+LAST_NAMES[rng.randi_range(0,9)], "management":rating, "planet_id":str(profile.id), "planet_name":str(profile.name), "cabin":""}
|
||||
|
||||
static func free_cabin(progress: Resource) -> String:
|
||||
for cabin in CABINS:
|
||||
if progress.freighter_rooms.get(cabin, "") != "crew_cabin": continue
|
||||
if cabin_crew(progress, cabin).is_empty(): return cabin
|
||||
return ""
|
||||
|
||||
static func cabin_crew(progress: Resource, cabin: String) -> Dictionary:
|
||||
for member in progress.crew.values():
|
||||
if str(member.cabin) == cabin: return member
|
||||
return {}
|
||||
|
||||
static func hire(progress: Resource, profile: Dictionary) -> bool:
|
||||
var candidate := recruit(profile)
|
||||
var cabin := free_cabin(progress)
|
||||
if not has_recruit(profile) or progress.recruited_planets.has(str(profile.id)) or cabin.is_empty(): return false
|
||||
candidate.cabin = cabin
|
||||
progress.crew[candidate.id] = candidate
|
||||
progress.recruited_planets[str(profile.id)] = true
|
||||
progress.emit_changed()
|
||||
return true
|
||||
|
||||
static func dismiss(progress: Resource, member_id: String) -> bool:
|
||||
if not progress.crew.has(member_id): return false
|
||||
for station in progress.mining_stations.values():
|
||||
if str(station.get("crew_id", "")) == member_id: station.crew_id = ""
|
||||
progress.crew.erase(member_id)
|
||||
progress.emit_changed()
|
||||
return true
|
||||
|
||||
static func build(progress: Resource, captain: Resource, profile: Dictionary, system: int) -> bool:
|
||||
var id := str(profile.id)
|
||||
if not has_deep_deposit(profile) or progress.mining_stations.has(id) or captain.parts < BUILD_COST: return false
|
||||
captain.parts -= BUILD_COST
|
||||
progress.mining_stations[id] = {"id":id, "planet_name":str(profile.name), "system":system, "crew_id":"", "produced":0.0}
|
||||
captain.emit_changed()
|
||||
progress.emit_changed()
|
||||
return true
|
||||
|
||||
static func assign(progress: Resource, station_id: String, member_id: String) -> bool:
|
||||
if not progress.mining_stations.has(station_id): return false
|
||||
if not member_id.is_empty() and not progress.crew.has(member_id): return false
|
||||
if not member_id.is_empty():
|
||||
for station in progress.mining_stations.values():
|
||||
if str(station.get("crew_id", "")) == member_id: station.crew_id = ""
|
||||
progress.mining_stations[station_id].crew_id = member_id
|
||||
progress.emit_changed()
|
||||
return true
|
||||
|
||||
static func station_rate(progress: Resource, station: Dictionary) -> float:
|
||||
var id := str(station.get("crew_id", ""))
|
||||
if not progress.crew.has(id): return 0.0
|
||||
return 1.0 + clampi(int(progress.crew[id].management), 1, 100)
|
||||
|
||||
static func total_rate(progress: Resource) -> float:
|
||||
var total := 0.0
|
||||
for station in progress.mining_stations.values(): total += station_rate(progress, station)
|
||||
return total
|
||||
|
||||
static func advance(progress: Resource, seconds: float) -> float:
|
||||
if seconds <= 0: return 0
|
||||
var gained := 0.0
|
||||
for station in progress.mining_stations.values():
|
||||
var amount := station_rate(progress, station) * seconds / 60.0
|
||||
station.produced = float(station.get("produced", 0)) + amount
|
||||
gained += amount
|
||||
progress.deuter += gained
|
||||
return gained
|
||||
1
scripts/planets/mining_network.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bt35et03ccbgg
|
||||
@ -8,7 +8,11 @@ const PROFILES := preload("res://scripts/planets/planet_profiles.gd")
|
||||
@export var delivered_modules: Array[Resource] = []
|
||||
@export var research_records: Dictionary = {}
|
||||
@export var alien_skills: Dictionary = {}
|
||||
@export var freighter_rooms: Dictionary = {}
|
||||
@export var freighter_rooms: Dictionary = {"expansion_3":"module_storage"}
|
||||
@export var mining_stations: Dictionary = {}
|
||||
@export var crew: Dictionary = {}
|
||||
@export var recruited_planets: Dictionary = {}
|
||||
@export var deuter := 0.0
|
||||
@export var freighter_storage: Array[Resource] = []
|
||||
@export var delivered_missiles := 0
|
||||
@export var analysis_samples := 0
|
||||
@ -70,7 +74,7 @@ func add_material(key: String, amount: int) -> void:
|
||||
emit_changed()
|
||||
|
||||
func resolve_poi(captain: Resource, poi: Dictionary, rng: RandomNumberGenerator) -> Dictionary:
|
||||
if not active or bool(poi.get("complete", false)):
|
||||
if not active or bool(poi.get("complete", false)) or not preload("res://scripts/planets/poi_rules.gd").STAGES.has(str(poi.get("kind", ""))):
|
||||
return {}
|
||||
var stage := int(poi.get("stage", 0))
|
||||
var chance := PROFILES.success_chance(active_profile, captain, stage)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
extends RefCounted
|
||||
const NAMES := {"deposit":"Złoże surowców", "ruins":"Starożytna struktura", "warehouse":"Opuszczony magazyn", "village":"Opuszczona wioska", "cave":"Jaskinia"}
|
||||
const NAMES := {"deposit":"Złoże surowców", "ruins":"Starożytna struktura", "warehouse":"Opuszczony magazyn", "village":"Opuszczona wioska", "cave":"Jaskinia", "deep_deposit":"Głębokie złoże deuteru", "crew":"Obóz specjalisty"}
|
||||
const STAGES := {
|
||||
"deposit":["Zbierz odsłonięte minerały", "Wykonaj odwiert", "Wydobądź głęboką żyłę"],
|
||||
"ruins":["Przeszukaj przedsionek", "Otwórz komorę", "Zbadaj rdzeń"],
|
||||
|
||||
@ -58,6 +58,9 @@ static func generate(seed_value: int, profile: Dictionary) -> Dictionary:
|
||||
var natural_count := rng.randi_range(MIN_NATURAL_POIS, MAX_NATURAL_POIS)
|
||||
for extra in range(natural_count - 4):
|
||||
kinds.append("cave" if rng.randf() < 0.5 else "deposit")
|
||||
var network := preload("res://scripts/planets/mining_network.gd")
|
||||
if network.has_deep_deposit(profile): kinds.append("deep_deposit")
|
||||
if network.has_recruit(profile): kinds.append("crew")
|
||||
for index in kinds.size():
|
||||
var kind: String = kinds[index]
|
||||
var chosen := Vector2.ZERO
|
||||
|
||||
@ -20,7 +20,10 @@ func _draw() -> void:
|
||||
for poi in world.data.pois:
|
||||
if poi.discovered:
|
||||
var at: Vector2 = (poi.position / total + Vector2.ONE * 0.5) * size
|
||||
draw_circle(at, 2.5, Color("708377") if poi.complete else Color("f4cb80"))
|
||||
var color := Color("708377") if poi.complete else Color("f4cb80")
|
||||
if poi.kind == "deep_deposit": color = Color("84dff3")
|
||||
elif poi.kind == "crew" and not poi.complete: color = Color("a7e5a2")
|
||||
draw_circle(at, 3.0 if poi.kind == "deep_deposit" else 2.5, color)
|
||||
for event in world.data.events:
|
||||
if not event.complete:
|
||||
var at: Vector2 = (event.position/total+Vector2.ONE*0.5)*size
|
||||
|
||||
@ -58,7 +58,9 @@ func _ready() -> void:
|
||||
container.texture = viewport.get_texture()
|
||||
world = Node2D.new()
|
||||
world.set_script(preload("res://scripts/planets/surface_world.gd"))
|
||||
world.data = GENERATOR.generate(progress.visit_seed, progress.active_profile)
|
||||
world.data = GENERATOR.generate(int(progress.active_profile.seed), progress.active_profile)
|
||||
for poi in world.data.pois:
|
||||
if poi.kind == "crew" and progress.recruited_planets.has(str(progress.active_profile.id)): poi.complete = true
|
||||
viewport.add_child(world)
|
||||
lander = Sprite2D.new()
|
||||
lander.physics_interpolation_mode = Node.PHYSICS_INTERPOLATION_MODE_ON
|
||||
@ -226,6 +228,9 @@ func _show_poi(message := "") -> void:
|
||||
POI_CARD.panel_style(_dialog)
|
||||
_choices.add_theme_constant_override("separation",8)
|
||||
_layout_dialog()
|
||||
if _poi.kind in ["deep_deposit", "crew"]:
|
||||
_show_colony_poi(message)
|
||||
return
|
||||
var stage := clampi(int(_poi.stage),0,2)
|
||||
POI_CARD.header(_choices,str(_poi.kind),stage,bool(_poi.complete))
|
||||
if not message.is_empty():
|
||||
@ -400,3 +405,54 @@ func _resize_surface_viewport() -> void:
|
||||
_layout_dialog()
|
||||
if is_instance_valid(_surface_viewport):
|
||||
_surface_viewport.size = Vector2i(Vector2(maxf(1,size.x),maxf(1,size.y))*SURFACE_RENDER_SCALE)
|
||||
|
||||
func _show_colony_poi(message: String) -> void:
|
||||
var network := preload("res://scripts/planets/mining_network.gd")
|
||||
var is_deposit: bool = _poi.kind == "deep_deposit"
|
||||
var art := TextureRect.new()
|
||||
art.texture = load("res://assets/planets/props/deuterium_outpost.png" if is_deposit else "res://assets/planets/props/engineer_camp.png")
|
||||
art.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
art.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
art.custom_minimum_size.y = 170
|
||||
_choices.add_child(art)
|
||||
POI_CARD.text(_choices, "GŁĘBOKIE ZŁOŻE / DEUTER" if is_deposit else "SPECJALISTA / REKRUTACJA", 15, POI_CARD.GOLD)
|
||||
if not message.is_empty(): POI_CARD.text(_choices, message, 13, POI_CARD.GOLD)
|
||||
if is_deposit:
|
||||
var id := str(progress.active_profile.id)
|
||||
if progress.mining_stations.has(id):
|
||||
var station: Dictionary = progress.mining_stations[id]
|
||||
POI_CARD.text(_choices, "Placówka zbudowana · %.0f deuteru/min" % network.station_rate(progress, station), 13)
|
||||
POI_CARD.text(_choices, "Przydziel załoganta w centrum dowodzenia fregaty. Deuter trafia automatycznie do magazynu, również gdy jesteś poza tą planetą.", 12)
|
||||
else:
|
||||
POI_CARD.text(_choices, "Pod powierzchnią znajduje się głęboki pokład deuteru. Placówka wymaga 200 części i załoganta do zarządzania.", 13)
|
||||
POI_CARD.text(_choices, "Bazowo 1 deuter/min + punkty zarządzania załoganta. Części: %d / 200" % int(captain.parts), 12)
|
||||
var build := POI_CARD.button(_choices, "ZBUDUJ PLACÓWKĘ · 200 CZĘŚCI", _build_outpost, true)
|
||||
build.name = "BuildMiningOutpost"
|
||||
build.disabled = captain.parts < network.BUILD_COST
|
||||
else:
|
||||
var candidate: Dictionary = network.recruit(progress.active_profile)
|
||||
POI_CARD.text(_choices, "%s\nZarządzanie: %d / 100\nPremia do wydobycia: +%d deuteru/min" % [candidate.name, candidate.management, candidate.management], 14)
|
||||
if progress.recruited_planets.has(str(progress.active_profile.id)):
|
||||
POI_CARD.text(_choices, "Specjalista został już zatrudniony.", 12)
|
||||
else:
|
||||
var cabin: String = network.free_cabin(progress)
|
||||
POI_CARD.text(_choices, "Brak wolnej, zbudowanej kajuty. Przygotuj pokój na fregacie." if cabin.is_empty() else "Zakwaterowanie: Kajuta %02d" % int(cabin.trim_prefix("cabin_")), 12)
|
||||
var hire := POI_CARD.button(_choices, "ZATRUDNIJ ZAŁOGANTA", _hire_crew, true)
|
||||
hire.name = "HireCrew"
|
||||
hire.disabled = cabin.is_empty()
|
||||
POI_CARD.button(_choices, "Wróć do wyprawy", func(): _dialog.hide())
|
||||
|
||||
func _build_outpost() -> void:
|
||||
if _ending or not progress.active or _poi.kind != "deep_deposit": return
|
||||
var network := preload("res://scripts/planets/mining_network.gd")
|
||||
if network.build(progress, captain, progress.active_profile, GameState.system_level):
|
||||
world.refresh_pois(lander.position)
|
||||
_show_poi("Placówka gotowa. Przydziel operatora w centrum dowodzenia.")
|
||||
else: _show_poi("Nie można zbudować placówki. Sprawdź liczbę części.")
|
||||
|
||||
func _hire_crew() -> void:
|
||||
if _ending or not progress.active or _poi.kind != "crew": return
|
||||
if preload("res://scripts/planets/mining_network.gd").hire(progress, progress.active_profile):
|
||||
_poi.complete = true
|
||||
_show_poi("Załogant zajął wolną kajutę na fregacie.")
|
||||
else: _show_poi("Zatrudnienie wymaga wolnej, zbudowanej kajuty.")
|
||||
|
||||
@ -61,7 +61,7 @@ func _ready() -> void:
|
||||
add_child(tree_canopy)
|
||||
for poi in data.pois:
|
||||
var sprite := Sprite2D.new()
|
||||
if poi.kind == "deposit":
|
||||
if poi.kind in ["deposit", "deep_deposit"]:
|
||||
sprite.set_script(preload("res://scripts/planets/surface_deposit.gd"))
|
||||
sprite.configure(data,poi)
|
||||
else:
|
||||
@ -69,7 +69,7 @@ func _ready() -> void:
|
||||
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"}
|
||||
var textures := {"ruins":"ruins", "warehouse":"props/warehouse", "village":"landmarks/abandoned_hamlet", "crew":"props/engineer_camp"}
|
||||
sprite.texture = load("res://assets/planets/%s.png" % textures[poi.kind])
|
||||
sprite.position = poi.position
|
||||
if sprite.texture != null and poi.kind != "cave":
|
||||
@ -140,8 +140,19 @@ func refresh_pois(lander_position: Vector2) -> void:
|
||||
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)
|
||||
label.text = "Placówka górnicza" if built else "Głębokie złoże deuteru"
|
||||
if lander_position.distance_to(poi.position) <= 150: label.text += "\n[F] Placówka" if built else "\n[F] Buduj"
|
||||
continue
|
||||
var title: String = preload("res://scripts/planets/poi_rules.gd").NAMES[poi.kind]
|
||||
label.text = title + (" · zbadano" if poi.complete else ("\n[F] Zbadaj" if lander_position.distance_to(poi.position) <= 150 else ""))
|
||||
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:
|
||||
|
||||
84
tests/levels/freighter_navigation_test.gd
Normal file
@ -0,0 +1,84 @@
|
||||
extends Node
|
||||
const NETWORK := preload("res://scripts/planets/mining_network.gd")
|
||||
const PROFILES := preload("res://scripts/planets/planet_profiles.gd")
|
||||
|
||||
func settle() -> void:
|
||||
for frame in 20: await get_tree().process_frame
|
||||
|
||||
func stop_game(game: Node) -> void:
|
||||
game.set_physics_process(false)
|
||||
game.player.set_physics_process(false)
|
||||
game.player.get_node("WeaponController").set_physics_process(false)
|
||||
for enemy in get_tree().get_nodes_in_group("enemies"): enemy.set_physics_process(false)
|
||||
|
||||
func _ready() -> void:
|
||||
GameState.start_new_run()
|
||||
GameState.set_process(false)
|
||||
GameState.system_seed = 12345
|
||||
GameState.remember_system()
|
||||
GameState.system_level = 3
|
||||
GameState.system_seed = 54321
|
||||
GameState.remember_system()
|
||||
GameState.system_level = 1
|
||||
GameState.system_seed = 12345
|
||||
GameState.cleared_systems[1] = true
|
||||
var captain: Resource = GameState.captain
|
||||
var profile: Dictionary
|
||||
for index in 100:
|
||||
var candidate := PROFILES.generate(12345, index, "Placówka testowa")
|
||||
if NETWORK.has_recruit(candidate) and NETWORK.has_deep_deposit(candidate):
|
||||
profile = candidate
|
||||
break
|
||||
captain.expedition.freighter_rooms.cabin_1 = "crew_cabin"
|
||||
captain.parts = 200
|
||||
assert(NETWORK.hire(captain.expedition, profile))
|
||||
assert(NETWORK.build(captain.expedition, captain, profile, 1))
|
||||
var member: Dictionary = NETWORK.cabin_crew(captain.expedition, "cabin_1")
|
||||
NETWORK.assign(captain.expedition, profile.id, member.id)
|
||||
NETWORK.advance(captain.expedition, 60)
|
||||
var stock: float = captain.expedition.deuter
|
||||
get_tree().current_scene = null
|
||||
var game := preload("res://scenes/game/game.tscn").instantiate()
|
||||
get_tree().root.add_child.call_deferred(game)
|
||||
await settle()
|
||||
get_tree().current_scene = game
|
||||
stop_game(game)
|
||||
assert(game.system_cleared and game.get_remaining_enemies() == 0)
|
||||
var layout: Dictionary = game.system_data
|
||||
var inventory = game.player.get_node("ShipInventory")
|
||||
inventory.ammunition = 321
|
||||
var manager = game.get_node("PlanetExpeditions")
|
||||
manager.open_freighter()
|
||||
manager.screen._select_section("command")
|
||||
assert(manager.screen._content.find_child("SystemDestination", true, false).item_count == 3)
|
||||
assert(not manager.request_system_travel(4))
|
||||
assert(is_instance_valid(manager.screen))
|
||||
var destination: OptionButton = manager.screen._content.find_child("SystemDestination", true, false)
|
||||
destination.select(2)
|
||||
destination.item_selected.emit(2)
|
||||
var travel: Button = manager.screen._content.find_child("TravelToSystem", true, false)
|
||||
assert(not travel.disabled)
|
||||
travel.pressed.emit()
|
||||
await settle()
|
||||
game = get_tree().current_scene
|
||||
stop_game(game)
|
||||
assert(GameState.system_level == 3 and GameState.system_seed == 54321 and GameState.highest_system == 3)
|
||||
assert(GameState.captain == captain and captain.expedition.deuter == stock)
|
||||
assert(game.player.get_node("ShipInventory").ammunition == 321)
|
||||
assert(captain.expedition.mining_stations[profile.id].crew_id == member.id)
|
||||
manager = game.get_node("PlanetExpeditions")
|
||||
manager.open_freighter()
|
||||
assert(manager.request_system_travel(1))
|
||||
await settle()
|
||||
game = get_tree().current_scene
|
||||
stop_game(game)
|
||||
assert(GameState.system_level == 1 and GameState.system_seed == 12345)
|
||||
assert(game.system_cleared and game.get_remaining_enemies() == 0)
|
||||
assert(game.system_data.star_name == layout.star_name)
|
||||
assert(game.system_data.planets[0].profile == layout.planets[0].profile)
|
||||
assert(captain.expedition.deuter == stock and captain.expedition.crew.size() == 1)
|
||||
assert(not game.travel_to_system(4))
|
||||
get_tree().current_scene = self
|
||||
game.free()
|
||||
print("FREIGHTER_NAVIGATION_TEST_OK: real scene reload 1 -> 3 -> 1, unlocked cap, original seeds and planet identities, cleared systems, inventory, crew, stations and deuter retained")
|
||||
get_tree().quit()
|
||||
1
tests/levels/freighter_navigation_test.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://w7bjpxclh38j
|
||||
5
tests/levels/freighter_navigation_test.tscn
Normal file
@ -0,0 +1,5 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/levels/freighter_navigation_test.gd" id="1"]
|
||||
[node name="FreighterNavigationTest" type="Node"]
|
||||
process_mode = 3
|
||||
script = ExtResource("1")
|
||||
87
tests/levels/mining_network_test.gd
Normal file
@ -0,0 +1,87 @@
|
||||
extends Node
|
||||
const NETWORK := preload("res://scripts/planets/mining_network.gd")
|
||||
const PROGRESS := preload("res://scripts/planets/planet_progress.gd")
|
||||
const PROFILES := preload("res://scripts/planets/planet_profiles.gd")
|
||||
|
||||
func _ready() -> void:
|
||||
GameState.start_new_run()
|
||||
GameState.set_process(false)
|
||||
var captain: Resource = GameState.captain
|
||||
var progress: Resource = captain.expedition
|
||||
assert(progress.freighter_rooms.expansion_3 == "module_storage")
|
||||
var profiles: Array[Dictionary] = []
|
||||
var deposits := 0
|
||||
for index in 1000:
|
||||
var profile := PROFILES.generate(87654, index, "Planeta %d" % index)
|
||||
profiles.append(profile)
|
||||
deposits += int(NETWORK.has_deep_deposit(profile))
|
||||
assert(NETWORK.has_deep_deposit(profile) == NETWORK.has_deep_deposit(profile.duplicate(true)))
|
||||
var easy: Dictionary = profile.duplicate(true)
|
||||
var hard: Dictionary = profile.duplicate(true)
|
||||
easy.difficulty = 0
|
||||
hard.difficulty = 1
|
||||
assert(NETWORK.recruit(easy).management in range(1, 21))
|
||||
assert(NETWORK.recruit(hard).management in range(81, 101))
|
||||
assert(deposits > 540 and deposits < 660)
|
||||
var source: Dictionary = profiles.filter(func(p): return NETWORK.has_recruit(p) and NETWORK.has_deep_deposit(p))[0]
|
||||
assert(not NETWORK.hire(progress, source))
|
||||
progress.freighter_rooms.cabin_1 = "crew_cabin"
|
||||
assert(NETWORK.hire(progress, source))
|
||||
assert(not NETWORK.hire(progress, source))
|
||||
var member: Dictionary = NETWORK.cabin_crew(progress, "cabin_1")
|
||||
assert(not member.is_empty() and NETWORK.free_cabin(progress).is_empty())
|
||||
captain.parts = 199
|
||||
assert(not NETWORK.build(progress, captain, source, 1) and captain.parts == 199)
|
||||
captain.parts = 400
|
||||
assert(NETWORK.build(progress, captain, source, 1) and captain.parts == 200)
|
||||
assert(not NETWORK.build(progress, captain, source, 1) and captain.parts == 200)
|
||||
assert(NETWORK.advance(progress, 600) == 0 and progress.deuter == 0)
|
||||
assert(NETWORK.assign(progress, source.id, member.id))
|
||||
var expected: float = 1 + int(member.management)
|
||||
NETWORK.advance(progress, 30)
|
||||
assert(is_equal_approx(progress.deuter, expected * 0.5))
|
||||
NETWORK.advance(progress, 30)
|
||||
assert(is_equal_approx(progress.deuter, expected))
|
||||
var second: Dictionary = profiles.filter(func(p): return NETWORK.has_deep_deposit(p) and p.id != source.id)[0]
|
||||
assert(NETWORK.build(progress, captain, second, 2) and captain.parts == 0)
|
||||
assert(NETWORK.assign(progress, second.id, member.id))
|
||||
assert(progress.mining_stations[source.id].crew_id == "")
|
||||
assert(NETWORK.total_rate(progress) == expected)
|
||||
assert(not NETWORK.assign(progress, source.id, "unknown"))
|
||||
var path := "res://tmp/mining_roundtrip.tres"
|
||||
assert(ResourceSaver.save(progress, path) == OK)
|
||||
var restored: Resource = ResourceLoader.load(path, "", ResourceLoader.CACHE_MODE_IGNORE)
|
||||
assert(restored.deuter == progress.deuter and restored.crew == progress.crew and restored.mining_stations == progress.mining_stations)
|
||||
var game := preload("res://scenes/game/game.tscn").instantiate()
|
||||
add_child(game)
|
||||
game.set_physics_process(false)
|
||||
game.player.set_physics_process(false)
|
||||
for enemy in get_tree().get_nodes_in_group("enemies"): enemy.set_physics_process(false)
|
||||
var before: float = progress.deuter
|
||||
GameState.advance_play_time(60, game)
|
||||
assert(is_equal_approx(progress.deuter - before, expected))
|
||||
get_tree().paused = true
|
||||
before = progress.deuter
|
||||
GameState.advance_play_time(60, game)
|
||||
assert(progress.deuter == before)
|
||||
var expeditions := game.get_node("PlanetExpeditions")
|
||||
expeditions.open_freighter()
|
||||
GameState.advance_play_time(60, game)
|
||||
assert(is_equal_approx(progress.deuter - before, expected))
|
||||
expeditions._leave()
|
||||
assert(progress.begin_visit(source))
|
||||
expeditions._enter()
|
||||
expeditions.screen = Control.new()
|
||||
expeditions._layer.add_child(expeditions.screen)
|
||||
before = progress.deuter
|
||||
GameState.advance_play_time(60, game)
|
||||
assert(is_equal_approx(progress.deuter - before, expected))
|
||||
progress.finish_visit(captain, true)
|
||||
assert(NETWORK.dismiss(progress, member.id))
|
||||
assert(NETWORK.total_rate(progress) == 0 and NETWORK.free_cabin(progress) == "cabin_1")
|
||||
assert(not NETWORK.hire(progress, source))
|
||||
expeditions._leave()
|
||||
get_tree().paused = false
|
||||
game.free()
|
||||
print("MINING_NETWORK_TEST_OK: 60%% stable sites (%d/1000), rating 1-100 by biome, cabins, hiring, 200 parts, assignment, 1+rating/min, game-time clock and pause, dismissal, resource persistence" % deposits)
|
||||
get_tree().quit()
|
||||
1
tests/levels/mining_network_test.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bm0jfqrvvtnnk
|
||||
5
tests/levels/mining_network_test.tscn
Normal file
@ -0,0 +1,5 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/levels/mining_network_test.gd" id="1"]
|
||||
[node name="MiningNetworkTest" type="Node"]
|
||||
process_mode = 3
|
||||
script = ExtResource("1")
|
||||
@ -49,7 +49,7 @@ func _ready() -> void:
|
||||
assert(GEAR.equip(captain,"breathing",crafted.uid))
|
||||
assert(GEAR.level(captain,"breathing") == 2)
|
||||
var world: Dictionary = SURFACE.generate(11447,profile)
|
||||
assert(world.pois.size() >= 6 and world.pois.size() <= 7 and world.trees.size() > 0 and world.mountains.size() > 0 and world.structures.size() > 0)
|
||||
assert(world.pois.size() >= 8 and world.pois.size() <= 16 and world.trees.size() > 0 and world.mountains.size() > 0 and world.structures.size() > 0)
|
||||
assert(SURFACE.generate(11447,profile).pois == world.pois)
|
||||
assert(SURFACE.generate(11448,profile).pois != world.pois)
|
||||
for seed_value in 100:
|
||||
@ -119,7 +119,7 @@ func _ready() -> void:
|
||||
manager.scan_nearby()
|
||||
manager.land_nearby()
|
||||
assert(get_tree().paused and GameState.captain.expedition.active)
|
||||
assert(manager.screen.world.data.pois.size() >= 6 and manager.screen.world.data.pois.size() <= 7)
|
||||
assert(manager.screen.world.data.pois.size() >= 8 and manager.screen.world.data.pois.size() <= 16)
|
||||
assert(manager.screen.planet_texture == manager._near_planet.body_texture)
|
||||
assert(manager.screen._telemetry.portrait.texture == manager._near_planet.body_texture)
|
||||
for poi in manager.screen.world.data.pois:
|
||||
|
||||
@ -11,7 +11,7 @@ func _ready() -> void:
|
||||
GameState.system_level = 20
|
||||
assert(state.begin_visit(profile))
|
||||
var samples_before := 0
|
||||
for kind in RULES.NAMES:
|
||||
for kind in RULES.STAGES:
|
||||
for stage in 3:
|
||||
var success := false
|
||||
for attempt in 100:
|
||||
|
||||
@ -9,7 +9,7 @@ func _ready() -> void:
|
||||
var profile: Dictionary = preload("res://scripts/planets/planet_profiles.gd").generate(711,index,"Test")
|
||||
var data: Dictionary = GENERATOR.generate(500+index,profile)
|
||||
var counts := {"warehouse":0,"village":0,"cave":0,"ruins":0,"deposit":0}
|
||||
for poi in data.pois: counts[poi.kind] += 1
|
||||
for poi in data.pois: counts[poi.kind] = int(counts.get(poi.kind, 0)) + 1
|
||||
for poi in data.pois:
|
||||
if poi.kind != "cave": continue
|
||||
assert(poi.has("mountain_position"))
|
||||
|
||||
@ -10,7 +10,8 @@ func _ready() -> void:
|
||||
assert(manager.freighter.find_children("*","Label",true,false).is_empty())
|
||||
manager.open_freighter()
|
||||
var screen: Control = manager.screen
|
||||
for section in ["expansion_1","expansion_2","expansion_3","cabin_1","cabin_2","cabin_3","cabin_4","cabin_5"]:
|
||||
assert(screen.deck.is_built("expansion_3"))
|
||||
for section in ["expansion_1","expansion_2","cabin_1","cabin_2","cabin_3","cabin_4","cabin_5"]:
|
||||
screen._select_section(section)
|
||||
for frame in 8: await get_tree().process_frame
|
||||
for mineral in preload("res://scripts/items/crafting_recipes.gd").MINERALS:
|
||||
@ -26,5 +27,5 @@ func _ready() -> void:
|
||||
manager.screen.closed.emit()
|
||||
game.free()
|
||||
await get_tree().process_frame
|
||||
print("CONSTRUCTION_LAYOUT_OK: no freighter label, all eight rooms, five single-line costs, full cost table visible")
|
||||
print("CONSTRUCTION_LAYOUT_OK: no freighter label, seven unbuilt rooms and default storage, five single-line costs, full cost table visible")
|
||||
get_tree().quit()
|
||||
|
||||
101
tests/previews/mining_colony_review.gd
Normal file
@ -0,0 +1,101 @@
|
||||
extends Node
|
||||
const NETWORK := preload("res://scripts/planets/mining_network.gd")
|
||||
const PROFILES := preload("res://scripts/planets/planet_profiles.gd")
|
||||
|
||||
func settle() -> void:
|
||||
for frame in 12: await get_tree().process_frame
|
||||
|
||||
func shot(file: String) -> void:
|
||||
await settle()
|
||||
await RenderingServer.frame_post_draw
|
||||
get_viewport().get_texture().get_image().save_png("res://artifacts/mining_%s.png" % file)
|
||||
|
||||
func _ready() -> void:
|
||||
GameState.start_new_run()
|
||||
GameState.set_process(false)
|
||||
var captain: Resource = GameState.captain
|
||||
var progress: Resource = captain.expedition
|
||||
var profile: Dictionary
|
||||
for index in 100:
|
||||
var p := PROFILES.generate(654321, index, "Asterion")
|
||||
if NETWORK.has_recruit(p) and NETWORK.has_deep_deposit(p):
|
||||
profile = p
|
||||
break
|
||||
var game := preload("res://scenes/game/game.tscn").instantiate()
|
||||
add_child(game)
|
||||
game.set_physics_process(false)
|
||||
game.player.set_physics_process(false)
|
||||
game.player.get_node("WeaponController").set_physics_process(false)
|
||||
for enemy in get_tree().get_nodes_in_group("enemies"): enemy.set_physics_process(false)
|
||||
var controller := game.get_node("PlanetExpeditions")
|
||||
assert(progress.begin_visit(profile))
|
||||
controller._enter()
|
||||
var surface := Control.new()
|
||||
surface.set_script(preload("res://scripts/planets/surface_screen.gd"))
|
||||
surface.captain = captain
|
||||
surface.progress = progress
|
||||
surface.flight_ship = game.player
|
||||
surface.finished.connect(controller.finish_surface)
|
||||
controller.screen = surface
|
||||
controller._layer.add_child(surface)
|
||||
await settle()
|
||||
surface.weather.set_condition("clear", true)
|
||||
var deposit: Dictionary = surface.world.data.pois.filter(func(p): return p.kind == "deep_deposit")[0]
|
||||
var camp: Dictionary = surface.world.data.pois.filter(func(p): return p.kind == "crew")[0]
|
||||
surface._poi = deposit
|
||||
surface.lander.position = deposit.position
|
||||
surface._previous_position = deposit.position
|
||||
surface.camera.position = deposit.position
|
||||
surface.camera.reset_smoothing()
|
||||
captain.parts = 199
|
||||
surface._show_poi()
|
||||
assert(surface._choices.find_child("BuildMiningOutpost", true, false).disabled)
|
||||
captain.parts = 200
|
||||
surface._show_poi()
|
||||
await shot("construction")
|
||||
surface._choices.find_child("BuildMiningOutpost", true, false).pressed.emit()
|
||||
assert(progress.mining_stations.size() == 1 and captain.parts == 0)
|
||||
assert(surface.world._poi_sprites[deposit.id].get_meta("outpost", false))
|
||||
await shot("built_outpost")
|
||||
surface._poi = camp
|
||||
surface._show_poi()
|
||||
assert(surface._choices.find_child("HireCrew", true, false).disabled)
|
||||
progress.freighter_rooms.cabin_1 = "crew_cabin"
|
||||
surface._show_poi()
|
||||
await shot("recruitment")
|
||||
surface._choices.find_child("HireCrew", true, false).pressed.emit()
|
||||
assert(progress.crew.size() == 1 and NETWORK.free_cabin(progress).is_empty())
|
||||
surface._return(true)
|
||||
await settle()
|
||||
controller.open_freighter()
|
||||
var screen: Control = controller.screen
|
||||
screen._select_section("command")
|
||||
await settle()
|
||||
var member: Dictionary = NETWORK.cabin_crew(progress, "cabin_1")
|
||||
var option: OptionButton = screen._content.find_child("StationCrew_"+str(profile.id).md5_text().substr(0, 8), true, false)
|
||||
assert(option.item_count == 2)
|
||||
option.select(1)
|
||||
screen._assign_station(profile.id, option)
|
||||
NETWORK.advance(progress, 60)
|
||||
progress.emit_changed()
|
||||
assert(progress.deuter == 1 + member.management)
|
||||
await shot("command")
|
||||
assert(screen._drawer.size.x <= 490 and screen._drawer.get_global_rect().end.y <= 721)
|
||||
screen._select_section("storage")
|
||||
await settle()
|
||||
assert(screen._economy_labels.has("stock_header"))
|
||||
var before: String = screen._economy_labels.stock_header.text
|
||||
NETWORK.advance(progress, 60)
|
||||
progress.emit_changed()
|
||||
assert(screen._economy_labels.stock_header.text != before)
|
||||
await shot("storage")
|
||||
screen._select_section("cabin_1")
|
||||
await shot("cabin")
|
||||
assert(screen._content.find_children("*", "Button", true, false).size() == 1)
|
||||
screen._dismiss_crew(member.id)
|
||||
assert(progress.crew.is_empty() and NETWORK.total_rate(progress) == 0)
|
||||
controller._leave()
|
||||
game.free()
|
||||
get_tree().paused = false
|
||||
print("MINING_COLONY_REVIEW_OK: surface construction gate and sprite, hiring gate and cabin, station assignment, live storage, cabin dismissal and compact layout")
|
||||
get_tree().quit()
|
||||
1
tests/previews/mining_colony_review.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://ndvsst8pe2wb
|
||||
5
tests/previews/mining_colony_review.tscn
Normal file
@ -0,0 +1,5 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/previews/mining_colony_review.gd" id="1"]
|
||||
[node name="MiningColonyReview" type="Node"]
|
||||
process_mode = 3
|
||||
script = ExtResource("1")
|
||||