Files
aetherbound-guild/runtime/entry/party_line_page_controller.gd
T

141 lines
5.1 KiB
GDScript

class_name ABGPartyLinePageController
extends RefCounted
## UI-independent Party Line view-data assembly.
##
## FormationRiskService remains responsible for loading, previewing and saving
## formation state. This controller only copies the supplied facts and exposes
## stable selection/command boundaries for the Party View.
func snapshot(
company: Dictionary,
formation: Dictionary,
draft_order: Array,
selected_recruit_id := "",
preview: Dictionary = {},
undo_order: Array = [],
locale := "zh_CN"
) -> Dictionary:
if company.is_empty():
return {"ok": false, "code": "COMPANY_REQUIRED"}
var raw_contract = company.get("active_contract", {})
if not raw_contract is Dictionary or Dictionary(raw_contract).is_empty():
return {"ok": false, "code": "FORMATION_CONTRACT_REQUIRED"}
if formation.is_empty():
return {"ok": false, "code": "FORMATION_REQUIRED"}
if not draft_order is Array:
return {"ok": false, "code": "FORMATION_ORDER_INVALID"}
var contract: Dictionary = Dictionary(raw_contract).duplicate(true)
var members := _members_by_id(company.get("owned_recruits", []))
var capacity := int(formation.get("line_capacity", contract.get("line_capacity", 0)))
var order_validation := _validate_order(draft_order, members, capacity)
if not order_validation.ok:
return order_validation
var normalized_order: Array = order_validation.ids
var selected := String(selected_recruit_id) if String(selected_recruit_id) in normalized_order else ""
var preview_data := _preview_data(preview, formation)
var relations: Array = Array(preview_data.get("relations", [])).duplicate(true)
var relation_by_id := _relations_by_id(relations)
var ordered_recruits: Array[Dictionary] = []
for position in range(normalized_order.size()):
var recruit_id := String(normalized_order[position])
var recruit: Dictionary = Dictionary(members[recruit_id]).duplicate(true)
ordered_recruits.append({
"position": position,
"recruit_id": recruit_id,
"recruit": recruit,
"relation": Dictionary(relation_by_id.get(recruit_id, {})).duplicate(true),
})
var base_order: Array = Array(formation.get("base_front_to_rear_ids", [])).duplicate(true)
return {
"ok": true,
"page_id": "party_line",
"locale": String(locale),
"company": {
"company_id": String(company.get("company_id", "")),
"owned_count": Array(company.get("owned_recruits", [])).size(),
"line_capacity": capacity,
"recruits": _copy_array(company.get("owned_recruits", [])),
},
"contract": {
"contract_id": String(contract.get("contract_id", "")),
"run_id": String(contract.get("run_id", "")),
"difficulty": String(contract.get("difficulty", "standard")),
"coin": int(contract.get("coin", 0)),
"line_capacity": int(contract.get("line_capacity", capacity)),
},
"formation": {
"status": String(formation.get("status", "draft")),
"orientation": String(formation.get("orientation", "rear_left_front_right")),
"front_position": int(formation.get("front_position", 0)),
"line_capacity": capacity,
"base_front_to_rear_ids": base_order,
"first_threat": Dictionary(formation.get("first_threat", {})).duplicate(true),
},
"order": {
"front_to_rear_ids": normalized_order.duplicate(true),
"ordered_recruits": ordered_recruits,
"selected_recruit_id": selected,
"selection_reason": "selected" if not selected.is_empty() else "no_selection",
},
"preview": preview_data,
"commands": {
"undo_enabled": not undo_order.is_empty(),
"reset_enabled": normalized_order != base_order,
"save_enabled": true,
"back_enabled": true,
},
}
func _preview_data(preview: Dictionary, formation: Dictionary) -> Dictionary:
var source := preview if bool(preview.get("ok", false)) else formation
return {
"relations": _copy_array(source.get("relations", [])),
"coverage": Dictionary(source.get("coverage", {})).duplicate(true),
"order_hash": String(preview.get("order_hash", "")),
}
func _validate_order(values: Array, members: Dictionary, capacity: int) -> Dictionary:
if capacity <= 0 or values.size() != capacity:
return {"ok": false, "code": "FORMATION_COUNT_INVALID"}
var ids: Array = []
for value in values:
var recruit_id := String(value)
if not members.has(recruit_id):
return {"ok": false, "code": "FORMATION_RECRUIT_UNKNOWN"}
if recruit_id in ids:
return {"ok": false, "code": "FORMATION_RECRUIT_DUPLICATE"}
ids.append(recruit_id)
return {"ok": true, "code": "FORMATION_ORDER_VALID", "ids": ids}
func _members_by_id(values) -> Dictionary:
var result := {}
if not values is Array:
return result
for value in values:
if value is Dictionary:
var copied: Dictionary = Dictionary(value).duplicate(true)
result[String(copied.get("recruit_id", ""))] = copied
return result
func _relations_by_id(values: Array) -> Dictionary:
var result := {}
for value in values:
if value is Dictionary:
result[String(value.get("recruit_id", ""))] = Dictionary(value).duplicate(true)
return result
func _copy_array(values) -> Array:
var result: Array = []
if not values is Array:
return result
for value in values:
result.append(value.duplicate(true) if value is Dictionary or value is Array else value)
return result