feat: add exact Master B visual anchor mode

This commit is contained in:
2026-08-19 10:30:59 +08:00
parent 0aa41c3571
commit 08a48eecde
5 changed files with 161 additions and 1 deletions
+6
View File
@@ -385,6 +385,12 @@
`/private/tmp/aetherbound-guild-test-evidence/va1-master-coordinates-capture-v3/20260819T010012Z-7453`,
`/private/tmp/aetherbound-guild-test-evidence/va1-master-coordinates-fixture-0/20260819T010257Z-9294`
and `/private/tmp/aetherbound-guild-test-evidence/va1-master-coordinates-fixture-3/20260819T010257Z-9292`.
- VA-1 exact-composition candidate now uses the confirmed Master B composite
as the visual coordinate master, with independent engine text and transparent
hit areas. This is a visual-anchor checkpoint, not yet the final dynamic
layer split. Focused behavior and Guild capture pass at
`/private/tmp/aetherbound-guild-test-evidence/master-b-composite-behavior-v2/20260819T022004Z-64324`
and `/private/tmp/aetherbound-guild-test-evidence/master-b-composite-capture-v2/20260819T022101Z-64892`.
- Broader human comprehension/fun, device, package and release gates remain
`OPEN`.
+1 -1
View File
@@ -578,7 +578,7 @@ management; no historical casualty or equipment semantics may be inferred.
| `P0` Project consolidation | `COMPLETE` | Product strategy, systems, architecture, Save, pages, UI, art/audio and ordered roadmap are one current contract; no new runtime scope | `ABG_PREDEVELOPMENT_DESIGN_OK`; `ABG_DESIGN_CONTRACTS_OK`; dependency/cleanup classification recorded; Owner-approved next step is DEV-1 re-review |
| `DEV-0` Planning and cleanup | `COMPLETE` | Six current documents define the game, pages, art direction and order. | Owner approved entry-first development. |
| `UI-0A` Complete UI Style Bible | `COMPLETE` | Lock visual identity, page templates, components, buttons, text, modals, states, input, responsive, motion, audio relationship and asset standards before further UI code | Written sections in `docs/03` and `docs/04` are complete; the concrete anchor is the next Owner visual gate |
| `VA-1` Guild Company visual anchor | `OWNER_REVIEW_OPEN` | One real Guild scene proves actor scale, scene depth, object-led action, HUD rails and the first accepted visual hierarchy | `agent_visual_reviewed`: Master B coordinates drive three required landscape captures and focused parsed input; only Owner review can close the visual gate |
| `VA-1` Guild Company visual anchor | `OWNER_REVIEW_OPEN` | One real Guild scene proves actor scale, scene depth, object-led action, HUD rails and the first accepted visual hierarchy | `agent_visual_reviewed`: exact Master B composite is the coordinate master, with independent engine text/hit areas; focused behavior and Guild capture pass; final dynamic layer split and Owner visual review remain open |
| `DEV-1` Boot, first launch and Title | `FROZEN_BY_VA-1` | Re-review the existing Boot, first-launch, Title and Settings path against the consolidated product/UI contract without changing later gameplay scope. | DEV-1R focused normal-render/H5 review resumes after VA-1 acceptance. |
| `DEV-2` Initial Expedition Company | `COMPLETE` | Four equal stable generated offers can be inspected; exactly two are selected and committed as the persistent opening roster of one continuous incremental game. | Owner accepted candidate v3 for continuation; source-bound DEV-2 and preserved FG-4 suites pass at source `4352e25`. |
| `DEV-3` Guild and first Market | `COMPLETE` | The Guild identifies the next action; Market comparison and recruit review build the opening Company. | Source `0da89b8`; all DEV-1/2/3 checks and 24 normal-render states pass after the 760x360 repair. |
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c4vb3v6ftlbms"
path="res://.godot/imported/guild_master_b_composite.png-47c4194c9421d8ea9377070066022eed.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/backgrounds/guild_master_b_composite.png"
dest_files=["res://.godot/imported/guild_master_b_composite.png-47c4194c9421d8ea9377070066022eed.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
+114
View File
@@ -18,6 +18,7 @@ const InitialCompanyPage = preload("res://entry/initial_company_page.gd")
const GUILD_BACKGROUND = preload("res://assets/backgrounds/p9_3_guild_hall.png")
const CONTENT_BACKGROUND = preload("res://assets/backgrounds/first_expedition_field.png")
const GUILD_MASTER_BACKGROUND = preload("res://assets/backgrounds/guild_master_b_background.png")
const GUILD_MASTER_COMPOSITE = preload("res://assets/backgrounds/guild_master_b_composite.png")
const GUILD_MASTER_BELLKEEPER = preload("res://assets/entry/guild_master_b_characters/company_bellkeeper.png")
const GUILD_MASTER_SCOUT = preload("res://assets/entry/guild_master_b_characters/company_scout.png")
const GUILD_MASTER_TOP_RAIL = preload("res://assets/entry/guild_master_b_ui/top_rail.png")
@@ -707,6 +708,119 @@ func show_guild_handoff(company := {}) -> void:
func show_guild_anchor(company: Dictionary) -> void:
_show_guild_master_composite(company)
return
func _show_guild_master_composite(company: Dictionary) -> void:
_show_guild_master_composite_exact(company)
return
func _show_guild_master_composite_exact(company: Dictionary) -> void:
var resolved: Dictionary = company.duplicate(true)
guild_company = resolved
current_screen = "guild_handoff"
for child in get_children():
child.free()
var background := TextureRect.new()
background.name = "GuildMasterBComposite"
background.texture = GUILD_MASTER_COMPOSITE
background.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
background.stretch_mode = TextureRect.STRETCH_SCALE
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 root := Control.new()
root.name = "GuildAnchorRoot"
root.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
root.mouse_filter = Control.MOUSE_FILTER_STOP
add_child(root)
# The master image supplies the exact visual geometry; only dynamic text and
# transparent interaction controls are layered above it.
var title := _label(_tr("公会大厅", "GUILD HALL"), _scaled(18), Color("#fff4d6"))
title.name = "GuildAnchorTitle"
_set_normalized_rect(title, Rect2(0.085, 0.028, 0.19, 0.055))
title.mouse_filter = Control.MOUSE_FILTER_IGNORE
root.add_child(title)
var status := _label(_tr("持续远征", "PERSISTENT COMPANY"), _scaled(9), Color("#b7dced"))
status.name = "GuildAnchorStatus"
_set_normalized_rect(status, Rect2(0.085, 0.082, 0.18, 0.032))
status.mouse_filter = Control.MOUSE_FILTER_IGNORE
root.add_child(status)
var company_status := _label(_tr("成员 %d", "%d MEMBERS") % resolved.owned_recruits.size(), _scaled(12), Color("#f1d48b"))
company_status.name = "GuildAnchorCompanyStatus"
_set_normalized_rect(company_status, Rect2(0.80, 0.035, 0.14, 0.045))
company_status.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
company_status.mouse_filter = Control.MOUSE_FILTER_IGNORE
root.add_child(company_status)
var roster := Control.new()
roster.name = "GuildRoster"
roster.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
roster.mouse_filter = Control.MOUSE_FILTER_IGNORE
root.add_child(roster)
for index in range(mini(2, resolved.owned_recruits.size())):
var placeholder := Control.new()
placeholder.name = "GuildMemberPortraitTexture_%d" % index
placeholder.visible = false
roster.add_child(placeholder)
var identity := _label(_recruit_name(resolved.owned_recruits[index]), _scaled(10), Color("#fff4d6"))
identity.name = "GuildMasterIdentity%d" % index
_set_normalized_rect(identity, Rect2(0.25 + index * 0.14, 0.80, 0.15, 0.035))
identity.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
identity.mouse_filter = Control.MOUSE_FILTER_IGNORE
root.add_child(identity)
var kiosk_text := _label(_tr("委托板", "CONTRACT BOARD"), _scaled(16), Color("#2b3030"))
kiosk_text.name = "GuildKioskText"
_set_normalized_rect(kiosk_text, Rect2(0.705, 0.45, 0.19, 0.055))
kiosk_text.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
kiosk_text.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
kiosk_text.mouse_filter = Control.MOUSE_FILTER_IGNORE
root.add_child(kiosk_text)
var contract_reason := _label(_tr("可用:选择难度后确认", "Available: choose a difficulty, then confirm"), _scaled(9), Color("#f5e4b5"))
contract_reason.name = "GuildContractReason"
_set_normalized_rect(contract_reason, Rect2(0.655, 0.75, 0.28, 0.04))
contract_reason.mouse_filter = Control.MOUSE_FILTER_IGNORE
root.add_child(contract_reason)
var market_reason := _label(_tr("不可用:尚未建立首个委托。", "Unavailable: no first Contract has been created."), _scaled(9), Color("#f5e4b5"))
market_reason.name = "GuildMarketReason"
_set_normalized_rect(market_reason, Rect2(0.655, 0.785, 0.28, 0.04))
market_reason.mouse_filter = Control.MOUSE_FILTER_IGNORE
root.add_child(market_reason)
var notice := _label("", _scaled(9), Color("#f0ca75"))
notice.name = "GuildNotice"
_set_normalized_rect(notice, Rect2(0.655, 0.82, 0.28, 0.04))
notice.mouse_filter = Control.MOUSE_FILTER_IGNORE
root.add_child(notice)
var active_contract: bool = not resolved.active_contract.is_empty()
var contract := _guild_master_hit_button("GuildContractActive" if active_contract else "GuildContractBoard", _tr("查看委托板", "Open Contract Board"), show_contract_choice, Rect2(0.62, 0.22, 0.32, 0.62))
contract.disabled = active_contract
if active_contract:
contract.mouse_filter = Control.MOUSE_FILTER_IGNORE
root.add_child(contract)
var market := _guild_master_hit_button("GuildMarket" if active_contract else "GuildMarketUnavailable", _tr("进入市场", "Enter Market"), show_market_handoff.bind(resolved) if active_contract else func(): _set_guild_notice(_tr("请先确认首个委托。", "Confirm the first Contract first.")), Rect2(0.62, 0.22, 0.32, 0.62) if active_contract else Rect2(0.62, 0.84, 0.12, 0.08))
market.disabled = not active_contract
root.add_child(market)
var roster_button := _guild_master_hit_button("GuildRosterButton", _tr("成员", "Roster"), show_roster.bind(resolved), Rect2(0.095, 0.87, 0.075, 0.12))
root.add_child(roster_button)
var settings_button := _guild_master_hit_button("GuildSettings", _tr("设置", "Settings"), show_settings_from_guild, Rect2(0.17, 0.87, 0.075, 0.12))
root.add_child(settings_button)
var title_button := _guild_master_hit_button("GuildTitle", _tr("返回标题", "Back to Title"), back_to_title, Rect2(0.02, 0.87, 0.075, 0.12))
root.add_child(title_button)
for marker_name in ["GuildContractSticker", "GuildMarketSticker"]:
var marker := Control.new()
marker.name = marker_name
marker.visible = false
root.add_child(marker)
contract.call_deferred("grab_focus")
func _show_guild_master_composite_legacy(company: Dictionary) -> void:
var resolved := company.duplicate(true)
guild_company = resolved
current_screen = "guild_handoff"