126 lines
4.7 KiB
GDScript
126 lines
4.7 KiB
GDScript
class_name ABGGuildPageController
|
|
extends RefCounted
|
|
|
|
const ContentRegistry = preload("res://p10_0/content_registry.gd")
|
|
|
|
## UI-independent Guild view-data assembly.
|
|
##
|
|
## The controller receives a Company snapshot and describes the Guild desk's
|
|
## state and destination boundaries. It never loads, saves or mutates
|
|
## persistence and never reaches into Godot nodes or Entry Shell globals.
|
|
|
|
const ACTIVE_CONTRACT_STATUSES: Array[String] = ["market", "battle", "result", "recovery"]
|
|
|
|
|
|
func snapshot(company: Dictionary, locale := "zh_CN") -> Dictionary:
|
|
if company.is_empty():
|
|
return {"ok": false, "code": "COMPANY_REQUIRED"}
|
|
var raw_recruits = company.get("owned_recruits", [])
|
|
if not raw_recruits is Array:
|
|
return {"ok": false, "code": "COMPANY_INVALID"}
|
|
var raw_contract = company.get("active_contract", {})
|
|
if not raw_contract is Dictionary:
|
|
return {"ok": false, "code": "CONTRACT_INVALID"}
|
|
|
|
var recruits := _copy_recruits(raw_recruits)
|
|
var contract: Dictionary = Dictionary(raw_contract).duplicate(true)
|
|
var status := String(contract.get("status", ""))
|
|
var has_contract := not contract.is_empty()
|
|
var is_active := status in ACTIVE_CONTRACT_STATUSES
|
|
var is_returned := status == "returned"
|
|
var state := "active" if is_active else "returned" if is_returned else "empty" if not has_contract else "blocked"
|
|
# M79-I06: after the final Contract the route is complete rather than open.
|
|
var contract_total := Array(ContentRegistry.snapshot().get("contracts", [])).size()
|
|
var route_complete := contract_total > 0 and int(company.get("next_contract_ordinal", 0)) >= contract_total and not is_active
|
|
_route_complete_flag = route_complete
|
|
var line_capacity := int(contract.get("line_capacity", 4))
|
|
var coin := int(contract.get("coin", 0))
|
|
var difficulty := String(contract.get("difficulty", "standard"))
|
|
var company_data := {
|
|
"company_id": String(company.get("company_id", "")),
|
|
"owned_count": recruits.size(),
|
|
"line_capacity": line_capacity,
|
|
"recruits": recruits,
|
|
"display_recruits": _copy_recruits(recruits.slice(0, mini(2, recruits.size()))),
|
|
}
|
|
var contract_data := {
|
|
"present": has_contract,
|
|
"active": is_active,
|
|
"returned": is_returned,
|
|
"state": state,
|
|
"status": status,
|
|
"contract_id": String(contract.get("contract_id", "")),
|
|
"run_id": String(contract.get("run_id", "")),
|
|
"route_id": String(contract.get("route_id", "windglass_verge")),
|
|
"difficulty": difficulty,
|
|
"coin": coin,
|
|
"line_capacity": line_capacity,
|
|
}
|
|
return {
|
|
"ok": true,
|
|
"page_id": "guild",
|
|
"company": company_data,
|
|
"contract": contract_data,
|
|
"route_complete": route_complete,
|
|
"contract_total": contract_total,
|
|
"renown": int(company.get("renown", 0)),
|
|
"clear_facts": Array(company.get("clear_facts", [])).size(),
|
|
"destinations": _destinations(state),
|
|
"locale": String(locale),
|
|
}
|
|
|
|
|
|
func destination_state(snapshot_data: Dictionary, destination_id: String) -> Dictionary:
|
|
var destinations = snapshot_data.get("destinations", {})
|
|
if destinations is Dictionary and destinations.has(destination_id):
|
|
return Dictionary(destinations.get(destination_id, {})).duplicate(true)
|
|
return {"enabled": false, "visible": false, "reason": "unknown_destination"}
|
|
|
|
|
|
func _destinations(state: String) -> Dictionary:
|
|
var has_active := state == "active"
|
|
var has_returned := state == "returned"
|
|
var _route_complete := _route_complete_flag
|
|
return {
|
|
"contract": {
|
|
# M79-I05: with the previous contract returned the guild must offer
|
|
# the next one instead of stranding the player. Once the route is
|
|
# complete the board closes with an explicit completion reason.
|
|
"enabled": (state == "empty" or has_returned) and not _route_complete,
|
|
"visible": true,
|
|
"reason": "route_complete" if _route_complete else "ready" if state == "empty" else "contract_active" if has_active else "contract_returned" if has_returned else "contract_invalid",
|
|
},
|
|
"market": {
|
|
"enabled": has_active,
|
|
"visible": has_active,
|
|
"reason": "ready" if has_active else "contract_returned" if has_returned else "contract_required",
|
|
},
|
|
"equipment": {
|
|
"enabled": has_active,
|
|
"visible": true,
|
|
"reason": "ready" if has_active else "contract_required" if not has_returned else "returned_contract",
|
|
},
|
|
"party": {
|
|
"enabled": has_active,
|
|
"visible": true,
|
|
"reason": "ready" if has_active else "contract_required" if not has_returned else "returned_contract",
|
|
},
|
|
"risk": {
|
|
"enabled": has_active,
|
|
"visible": true,
|
|
"reason": "ready" if has_active else "contract_required" if not has_returned else "returned_contract",
|
|
},
|
|
}
|
|
|
|
|
|
func _copy_recruits(values) -> Array[Dictionary]:
|
|
var result: Array[Dictionary] = []
|
|
if not values is Array:
|
|
return result
|
|
for value in values:
|
|
if value is Dictionary:
|
|
result.append(Dictionary(value).duplicate(true))
|
|
return result
|
|
|
|
var _route_complete_flag := false
|