205 lines
8.1 KiB
GDScript
205 lines
8.1 KiB
GDScript
class_name ABGRiskCommitmentPageController
|
|
extends RefCounted
|
|
|
|
## UI-independent Risk Commitment view-data assembly.
|
|
##
|
|
## Entry Shell owns loading, acknowledgement and BattleService commands. This
|
|
## controller validates the supplied selected-risk boundary and copies the
|
|
## facts the accepted RSK-002 View renders.
|
|
|
|
const REQUIRED_CONSEQUENCE_COUNT := 6
|
|
|
|
|
|
func snapshot(
|
|
company: Dictionary,
|
|
formation: Dictionary,
|
|
option: Dictionary,
|
|
consequence_facts: Array = [],
|
|
dependency: Dictionary = {},
|
|
binding: Dictionary = {},
|
|
acknowledged := false,
|
|
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 or Dictionary(raw_contract).is_empty():
|
|
return {"ok": false, "code": "COMMITMENT_CONTRACT_REQUIRED"}
|
|
if formation.is_empty():
|
|
return {"ok": false, "code": "COMMITMENT_FORMATION_REQUIRED"}
|
|
if String(formation.get("status", "")) != "ready":
|
|
return {"ok": false, "code": "COMMITMENT_READINESS_REQUIRED"}
|
|
var raw_snapshot = formation.get("accepted_party_snapshot", {})
|
|
if not raw_snapshot is Dictionary or Dictionary(raw_snapshot).is_empty():
|
|
return {"ok": false, "code": "COMMITMENT_PARTY_SNAPSHOT_REQUIRED"}
|
|
if not option is Dictionary or Dictionary(option).is_empty():
|
|
return {"ok": false, "code": "COMMITMENT_OPTION_REQUIRED"}
|
|
var contract: Dictionary = Dictionary(raw_contract).duplicate(true)
|
|
var members := _members_by_id(raw_recruits)
|
|
var party_snapshot: Dictionary = Dictionary(raw_snapshot).duplicate(true)
|
|
var capacity := int(formation.get("line_capacity", contract.get("line_capacity", 0)))
|
|
var raw_party_ids = party_snapshot.get("front_to_rear_ids", formation.get("saved_front_to_rear_ids", []))
|
|
if not raw_party_ids is Array or raw_party_ids.is_empty():
|
|
return {"ok": false, "code": "COMMITMENT_PARTY_ORDER_REQUIRED"}
|
|
var order_validation := _validate_order(raw_party_ids, members, capacity)
|
|
if not order_validation.ok:
|
|
return order_validation
|
|
|
|
var option_id := String(option.get("risk_option_id", ""))
|
|
if option_id.is_empty():
|
|
return {"ok": false, "code": "COMMITMENT_OPTION_ID_INVALID"}
|
|
var sourced_option := _find_option(formation.get("risk_options", []), option_id)
|
|
if sourced_option.is_empty():
|
|
return {"ok": false, "code": "COMMITMENT_OPTION_STALE"}
|
|
var supplied_option: Dictionary = Dictionary(option).duplicate(true)
|
|
if String(supplied_option.get("option_hash", "")) != String(sourced_option.get("option_hash", "")) and not String(sourced_option.get("option_hash", "")).is_empty():
|
|
return {"ok": false, "code": "COMMITMENT_OPTION_STALE"}
|
|
|
|
if not consequence_facts is Array or consequence_facts.size() != REQUIRED_CONSEQUENCE_COUNT:
|
|
return {"ok": false, "code": "COMMITMENT_CONSEQUENCES_INVALID"}
|
|
var copied_facts: Array = _copy_array(consequence_facts)
|
|
var copied_dependency: Dictionary = Dictionary(dependency).duplicate(true)
|
|
var dependency_ok := bool(copied_dependency.get("ok", false))
|
|
var dependency_code := String(copied_dependency.get("code", "DEPENDENCY_UNVERIFIED"))
|
|
var copied_binding: Dictionary = Dictionary(binding).duplicate(true)
|
|
var binding_stale := bool(copied_binding.get("stale", false)) or String(copied_binding.get("state", "valid")) == "stale"
|
|
var binding_state := "stale" if binding_stale else "valid" if not copied_binding.is_empty() else "unverified"
|
|
var confirmed := bool(acknowledged)
|
|
var ready_to_begin := confirmed and dependency_ok and not binding_stale
|
|
|
|
var relation_source = party_snapshot.get("relations", formation.get("relations", []))
|
|
var copied_relations: Array = _copy_array(relation_source)
|
|
var copied_coverage: Dictionary = Dictionary(party_snapshot.get("coverage", formation.get("coverage", {}))).duplicate(true)
|
|
var relation_by_id := _relations_by_id(copied_relations)
|
|
var ordered_recruits: Array[Dictionary] = []
|
|
for position in range(order_validation.ids.size()):
|
|
var recruit_id := String(order_validation.ids[position])
|
|
ordered_recruits.append({
|
|
"position": position,
|
|
"recruit_id": recruit_id,
|
|
"recruit": Dictionary(members[recruit_id]).duplicate(true),
|
|
"relation": Dictionary(relation_by_id.get(recruit_id, {})).duplicate(true),
|
|
})
|
|
|
|
var copied_option: Dictionary = supplied_option.duplicate(true)
|
|
var contract_data := {
|
|
"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)),
|
|
"contract_hash": String(contract.get("contract_hash", "")),
|
|
}
|
|
var company_data := {
|
|
"company_id": String(company.get("company_id", "")),
|
|
"owned_count": members.size(),
|
|
"line_capacity": capacity,
|
|
}
|
|
return {
|
|
"ok": true,
|
|
"page_id": "risk_commitment",
|
|
"locale": String(locale),
|
|
"company": company_data,
|
|
"contract": contract_data,
|
|
"risk": {
|
|
"risk_option_id": option_id,
|
|
"option": copied_option,
|
|
"risk": int(copied_option.get("risk", 0)),
|
|
"option_hash": String(copied_option.get("option_hash", "")),
|
|
"snapshot_hash": String(party_snapshot.get("snapshot_hash", "")),
|
|
"snapshot_id": String(party_snapshot.get("snapshot_id", "")),
|
|
},
|
|
"consequences": {
|
|
"facts": copied_facts,
|
|
"count": copied_facts.size(),
|
|
},
|
|
"party": {
|
|
"snapshot_id": String(party_snapshot.get("snapshot_id", "")),
|
|
"snapshot_hash": String(party_snapshot.get("snapshot_hash", "")),
|
|
"order_hash": String(party_snapshot.get("order_hash", "")),
|
|
"front_to_rear_ids": order_validation.ids.duplicate(true),
|
|
"ordered_recruits": ordered_recruits,
|
|
"orientation": String(party_snapshot.get("orientation", formation.get("orientation", "rear_left_front_right"))),
|
|
"front_position": int(party_snapshot.get("front_position", formation.get("front_position", 0))),
|
|
"line_capacity": capacity,
|
|
"relations": copied_relations,
|
|
"coverage": copied_coverage,
|
|
},
|
|
"dependency": {
|
|
"ok": dependency_ok,
|
|
"code": dependency_code,
|
|
"facts": copied_dependency,
|
|
},
|
|
"binding": {
|
|
"state": binding_state,
|
|
"stale": binding_stale,
|
|
"facts": copied_binding,
|
|
},
|
|
"confirmation": {
|
|
"acknowledged": confirmed,
|
|
"state": "acknowledged" if confirmed else "required",
|
|
},
|
|
"commands": {
|
|
"settings_enabled": true,
|
|
"selected_details_enabled": true,
|
|
"consequences_review_enabled": true,
|
|
"cancel_enabled": true,
|
|
"acknowledge_enabled": not ready_to_begin,
|
|
"begin_enabled": ready_to_begin,
|
|
},
|
|
}
|
|
|
|
|
|
func _validate_order(values: Array, members: Dictionary, capacity: int) -> Dictionary:
|
|
if capacity <= 0 or values.size() != capacity:
|
|
return {"ok": false, "code": "COMMITMENT_PARTY_COUNT_INVALID"}
|
|
var ids: Array = []
|
|
for value in values:
|
|
var recruit_id := String(value)
|
|
if not members.has(recruit_id):
|
|
return {"ok": false, "code": "COMMITMENT_PARTY_RECRUIT_UNKNOWN"}
|
|
if recruit_id in ids:
|
|
return {"ok": false, "code": "COMMITMENT_PARTY_RECRUIT_DUPLICATE"}
|
|
ids.append(recruit_id)
|
|
return {"ok": true, "code": "COMMITMENT_PARTY_ORDER_VALID", "ids": ids}
|
|
|
|
|
|
func _find_option(values, option_id: String) -> Dictionary:
|
|
if not values is Array:
|
|
return {}
|
|
for value in values:
|
|
if value is Dictionary and String(value.get("risk_option_id", "")) == option_id:
|
|
return Dictionary(value).duplicate(true)
|
|
return {}
|
|
|
|
|
|
func _members_by_id(values) -> Dictionary:
|
|
var result := {}
|
|
for value in values:
|
|
if value is Dictionary:
|
|
var copied: Dictionary = Dictionary(value).duplicate(true)
|
|
var recruit_id := String(copied.get("recruit_id", ""))
|
|
if not recruit_id.is_empty():
|
|
result[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
|