extends RefCounted ## Read-only presentation. Counts refer to people, never storage capacity. static func describe(instance: Variant) -> Dictionary: if instance == null: return {} var ids: Array[StringName] = [] for service: Variant in instance.active_services.values(): for id: StringName in service.guest_ids: if not ids.has(id): ids.append(id) ids.sort_custom(func(a: StringName, b: StringName) -> bool: return String(a) < String(b)) return {&"state": int(instance.state), &"state_name": FacilityInstance.State.keys()[instance.state], &"reasons": instance.state_reasons.duplicate(), &"operation": int(instance.operation_state), &"people": ids, &"count": ids.size(), &"limit": int(instance.customer_capacity), &"staff": instance.active_staff_ids.duplicate(), &"suspension": StringName(instance.suspension_reason)} static func slots(rect: Rect2, p: float, id: StringName) -> Array[Vector2]: # Each anchor owns a 16x18 person footprint. Overflow is reported as a count, # not drawn on top of another person. Furniture uses these same anchors. var result: Array[Vector2] = [] var step := 20.0 if id in [&"cafeteria", &"tavern"] else 16.0 var columns := maxi(int(rect.size.x / p / step), 1) var rows := maxi(int((rect.size.y / p - 10.0) / 20.0), 1) if id == &"chapel": columns = mini(columns, 4) rows = maxi(int((rect.size.y / p - 30.0) / 20.0), 1) for row: int in rows: for col: int in columns: if id == &"chapel" and result.size() == 8: return result result.append(Vector2(rect.position.x + (float(col) + 0.5) * rect.size.x / columns, rect.end.y - (4.0 + row * 20.0) * p)) return result static func label(data: Dictionary, visible_count: int) -> String: if data.is_empty(): return "" var operation := int(data[&"operation"]) if operation == FacilityInstance.OperationState.SUSPENDED: return "休止・摘発" if data[&"suspension"] == &"RAIDED" else "休止・破壊" if operation == FacilityInstance.OperationState.INACTIVE: return "未稼働" var count := int(data[&"count"]) var limit := int(data[&"limit"]) var value := "利用%d/%d人" % [count, limit] if limit >= 0 else "利用%d人" % count if limit > 0 and count >= limit: value = "満員 " + value if count > visible_count: value += "(他%d人)" % (count - visible_count) return value static func business_label(data: Dictionary) -> String: if data.is_empty(): return "" if int(data[&"operation"]) == FacilityInstance.OperationState.SUSPENDED: return "休止・摘発" if data[&"suspension"] == &"RAIDED" else "休止・破壊" match int(data[&"state"]): FacilityInstance.State.BROKEN: return "破損" FacilityInstance.State.NO_ACCESS: return "通路なし" FacilityInstance.State.NO_POWER: return "魔力なし" FacilityInstance.State.NO_STAFF: return "職員不足" FacilityInstance.State.CLOSED: return "営業停止" FacilityInstance.State.DEGRADED: return "低下運転" FacilityInstance.State.OPEN: return "営業中" return String(data[&"state_name"]) static func queue_label(count: int, overflow: int) -> String: return "待ち%d人" % count + ("(他%d人)" % overflow if overflow > 0 else "") static func elevator_label(shaft: Dictionary) -> String: var count := (shaft[&"boarded"] as Array).size() var capacity := int(shaft[&"capacity"]) var value := "%d/%d人" % [count, capacity] if capacity > 0 and count >= capacity: value = "満員 " + value if not bool(shaft[&"operational"]): value = "停止 " + value else: value = "運転 " + value var phase := String(shaft.get(&"phase", &"IDLE")) var doors_open := bool(shaft[&"operational"]) and phase in ["IDLE", "BOARDING", "ALIGHTING"] return value + (" 開 " if doors_open else " 閉 ") + phase static func supply_label(requests: Array[Dictionary]) -> String: # These are requests, never invented stock quantities. Preserve actual states. var states: Dictionary = {} for request: Dictionary in requests: var state := String(request[&"state"]) states[state] = int(states.get(state, 0)) + 1 var names: Array = states.keys() names.sort() var parts: PackedStringArray = [] for state: String in names: parts.append("%s:%d" % [state, states[state]]) return "物資依頼 " + " / ".join(parts)