138 lines
5.4 KiB
GDScript
138 lines
5.4 KiB
GDScript
extends Control
|
||
## FragmentCraftPanel — Shows all craftable skins and their fragment requirements.
|
||
## Linked from GachaPanel via the "🧩 Fragment Craft" button.
|
||
|
||
signal closed
|
||
|
||
# ─── Node refs ───────────────────────────────────────────────────────────────
|
||
@onready var back_btn := %BackBtn as Button
|
||
@onready var recipe_list := %RecipeList as VBoxContainer
|
||
@onready var status_label := %StatusLabel as Label
|
||
@onready var frag_balance := %FragBalance as Label
|
||
|
||
const FRAG_ICONS := {
|
||
"frag_common": "⬜",
|
||
"frag_uncommon": "🟩",
|
||
"frag_rare": "🟦"
|
||
}
|
||
|
||
# ─── Lifecycle ────────────────────────────────────────────────────────────────
|
||
func _ready() -> void:
|
||
back_btn.pressed.connect(_on_close)
|
||
|
||
func show_panel() -> void:
|
||
show()
|
||
_refresh()
|
||
|
||
func _refresh() -> void:
|
||
_update_frag_balance()
|
||
_rebuild_recipe_list()
|
||
|
||
# ─── Fragment balance header ──────────────────────────────────────────────────
|
||
func _update_frag_balance() -> void:
|
||
var frags: Dictionary = UserProfileManager.fragments
|
||
var parts: Array = []
|
||
for fid in ["frag_common", "frag_uncommon", "frag_rare"]:
|
||
var icon: String = FRAG_ICONS.get(fid, "?")
|
||
var count: int = frags.get(fid, 0)
|
||
parts.append("%s ×%d" % [icon, count])
|
||
frag_balance.text = " ".join(parts)
|
||
|
||
# ─── Recipe cards ─────────────────────────────────────────────────────────────
|
||
func _rebuild_recipe_list() -> void:
|
||
for c in recipe_list.get_children(): c.queue_free()
|
||
await get_tree().process_frame
|
||
|
||
var recipes: Dictionary = GachaManager.get_all_recipes()
|
||
for recipe_id in recipes:
|
||
var recipe: Dictionary = recipes[recipe_id]
|
||
var card := _make_recipe_card(recipe_id, recipe)
|
||
recipe_list.add_child(card)
|
||
|
||
func _make_recipe_card(recipe_id: String, recipe: Dictionary) -> PanelContainer:
|
||
var can_craft: bool = GachaManager.can_craft(recipe_id)
|
||
var frags: Dictionary = UserProfileManager.fragments
|
||
|
||
var panel := PanelContainer.new()
|
||
panel.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
|
||
var margin := MarginContainer.new()
|
||
margin.add_theme_constant_override("margin_left", 14)
|
||
margin.add_theme_constant_override("margin_top", 10)
|
||
margin.add_theme_constant_override("margin_right", 14)
|
||
margin.add_theme_constant_override("margin_bottom", 10)
|
||
panel.add_child(margin)
|
||
|
||
var hbox := HBoxContainer.new()
|
||
hbox.add_theme_constant_override("separation", 14)
|
||
margin.add_child(hbox)
|
||
|
||
# Left info
|
||
var vbox := VBoxContainer.new()
|
||
vbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
vbox.add_theme_constant_override("separation", 4)
|
||
hbox.add_child(vbox)
|
||
|
||
var name_lbl := Label.new()
|
||
name_lbl.text = recipe.get("name", recipe_id)
|
||
name_lbl.add_theme_font_size_override("font_size", 16)
|
||
name_lbl.add_theme_color_override("font_color", Color(0.9, 0.8, 0.3))
|
||
vbox.add_child(name_lbl)
|
||
|
||
var char_cat_lbl := Label.new()
|
||
char_cat_lbl.text = "%s • %s" % [recipe.get("character", "All"), recipe.get("category", "").capitalize()]
|
||
char_cat_lbl.add_theme_font_size_override("font_size", 11)
|
||
char_cat_lbl.add_theme_color_override("font_color", Color(0.65, 0.65, 0.65))
|
||
vbox.add_child(char_cat_lbl)
|
||
|
||
# Fragment cost row
|
||
var cost_hbox := HBoxContainer.new()
|
||
cost_hbox.add_theme_constant_override("separation", 12)
|
||
vbox.add_child(cost_hbox)
|
||
|
||
var cost: Dictionary = recipe.get("cost", {})
|
||
for fid in ["frag_common", "frag_uncommon", "frag_rare"]:
|
||
if not cost.has(fid): continue
|
||
var needed: int = cost[fid]
|
||
var have: int = frags.get(fid, 0)
|
||
var icon: String = FRAG_ICONS.get(fid, "?")
|
||
var cost_lbl := Label.new()
|
||
cost_lbl.text = "%s %d/%d" % [icon, have, needed]
|
||
cost_lbl.add_theme_font_size_override("font_size", 13)
|
||
cost_lbl.add_theme_color_override("font_color",
|
||
Color(0.4, 1.0, 0.5) if have >= needed else Color(1.0, 0.4, 0.4))
|
||
cost_hbox.add_child(cost_lbl)
|
||
|
||
# Craft button
|
||
var craft_btn := Button.new()
|
||
craft_btn.text = "🔨 Craft"
|
||
craft_btn.custom_minimum_size = Vector2(100, 40)
|
||
craft_btn.disabled = not can_craft
|
||
if not can_craft:
|
||
craft_btn.modulate = Color(0.5, 0.5, 0.5, 0.7)
|
||
craft_btn.pressed.connect(_on_craft_pressed.bind(recipe_id, panel))
|
||
hbox.add_child(craft_btn)
|
||
|
||
return panel
|
||
|
||
# ─── Craft action ─────────────────────────────────────────────────────────────
|
||
func _on_craft_pressed(recipe_id: String, _card: PanelContainer) -> void:
|
||
var ok := GachaManager.craft(recipe_id)
|
||
if ok:
|
||
var recipes := GachaManager.get_all_recipes()
|
||
var name: String = recipes.get(recipe_id, {}).get("name", recipe_id)
|
||
_set_status("✅ Crafted: %s!" % name, Color(0.4, 1.0, 0.4))
|
||
_refresh()
|
||
else:
|
||
_set_status("❌ Not enough fragments.", Color(1.0, 0.4, 0.4))
|
||
|
||
func _set_status(msg: String, col: Color = Color.WHITE) -> void:
|
||
status_label.add_theme_color_override("font_color", col)
|
||
status_label.text = msg
|
||
await get_tree().create_timer(3.0).timeout
|
||
if status_label.text == msg: status_label.text = ""
|
||
|
||
func _on_close() -> void:
|
||
hide()
|
||
closed.emit()
|