feat: rebuild Guild anchor scene composition

This commit is contained in:
2026-08-18 22:20:08 +08:00
parent 139cc3ef12
commit beabbfb0e5
+160
View File
@@ -563,6 +563,8 @@ func show_guild_handoff(company := {}) -> void:
resolved = loaded.company.duplicate(true)
guild_contract_service.company_path = initial_company_service.company_path
guild_company = resolved
show_guild_anchor(resolved)
return
current_screen = "guild_handoff"
_build_world_base(true)
var frame_safe := MarginContainer.new()
@@ -696,6 +698,164 @@ func show_guild_handoff(company := {}) -> void:
focus_target.call_deferred("grab_focus")
func show_guild_anchor(company: Dictionary) -> void:
var resolved := company.duplicate(true)
guild_company = resolved
current_screen = "guild_handoff"
_build_world_base(true)
var margin := maxi(14, int(settings.get("safe_area", 24)))
var root := Control.new()
root.name = "GuildAnchorRoot"
root.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
root.offset_left = margin
root.offset_right = -margin
root.offset_top = 10
root.offset_bottom = -10
add_child(root)
var top_rail := ColorRect.new()
top_rail.name = "GuildAnchorTopRail"
top_rail.set_anchors_and_offsets_preset(Control.PRESET_TOP_WIDE)
top_rail.offset_bottom = 64
top_rail.color = Color(0.04, 0.10, 0.13, 0.72)
top_rail.mouse_filter = Control.MOUSE_FILTER_IGNORE
root.add_child(top_rail)
var top_rule := ColorRect.new()
top_rule.name = "GuildAnchorTopRule"
top_rule.position = Vector2(18, 58)
top_rule.size = Vector2(maxf(1.0, size.x - margin * 2.0 - 36.0), 2)
top_rule.color = Color("#d6b76c")
top_rule.mouse_filter = Control.MOUSE_FILTER_IGNORE
root.add_child(top_rule)
var title := _label(_tr("公会大厅", "GUILD HALL"), _scaled(22), Color("#fff4d6"))
title.name = "GuildAnchorTitle"
title.position = Vector2(18, 9)
title.size = Vector2(330, 30)
root.add_child(title)
var status := _label(_tr("持续远征", "PERSISTENT COMPANY"), _scaled(11), Color("#a9d9ef"))
status.name = "GuildAnchorStatus"
status.position = Vector2(20, 38)
status.size = Vector2(330, 18)
root.add_child(status)
var company_status := _label(_tr("成员 %d", "%d MEMBERS") % resolved.owned_recruits.size(), _scaled(13), Color("#f0ca75"))
company_status.name = "GuildAnchorCompanyStatus"
company_status.anchor_left = 1.0
company_status.anchor_right = 1.0
company_status.offset_left = -230
company_status.offset_right = -18
company_status.offset_top = 20
company_status.offset_bottom = 48
company_status.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
root.add_child(company_status)
var body := Control.new()
body.name = "GuildHandoffBody"
body.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
body.offset_top = 74
body.offset_bottom = -62
root.add_child(body)
var roster := HBoxContainer.new()
roster.name = "GuildRoster"
roster.anchor_right = 0.57
roster.anchor_bottom = 1.0
roster.offset_left = 18
roster.offset_top = 10
roster.offset_right = -6
roster.offset_bottom = -8
roster.size_flags_horizontal = Control.SIZE_EXPAND_FILL
roster.add_theme_constant_override("separation", 8)
body.add_child(roster)
for index in range(resolved.owned_recruits.size()):
roster.add_child(_guild_member_column(index, resolved.owned_recruits[index]))
var next := VBoxContainer.new()
next.name = "GuildNextActions"
next.anchor_left = 0.59
next.anchor_right = 1.0
next.anchor_bottom = 1.0
next.offset_left = 0
next.offset_top = 10
next.offset_right = -8
next.offset_bottom = -8
next.add_theme_constant_override("separation", 5)
body.add_child(next)
var active_contract: bool = String(resolved.get("active_contract", {}).get("status", "")) in ["market", "battle", "result", "recovery"]
var returned_contract: bool = String(resolved.get("active_contract", {}).get("status", "")) == "returned"
var next_label := _label(_tr("下一步", "NEXT ACTION"), _scaled(10), Color("#e8d39d"))
next_label.name = "GuildNextHeading"
next.add_child(next_label)
var next_copy := _label(
_tr("前往市场扩充远征团。", "Enter the Market to expand the Company.") if active_contract else _tr("选择首个委托与难度。", "Choose the first Contract and difficulty."),
_scaled(14), Color("#fff4d6")
)
next_copy.name = "GuildNextCopy"
next_copy.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
next.add_child(next_copy)
var contract := _guild_destination_button(
"GuildContractActive" if active_contract else "GuildContractBoard",
"contract",
_tr("委托已开始", "Contract Active") if active_contract else _tr("委托板", "Contract Board"),
func(): _set_guild_notice(_tr("委托已开始,请进入市场。", "The Contract is active; enter its Market.")) if active_contract else show_contract_choice()
)
_set_entry_button_disabled(contract, active_contract or returned_contract)
contract.visible = not active_contract and not returned_contract
next.add_child(contract)
var contract_reason := _label(
_tr("已开始:风镜初渡", "Active: First Windglass Crossing") if active_contract else _tr("可用:选择难度后确认", "Available: choose a difficulty, then confirm"),
_scaled(10), Color("#e8d39d")
)
contract_reason.name = "GuildContractReason"
contract_reason.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
next.add_child(contract_reason)
var market := _guild_destination_button(
"GuildMarket" if active_contract else "GuildMarketUnavailable",
"market",
_tr("进入市场", "Enter Market") if active_contract else _tr("市场", "Market"),
func(): show_market_handoff(resolved) if active_contract else _set_guild_notice(_tr("请先确认首个委托。", "Confirm the first Contract first."))
)
_set_entry_button_disabled(market, not active_contract)
market.visible = active_contract
next.add_child(market)
var market_reason := _label(
_tr("可用:市场准备", "Available: Market preparation") if active_contract else _tr("不可用:尚未建立首个委托。", "Unavailable: no first Contract has been created."),
_scaled(10), Color("#e8d39d")
)
market_reason.name = "GuildMarketReason"
market_reason.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
next.add_child(market_reason)
var notice := _label("", _scaled(10), Color("#f0ca75"))
notice.name = "GuildNotice"
notice.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
next.add_child(notice)
var bottom_rail := ColorRect.new()
bottom_rail.name = "GuildAnchorBottomRail"
bottom_rail.set_anchors_and_offsets_preset(Control.PRESET_BOTTOM_WIDE)
bottom_rail.offset_top = -54
bottom_rail.color = Color(0.04, 0.09, 0.11, 0.76)
bottom_rail.mouse_filter = Control.MOUSE_FILTER_IGNORE
root.add_child(bottom_rail)
var footer := HBoxContainer.new()
footer.name = "GuildHandoffFooter"
footer.set_anchors_and_offsets_preset(Control.PRESET_BOTTOM_WIDE)
footer.offset_top = -52
footer.add_theme_constant_override("separation", 8)
root.add_child(footer)
var back := _company_button("GuildTitle", _tr("返回标题", "Back to Title"), back_to_title, "company_utility", "back")
back.custom_minimum_size = Vector2(190, 48)
footer.add_child(back)
var footer_spacer := Control.new()
footer_spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
footer.add_child(footer_spacer)
var roster_button := _company_button("GuildRosterButton", _tr("成员", "Roster"), show_roster.bind(resolved), "content_secondary", "inspect")
roster_button.custom_minimum_size = Vector2(160, 48)
footer.add_child(roster_button)
var settings_button := _company_button("GuildSettings", _tr("设置", "Settings"), show_settings_from_guild, "content_secondary", "settings")
settings_button.custom_minimum_size = Vector2(160, 48)
footer.add_child(settings_button)
(contract if contract.visible else market if market.visible else roster_button).call_deferred("grab_focus")
func show_roster(company := {}) -> void:
var resolved: Dictionary = Dictionary(company).duplicate(true) if company is Dictionary else guild_company.duplicate(true)
if resolved.is_empty():