fix(content): lay the Vigilant hull along la Saignee within the distance budget
The target hull now lies along the groove axis (yaw derived from the groove constants), set back 22 m from the groove end so both hull ends rest on the flat groove floor. The mooring, spawn and first route waypoints move to z = -210 and the decoy yacht to (-30, -150) so no wreck is farther than 320 m from the mooring and no two wrecks are farther than 260 m apart (spec 4.1). The spawn faces south toward the site. Four contract assertions pin the budget, the spawn heading and the hull orientation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5344b045d9
commit
be16d2ee07
4 files changed
+63
-19
No files matched your search
@@ -9,15 +9,15 @@
|
||||
script = ExtResource("1_n3xpu")
|
||||
placement_id = &"prospection_vessel"
|
||||
kind = 0
|
||||
position_m = Vector3(-12, -37.10001, 108)
|
||||
yaw_radians = 0.35
|
||||
position_m = Vector3(-14.154642, -37.198338, 98.39586)
|
||||
yaw_radians = -1.380808047881126
|
||||
footprint_m = Vector3(28, 8, 9)
|
||||
|
||||
[sub_resource type="Resource" id="Resource_xcojm"]
|
||||
script = ExtResource("1_n3xpu")
|
||||
placement_id = &"decoy_yacht"
|
||||
kind = 1
|
||||
position_m = Vector3(-40, -24.655516, -200)
|
||||
position_m = Vector3(-30, -25.199738, -150)
|
||||
yaw_radians = 1.1
|
||||
footprint_m = Vector3(12, 3, 4)
|
||||
|
||||
@@ -71,7 +71,7 @@ footprint_m = Vector3(4, 1.5, 1.5)
|
||||
script = ExtResource("1_n3xpu")
|
||||
placement_id = &"vessel_anchor"
|
||||
kind = 5
|
||||
position_m = Vector3(0, -14, -250)
|
||||
position_m = Vector3(0, -14, -210)
|
||||
|
||||
[sub_resource type="Resource" id="Resource_e72vy"]
|
||||
script = ExtResource("1_n3xpu")
|
||||
@@ -101,13 +101,13 @@ position_m = Vector3(40, -40, 125)
|
||||
[sub_resource type="Resource" id="Resource_xvesq"]
|
||||
script = ExtResource("2_36hd6")
|
||||
route_id = &"safe_ridge"
|
||||
waypoints_m = PackedVector3Array(0, -14, -250, 70, -16, -200, 76, -16, -100, 78, -16, 0, 76, -18, 80, 40, -24, 105, 0, -26, 100, -14, -30, 98)
|
||||
waypoints_m = PackedVector3Array(0, -14, -210, 70, -16, -200, 76, -16, -100, 78, -16, 0, 76, -18, 80, 40, -24, 105, 0, -26, 100, -14, -30, 98)
|
||||
maximum_depth_m = 32.0
|
||||
|
||||
[sub_resource type="Resource" id="Resource_lcu7s"]
|
||||
script = ExtResource("2_36hd6")
|
||||
route_id = &"risky_groove"
|
||||
waypoints_m = PackedVector3Array(0, -14, -250, -60, -20, -150, -50, -31, -100, -35, -33, -20, -22, -34, 60, -14, -33, 98)
|
||||
waypoints_m = PackedVector3Array(0, -14, -210, -60, -20, -150, -50, -31, -100, -35, -33, -20, -22, -34, 60, -14, -33, 98)
|
||||
maximum_depth_m = 48.0
|
||||
|
||||
[resource]
|
||||
@@ -116,6 +116,7 @@ site_id = &"zone1_vigilant"
|
||||
display_name = "Banc du Vigilant"
|
||||
terrain = ExtResource("4_i0v8k")
|
||||
playable_bounds_m = Rect2(-300, -300, 600, 600)
|
||||
spawn_position_m = Vector3(0, -10, -250)
|
||||
spawn_position_m = Vector3(0, -10, -210)
|
||||
spawn_yaw_radians = 3.141592653589793
|
||||
placements = Array[ExtResource("1_n3xpu")]([SubResource("Resource_rqt47"), SubResource("Resource_xcojm"), SubResource("Resource_yljal"), SubResource("Resource_aqgwj"), SubResource("Resource_aervf"), SubResource("Resource_qgawl"), SubResource("Resource_q0ace"), SubResource("Resource_hd5cl"), SubResource("Resource_wy8hl"), SubResource("Resource_e72vy"), SubResource("Resource_3n33i"), SubResource("Resource_cdmnh"), SubResource("Resource_u8dqp"), SubResource("Resource_3uttw")])
|
||||
routes = Array[ExtResource("2_36hd6")]([SubResource("Resource_xvesq"), SubResource("Resource_lcu7s")])
|
||||
@@ -86,7 +86,7 @@ crédibilité, conformément à la direction artistique.
|
||||
| Champ de hauteur | 513 × 513 cellules, 1,5 m par cellule, élévations float32 (`SiteTerrainData`) |
|
||||
| Profondeur min / max du terrain | 20 m / 88 m |
|
||||
| Profondeur d'écrasement coque I | hors terrain : le fond ne tue jamais par lui-même |
|
||||
| Mouillage du navire | centre nord du plateau, 24 m de fond |
|
||||
| Mouillage du navire | centre nord du plateau, 25 m de fond |
|
||||
| Point de départ du sous-marin | sous le navire, 10 m de profondeur |
|
||||
|
||||
Les distances sont dimensionnées pour l'autonomie Standard (environ 1,2 km,
|
||||
@@ -150,14 +150,14 @@ correspond pas au rapport.
|
||||
|
||||
### 4.4 Les deux routes vers la cible
|
||||
|
||||
**Route sûre — par l'Échine (≈ 470 m, 26–32 m).** Depuis le navire, suivre la
|
||||
**Route sûre — par l'Échine (≈ 450 m, 26–32 m).** Depuis le navire, suivre la
|
||||
crête longue vers le sud. Elle est lumineuse, large, sans obstacle, et se lit
|
||||
d'un seul scan. Elle mène au bord du plateau au-dessus de la Saignée : il
|
||||
faut ensuite descendre dans le sillon par son extrémité nord, à faible
|
||||
pente. Coût : temps et batterie. Récompense : zéro dégât, retour facile à
|
||||
estimer.
|
||||
|
||||
**Route risquée — par la Saignée (≈ 370 m, 36–48 m).** Un sillon de 12 à
|
||||
**Route risquée — par la Saignée (≈ 340 m, 36–48 m).** Un sillon de 12 à
|
||||
18 m de large, aux parois de 8 à 10 m, qui coupe le plateau en diagonale et
|
||||
débouche directement sur la proue de la cible. Sombre (les projecteurs
|
||||
deviennent nécessaires), étroit (collisions), en pente (la batterie de
|
||||
|
||||
@@ -15,7 +15,11 @@ const DiveRulesResolver = preload("res://game/domain/rules/dive_rules_resolver.g
|
||||
const SITE_PATH := "res://content/sites/zone1_vigilant.tres"
|
||||
const ROUTE_CLEARANCE_M := 3.0
|
||||
const MINIMUM_LANDMARK_SPACING_M := 60.0
|
||||
const TEST_COUNT := 30
|
||||
const MAXIMUM_ANCHOR_TO_WRECK_M := 320.0
|
||||
const MAXIMUM_WRECK_SPACING_M := 260.0
|
||||
const HULL_HALF_LENGTH_M := 14.0
|
||||
const HULL_SEABED_TOLERANCE_M := 2.0
|
||||
const TEST_COUNT := 34
|
||||
|
||||
var _failures: Array[String] = []
|
||||
|
||||
@@ -107,6 +111,26 @@ func _test_zone1_content() -> void:
|
||||
spaced = false
|
||||
_expect(spaced, "landmarks are at least 60 m apart")
|
||||
|
||||
var wrecks := targets + decoys
|
||||
if anchors.size() == 1:
|
||||
var anchor := anchors[0].position_m
|
||||
var farthest := 0.0
|
||||
for wreck: SitePlacement in wrecks:
|
||||
farthest = maxf(farthest, _xz_distance(anchor, wreck.position_m))
|
||||
_expect(farthest <= MAXIMUM_ANCHOR_TO_WRECK_M, "every wreck lies within 320 m of the mooring (farthest %.0f m)" % farthest)
|
||||
var widest := 0.0
|
||||
for i in wrecks.size():
|
||||
for j in range(i + 1, wrecks.size()):
|
||||
widest = maxf(widest, _xz_distance(wrecks[i].position_m, wrecks[j].position_m))
|
||||
_expect(widest <= MAXIMUM_WRECK_SPACING_M, "every pair of wrecks lies within 260 m (widest %.0f m)" % widest)
|
||||
if targets.size() == 1:
|
||||
var target_xz := Vector2(targets[0].position_m.x, targets[0].position_m.z)
|
||||
var spawn_xz := Vector2(spawn.x, spawn.z)
|
||||
var yaw := definition.spawn_yaw_radians
|
||||
var spawn_forward := Vector2(-sin(yaw), -cos(yaw))
|
||||
_expect(spawn_forward.dot(target_xz - spawn_xz) > 0.0, "the spawn faces the target wreck")
|
||||
_expect(_hull_lies_along_seabed(field, targets[0]), "the target hull lies along the groove floor")
|
||||
|
||||
|
||||
func _rests_on_terrain(field: TerrainHeightField, placement: SitePlacement) -> bool:
|
||||
var seabed := field.elevation_at(placement.position_m.x, placement.position_m.z)
|
||||
@@ -114,6 +138,17 @@ func _rests_on_terrain(field: TerrainHeightField, placement: SitePlacement) -> b
|
||||
return bottom >= seabed - placement.footprint_m.y and bottom <= seabed + 1.0
|
||||
|
||||
|
||||
func _hull_lies_along_seabed(field: TerrainHeightField, hull: SitePlacement) -> bool:
|
||||
var centre := Vector2(hull.position_m.x, hull.position_m.z)
|
||||
var long_axis := Vector2(cos(hull.yaw_radians), -sin(hull.yaw_radians))
|
||||
var centre_seabed := field.elevation_at(centre.x, centre.y)
|
||||
for side: float in [-1.0, 1.0]:
|
||||
var end := centre + long_axis * HULL_HALF_LENGTH_M * side
|
||||
if absf(field.elevation_at(end.x, end.y) - centre_seabed) > HULL_SEABED_TOLERANCE_M:
|
||||
return false
|
||||
return true
|
||||
|
||||
|
||||
func _route_clears_terrain(field: TerrainHeightField, route: SiteRoute) -> bool:
|
||||
for i in range(route.waypoints_m.size() - 1):
|
||||
var a := route.waypoints_m[i]
|
||||
|
||||
@@ -16,6 +16,9 @@ const GROOVE_END := Vector2(-10.0, 120.0)
|
||||
const RIDGE_START := Vector2(70.0, -150.0)
|
||||
const RIDGE_END := Vector2(80.0, 90.0)
|
||||
const BREAK_Z := 125.0
|
||||
# The target's centre sits this far up the groove from GROOVE_END, so its 28 m hull
|
||||
# stops one groove half-width short of the end cap and rests on the flat groove floor.
|
||||
const TARGET_SET_BACK_M := 22.0
|
||||
|
||||
|
||||
static func recipe() -> SiteTerrainBaker.Recipe:
|
||||
@@ -30,7 +33,7 @@ static func recipe() -> SiteTerrainBaker.Recipe:
|
||||
result.rock_reflectivity = 0.72
|
||||
result.sand_reflectivity = 0.45
|
||||
result.primitives = [
|
||||
# Plateau: 24 m deep at the vessel (z = -300), 6 m deeper over 400 m toward the south.
|
||||
# Plateau: 24 m deep at z = -300 (about 25 m at the mooring), 6 m deeper over 400 m toward the south.
|
||||
SiteTerrainBaker.SlopedPlane.new(24.0, 0.0, -0.015, 0.0, -300.0),
|
||||
# L'Échine: long north-south rock ridge, 6 m high, flanks steeper than 20°.
|
||||
SiteTerrainBaker.Ridge.new(RIDGE_START, RIDGE_END, 12.0, 6.0, 25.0),
|
||||
@@ -63,18 +66,23 @@ static func recipe() -> SiteTerrainBaker.Recipe:
|
||||
|
||||
static func definition(terrain: SiteTerrainData) -> DiveSiteDefinition:
|
||||
var field := TerrainHeightField.from_data(terrain)
|
||||
# The target hull's long axis (local +X) lies along la Saignée.
|
||||
var groove_axis := (GROOVE_END - GROOVE_START).normalized()
|
||||
var groove_yaw := atan2(-groove_axis.y, groove_axis.x)
|
||||
var target_xz := GROOVE_END - groove_axis * TARGET_SET_BACK_M
|
||||
var result := DiveSiteDefinition.new()
|
||||
result.site_id = &"zone1_vigilant"
|
||||
result.display_name = "Banc du Vigilant"
|
||||
result.terrain = terrain
|
||||
result.playable_bounds_m = Rect2(-300.0, -300.0, 600.0, 600.0)
|
||||
result.spawn_position_m = Vector3(0.0, -10.0, -250.0)
|
||||
result.spawn_yaw_radians = 0.0
|
||||
# Spawn beside the mooring, facing south toward the site.
|
||||
result.spawn_position_m = Vector3(0.0, -10.0, -210.0)
|
||||
result.spawn_yaw_radians = PI
|
||||
result.placements = [
|
||||
_on_seabed(field, &"prospection_vessel", SitePlacement.Kind.WRECK_TARGET,
|
||||
Vector2(-12.0, 108.0), 0.35, Vector3(28.0, 8.0, 9.0), 2.0),
|
||||
target_xz, groove_yaw, Vector3(28.0, 8.0, 9.0), 2.0),
|
||||
_on_seabed(field, &"decoy_yacht", SitePlacement.Kind.WRECK_DECOY,
|
||||
Vector2(-40.0, -200.0), 1.1, Vector3(12.0, 3.0, 4.0), 0.5),
|
||||
Vector2(-30.0, -150.0), 1.1, Vector3(12.0, 3.0, 4.0), 0.5),
|
||||
_on_seabed(field, &"decoy_coaster", SitePlacement.Kind.WRECK_DECOY,
|
||||
Vector2(140.0, 40.0), -0.6, Vector3(26.0, 6.0, 8.0), 1.2),
|
||||
_on_seabed(field, &"secondary_item", SitePlacement.Kind.SECONDARY_ITEM,
|
||||
@@ -87,7 +95,7 @@ static func definition(terrain: SiteTerrainData) -> DiveSiteDefinition:
|
||||
Vector2(-9.0, 146.0), 0.0, Vector3(2.0, 1.5, 2.0), 0.2),
|
||||
_on_seabed(field, &"debris_4", SitePlacement.Kind.DEBRIS,
|
||||
Vector2(-7.0, 152.0), 2.0, Vector3(4.0, 1.5, 1.5), 0.3),
|
||||
_marker(&"vessel_anchor", SitePlacement.Kind.VESSEL_ANCHOR, Vector3(0.0, -14.0, -250.0)),
|
||||
_marker(&"vessel_anchor", SitePlacement.Kind.VESSEL_ANCHOR, Vector3(0.0, -14.0, -210.0)),
|
||||
_marker(&"echine", SitePlacement.Kind.LANDMARK, Vector3(75.0, -20.0, -50.0)),
|
||||
_marker(&"deux_freres", SitePlacement.Kind.LANDMARK, Vector3(-151.0, -18.0, -125.0)),
|
||||
_marker(&"rides", SitePlacement.Kind.LANDMARK, Vector3(0.0, -25.0, -230.0)),
|
||||
@@ -96,12 +104,12 @@ static func definition(terrain: SiteTerrainData) -> DiveSiteDefinition:
|
||||
]
|
||||
result.routes = [
|
||||
_route(&"safe_ridge", 32.0, [
|
||||
Vector3(0.0, -14.0, -250.0), Vector3(70.0, -16.0, -200.0), Vector3(76.0, -16.0, -100.0),
|
||||
Vector3(0.0, -14.0, -210.0), Vector3(70.0, -16.0, -200.0), Vector3(76.0, -16.0, -100.0),
|
||||
Vector3(78.0, -16.0, 0.0), Vector3(76.0, -18.0, 80.0), Vector3(40.0, -24.0, 105.0),
|
||||
Vector3(0.0, -26.0, 100.0), Vector3(-14.0, -30.0, 98.0),
|
||||
]),
|
||||
_route(&"risky_groove", 48.0, [
|
||||
Vector3(0.0, -14.0, -250.0), Vector3(-60.0, -20.0, -150.0), Vector3(-50.0, -31.0, -100.0),
|
||||
Vector3(0.0, -14.0, -210.0), Vector3(-60.0, -20.0, -150.0), Vector3(-50.0, -31.0, -100.0),
|
||||
Vector3(-35.0, -33.0, -20.0), Vector3(-22.0, -34.0, 60.0), Vector3(-14.0, -33.0, 98.0),
|
||||
]),
|
||||
]
|
||||
|
||||
Reference in new issue
Block a user