class_name CockpitSideEquipment extends Node3D const CockpitMaterialPalette = preload( "res://game/presentation/cockpit/cockpit_material_palette.gd" ) const CockpitMeshFactory = preload( "res://game/presentation/cockpit/cockpit_mesh_factory.gd" ) var _materials: CockpitMaterialPalette var _tank_count := 0 var _junction_box_count := 0 var _control_count := 0 func _init(materials: CockpitMaterialPalette) -> void: _materials = materials name = "SideEquipment" _build_left_life_support_bank() _build_right_electrical_bank() _build_cable_looms() _build_control_rails() func tank_count() -> int: return _tank_count func junction_box_count() -> int: return _junction_box_count func control_count() -> int: return _control_count func _build_left_life_support_bank() -> void: var root := Node3D.new() root.name = "LifeSupportBank" add_child(root) for tank_data: Vector3 in [ Vector3(-0.78, 0.55, -1.17), Vector3(-0.68, 0.47, -1.19), ]: _add_tank(root, tank_data) _add_service_box(root, Vector3(-0.61, 0.42, -1.14), "O₂", -10.0) _add_indicator_column(root, Vector3(-0.55, 0.39, -1.055)) _add_valve_wheel(root, Vector3(-0.66, 0.12, -1.08)) CockpitMeshFactory.add_cylinder_between( "ManifoldPipe", root, Vector3(-0.78, 0.24, -1.13), Vector3(-0.67, 0.09, -1.11), 0.018, _materials.copper ) CockpitMeshFactory.add_cylinder_between( "ManifoldReturn", root, Vector3(-0.68, 0.25, -1.15), Vector3(-0.59, 0.02, -1.10), 0.014, _materials.brass ) func _add_tank(root: Node3D, tank_position: Vector3) -> void: CockpitMeshFactory.add_cylinder( "OxygenTank", root, tank_position, 0.055, 0.43, _materials.safety_yellow ) CockpitMeshFactory.add_sphere( "TankTop", root, tank_position + Vector3(0.0, 0.215, 0.0), 0.055, _materials.safety_yellow ) CockpitMeshFactory.add_sphere( "TankBottom", root, tank_position - Vector3(0.0, 0.215, 0.0), 0.055, _materials.safety_yellow ) for offset_y: float in [-0.13, 0.13]: var strap := MeshInstance3D.new() strap.name = "TankStrap" var torus := TorusMesh.new() torus.inner_radius = 0.054 torus.outer_radius = 0.066 torus.rings = 20 torus.ring_segments = 6 strap.mesh = torus strap.material_override = _materials.dark_steel strap.position = tank_position + Vector3(0.0, offset_y, 0.0) root.add_child(strap) CockpitMeshFactory.add_cylinder( "TankValve", root, tank_position + Vector3(0.0, 0.29, 0.0), 0.017, 0.075, _materials.brass ) _tank_count += 1 func _build_right_electrical_bank() -> void: var root := Node3D.new() root.name = "ElectricalBank" add_child(root) _add_service_box(root, Vector3(0.72, 0.65, -1.17), "ELEC", 11.0) _add_service_box(root, Vector3(0.73, 0.36, -1.16), "POMPES", 8.0) _add_vent(root, Vector3(0.705, 0.69, -1.095)) _add_vent(root, Vector3(0.715, 0.40, -1.085)) _add_knob(root, Vector3(0.66, 0.55, -1.08)) _add_knob(root, Vector3(0.68, 0.25, -1.07)) _add_indicator_column(root, Vector3(0.795, 0.49, -1.075)) for pipe_x: float in [0.64, 0.82]: CockpitMeshFactory.add_cylinder( "ElectricalConduit", root, Vector3(pipe_x, 0.70, -1.20), 0.017, 0.58, _materials.copper ) func _add_service_box( root: Node3D, box_position: Vector3, caption: String, yaw_degrees: float ) -> void: CockpitMeshFactory.add_box( "JunctionBox", root, box_position, Vector3(0.17, 0.23, 0.12), _materials.overhead_steel, Vector3(0.0, yaw_degrees, 0.0) ) var label := Label3D.new() label.name = "%sPlate" % caption.to_pascal_case() label.text = caption label.font_size = 12 label.pixel_size = 0.00065 label.modulate = Color(0.13, 0.16, 0.14) label.position = box_position + Vector3(0.0, 0.075, 0.067) root.add_child(label) for corner: Vector2 in [ Vector2(-0.065, -0.085), Vector2(-0.065, 0.085), Vector2(0.065, -0.085), Vector2(0.065, 0.085), ]: CockpitMeshFactory.add_cylinder( "BoxFastener", root, box_position + Vector3(corner.x, corner.y, 0.065), 0.008, 0.01, _materials.dark_steel, Vector3(90.0, 0.0, 0.0) ) _junction_box_count += 1 func _add_vent(root: Node3D, center: Vector3) -> void: for row in 5: CockpitMeshFactory.add_box( "VentSlit", root, center + Vector3(0.0, (row - 2) * 0.018, 0.0), Vector3(0.085, 0.007, 0.009), _materials.dark_steel ) func _add_knob(root: Node3D, knob_position: Vector3) -> void: CockpitMeshFactory.add_cylinder( "ControlKnob", root, knob_position, 0.027, 0.026, _materials.rubber, Vector3(90.0, 0.0, 0.0) ) _control_count += 1 func _add_indicator_column(root: Node3D, center: Vector3) -> void: var indicator_materials: Array[StandardMaterial3D] = [ _materials.indicator_green, _materials.indicator_amber, _materials.indicator_red, ] for index in 3: CockpitMeshFactory.add_box( "PilotLightBezel", root, center + Vector3(0.0, (1 - index) * 0.055, -0.004), Vector3(0.038, 0.038, 0.018), _materials.dark_steel ) CockpitMeshFactory.add_sphere( "PilotLight", root, center + Vector3(0.0, (1 - index) * 0.055, 0.010), 0.013, indicator_materials[index] ) _control_count += 1 func _add_valve_wheel(root: Node3D, wheel_position: Vector3) -> void: var wheel := MeshInstance3D.new() wheel.name = "ValveWheel" var torus := TorusMesh.new() torus.inner_radius = 0.034 torus.outer_radius = 0.046 torus.rings = 20 torus.ring_segments = 7 wheel.mesh = torus wheel.material_override = _materials.signal_red wheel.position = wheel_position wheel.rotation_degrees.x = 90.0 root.add_child(wheel) for angle_degrees: float in [0.0, 45.0, 90.0, 135.0]: CockpitMeshFactory.add_box( "ValveSpoke", root, wheel_position + Vector3(0.0, 0.0, 0.002), Vector3(0.075, 0.007, 0.008), _materials.signal_red, Vector3(0.0, 0.0, angle_degrees) ) _control_count += 1 func _build_cable_looms() -> void: var root := Node3D.new() root.name = "CableLooms" add_child(root) var left_points: Array[Vector3] = [ Vector3(-0.82, 0.93, -1.15), Vector3(-0.72, 0.87, -1.16), Vector3(-0.64, 0.73, -1.14), Vector3(-0.61, 0.58, -1.12), ] var right_points: Array[Vector3] = [ Vector3(0.84, 0.91, -1.15), Vector3(0.75, 0.86, -1.16), Vector3(0.68, 0.73, -1.14), Vector3(0.65, 0.59, -1.12), ] _add_cable_path(root, left_points) _add_cable_path(root, right_points) func _add_cable_path(root: Node3D, points: Array[Vector3]) -> void: for point_index in points.size() - 1: CockpitMeshFactory.add_cylinder_between( "ArmouredCable", root, points[point_index], points[point_index + 1], 0.012, _materials.rubber ) func _build_control_rails() -> void: var root := Node3D.new() root.name = "ControlRails" add_child(root) CockpitMeshFactory.add_cylinder_between( "LowerSteelRail", root, Vector3(-0.82, -0.34, -1.12), Vector3(0.82, -0.34, -1.12), 0.026, _materials.brushed_steel ) CockpitMeshFactory.add_cylinder_between( "LeftGrip", root, Vector3(-0.58, -0.34, -1.11), Vector3(-0.18, -0.34, -1.11), 0.034, _materials.rubber ) CockpitMeshFactory.add_cylinder_between( "RightGrip", root, Vector3(0.18, -0.34, -1.11), Vector3(0.58, -0.34, -1.11), 0.034, _materials.rubber ) for x: float in [-0.82, 0.82]: CockpitMeshFactory.add_cylinder_between( "RailSupport", root, Vector3(x, -0.34, -1.12), Vector3(x, -0.20, -1.08), 0.022, _materials.brushed_steel )