extends RefCounted ## A07/A08 Mana warp: every completed warp is linked to every other warp of the ## same kind by one path connector, so crossing is a single instant step. The ## FRONT guest warp excludes staff routes; the BACK service warp is staff-only. ## Connectors are derived from construction state; their operational state ## follows the reserve and the warps' own power. The Runtime charges fares. const PathType := preload("res://scripts/world/path_service.gd") const DEFINITION_ID := &"mana_warp" const SERVICE_DEFINITION_ID := &"service_warp" const DEFINITION_IDS: Array[StringName] = [DEFINITION_ID, SERVICE_DEFINITION_ID] const ACCESS_BY_DEFINITION := {&"mana_warp": &"!staff", &"service_warp": &"staff"} const PREFIX := "warp.connector:" const MANA_PER_TRIP := 3 const PATH_COST := 400 static func is_warp_connector(connector_id: StringName) -> bool: return String(connector_id).begins_with(PREFIX) ## Completed warps sorted by instance id: [{instance_id, origin}]. static func warps_from_facilities(facilities: Array) -> Array[Dictionary]: var warps: Array[Dictionary] = [] for value: Variant in facilities: if not value is Dictionary: continue var facility: Dictionary = value var definition_id := StringName(str(facility.get(&"definition_id", ""))) if definition_id not in DEFINITION_IDS: continue var origin: Variant = facility.get(&"origin") if not origin is Vector3i: continue warps.append({&"instance_id": StringName(str(facility.get(&"instance_id", ""))), &"origin": origin, &"definition_id": definition_id}) warps.sort_custom(func(a: Dictionary, b: Dictionary) -> bool: return String(a[&"instance_id"]) < String(b[&"instance_id"])) return warps static func expected_connectors(facilities: Array) -> Array[Dictionary]: var warps := warps_from_facilities(facilities) var result: Array[Dictionary] = [] for i: int in warps.size(): for j: int in range(i + 1, warps.size()): if warps[i][&"definition_id"] != warps[j][&"definition_id"]: continue result.append({ &"access_id": ACCESS_BY_DEFINITION[warps[i][&"definition_id"]], &"id": StringName("%s%s|%s" % [PREFIX, warps[i][&"instance_id"], warps[j][&"instance_id"]]), &"from": warps[i][&"origin"], &"to": warps[j][&"origin"], &"endpoints": [warps[i][&"instance_id"], warps[j][&"instance_id"]], }) return result ## Rebuilds warp connectors from construction state and applies availability. ## available: instance_id -> bool. Atomic: on failure the path is restored. The ## rollback snapshot is taken only when a change is actually needed. static func synchronize(path: PathService, facilities: Array, available: Dictionary, fare_affordable: bool) -> Dictionary: var expected := expected_connectors(facilities) var expected_ids: Dictionary = {} for connector: Dictionary in expected: expected_ids[connector[&"id"]] = true var before: Variant = null for connector_id: StringName in path.get_connector_ids_with_prefix(PREFIX): if expected_ids.has(connector_id): continue if before == null: before = path.create_snapshot() if not path.remove_connector(connector_id): path.restore_snapshot(before) return {&"ok": false, &"code": &"WARP_CONNECTOR_REMOVE_FAILED", &"reason": path.last_error} for connector: Dictionary in expected: var connector_id: StringName = connector[&"id"] var existing := path.get_connector(connector_id) var endpoints: Array = connector[&"endpoints"] var usable := fare_affordable and bool(available.get(endpoints[0], false)) and bool(available.get(endpoints[1], false)) var state := PathType.CONNECTOR_OPERATIONAL if usable else PathType.CONNECTOR_OUTAGE if not existing.is_empty() and existing[&"from"] == connector[&"from"] and existing[&"to"] == connector[&"to"] \ and existing[&"access_id"] == connector[&"access_id"] and existing[&"operational_state"] == state: continue if before == null: before = path.create_snapshot() if existing.is_empty() or existing[&"from"] != connector[&"from"] or existing[&"to"] != connector[&"to"] \ or existing[&"access_id"] != connector[&"access_id"]: if not existing.is_empty(): path.remove_connector(connector_id) if not path.configure_connector(connector_id, connector[&"from"], connector[&"to"], PATH_COST, true, connector[&"access_id"], true, {&"movement_type": PathType.MOVEMENT_CONNECTOR}): path.restore_snapshot(before) return {&"ok": false, &"code": &"WARP_CONNECTOR_CONFIGURE_FAILED", &"reason": path.last_error} if not path.set_connector_operational_state(connector_id, state): path.restore_snapshot(before) return {&"ok": false, &"code": &"WARP_CONNECTOR_STATE_FAILED", &"reason": path.last_error} return {&"ok": true, &"connector_count": expected.size()} ## Saved paths must hold exactly the derived warp connectors. static func connectors_match(path: PathService, facilities: Array) -> bool: var expected := expected_connectors(facilities) var ids := path.get_connector_ids_with_prefix(PREFIX) if ids.size() != expected.size(): return false for connector: Dictionary in expected: var existing := path.get_connector(connector[&"id"]) if existing.is_empty() or existing[&"from"] != connector[&"from"] or existing[&"to"] != connector[&"to"] \ or int(existing[&"cost"]) != PATH_COST or StringName(existing[&"access_id"]) != connector[&"access_id"] \ or existing[&"movement_type"] != PathType.MOVEMENT_CONNECTOR: return false return true