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