Quality Gate / Quality Gate (pull_request) Successful in 9m4s
Instance twelve Blender-scripted glTF models in the cockpit scene and rebuild the cabin around them: gauge panel, sonar, switch panel, alert box, speaker, porthole, hull wall, caged lamps, gas bottle, handrails and side consoles. Presentation only; no domain, application or world rule changes beyond enabling glow in the test environment. - Needles, alert lamps and sonar screen are driven by the existing snapshots; the alert box now carries SYS/ATTN/ALRM. - Depth dial reads percent of certified depth. - Sonar display restyled as a turquoise holographic relief with a shader grid and height scale; SubViewport matches the glass (960x604). - Cabin lighting retuned: warm pooled lamp light, cool porthole rim, lamp shadows, dial backlight. - Procedural stand-ins removed (bulkhead, tanks, consoles, levers, indicator columns, placeholder pipe run, dial face PNGs). - Tests adapted where nodes disappeared; one assertion removed (pipe_segment_count) until the pipe kit is placed. - Model .glb files are committed without LFS; textures Godot extracts next to them at import are ignored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
165 lines
5.3 KiB
GDScript
165 lines
5.3 KiB
GDScript
class_name CockpitDetailing
|
|
extends Node3D
|
|
|
|
const DiveUpdate = preload("res://game/domain/dive/dive_update.gd")
|
|
const DiveAlertLevel = preload("res://game/domain/dive/dive_alert_level.gd")
|
|
const VehicleTelemetry = preload("res://game/application/dive/vehicle_telemetry.gd")
|
|
const CockpitAlertBox = preload("res://game/presentation/cockpit/cockpit_alert_box.gd")
|
|
const CockpitAnalogGauges = preload("res://game/presentation/cockpit/cockpit_analog_gauges.gd")
|
|
const CockpitDashboardDetailing = preload(
|
|
"res://game/presentation/cockpit/cockpit_dashboard_detailing.gd"
|
|
)
|
|
const CockpitMaterialPalette = preload("res://game/presentation/cockpit/cockpit_material_palette.gd")
|
|
const CockpitMeshFactory = preload("res://game/presentation/cockpit/cockpit_mesh_factory.gd")
|
|
const CockpitSideEquipment = preload(
|
|
"res://game/presentation/cockpit/cockpit_side_equipment.gd"
|
|
)
|
|
const CockpitSonarConsole = preload(
|
|
"res://game/presentation/cockpit/cockpit_sonar_console.gd"
|
|
)
|
|
const CockpitPracticalLighting = preload(
|
|
"res://game/presentation/cockpit/cockpit_practical_lighting.gd"
|
|
)
|
|
const CockpitSwitchPanel = preload(
|
|
"res://game/presentation/cockpit/cockpit_switch_panel.gd"
|
|
)
|
|
|
|
var _materials: CockpitMaterialPalette
|
|
var _painted_steel: Material
|
|
var _dark_steel: Material
|
|
var _analog_gauges: CockpitAnalogGauges
|
|
var _alert_box: CockpitAlertBox
|
|
var _switch_panel: CockpitSwitchPanel
|
|
var _gas_bottle: Node3D
|
|
var _dashboard_detailing: CockpitDashboardDetailing
|
|
var _side_equipment: CockpitSideEquipment
|
|
var _sonar_console: CockpitSonarConsole
|
|
var _practical_lighting: CockpitPracticalLighting
|
|
|
|
|
|
func _ready() -> void:
|
|
_create_materials()
|
|
_apply_materials_to_existing_cockpit()
|
|
_build_dashboard_instrumentation()
|
|
_build_equipment_assemblies()
|
|
|
|
|
|
func present(update: DiveUpdate, telemetry: VehicleTelemetry) -> void:
|
|
if update == null or update.snapshot == null or telemetry == null:
|
|
return
|
|
var snapshot = update.snapshot
|
|
var alert_level: DiveAlertLevel.Value = snapshot.alerts.maximum
|
|
if _analog_gauges != null:
|
|
_analog_gauges.present(
|
|
snapshot.oxygen.ratio,
|
|
snapshot.battery.ratio,
|
|
snapshot.hull.ratio,
|
|
clampf(
|
|
snapshot.depth.current_m
|
|
/ maxf(snapshot.depth.certified_m, 0.001),
|
|
0.0,
|
|
1.0
|
|
)
|
|
)
|
|
if _alert_box != null:
|
|
_alert_box.present(alert_level)
|
|
_practical_lighting.present(alert_level)
|
|
|
|
|
|
func battery_needle_degrees() -> float:
|
|
return 0.0 if _analog_gauges == null else _analog_gauges.battery_needle_degrees()
|
|
|
|
|
|
func textures_are_loaded() -> bool:
|
|
return (
|
|
_materials != null
|
|
and _materials.overhead_steel.albedo_texture != null
|
|
and _analog_gauges != null
|
|
and _analog_gauges.dial_texture_is_loaded()
|
|
)
|
|
|
|
|
|
func dashboard_control_count() -> int:
|
|
return 0 if _switch_panel == null else _switch_panel.control_count()
|
|
|
|
|
|
func side_equipment_count() -> int:
|
|
if _side_equipment == null:
|
|
return 0
|
|
return _side_equipment.junction_box_count() + (0 if _gas_bottle == null else 1)
|
|
|
|
|
|
func side_control_count() -> int:
|
|
if _side_equipment == null:
|
|
return 0
|
|
var bottle_valve_count := (
|
|
0
|
|
if _gas_bottle == null
|
|
else _gas_bottle.find_children("*ValveWheel", "Node3D", true, false).size()
|
|
)
|
|
return _side_equipment.control_count() + bottle_valve_count
|
|
|
|
|
|
func sonar_control_count() -> int:
|
|
return 0 if _sonar_console == null else _sonar_console.control_count()
|
|
|
|
|
|
func practical_light_count() -> int:
|
|
return 0 if _practical_lighting == null else _practical_lighting.practical_light_count()
|
|
|
|
|
|
func gauges_are_dashboard_mounted() -> bool:
|
|
return _analog_gauges != null and _analog_gauges.get_parent() == get_parent().get_node("Dashboard")
|
|
|
|
|
|
func _create_materials() -> void:
|
|
_materials = CockpitMaterialPalette.new()
|
|
_painted_steel = _materials.painted_steel
|
|
_dark_steel = _materials.dark_steel
|
|
|
|
|
|
func _apply_materials_to_existing_cockpit() -> void:
|
|
_apply_material_to_paths(
|
|
_painted_steel,
|
|
[
|
|
"CabinShell/LeftWall",
|
|
"CabinShell/RightWall",
|
|
]
|
|
)
|
|
_apply_material_to_paths(_dark_steel, ["CabinShell/RearBulkhead"])
|
|
_apply_material_to_paths(
|
|
_materials.overhead_steel,
|
|
["CabinShell/Ceiling"]
|
|
)
|
|
func _apply_material_to_paths(material: Material, paths: Array[String]) -> void:
|
|
var cockpit := get_parent()
|
|
for path: String in paths:
|
|
var mesh := cockpit.get_node_or_null(path) as MeshInstance3D
|
|
if mesh != null:
|
|
mesh.material_override = material
|
|
|
|
|
|
func _build_dashboard_instrumentation() -> void:
|
|
var dashboard := get_parent().get_node_or_null("Dashboard") as Node3D
|
|
if dashboard == null:
|
|
return
|
|
_dashboard_detailing = CockpitDashboardDetailing.new()
|
|
dashboard.add_child(_dashboard_detailing)
|
|
_dashboard_detailing.hide_obsolete_elements(get_parent())
|
|
_analog_gauges = dashboard.get_node_or_null("AnalogGauges") as CockpitAnalogGauges
|
|
|
|
|
|
func _build_equipment_assemblies() -> void:
|
|
_side_equipment = CockpitSideEquipment.new(_materials)
|
|
add_child(_side_equipment)
|
|
var cockpit := get_parent()
|
|
_sonar_console = cockpit.get_node_or_null("SonarMonitor") as CockpitSonarConsole
|
|
_alert_box = cockpit.get_node_or_null("AlertBox") as CockpitAlertBox
|
|
_switch_panel = cockpit.get_node_or_null("SwitchPanel") as CockpitSwitchPanel
|
|
_gas_bottle = cockpit.get_node_or_null("GasBottle") as Node3D
|
|
_practical_lighting = CockpitPracticalLighting.new(_materials)
|
|
add_child(_practical_lighting)
|
|
# The alert box hangs between the left lamp and the gas bottle: casting, it
|
|
# puts the bottle in full shadow.
|
|
CockpitMeshFactory.disable_shadow_casting(_alert_box)
|