Randoloot/scripts/planets/freighter_screen.gd
2026-10-25 12:34:56 +01:00

638 lines
29 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends Control
signal closed
const UI := preload("res://scripts/planets/expedition_ui.gd")
const MENU := preload("res://scripts/planets/freighter_menu.gd")
const GEAR := preload("res://scripts/planets/captain_equipment.gd")
const RECIPES := preload("res://scripts/items/crafting_recipes.gd")
const CATALOG := preload("res://scripts/game/ship_catalog.gd")
var captain: Resource
var inventory: Node
var _content: VBoxContainer
var _tab := "overview"
var _drawer: PanelContainer
var _drawer_title: Label
var _wallet: Label
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:
offset_top = preload("res://scripts/ui/resource_bar.gd").HEIGHT
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)
var chassis := CATALOG.for_path(GameState.selected_ship_path)
deck.ship_name = str(chassis.name)
var sprite: Sprite2D
if is_instance_valid(inventory):
var ship: Node = inventory.get_parent()
sprite = ship.get_node_or_null("Sprite2D") as Sprite2D
deck.ship_texture = sprite.texture if sprite != null else load(CATALOG.texture_path(chassis))
if sprite != null:
deck.ship_name = str(CATALOG.for_path(sprite.texture.resource_path).name)
_build_header()
_build_footer()
_build_drawer()
resized.connect(_layout)
captain.changed.connect(_sync_header)
_sync_header()
_layout()
_refresh()
func _build_header() -> void:
var header := HBoxContainer.new()
header.name = "Header"
header.set_anchors_and_offsets_preset(Control.PRESET_TOP_WIDE)
header.offset_left = 26
header.offset_right = -26
header.offset_top = 20
header.add_theme_constant_override("separation",22)
add_child(header)
var heading := VBoxContainer.new()
heading.size_flags_horizontal = Control.SIZE_EXPAND_FILL
header.add_child(heading)
MENU.label(heading,"FREGATA / POKŁAD OPERACYJNY",24,Color("e3e9e8"))
MENU.label(heading,"01 / POKŁAD GŁÓWNY · POŁĄCZENIE ZABEZPIECZONE",11,Color("77969f"))
_wallet = MENU.label(header,"",13,Color("c9aa7c"))
_wallet.custom_minimum_size.x = 150
_wallet.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
var storage_button := MENU.button(header,"MAGAZYN",func(): _select_section("storage"))
storage_button.custom_minimum_size.x = 100
storage_button.size_flags_vertical = Control.SIZE_SHRINK_CENTER
if not GameState.active_distant_map.is_empty():
var return_button := MENU.button(header,"POWRÓT Z WYPRAWY",_return_from_distant,true)
return_button.name = "ReturnFromDistant"
return_button.size_flags_vertical = Control.SIZE_SHRINK_CENTER
return_button.tooltip_text = "Zakończ wyprawę i wróć do układu startowego. Powrót jest bezpłatny."
var leave := MENU.button(header,"ODLOT [L]",func(): closed.emit())
leave.custom_minimum_size.x = 110
leave.size_flags_vertical = Control.SIZE_SHRINK_CENTER
func _build_footer() -> void:
var footer := HBoxContainer.new()
footer.name = "Footer"
footer.set_anchors_and_offsets_preset(Control.PRESET_BOTTOM_WIDE)
footer.offset_left = 26
footer.offset_right = -26
footer.offset_top = -43
footer.offset_bottom = -12
add_child(footer)
_hint = MENU.label(footer,"Wybierz pomieszczenie na pokładzie. · Warsztat i hangar są dostępne.",12,Color("91a9ae"))
_hint.size_flags_horizontal = Control.SIZE_EXPAND_FILL
footer.add_theme_constant_override("separation",18)
MENU.label(footer,"● OPERACYJNE",11,Color("79d9d8")).custom_minimum_size.x = 110
MENU.label(footer,"● W REMONCIE",11,Color("bca078")).custom_minimum_size.x = 110
func _build_drawer() -> void:
_drawer = UI.panel(self)
_drawer.name = "SectionPanel"
MENU.style(_drawer)
var stack := VBoxContainer.new()
stack.add_theme_constant_override("separation",8)
_drawer.add_child(stack)
var row := HBoxContainer.new()
stack.add_child(row)
_drawer_title = MENU.label(row,"",18,MENU.GOLD)
_drawer_title.size_flags_horizontal = Control.SIZE_EXPAND_FILL
MENU.button(row,"×",_close_section).custom_minimum_size.x = 32
var scroll := ScrollContainer.new()
scroll.name = "SectionScroll"
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
stack.add_child(scroll)
_content = VBoxContainer.new()
_content.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_content.add_theme_constant_override("separation",8)
scroll.add_child(_content)
func _layout() -> void:
if not is_instance_valid(_drawer): return
var viewport_size := size
var storage: bool = _tab == "storage" or (_tab == "expansion_3" and deck.is_built(_tab))
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 (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)
MENU.style(_drawer)
if is_instance_valid(_storage_columns): _storage_columns.columns = 2 if width >= 640 else 1
func _sync_header() -> void:
if is_instance_valid(_wallet):
_wallet.text = "%d KREDYTÓW\n%d CZĘŚCI\n%d KRYSZTAŁÓW CZASU" % [captain.credits,floori(captain.parts),captain.expedition.time_crystals]
func _hover_section(section: String) -> void:
var data: Dictionary = deck.room(section)
_hint.text = "%s / %s" % [data.title,data.status] if not data.is_empty() else "Wybierz pomieszczenie na pokładzie. · Warsztat i hangar są dostępne."
func _select_section(section: String) -> void:
var room: Dictionary = deck.room("expansion_3" if section == "storage" else section)
var pan: float = 0.0 if room.is_empty() else ((room.rect as Rect2).get_center().x / deck.DESIGN_SIZE.x - 0.5)*1.4
_audio.enter_section(section,pan)
_storage_notice = ""
_tab = section
deck.selected = section
_refresh()
func _close_section() -> void:
_audio.close_section()
_tab = "overview"
deck.selected = ""
_drawer.hide()
deck.queue_redraw()
func _input(event: InputEvent) -> void:
if not event is InputEventKey or not event.pressed or event.echo:
return
if event.keycode not in [KEY_L,KEY_ESCAPE]:
return
# Docking removes this scene immediately, so consume input before emitting closed.
get_viewport().set_input_as_handled()
if event.keycode == KEY_L:
closed.emit()
elif _drawer.visible:
_close_section()
else:
closed.emit()
func _label(text: String, size_value := 14, color := Color("c5d3d7")) -> Label:
var node := MENU.label(_content,text,size_value,color)
node.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
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():
_content.remove_child(child)
child.queue_free()
_sync_header()
if _tab == "overview":
_drawer.hide()
return
_drawer.show()
_layout()
_content.get_parent().set("scroll_vertical",0)
if _tab == "workshop":
_drawer_title.text = "WARSZTAT"
_build_workshop()
elif _tab == "hangar":
_drawer_title.text = "HANGAR / OBSŁUGA"
_build_hangar()
elif _tab == "command":
_drawer_title.text = "CENTRUM DOWODZENIA"
_build_command()
elif _tab == "storage" or (_tab == "expansion_3" and deck.is_built(_tab)):
_drawer_title.text = "MAGAZYN FRACHTOWCA"
_build_storage()
else:
_build_room()
func _build_room() -> void:
var section: Dictionary = deck.room(_tab)
_drawer_title.text = str(section.get("title","SEKCJA ROZWOJOWA"))
if not deck.is_buildable(_tab):
_label("Wybierz pomieszczenie na pokładzie.")
return
var plan: Dictionary = deck.plan(_tab)
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):
_label("Pomieszczenie jest wyposażone. Jego mechanika zostanie dodana w kolejnym etapie.",14,Color("849da5"))
else:
_build_construction(_content, _tab, "ZBUDUJ SEKCJĘ")
MENU.button(_content,"Wróć na pokład",_close_section)
func _can_construct(id: String) -> bool:
if not deck.is_buildable(id) or deck.is_built(id): return false
for mineral in RECIPES.MINERALS:
if int(captain.minerals.get(mineral, 0)) < 100: return false
return true
func _build_construction(parent: Node, id: String, title: String) -> void:
var costs := MENU.card(parent)
MENU.style(costs.get_parent(), 8, 0.56)
costs.add_theme_constant_override("separation", 3)
var header := MENU.row(costs)
var caption := MENU.label(header, "KOSZT BUDOWY", 12, MENU.GOLD)
caption.size_flags_horizontal = Control.SIZE_EXPAND_FILL
caption.autowrap_mode = TextServer.AUTOWRAP_OFF
MENU.label(header, "POSIADASZ / WYMAGANE", 11, MENU.MUTED).autowrap_mode = TextServer.AUTOWRAP_OFF
for mineral in RECIPES.MINERALS:
var row := MENU.row(costs)
row.name = "Cost" + str(mineral).capitalize()
row.custom_minimum_size.y = 22
MENU.icon(row, RECIPES.icon(mineral), 18).mouse_filter = Control.MOUSE_FILTER_IGNORE
var resource_name := MENU.label(row, RECIPES.NAMES[mineral], 12)
resource_name.size_flags_horizontal = Control.SIZE_EXPAND_FILL
resource_name.autowrap_mode = TextServer.AUTOWRAP_OFF
var owned := int(captain.minerals.get(mineral, 0))
var amount := MENU.label(row, "%d / 100" % owned, 12, UI.CYAN if owned >= 100 else Color("ef8e84"))
amount.name = "Amount"
amount.autowrap_mode = TextServer.AUTOWRAP_OFF
amount.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
amount.custom_minimum_size.x = 80
var build := MENU.button(parent, title, _construct_room.bind(id), true)
build.disabled = not _can_construct(id)
build.tooltip_text = "Budowa wymaga po 100 każdego z pięciu surowców kosmicznych."
func _construct_room(id: String) -> void:
if not _can_construct(id): return
for mineral in RECIPES.MINERALS:
captain.minerals[mineral] = int(captain.minerals.get(mineral, 0)) - 100
captain.emit_changed()
captain.expedition.freighter_rooms[id] = str(deck.plan(id).kind)
captain.expedition.emit_changed()
deck.sync_rooms(captain.expedition.freighter_rooms)
_audio.service_completed()
_hover_section(id)
_refresh()
func _build_hangar() -> void:
var progress: Resource = captain.expedition
MENU.hero(_content,"hangar","")
var ship_row := MENU.row(_content)
MENU.icon(ship_row,deck.ship_texture,32)
var ship_text := VBoxContainer.new()
ship_text.size_flags_horizontal = Control.SIZE_EXPAND_FILL
ship_row.add_child(ship_text)
MENU.label(ship_text,deck.ship_name,15,MENU.GOLD)
MENU.label(ship_text,"Żelazo %d · Części %d" % [int(captain.minerals.get("iron",0)),int(captain.parts)],12,MENU.MUTED)
var service := MENU.card(_content)
MENU.style(service.get_parent(),8,0.70)
var row := MENU.row(service)
MENU.icon(row,preload("res://assets/planets/lander.png"),34)
var info := VBoxContainer.new()
info.size_flags_horizontal = Control.SIZE_EXPAND_FILL
row.add_child(info)
MENU.label(info,"Lądownik · %d%%" % ceili(progress.lander_hp),13,MENU.GOLD)
var bar := ProgressBar.new()
bar.value = progress.lander_hp
bar.show_percentage = false
bar.custom_minimum_size.y = 5
var fill := StyleBoxFlat.new()
fill.bg_color = Color("85b7a0")
fill.set_corner_radius_all(3)
bar.add_theme_stylebox_override("fill",fill)
info.add_child(bar)
var cost: int = progress.repair_cost()
var cost_row := MENU.row(info)
MENU.icon(cost_row,RECIPES.icon("parts"),14)
var repair_cost := MENU.label(cost_row,str(cost),11,MENU.MUTED)
repair_cost.name = "RepairCost"
repair_cost.autowrap_mode = TextServer.AUTOWRAP_OFF
var repair := MENU.button(row,"Napraw",func():
if progress.repair(captain): _audio.service_completed(0.65)
_refresh(),true)
repair.name = "RepairLander"
repair.custom_minimum_size = Vector2(58,26)
repair.size_flags_vertical = Control.SIZE_SHRINK_CENTER
repair.tooltip_text = "Napraw do 100%% · koszt %d części. Pełny kadłub wymagany do lądowania." % cost
repair.disabled = cost == 0 or captain.parts < cost
_build_slot_upgrades()
var delivery := MENU.card(_content)
MENU.style(delivery.get_parent(),8,0.70)
var delivery_row := MENU.row(delivery)
MENU.icon(delivery_row,preload("res://assets/icons/shield.png"),24)
var label := MENU.label(delivery_row,"Odzyskane moduły · %d" % progress.delivered_modules.size(),12,MENU.MUTED)
label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
var take := MENU.button(delivery_row,"Odbierz",func():
if is_instance_valid(inventory): progress.deliver_modules(inventory)
_refresh())
take.name = "CollectRecovered"
take.custom_minimum_size = Vector2(58,26)
take.tooltip_text = "Odbierz do ładowni statku. Przedmioty bez miejsca pozostają na fregacie."
take.disabled = progress.delivered_modules.is_empty() or not is_instance_valid(inventory)
func _build_slot_upgrades() -> void:
if not is_instance_valid(inventory):
_label("Zadokuj statkiem, aby rozbudować sloty.",12,MENU.MUTED)
return
_label("ROZBUDOWA STATKU",13,MENU.GOLD)
var grid := GridContainer.new()
grid.columns = 3
grid.add_theme_constant_override("h_separation",6)
_content.add_child(grid)
for kind in ["cargo","weapon","extension"]:
var count: int = inventory.unlocked_cargo_slots if kind == "cargo" else (inventory.unlocked_weapon_slots if kind == "weapon" else inventory.unlocked_extension_slots)
var limit: int = inventory.CARGO_SIZE if kind == "cargo" else (inventory.WEAPON_SLOT_COUNT if kind == "weapon" else inventory.EXTENSION_SLOT_COUNT)
var card := MENU.card(grid)
MENU.style(card.get_parent(),6,0.70)
card.add_theme_constant_override("separation",4)
var row := MENU.row(card)
row.add_theme_constant_override("separation",5)
var icons := {"cargo":"res://assets/icons/cargo_crate.svg","weapon":"res://assets/icons/machine_gun.png","extension":"res://assets/icons/computer.png"}
MENU.icon(row,load(icons[kind]),26)
var title := VBoxContainer.new()
title.size_flags_horizontal = Control.SIZE_EXPAND_FILL
row.add_child(title)
MENU.label(title,{"cargo":"Ładownia","weapon":"Broń","extension":"Rozszerzenia"}[kind],11,MENU.TEXT)
MENU.label(title,"%d / %d" % [count,limit],11,MENU.MUTED)
var action := MENU.row(card)
action.add_theme_constant_override("separation",4)
var prices := VBoxContainer.new()
prices.size_flags_horizontal = Control.SIZE_EXPAND_FILL
prices.add_theme_constant_override("separation", 1)
action.add_child(prices)
var cost: Dictionary = inventory.get_slot_unlock_cost(kind)
for mineral in cost:
var price_row := MENU.row(prices)
price_row.add_theme_constant_override("separation", 3)
price_row.tooltip_text = RECIPES.NAMES[mineral]
MENU.icon(price_row, RECIPES.icon(mineral), 14).mouse_filter = Control.MOUSE_FILTER_IGNORE
MENU.label(price_row, str(cost[mineral]), 11, MENU.MUTED).autowrap_mode = TextServer.AUTOWRAP_OFF
var unlock := MENU.button(action,"+1" if count < limit else "✓",_unlock_ship_slot.bind(kind),true)
unlock.name = "Unlock"+kind.capitalize()
unlock.custom_minimum_size = Vector2(30,24)
unlock.size_flags_vertical = Control.SIZE_SHRINK_CENTER
unlock.tooltip_text = "Osiągnięto limit." if count >= limit else "Odblokuj 1 slot · " + inventory.get_slot_unlock_cost_text(kind)
unlock.disabled = not inventory.can_unlock_slot(kind,captain)
func _unlock_ship_slot(kind: String) -> void:
if is_instance_valid(inventory):
inventory.unlock_slot(kind,captain)
_refresh()
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)
MENU.label(construction,"SKŁAD MODUŁÓW W REMONCIE",15,MENU.GOLD)
_build_construction(construction, "expansion_3", "ZBUDUJ SKŁAD")
return
if not is_instance_valid(inventory): return
_label("MODUŁY / Kliknij ikonę, aby przenieść przedmiot",14,MENU.GOLD)
if not _storage_notice.is_empty(): _label(_storage_notice,12,MENU.GOLD)
_storage_columns = GridContainer.new()
_storage_columns.columns = 2 if _drawer.size.x >= 640 else 1
_storage_columns.add_theme_constant_override("h_separation",12)
_storage_columns.add_theme_constant_override("v_separation",12)
_content.add_child(_storage_columns)
for retrieve in [false,true]:
var column := VBoxContainer.new()
column.size_flags_horizontal = Control.SIZE_EXPAND_FILL
column.add_theme_constant_override("separation",6)
_storage_columns.add_child(column)
var storage: Array = captain.expedition.freighter_storage
MENU.label(column,"FREGATA · %d" % storage.size() if retrieve else "STATEK · %d / %d" % [inventory.get_cargo_used(),inventory.get_cargo_capacity()],14,MENU.GOLD)
var bulk := MENU.button(column,"← Odbierz wszystko" if retrieve else "Odłóż wszystko →",_transfer_all.bind(retrieve))
bulk.disabled = storage.is_empty() or inventory.get_cargo_used() >= inventory.get_cargo_capacity() if retrieve else inventory.get_cargo_used() == 0
var grid := GridContainer.new()
grid.name = "FreighterSlots" if retrieve else "ShipSlots"
grid.columns = 5
grid.add_theme_constant_override("h_separation",4)
grid.add_theme_constant_override("v_separation",4)
column.add_child(grid)
var count: int = maxi(20,ceili(storage.size()/5.0)*5) if retrieve else inventory.CARGO_SIZE
for index in count:
var item: ItemInstance = storage[index] if retrieve and index < storage.size() else (inventory.get_item("cargo",index) if not retrieve else null)
var slot := Button.new()
slot.set_script(preload("res://scripts/planets/freighter_storage_slot.gd"))
slot.item = item
slot.retrieve = retrieve
slot.locked = not retrieve and index >= inventory.get_cargo_capacity()
if item != null: slot.transfer = _transfer_storage.bind(retrieve,index,item)
grid.add_child(slot)
if retrieve and item != null: slot.disabled = inventory.get_cargo_used() >= inventory.get_cargo_capacity()
_label("ZAMONTOWANE NA STATKU",12,MENU.MUTED)
var mounted := HFlowContainer.new()
_content.add_child(mounted)
for group in [inventory.weapon_slots,inventory.module_slots,inventory.extension_slots]:
for item in group:
if item == null: continue
var picture := MENU.icon(mounted,item.definition.icon,32)
picture.mouse_filter = Control.MOUSE_FILTER_STOP
picture.tooltip_text = item.get_tooltip_text()+"\nZamontowane — najpierw zdejmij do ładowni."
_label("SPRZĘT KAPITANA · %d szt. ODZYSKANE MODUŁY · %d" % [captain.gear_items.size(),captain.expedition.delivered_modules.size()],12,MENU.MUTED)
var owned := HFlowContainer.new()
_content.add_child(owned)
for gear in captain.gear_items:
var picture := MENU.icon(owned,GEAR.icon(str(gear.kind)),28)
picture.mouse_filter = Control.MOUSE_FILTER_STOP
picture.tooltip_text = "%s · poziom %d" % [GEAR.NAMES[gear.kind],gear.level]
for item in captain.expedition.delivered_modules:
var picture := MENU.icon(owned,item.definition.icon,28)
picture.mouse_filter = Control.MOUSE_FILTER_STOP
picture.tooltip_text = item.get_tooltip_text()+"\nOdbierz w Hangarze."
_content.add_child(HSeparator.new())
_build_resource_overview()
func _build_resource_overview() -> void:
_label("ZAPASY GRACZA",14,MENU.GOLD)
var grid := GridContainer.new()
grid.name = "ResourceOverview"
grid.columns = 4 if _drawer.size.x >= 600 else 3
grid.add_theme_constant_override("h_separation",6)
grid.add_theme_constant_override("v_separation",5)
_content.add_child(grid)
var values: Dictionary = {"credits":captain.credits,"parts":int(captain.parts)}
for key in RECIPES.MINERALS+preload("res://scripts/planets/planet_profiles.gd").MATERIALS:
values[key] = int(captain.minerals.get(key,0))
for key in captain.minerals: values[key] = int(captain.minerals[key])
if is_instance_valid(inventory):
for key in ["ammunition","missile","irradiated_ammunition","energy_bank"]: values[key] = inventory.get_crafted_stock(key)
values.time_crystals = captain.expedition.time_crystals
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","deuter":"Deuter","time_crystals":"Kryształy czasu"})
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","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)
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
var count := 0
if retrieve:
for index in range(captain.expedition.freighter_storage.size()-1,-1,-1):
if inventory.retrieve_from_freighter(index,captain.expedition.freighter_storage[index],captain): count += 1
else:
for index in range(inventory.get_cargo_capacity()-1,-1,-1):
var item: ItemInstance = inventory.get_item("cargo",index)
if item != null and inventory.store_on_freighter(index,item,captain): count += 1
_storage_notice = "Przeniesiono %d przedmiotów." % count
_refresh()
func _transfer_storage(retrieve: bool, index: int, expected: ItemInstance) -> void:
if not is_instance_valid(inventory): return
if retrieve: inventory.retrieve_from_freighter(index,expected,captain)
else: inventory.store_on_freighter(index,expected,captain)
_refresh()
func _build_supply_production() -> void:
for group in [["AMUNICJA I RAKIETY",["ammunition","missile","irradiated_ammunition"]],["ZAOPATRZENIE",["parts","energy_bank"]]]:
_label(group[0],13,MENU.GOLD)
var grid := GridContainer.new()
grid.columns = 3
grid.add_theme_constant_override("h_separation",6)
_content.add_child(grid)
for id in group[1]:
var recipe: Dictionary = RECIPES.DATA[id]
var card := MENU.card(grid)
MENU.style(card.get_parent(),6)
card.add_theme_constant_override("separation",4)
card.get_parent().tooltip_text = recipe.name+" · partia: %d szt." % recipe.amount
var row := MENU.row(card)
MENU.icon(row,RECIPES.icon(id),28)
var stock := MENU.label(row,str(inventory.get_crafted_stock(id) if is_instance_valid(inventory) else 0),13,MENU.GOLD)
stock.size_flags_horizontal = Control.SIZE_EXPAND_FILL
var actions := MENU.row(card)
actions.add_theme_constant_override("separation",4)
for batches in [1,10]:
var button := MENU.button(actions,"+%d" % batches,_craft_supply.bind(id,batches),true)
button.name = ("Craft_" if batches == 1 else "Craft10_")+id
button.custom_minimum_size = Vector2(36,24)
button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
var cost: Dictionary = recipe.cost.duplicate()
for key in cost: cost[key] = int(cost[key])*batches
button.tooltip_text = "%s: %d partii = %d szt.\nKoszt: %s" % [recipe.name,batches,int(recipe.amount)*batches,UI.material_text(cost)]
button.disabled = not _can_craft_supply(id,batches)
func _can_craft_supply(id: String, batches: int) -> bool:
if not is_instance_valid(inventory) or not RECIPES.DATA.has(id) or batches not in [1,10]: return false
for key in RECIPES.DATA[id].cost:
if int(captain.minerals.get(key,0)) < int(RECIPES.DATA[id].cost[key])*batches: return false
return true
func _craft_supply(id: String, batches := 1) -> void:
if _tab != "workshop" or not _can_craft_supply(id,batches): return
for index in batches: inventory.craft(id)
_audio.service_completed(-0.48)
_refresh()
func _build_workshop() -> void:
MENU.hero(_content,"workshop","")
_build_supply_production()
preload("res://scripts/planets/orb_workshop.gd").build(self)
_label("EKWIPUNEK KAPITANA",13,MENU.GOLD)
var grid := GridContainer.new()
grid.columns = 3
grid.add_theme_constant_override("h_separation",6)
_content.add_child(grid)
for kind in GEAR.KINDS:
var card := MENU.card(grid)
MENU.style(card.get_parent(),6)
card.add_theme_constant_override("separation",4)
var row := MENU.row(card)
MENU.icon(row,GEAR.icon(kind),32)
var levels := MENU.label(row,"L%d → L%d" % [GEAR.level(captain,kind),GEAR.next_level(captain,kind)],12,GEAR.COLORS[kind])
levels.size_flags_horizontal = Control.SIZE_EXPAND_FILL
var build := MENU.button(row,"+1",_craft.bind(kind),true)
build.name = "CraftGear_"+kind
build.custom_minimum_size = Vector2(36,24)
build.size_flags_vertical = Control.SIZE_SHRINK_CENTER
build.tooltip_text = "%s · poziom %d\nKoszt: %s\nWytwarza i zakłada nowy przedmiot." % [GEAR.NAMES[kind],GEAR.next_level(captain,kind),GEAR.recipe_text(captain,kind)]
card.get_parent().tooltip_text = build.tooltip_text
build.disabled = not GEAR.can_craft(captain,kind)
MENU.button(_content,"Posiadane "+("−" if _owned_open else "+"),func():
_owned_open = not _owned_open
_refresh())
if _owned_open:
for gear in captain.gear_items:
var equipped: bool = captain.gear_slots.get(gear.kind,-1) == gear.uid
var label_text := "%s · L%d%s" % [GEAR.NAMES[gear.kind],gear.level," [ZAŁOŻONE]" if equipped else ""]
var button := MENU.button(_content,label_text,_equip.bind(gear.kind,gear.uid))
button.disabled = equipped
func _build_command() -> void:
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 _travel_to_distant(map_id: String) -> void:
var controller := get_parent().get_parent()
if controller.has_method("request_distant_travel"): controller.request_distant_travel(map_id)
func _return_from_distant() -> void:
var controller := get_parent().get_parent()
if controller.has_method("request_distant_return"): controller.request_distant_return()
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
if key == "expedition_fuel":
label.text = "Zapas paliwa: %.1f deuteru" % captain.expedition.deuter
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
var gear: Dictionary = GEAR.craft(captain,kind)
if not gear.is_empty():
GEAR.equip(captain,kind,int(gear.uid))
_audio.service_completed(-0.48)
_refresh()
func _equip(kind: String, uid: int) -> void:
GEAR.equip(captain,kind,uid)
_refresh()
func _build_alien_research() -> void:
var progress: Resource = captain.expedition
var row := MENU.row(_content)
var balance := MENU.label(row, "PRÓBKI / %d" % progress.analysis_samples, 15, MENU.GOLD)
balance.size_flags_horizontal = Control.SIZE_EXPAND_FILL
MENU.label(row, "%d / %d ZBADANO" % [preload("res://scripts/planets/alien_research.gd").learned_count(progress),preload("res://scripts/planets/alien_research.gd").ACTIVE_IDS.size()], 12, MENU.MUTED).custom_minimum_size.x = 110
var tree := preload("res://scripts/planets/alien_research_tree.gd").new()
tree.progress = progress
tree.refreshed = _research_completed
tree.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_content.add_child(tree)
func _research_completed() -> void:
_audio.service_completed()
captain.emit_changed()
_refresh()