|
|
|
@@ -9,7 +9,6 @@ extends "res://presentation/page_view.gd"
|
|
|
|
|
|
|
|
|
|
const InitialCompanyArt = preload("res://entry/initial_company_art.gd")
|
|
|
|
|
const MARKET_STATIC_MASTER = preload("res://assets/entry/shp_001_market/market-static-master.png")
|
|
|
|
|
const M50_MARKET_BACKGROUND = preload("res://assets/ui_m50/market_background.png")
|
|
|
|
|
const M52_Q_MARKET_BACKGROUND = preload("res://assets/backgrounds/m52_q_market_world_only.png")
|
|
|
|
|
const MarketChrome = preload("res://ui/shared/market_chrome.gd")
|
|
|
|
|
const MarketSlots = preload("res://ui/shared/m52_market_slots.gd")
|
|
|
|
@@ -20,7 +19,6 @@ const M52MarketHeader = preload("res://ui/m52/market_header.gd")
|
|
|
|
|
const M52ResourceStatusGroup = preload("res://ui/m52/resource_status_group.gd")
|
|
|
|
|
const M52FooterNav = preload("res://ui/m52/footer_nav.gd")
|
|
|
|
|
|
|
|
|
|
const USE_M50_RESPONSIVE_SLICE := true
|
|
|
|
|
|
|
|
|
|
var design_canvas: Control
|
|
|
|
|
|
|
|
|
@@ -33,37 +31,7 @@ func _notification(what: int) -> void:
|
|
|
|
|
func _render_view(data: Dictionary) -> void:
|
|
|
|
|
clear_view_children()
|
|
|
|
|
design_canvas = null
|
|
|
|
|
if USE_M50_RESPONSIVE_SLICE:
|
|
|
|
|
_render_m52_market_restore(data)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
var matte := ColorRect.new()
|
|
|
|
|
matte.name = "MarketMasterMatte"
|
|
|
|
|
matte.color = Color("#17252c")
|
|
|
|
|
matte.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
|
|
|
matte.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
|
|
|
add_child(matte)
|
|
|
|
|
|
|
|
|
|
design_canvas = Control.new()
|
|
|
|
|
design_canvas.name = "MarketMasterCanvas"
|
|
|
|
|
design_canvas.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
|
|
|
add_child(design_canvas)
|
|
|
|
|
_layout_design_canvas()
|
|
|
|
|
|
|
|
|
|
var master := TextureRect.new()
|
|
|
|
|
master.name = "MarketStaticMaster"
|
|
|
|
|
master.texture = MARKET_STATIC_MASTER
|
|
|
|
|
master.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
|
|
|
|
master.stretch_mode = TextureRect.STRETCH_SCALE
|
|
|
|
|
master.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS
|
|
|
|
|
master.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
|
|
|
master.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
|
|
|
design_canvas.add_child(master)
|
|
|
|
|
|
|
|
|
|
if not bool(data.get("ok", false)):
|
|
|
|
|
_render_invalid(data)
|
|
|
|
|
return
|
|
|
|
|
_build_overlay(data)
|
|
|
|
|
_render_m52_market_restore(data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _layout_design_canvas() -> void:
|
|
|
|
@@ -500,269 +468,6 @@ func _market_command_button(node_name: String, area: Rect2, intent_id: String, p
|
|
|
|
|
return button
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## M50 responsive slice -----------------------------------------------------
|
|
|
|
|
## This path is intentionally self-contained so the old SHP-001 composition
|
|
|
|
|
## can remain available while the owner evaluates the new component grammar.
|
|
|
|
|
## It uses a full-bleed world image plus stretch-safe generated elements; no
|
|
|
|
|
## runtime text is baked into those images.
|
|
|
|
|
|
|
|
|
|
func _render_m50_responsive_slice(data: Dictionary) -> void:
|
|
|
|
|
var background := TextureRect.new()
|
|
|
|
|
background.name = "M50MarketWorldBackground"
|
|
|
|
|
background.texture = M52_Q_MARKET_BACKGROUND
|
|
|
|
|
background.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
|
|
|
|
background.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_COVERED
|
|
|
|
|
background.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS
|
|
|
|
|
background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
|
|
|
background.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
|
|
|
add_child(background)
|
|
|
|
|
var matte := ColorRect.new()
|
|
|
|
|
matte.name = "MarketMasterMatte"
|
|
|
|
|
matte.color = Color(0.08, 0.05, 0.03, 0.05)
|
|
|
|
|
matte.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
|
|
|
matte.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
|
|
|
add_child(matte)
|
|
|
|
|
|
|
|
|
|
var veil := ColorRect.new()
|
|
|
|
|
veil.name = "MarketLegacyVeil"
|
|
|
|
|
# The approved Q background already carries its own painted value structure;
|
|
|
|
|
# keep only a light readability veil so the scene does not become a dark
|
|
|
|
|
# dashboard beneath the runtime controls.
|
|
|
|
|
veil.color = Color(0.02, 0.035, 0.05, 0.08)
|
|
|
|
|
veil.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
|
|
|
veil.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
|
|
|
add_child(veil)
|
|
|
|
|
# Stable legacy identities remain present for route/capture contracts while
|
|
|
|
|
# the responsive slice owns the visible composition.
|
|
|
|
|
var legacy_canvas := Control.new()
|
|
|
|
|
legacy_canvas.name = "MarketMasterCanvas"
|
|
|
|
|
legacy_canvas.visible = false
|
|
|
|
|
add_child(legacy_canvas)
|
|
|
|
|
var legacy_available := size
|
|
|
|
|
if legacy_available.x > 0.0 and legacy_available.y > 0.0:
|
|
|
|
|
var legacy_canvas_size := Vector2(legacy_available.y * (16.0 / 9.0), legacy_available.y) if legacy_available.x / legacy_available.y >= (16.0 / 9.0) else Vector2(legacy_available.x, legacy_available.x / (16.0 / 9.0))
|
|
|
|
|
legacy_canvas.position = (legacy_available - legacy_canvas_size) * 0.5
|
|
|
|
|
legacy_canvas.size = legacy_canvas_size
|
|
|
|
|
var legacy_master := TextureRect.new()
|
|
|
|
|
legacy_master.name = "MarketStaticMaster"
|
|
|
|
|
legacy_master.texture = MARKET_STATIC_MASTER
|
|
|
|
|
legacy_master.visible = false
|
|
|
|
|
legacy_canvas.add_child(legacy_master)
|
|
|
|
|
var legacy_layout := Control.new()
|
|
|
|
|
legacy_layout.name = "MarketLayout"
|
|
|
|
|
legacy_layout.visible = false
|
|
|
|
|
legacy_canvas.add_child(legacy_layout)
|
|
|
|
|
if not bool(data.get("ok", false)):
|
|
|
|
|
var invalid := UIFactory.label(String(data.get("notice", data.get("code", _tr("市场不可用", "MARKET UNAVAILABLE")))), "body", 1.0, Tokens.COLOR_IVORY)
|
|
|
|
|
invalid.name = "MarketInvalidOverlay"
|
|
|
|
|
invalid.set_anchors_and_offsets_preset(Control.PRESET_CENTER)
|
|
|
|
|
invalid.custom_minimum_size = Vector2(280, 80)
|
|
|
|
|
invalid.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
|
|
|
invalid.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
|
|
|
|
invalid.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
|
|
|
|
add_child(invalid)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
var safe := MarginContainer.new()
|
|
|
|
|
safe.name = "M50MarketSafeArea"
|
|
|
|
|
safe.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
|
|
|
var margin := 18 if size.x >= 900.0 else 12
|
|
|
|
|
safe.add_theme_constant_override("margin_left", margin)
|
|
|
|
|
safe.add_theme_constant_override("margin_right", margin)
|
|
|
|
|
safe.add_theme_constant_override("margin_top", 12)
|
|
|
|
|
safe.add_theme_constant_override("margin_bottom", 12)
|
|
|
|
|
add_child(safe)
|
|
|
|
|
|
|
|
|
|
var page := VBoxContainer.new()
|
|
|
|
|
page.name = "M50MarketPage"
|
|
|
|
|
page.add_theme_constant_override("separation", 8)
|
|
|
|
|
page.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
|
|
|
safe.add_child(page)
|
|
|
|
|
|
|
|
|
|
var top := HBoxContainer.new()
|
|
|
|
|
top.name = "M50MarketTopBar"
|
|
|
|
|
top.custom_minimum_size.y = 58
|
|
|
|
|
top.add_theme_constant_override("separation", 10)
|
|
|
|
|
var top_surface := Panel.new()
|
|
|
|
|
top_surface.name = "MarketTopBarSurface"
|
|
|
|
|
top_surface.custom_minimum_size.y = 58
|
|
|
|
|
top_surface.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
|
|
|
var top_style := StyleBoxFlat.new()
|
|
|
|
|
top_style.bg_color = Color(0.08, 0.13, 0.15, 0.78)
|
|
|
|
|
top_style.border_color = Color(Tokens.COLOR_GOLD_LIGHT, 0.62)
|
|
|
|
|
top_style.set_border_width_all(1)
|
|
|
|
|
top_style.set_corner_radius_all(10)
|
|
|
|
|
top_surface.add_theme_stylebox_override("panel", top_style)
|
|
|
|
|
page.add_child(top_surface)
|
|
|
|
|
top.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
|
|
|
top_surface.add_child(top)
|
|
|
|
|
var title_plaque := PanelContainer.new()
|
|
|
|
|
title_plaque.name = "MarketTitlePlaque"
|
|
|
|
|
title_plaque.custom_minimum_size = Vector2(210, 52)
|
|
|
|
|
title_plaque.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
|
|
|
|
title_plaque.add_theme_stylebox_override("panel", _flat_style(Color(0.94, 0.87, 0.70, 0.97), Color(0.47, 0.31, 0.18, 0.95), 2, 10))
|
|
|
|
|
var title_stack := VBoxContainer.new()
|
|
|
|
|
title_stack.alignment = BoxContainer.ALIGNMENT_CENTER
|
|
|
|
|
title_stack.add_theme_constant_override("separation", 0)
|
|
|
|
|
var title := UIFactory.label(_tr("市场", "MARKET", data), "heading", 1.0, Tokens.COLOR_INK)
|
|
|
|
|
title.name = "M50MarketTitle"
|
|
|
|
|
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
|
|
|
title.add_theme_color_override("font_outline_color", Color(0.80, 0.65, 0.40, 0.45))
|
|
|
|
|
title.add_theme_constant_override("outline_size", 1)
|
|
|
|
|
title_stack.add_child(title)
|
|
|
|
|
var stage := UIFactory.label(_tr("准备出发", "PREPARE TO DEPART", data), "micro", 1.0, Color("#7b5228"))
|
|
|
|
|
stage.name = "M50MarketStage"
|
|
|
|
|
stage.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
|
|
|
title_stack.add_child(stage)
|
|
|
|
|
title_plaque.add_child(title_stack)
|
|
|
|
|
top.add_child(title_plaque)
|
|
|
|
|
var company_facts: Dictionary = Dictionary(data.get("company", {}))
|
|
|
|
|
var company_status := _m50_resource_chip("MarketCompanyStatus", "company", "%s %d/%d" % [_tr("队伍", "LINE", data), int(company_facts.get("owned_count", 0)), int(company_facts.get("line_capacity", 0))])
|
|
|
|
|
top.add_child(company_status)
|
|
|
|
|
var coin := _m50_resource_chip("MarketCoinStatus", "coin", "%s %d" % [_tr("金币", "COIN", data), int(company_facts.get("coin", 0))])
|
|
|
|
|
top.add_child(coin)
|
|
|
|
|
var settings := UIFactory.command_button("MarketSettings", "", "icon", "settings", "flat", "content", Vector2(52, 48))
|
|
|
|
|
settings.tooltip_text = _tr("打开设置", "Open settings", data)
|
|
|
|
|
settings.pressed.connect(func(): emit_intent("settings", {}), CONNECT_DEFERRED)
|
|
|
|
|
top.add_child(settings)
|
|
|
|
|
|
|
|
|
|
var body := HBoxContainer.new()
|
|
|
|
|
body.name = "M50MarketBody"
|
|
|
|
|
body.add_theme_constant_override("separation", 8 if size.x < 820.0 else 14)
|
|
|
|
|
body.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
|
|
|
page.add_child(body)
|
|
|
|
|
|
|
|
|
|
var left := VBoxContainer.new()
|
|
|
|
|
left.name = "M50MarketOffersColumn"
|
|
|
|
|
left.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
|
|
|
left.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
|
|
|
left.add_theme_constant_override("separation", 8)
|
|
|
|
|
body.add_child(left)
|
|
|
|
|
var offer_heading := UIFactory.label(_tr("可用招募", "AVAILABLE RECRUITS", data), "label", 1.0, Tokens.COLOR_IVORY)
|
|
|
|
|
offer_heading.name = "M50MarketOffersHeading"
|
|
|
|
|
var offer_heading_surface := PanelContainer.new()
|
|
|
|
|
offer_heading_surface.name = "MarketOffersHeadingSurface"
|
|
|
|
|
offer_heading_surface.custom_minimum_size.y = 32
|
|
|
|
|
var heading_style := StyleBoxFlat.new()
|
|
|
|
|
heading_style.bg_color = Color(0.08, 0.13, 0.15, 0.68)
|
|
|
|
|
heading_style.border_color = Color(Tokens.COLOR_GOLD_LIGHT, 0.48)
|
|
|
|
|
heading_style.set_border_width_all(1)
|
|
|
|
|
heading_style.set_corner_radius_all(8)
|
|
|
|
|
offer_heading_surface.add_theme_stylebox_override("panel", heading_style)
|
|
|
|
|
offer_heading_surface.add_child(offer_heading)
|
|
|
|
|
left.add_child(offer_heading_surface)
|
|
|
|
|
var offer_list := HBoxContainer.new()
|
|
|
|
|
offer_list.name = "MarketOfferList"
|
|
|
|
|
offer_list.add_theme_constant_override("separation", 10)
|
|
|
|
|
offer_list.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
|
|
|
left.add_child(offer_list)
|
|
|
|
|
|
|
|
|
|
var offers: Dictionary = Dictionary(data.get("offers", {}))
|
|
|
|
|
var recruit_offers: Array = Array(offers.get("recruit", []))
|
|
|
|
|
var selected_offer_id := String(data.get("selected_offer_id", ""))
|
|
|
|
|
var selected_kind := String(data.get("selected_kind", ""))
|
|
|
|
|
for index in range(mini(3, recruit_offers.size())):
|
|
|
|
|
offer_list.add_child(_m50_recruit_card(index, recruit_offers[index], selected_kind, selected_offer_id, data))
|
|
|
|
|
if String(data.get("category", "recruit")) == "equipment":
|
|
|
|
|
# Keep the legacy four-socket contract while the first slice focuses on
|
|
|
|
|
# recruit cards; equipment presentation migrates after owner review.
|
|
|
|
|
while offer_list.get_child_count() < 4:
|
|
|
|
|
var compatibility_socket := Control.new()
|
|
|
|
|
compatibility_socket.name = "MarketEquipmentSocket%d" % offer_list.get_child_count()
|
|
|
|
|
compatibility_socket.visible = false
|
|
|
|
|
offer_list.add_child(compatibility_socket)
|
|
|
|
|
if recruit_offers.is_empty():
|
|
|
|
|
var empty := UIFactory.label(_tr("暂无可用招募", "NO RECRUITS AVAILABLE"), "body", 1.0, Tokens.COLOR_IVORY)
|
|
|
|
|
empty.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
|
|
|
|
offer_list.add_child(empty)
|
|
|
|
|
|
|
|
|
|
var selected: Dictionary = Dictionary(data.get("selected_offer", {}))
|
|
|
|
|
var board := Panel.new()
|
|
|
|
|
board.name = "MarketContextSurface"
|
|
|
|
|
board.add_theme_stylebox_override("panel", _flat_style(Color(0.15, 0.25, 0.25, 0.94), Color(Tokens.COLOR_GOLD_LIGHT, 0.78), 2, 10))
|
|
|
|
|
board.custom_minimum_size = Vector2(260 if size.x < 820.0 else 286, 0)
|
|
|
|
|
board.size_flags_horizontal = Control.SIZE_EXPAND
|
|
|
|
|
board.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
|
|
|
body.add_child(board)
|
|
|
|
|
var board_margin := MarginContainer.new()
|
|
|
|
|
board_margin.name = "M50CommissionBoardContent"
|
|
|
|
|
board_margin.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
|
|
|
var board_side_margin := 18 if size.x < 820.0 else 28
|
|
|
|
|
board_margin.add_theme_constant_override("margin_left", board_side_margin)
|
|
|
|
|
board_margin.add_theme_constant_override("margin_right", board_side_margin)
|
|
|
|
|
board_margin.add_theme_constant_override("margin_top", 24 if size.x < 820.0 else 32)
|
|
|
|
|
board_margin.add_theme_constant_override("margin_bottom", 20 if size.x < 820.0 else 28)
|
|
|
|
|
board.add_child(board_margin)
|
|
|
|
|
var board_content := VBoxContainer.new()
|
|
|
|
|
board_content.add_theme_constant_override("separation", 7)
|
|
|
|
|
board_margin.add_child(board_content)
|
|
|
|
|
var board_title := UIFactory.label(_tr("候选人详情", "CANDIDATE DETAILS"), "heading", 1.0, Tokens.COLOR_IVORY)
|
|
|
|
|
board_title.name = "M50CommissionBoardTitle"
|
|
|
|
|
board_title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
|
|
|
if size.x < 820.0:
|
|
|
|
|
board_title.add_theme_font_size_override("font_size", 18)
|
|
|
|
|
board_content.add_child(board_title)
|
|
|
|
|
var instruction := UIFactory.label(_tr("职业、特质与招募价格", "ROLE, TRAIT AND RECRUITMENT COST"), "micro", 1.0, Color("#ead49b"))
|
|
|
|
|
instruction.name = "M50CommissionInstruction"
|
|
|
|
|
instruction.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
|
|
|
|
instruction.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
|
|
|
board_content.add_child(instruction)
|
|
|
|
|
var divider := HSeparator.new()
|
|
|
|
|
divider.name = "M50CommissionDivider"
|
|
|
|
|
board_content.add_child(divider)
|
|
|
|
|
var detail_surface := PanelContainer.new()
|
|
|
|
|
detail_surface.name = "MarketCandidateFactSurface"
|
|
|
|
|
detail_surface.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
|
|
|
detail_surface.add_theme_stylebox_override("panel", _flat_style(Color(0.94, 0.86, 0.68, 0.94), Color(0.47, 0.31, 0.18, 0.70), 1, 8))
|
|
|
|
|
var detail := UIFactory.label("", "body", 1.0, Tokens.COLOR_INK)
|
|
|
|
|
detail.name = "M50CommissionDetail"
|
|
|
|
|
detail.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
|
|
|
|
detail.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
|
|
|
|
detail_surface.add_child(detail)
|
|
|
|
|
board_content.add_child(detail_surface)
|
|
|
|
|
var review := UIFactory.command_button("MarketReviewRecruit", _tr("查看详情", "REVIEW DETAILS"), "primary", "inspect", "angular", "company", Vector2(0, 52))
|
|
|
|
|
review.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
|
|
|
review.disabled = selected_offer_id.is_empty() or selected_kind != "recruit"
|
|
|
|
|
UIFactory.refresh_command_button(review, review.disabled, false)
|
|
|
|
|
review.pressed.connect(func(): emit_intent("recruit_review", {}), CONNECT_DEFERRED)
|
|
|
|
|
board_content.add_child(review)
|
|
|
|
|
if selected_offer_id.is_empty():
|
|
|
|
|
detail.text = _tr("从左侧选择一名候选人。\n这里会显示职业、特质和招募价格。", "Select a candidate on the left.\nProfession, trait and recruitment cost will appear here.")
|
|
|
|
|
else:
|
|
|
|
|
var p := _offer_presentation(selected)
|
|
|
|
|
detail.text = "%s\n%s\n%s" % [String(p.get("title", "")), String(p.get("short_detail", "")), String(p.get("state_text", ""))]
|
|
|
|
|
|
|
|
|
|
var footer := HBoxContainer.new()
|
|
|
|
|
footer.name = "M50MarketFooter"
|
|
|
|
|
footer.add_theme_constant_override("separation", 10)
|
|
|
|
|
footer.custom_minimum_size.y = 52
|
|
|
|
|
page.add_child(footer)
|
|
|
|
|
var back := UIFactory.command_button("MarketBackGuild", _tr("返回公会", "BACK TO GUILD"), "utility", "back", "angular", "content", Vector2(150, 48))
|
|
|
|
|
back.pressed.connect(func(): emit_intent("back", {}), CONNECT_DEFERRED)
|
|
|
|
|
footer.add_child(back)
|
|
|
|
|
var footer_hint := UIFactory.label(_tr("准备 → 编队 → 风险 → 出发", "PREPARE → FORM → RISK → DEPART"), "micro", 1.0, Tokens.COLOR_GOLD_LIGHT)
|
|
|
|
|
footer_hint.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
|
|
|
|
footer_hint.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
|
|
|
footer.add_child(footer_hint)
|
|
|
|
|
var return_command_facts: Dictionary = Dictionary(Dictionary(data.get("commands", {})).get("return_contract", {}))
|
|
|
|
|
var return_enabled := bool(return_command_facts.get("enabled", false))
|
|
|
|
|
var return_contract := UIFactory.command_button("MarketReturnContract", _tr("返回委托", "RETURN"), "danger", "risk", "angular", "company", Vector2(148, 48))
|
|
|
|
|
return_contract.disabled = not return_enabled
|
|
|
|
|
UIFactory.refresh_command_button(return_contract, return_contract.disabled, false)
|
|
|
|
|
return_contract.set_meta("market_command_role", "contract_return")
|
|
|
|
|
return_contract.tooltip_text = _return_contract_tooltip(String(return_command_facts.get("reason", "market_required")), data)
|
|
|
|
|
return_contract.pressed.connect(func(): emit_intent("return_contract", {}), CONNECT_DEFERRED)
|
|
|
|
|
footer.add_child(return_contract)
|
|
|
|
|
|
|
|
|
|
# Category commands stay available to keyboard/touch contracts but remain
|
|
|
|
|
# secondary to the recruit decision in this first responsive slice.
|
|
|
|
|
for category in ["equipment", "battle"]:
|
|
|
|
|
var category_button := UIFactory.command_button("MarketCategory%s" % category.capitalize(), "", "secondary", "generic", "flat", "content")
|
|
|
|
|
category_button.visible = false
|
|
|
|
|
category_button.pressed.connect(func(): emit_intent("category", {"category": category}), CONNECT_DEFERRED)
|
|
|
|
|
add_child(category_button)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## M52 design restoration --------------------------------------------------
|
|
|
|
|
## The page follows the approved board's physical grammar: a market rail,
|
|
|
|
|
## hanging parchment recruit cards, a warm adventurer ledger and matching wood
|
|
|
|
@@ -823,6 +528,10 @@ func _render_m52_market_restore(data: Dictionary) -> void:
|
|
|
|
|
page.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
|
|
|
page.mouse_filter = Control.MOUSE_FILTER_PASS
|
|
|
|
|
canvas.add_child(page)
|
|
|
|
|
# Slot adapters choose the authored compact/desktop grammar from the
|
|
|
|
|
# fitted viewport, never from the fixed root's 1280 design units.
|
|
|
|
|
var fitted_width := minf(size.x, size.y * (16.0 / 9.0))
|
|
|
|
|
var fitted_layout_size := Vector2(fitted_width, fitted_width * (9.0 / 16.0))
|
|
|
|
|
|
|
|
|
|
# Header owns the plaque and its local text safety slots. Market only
|
|
|
|
|
# positions this module on the shared 16:9 design canvas.
|
|
|
|
@@ -879,7 +588,7 @@ func _render_m52_market_restore(data: Dictionary) -> void:
|
|
|
|
|
var market_category := String(data.get("category", "recruit"))
|
|
|
|
|
var selected_offer_id := String(data.get("selected_offer_id", ""))
|
|
|
|
|
var selected_kind := String(data.get("selected_kind", ""))
|
|
|
|
|
var card_areas: Array[Rect2] = M52MarketSlotAdapter.card_areas(design_canvas.size)
|
|
|
|
|
var card_areas: Array[Rect2] = M52MarketSlotAdapter.card_areas(fitted_layout_size)
|
|
|
|
|
if market_category == "recruit":
|
|
|
|
|
for index in range(mini(3, recruit_offers.size())):
|
|
|
|
|
offer_list.add_child(_m52_recruit_card_component(index, recruit_offers[index], card_areas[index], selected_kind, selected_offer_id, data))
|
|
|
|
@@ -922,7 +631,7 @@ func _render_m52_market_restore(data: Dictionary) -> void:
|
|
|
|
|
"action_disabled": not has_selection,
|
|
|
|
|
})
|
|
|
|
|
ledger.name = "MarketContextSurface"
|
|
|
|
|
_market_place(ledger, M52MarketSlotAdapter.ledger_area(design_canvas.size))
|
|
|
|
|
_market_place(ledger, M52MarketSlotAdapter.ledger_area(fitted_layout_size))
|
|
|
|
|
ledger.z_index = 12
|
|
|
|
|
ledger.action_requested.connect(func(): emit_intent("recruit_review", {}), CONNECT_DEFERRED)
|
|
|
|
|
page.add_child(ledger)
|
|
|
|
|