class_name ABGContractChoicePageController extends RefCounted const GuildContractService = preload("res://entry/guild_contract_service.gd") ## UI-independent Contract Choice view-data assembly. ## Contract creation remains owned by GuildContractService; this controller only ## describes the stable choice surface and whether the Confirm boundary may be ## exposed. func snapshot(company: Dictionary, selected_difficulty := "standard", locale := "zh_CN") -> Dictionary: if company.is_empty(): return {"ok": false, "code": "COMPANY_REQUIRED"} var active_contract = company.get("active_contract", {}) if not active_contract is Dictionary: return {"ok": false, "code": "COMPANY_INVALID"} if not Dictionary(active_contract).is_empty(): return {"ok": false, "code": "CONTRACT_ALREADY_ACTIVE"} var normalized := normalize_difficulty(selected_difficulty) var catalog := _difficulty_catalog(locale, normalized) var recruits := _copy_array(company.get("owned_recruits", [])) var company_data := { "company_id": String(company.get("company_id", "")), "owned_count": recruits.size(), "recruits": recruits, } var creation_facts := { "contract_id": GuildContractService.FIRST_CONTRACT_ID, "route_id": "windglass_verge", "route_title": _tr("风镜初渡", "FIRST WINDGLASS CROSSING", locale), "route_copy": _tr("穿越悬浮风镜,建立公会的第一条安全通路。", "Cross the suspended windglass and establish the Guild's first safe route.", locale), "starting_coin": GuildContractService.STARTING_COIN, "line_capacity": GuildContractService.STARTING_LINE_CAPACITY, "market_counts": {"recruit": 3, "equipment": 4, "battle": 3}, } return { "ok": true, "page_id": "contract_choice", "company": company_data, "contract": creation_facts, "difficulties": catalog, "selected_difficulty": normalized, "confirm": { "eligible": true, "reason": "ready", }, "locale": String(locale), } func normalize_difficulty(value: String) -> String: return value if value in GuildContractService.DIFFICULTIES else "standard" func is_valid_difficulty(value: String) -> bool: return value in GuildContractService.DIFFICULTIES func confirm_state(company: Dictionary, selected_difficulty := "standard") -> Dictionary: if company.is_empty(): return {"eligible": false, "reason": "company_required"} var active_contract = company.get("active_contract", {}) if not active_contract is Dictionary: return {"eligible": false, "reason": "company_invalid"} if not Dictionary(active_contract).is_empty(): return {"eligible": false, "reason": "contract_already_active"} if not is_valid_difficulty(selected_difficulty): return {"eligible": false, "reason": "invalid_difficulty"} return {"eligible": true, "reason": "ready"} func _difficulty_catalog(locale: String, selected: String) -> Array[Dictionary]: var result: Array[Dictionary] = [] for difficulty in GuildContractService.DIFFICULTIES: var id := String(difficulty) result.append({ "id": id, "name": _difficulty_name(id, locale), "copy": _difficulty_copy(id, locale), "selected": id == selected, }) return result func _difficulty_name(value: String, locale: String) -> String: match value: "wayfinder": return _tr("引路", "Wayfinder", locale) "stormbound": return _tr("风暴", "Stormbound", locale) "iron_oath": return _tr("铁誓", "Iron Oath", locale) return _tr("标准", "Standard", locale) func _difficulty_copy(value: String, locale: String) -> String: match value: "wayfinder": return _tr("较宽容的敌方参数;所有系统、进度与记录仍然可用。", "More forgiving enemy parameters; all systems, progression and Records remain available.", locale) "stormbound": return _tr("更高压力与回报;目标规则和远征团所有权不变。", "Higher pressure and rewards; target rules and Company ownership remain unchanged.", locale) "iron_oath": return _tr("最高压力;只改变敌人与回报参数,不隐藏规则。", "Highest pressure; only enemy and reward parameters change, never hidden rules.", locale) return _tr("完整的标准平衡;不需要额外永久战力。", "The complete standard balance; no extra permanent power is required.", locale) func _copy_array(value) -> Array: var result: Array = [] if value is Array: for item in value: result.append(item.duplicate(true) if item is Dictionary or item is Array else item) return result func _tr(zh: String, en: String, locale: String) -> String: return en if String(locale).to_lower().begins_with("en") else zh