feat(composition): dive world assembled from a selected site definition

The calibration site spawn sat 16 m from the south bounds edge, inside the
40 m warning margin. The vehicle_test recipe now extends the terrain and
playable bounds 42 m to the south so the spawn is inside the zone.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
OlivierandClaude Sonnet 5.5 committed 2026-10-06 20:16:45 +02:00
1 parent bbf1dc9990
commit 51634820bd
12 files changed
+154 -258

No files matched your search

@@ -29,6 +29,12 @@ const SubmarineTelemetryAdapter = preload(
const ReferenceBathymetryAcquisition = preload(
"res://game/world/sonar/reference_bathymetry_acquisition.gd"
)
const DiveSiteDefinition = preload("res://game/domain/sites/dive_site_definition.gd")
const DiveSite = preload("res://game/world/sites/dive_site.gd")
const PlayableBoundsRule = preload("res://game/application/sites/playable_bounds_rule.gd")
const PlayableBoundsStatus = preload(
"res://game/application/sites/playable_bounds_status.gd"
)
const ProductionInputAdapter = preload(
"res://game/infrastructure/input/production_input_adapter.gd"
)
@@ -51,9 +57,8 @@ const ConfirmationDialogScreen = preload(
const RebindResult = preload("res://game/application/input/rebind_result.gd")
const MAIN_MENU_SCENE = preload("res://game/presentation/main_menu/main_menu_screen.tscn")
const VEHICLE_TEST_WORLD_SCENE_PATH := (
"res://game/composition/vertical_slice/vehicle_test_world.tscn"
)
const DIVE_WORLD_SCENE_PATH := "res://game/composition/vertical_slice/dive_world.tscn"
const DEFAULT_SITE_PATH := "res://content/sites/vehicle_test.tres"
const COCKPIT_HUD_SCENE = preload("res://game/presentation/cockpit/cockpit_hud.tscn")
const SONAR_DISPLAY_SCENE = preload(
"res://game/presentation/sonar/sonar_display.tscn"
@@ -87,6 +92,10 @@ var _sonar_service: SonarService
var _sonar_display: SonarDisplay
var _latest_update: DiveUpdate
var _active_world: Node3D
var _selected_site_path := DEFAULT_SITE_PATH
var _dive_site: DiveSite
var _bounds_rule: PlayableBoundsRule
var _bounds_status: PlayableBoundsStatus
var _active_screen: Control
var _active_overlay: Control
var _vehicle_command_sequence := 0
@@ -105,7 +114,7 @@ func _ready() -> void:
_show_main_menu()
func _start_vehicle_test() -> void:
func _start_dive() -> void:
var rules = DiveRulesResolver.new().resolve(
DiveDifficultyProfile.standard(),
DiveUpgradeEffects.new(),
@@ -117,12 +126,29 @@ func _start_vehicle_test() -> void:
if not session.is_ready():
return
var world_scene := load(VEHICLE_TEST_WORLD_SCENE_PATH) as PackedScene
var definition := load(_selected_site_path) as DiveSiteDefinition
if definition == null:
push_error("dive site definition %s cannot be loaded" % _selected_site_path)
return
var definition_error := definition.validation_error()
if not definition_error.is_empty():
push_error("dive site %s is invalid: %s" % [_selected_site_path, definition_error])
return
var world_scene := load(DIVE_WORLD_SCENE_PATH) as PackedScene
if world_scene == null:
return
var world := world_scene.instantiate() as Node3D
_replace_active_world(world)
_dive_site = world.get_node("%DiveSite") as DiveSite
var site_error := _dive_site.configure(definition)
if not site_error.is_empty():
push_error("dive site %s cannot be built: %s" % [_selected_site_path, site_error])
_show_main_menu()
return
_actor = world.get_node("%SubmarineActor") as SubmarineActor
_actor.global_transform = _dive_site.spawn_transform()
_bounds_rule = PlayableBoundsRule.new(definition.playable_bounds_m)
_bounds_status = _bounds_rule.evaluate(_actor.global_position)
_camera_controller = world.get_node("%CockpitCameraRig") as CockpitCameraController
_instrument_panel = world.get_node("%CockpitInterior") as CockpitInstrumentPanel
_hud = COCKPIT_HUD_SCENE.instantiate() as CockpitHud
@@ -154,6 +180,7 @@ func _start_vehicle_test() -> void:
_runner.next_sequence()
)
_hud.present(_latest_update, initial_telemetry)
_hud.present_bounds(_bounds_status)
_instrument_panel.present(_latest_update, initial_telemetry)
_camera_controller.present_telemetry(initial_telemetry)
_input_adapter.set_gameplay_enabled(true)
@@ -196,6 +223,8 @@ func _physics_process(delta: float) -> void:
return_route
)
_hud.present(_latest_update, telemetry)
_bounds_status = _bounds_rule.evaluate(_actor.global_position)
_hud.present_bounds(_bounds_status)
_instrument_panel.present(_latest_update, telemetry)
_sonar_service.advance(delta)
_present_sonar()
@@ -243,6 +272,18 @@ func sonar_display() -> SonarDisplay:
return _sonar_display
func select_dive_site(definition_path: String) -> void:
_selected_site_path = definition_path
func dive_site() -> DiveSite:
return _dive_site
func latest_bounds_status() -> PlayableBoundsStatus:
return _bounds_status
func _finish_dive_motion() -> void:
_dive_terminal = true
_input_adapter.set_gameplay_enabled(false)
@@ -444,6 +485,9 @@ func _show_main_menu() -> void:
_pilot_use_case = null
_telemetry_adapter = null
_actor = null
_dive_site = null
_bounds_rule = null
_bounds_status = null
_camera_controller = null
_instrument_panel = null
_hud = null
@@ -457,7 +501,7 @@ func _show_main_menu() -> void:
_replace_active_world(null)
var screen := MAIN_MENU_SCENE.instantiate() as MainMenuScreen
_replace_active_screen(screen)
screen.new_game_requested.connect(_start_vehicle_test)
screen.new_game_requested.connect(_start_dive)
screen.quit_requested.connect(_quit_game)