class_name CockpitAnalogGauges extends Node3D ## Drives the imported gauge panel model: four needles and its six pilot lights. ## The model scene is instanced by `cockpit_interior.tscn`; this script only ## rotates needles and sets emission, it never rebuilds geometry. const CockpitMeshFactory = preload("res://game/presentation/cockpit/cockpit_mesh_factory.gd") ## Printed dial sweep: ratio 0 points lower-left, ratio 1 lower-right, clockwise. const NEEDLE_DEGREES_AT_ZERO := 120.0 const NEEDLE_DEGREES_AT_FULL := -120.0 ## The snapshot carries no per-instrument lamp state, so the panel pilot lights ## stay dark; the alert level is reported by `CockpitAlertBox`. const PILOT_LIGHT_REST_ENERGY := 0.0 ## Scales the dial backlight baked in the model (1.0 = as exported), so the ## paper reads as lit ivory without outshining the cabin's warm lamps. const DIAL_BACKLIGHT_ENERGY := 0.7 const NEEDLE_NAMES: Array[String] = [ "Needle_Oxygen", "Needle_Battery", "Needle_Hull", "Needle_Depth", ] var _needles: Dictionary[String, Node3D] = {} var _dials: MeshInstance3D var _pilot_light_materials: Array[BaseMaterial3D] = [] func _ready() -> void: for needle_name: String in NEEDLE_NAMES: var needle := find_child(needle_name, true, false) as Node3D if needle == null: push_error("Gauge panel model has no %s node" % needle_name) continue _needles[needle_name] = needle _dials = find_child("GaugeDials", true, false) as MeshInstance3D var dial_material := CockpitMeshFactory.own_surface_material(_dials) if dial_material != null: dial_material.emission_energy_multiplier = DIAL_BACKLIGHT_ENERGY for light: Node in find_children("Light_*", "MeshInstance3D", true, false): var material := CockpitMeshFactory.own_surface_material(light as MeshInstance3D) if material != null: material.emission_energy_multiplier = PILOT_LIGHT_REST_ENERGY _pilot_light_materials.append(material) func present( oxygen_ratio: float, battery_ratio: float, hull_ratio: float, depth_ratio: float ) -> void: _set_needle_ratio("Needle_Oxygen", oxygen_ratio) _set_needle_ratio("Needle_Battery", battery_ratio) _set_needle_ratio("Needle_Hull", hull_ratio) _set_needle_ratio("Needle_Depth", depth_ratio) func gauge_count() -> int: return _needles.size() func pilot_light_count() -> int: return _pilot_light_materials.size() func lit_pilot_light_count() -> int: var count := 0 for material: BaseMaterial3D in _pilot_light_materials: if material.emission_energy_multiplier > 0.0: count += 1 return count func needle_degrees(needle_name: String) -> float: var needle: Node3D = _needles.get(needle_name) return 0.0 if needle == null else needle.rotation_degrees.z func battery_needle_degrees() -> float: return needle_degrees("Needle_Battery") func dial_texture_is_loaded() -> bool: if _dials == null or _dials.mesh == null or _dials.mesh.get_surface_count() == 0: return false var material := _dials.mesh.surface_get_material(0) as BaseMaterial3D return material != null and material.albedo_texture != null func _set_needle_ratio(needle_name: String, ratio: float) -> void: var needle: Node3D = _needles.get(needle_name) if needle != null: needle.rotation_degrees.z = lerpf( NEEDLE_DEGREES_AT_ZERO, NEEDLE_DEGREES_AT_FULL, clampf(ratio, 0.0, 1.0) )