extends Control signal next_level_requested const BUTTON_STYLE := preload("res://scripts/ui/hud_button_style.gd") const CREDIT_ICON := preload("res://assets/icons/resources/credits.svg") @onready var next_button: Button = $Center/Panel/Contents/NextButton @onready var buy_ammunition_button: Button = $Center/Panel/Contents/BuyAmmunitionButton @onready var reset_skills_button: Button = $Center/Panel/Contents/ResetSkillsButton @onready var services_label: Label = $Center/Panel/Contents/Services @onready var status_label: Label = $Center/Panel/Contents/Status @onready var panel: PanelContainer = $Center/Panel var _inventory: ShipInventory var planet: Node2D var _open_tween: Tween var _missile_button: Button var _gamma_buy: Button var _stock_labels: Dictionary = {} func _ready() -> void: _gamma_buy = Button.new() _gamma_buy.name = "BuyIrradiatedAmmunition" _missile_button = Button.new() _missile_button.name = "BuyMissile" var contents := $Center/Panel/Contents contents.add_child(_gamma_buy) contents.add_child(_missile_button) reset_skills_button.hide() _build_compact_shop() get_parent().get_node("FloatingWindows").call("register_window", self, panel, contents.get_node("Title")) next_button.pressed.connect(func() -> void: next_level_requested.emit()) buy_ammunition_button.pressed.connect(_buy_ammunition) _gamma_buy.pressed.connect(func() -> void: if visible and _inventory: _inventory.buy_irradiated_ammunition() ) _missile_button.pressed.connect(func() -> void: if visible and _inventory: _inventory.buy_missile() ) _inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory if _inventory: _inventory.ammunition_changed.connect(_refresh_ammunition_service) _inventory.inventory_changed.connect(_refresh_ammunition_service) GameState.captain.changed.connect(_refresh_ammunition_service) _refresh_ammunition_service() func _build_compact_shop() -> void: var contents := $Center/Panel/Contents contents.add_theme_constant_override("separation", 7) status_label.add_theme_font_size_override("font_size", 10) status_label.add_theme_color_override("font_color", Color("86b7aa")) services_label.add_theme_font_size_override("font_size", 11) services_label.add_theme_color_override("font_color", Color("efc982")) services_label.size_flags_vertical = Control.SIZE_FILL var wallet := HBoxContainer.new() wallet.name = "Wallet" wallet.alignment = BoxContainer.ALIGNMENT_CENTER wallet.add_theme_constant_override("separation", 6) contents.add_child(wallet) contents.move_child(wallet, 2) var money_icon := TextureRect.new() money_icon.texture = CREDIT_ICON money_icon.custom_minimum_size = Vector2(15, 15) money_icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE money_icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED money_icon.mouse_filter = Control.MOUSE_FILTER_IGNORE wallet.add_child(money_icon) services_label.reparent(wallet) var offers := HBoxContainer.new() offers.name = "Offers" offers.add_theme_constant_override("separation", 6) contents.add_child(offers) contents.move_child(offers, 3) _add_offer(offers, buy_ammunition_button, "ammunition", "Zwykła", 100, Color("e8b46f")) _add_offer(offers, _gamma_buy, "irradiated_ammunition", "Radiacyjna", 10, Color("add580")) _add_offer(offers, _missile_button, "missile", "Rakieta", 1, Color("82cddd")) BUTTON_STYLE.apply(next_button, Color("78d7be")) next_button.custom_minimum_size = Vector2(0, 34) next_button.add_theme_font_size_override("font_size", 11) next_button.icon = preload("res://assets/icons/extensions/teleport_art.png") next_button.expand_icon = true next_button.add_theme_constant_override("icon_max_width", 21) contents.move_child(next_button, contents.get_child_count() - 1) func _add_offer(offers: HBoxContainer, button: Button, item_id: String, caption: String, amount: int, accent: Color) -> void: var card := PanelContainer.new() card.name = item_id.capitalize().replace(" ", "") + "Offer" card.custom_minimum_size.x = 94 card.size_flags_horizontal = Control.SIZE_EXPAND_FILL var style := StyleBoxFlat.new() style.bg_color = Color("101e2a") style.border_color = accent.darkened(0.65) style.set_border_width_all(1) style.border_width_top = 2 style.set_corner_radius_all(6) style.set_content_margin_all(6) card.add_theme_stylebox_override("panel", style) offers.add_child(card) var column := VBoxContainer.new() column.add_theme_constant_override("separation", 4) card.add_child(column) var icon := TextureRect.new() icon.texture = load("res://assets/icons/resources/%s.png" % item_id) icon.custom_minimum_size = Vector2(36, 36) icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED icon.mouse_filter = Control.MOUSE_FILTER_IGNORE column.add_child(icon) var title := Label.new() title.text = "%s ×%d" % [caption, amount] title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER title.add_theme_font_size_override("font_size", 10) title.add_theme_color_override("font_color", accent.lightened(0.2)) column.add_child(title) var stock := Label.new() stock.name = "Stock" stock.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER stock.add_theme_font_size_override("font_size", 9) stock.add_theme_color_override("font_color", Color("8ba4b7")) column.add_child(stock) _stock_labels[item_id] = stock button.reparent(column) BUTTON_STYLE.apply(button, accent) button.custom_minimum_size = Vector2(0, 28) button.add_theme_font_size_override("font_size", 10) button.icon = CREDIT_ICON button.expand_icon = true button.add_theme_constant_override("icon_max_width", 12) for state in ["normal", "hover", "pressed", "disabled"]: var frame := button.get_theme_stylebox(state).duplicate() as StyleBoxFlat frame.set_content_margin_all(4) frame.set_corner_radius_all(4) frame.shadow_size = 0 button.add_theme_stylebox_override(state, frame) func show_services(at_level_cap: bool, portal_open: bool = false) -> void: _refresh_ammunition_service() next_button.disabled = at_level_cap or portal_open next_button.text = "OSTATNI UKŁAD" if at_level_cap else ("WORMHOLE OTWARTY" if portal_open else "OTWÓRZ WORMHOLE") status_label.text = "Wleć w wormhole, aby przejść dalej." if portal_open else "Bezpieczny układ · zaopatrzenie" if visible: return show() _position_at_planet() scale = Vector2(0.05, 1.0) _open_tween = create_tween() _open_tween.tween_property(self, "scale:x", 1.0, 0.2).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_OUT) func hide_services() -> void: if _open_tween != null and _open_tween.is_running(): _open_tween.kill() hide() scale = Vector2.ONE func _process(_delta: float) -> void: if visible: _position_at_planet() func _position_at_planet() -> void: if has_meta("floating_window_dragged"): get_parent().get_node("FloatingWindows").call("clamp_window", self) return if not is_instance_valid(planet): return var canvas := get_viewport().get_canvas_transform() var planet_screen := canvas * planet.global_position var planet_radius := float(planet.get("radius")) * canvas.x.length() size = panel.get_combined_minimum_size() var viewport_size := get_viewport_rect().size var sidebar := get_parent().get_node_or_null("ShipDrawer") as Control var screen_right := minf(viewport_size.x - 8.0, sidebar.get_global_rect().position.x - 8.0) if sidebar != null and sidebar.visible else viewport_size.x - 8.0 var target := planet_screen + Vector2(planet_radius + 24.0, -size.y * 0.5) if target.x + size.x > screen_right: target.x = planet_screen.x - planet_radius - 24.0 - size.x position = Vector2(clampf(target.x, 8.0, maxf(8.0, screen_right - size.x)), clampf(target.y, 8.0, maxf(8.0, viewport_size.y - size.y - 150.0))) func _refresh_ammunition_service() -> void: var ordinary_cost := _inventory.get_ammunition_buy_cost() if _inventory else GameState.captain.discounted_price(ShipInventory.AMMUNITION_BUY_BASE_COST * maxi(1, GameState.system_level)) var gamma_cost := _inventory.get_irradiated_ammunition_buy_cost() if _inventory else GameState.captain.discounted_price(ShipInventory.IRRADIATED_AMMUNITION_BUY_BASE_COST * maxi(1, GameState.system_level)) var missile_cost := _inventory.get_missile_buy_cost() if _inventory else GameState.captain.discounted_price(ShipInventory.MISSILE_BUY_BASE_COST * maxi(1, GameState.system_level)) buy_ammunition_button.text = "KUP %d" % ordinary_cost _gamma_buy.text = "KUP %d" % gamma_cost _missile_button.text = "KUP %d" % missile_cost buy_ammunition_button.disabled = _inventory == null or not _inventory.can_buy_ammunition() _gamma_buy.disabled = _inventory == null or not _inventory.can_buy_irradiated_ammunition() _missile_button.disabled = _inventory == null or not _inventory.can_buy_missile() buy_ammunition_button.tooltip_text = "Kup 100 zwykłych pocisków za %d kredytów." % ordinary_cost _gamma_buy.tooltip_text = "Kup 10 pocisków radiacyjnych za %d kredytów." % gamma_cost _missile_button.tooltip_text = "Kup 1 rakietę za %d kredytów." % missile_cost var discount := roundi(GameState.captain.get_skill_bonus("business_shark") * 100) services_label.text = "%d kredytów%s" % [GameState.captain.credits, " · rabat %d%%" % discount if discount > 0 else ""] _stock_labels["ammunition"].text = "Zapas: %d" % (_inventory.ammunition if _inventory else 0) _stock_labels["irradiated_ammunition"].text = "Zapas: %d" % (_inventory.irradiated_ammunition if _inventory else 0) _stock_labels["missile"].text = "Zapas: %d" % (_inventory.missile_ammunition if _inventory else 0) func _buy_ammunition() -> void: if visible and _inventory: _inventory.buy_ammunition()