extends SceneTree ## Focused deterministic regression checks for the Phase 6a terrain controller. ## Runtime terrain/ramp integration remains covered by the existing stage suites. const RIG_SCENE := preload("res://master_rig.tscn") const RIG := preload("res://scripts/stickman_rig.gd") var _checks: int = 0 var _failures: int = 0 func _initialize() -> void: call_deferred("_run") func _run() -> void: var rig := RIG_SCENE.instantiate() as Node2D root.add_child(rig) await physics_frame var controller := rig as StickmanRig _check(controller != null, "master rig exposes StickmanRig") if controller != null: _test_air_pose_and_momentum(controller) _test_grounded_reset_and_ragdoll_cleanup(controller) _test_landing_timeline_and_barrier(controller) rig.queue_free() await process_frame if _failures == 0: print("RESULT: ALL PASSED (%d assertions, 0 failures)" % _checks) quit(0) else: print("RESULT: %d FAILURE(S) out of %d assertions" % [_failures, _checks]) quit(1) func _test_air_pose_and_momentum(rig: StickmanRig) -> void: var left_hand := rig._get_ik_marker("Left_Hand") var right_hand := rig._get_ik_marker("Right_Hand") var left_base := left_hand.position var right_base := right_hand.position rig._enter_airborne(300.0) _check(rig._terrain_motion == RIG.TerrainMotion.AIRBORNE, "enter_airborne selects AIRBORNE") _check(is_equal_approx(rig._terrain_air_velocity.x, 300.0), "takeoff keeps signed horizontal velocity") rig._terrain_air_velocity.y = RIG.AIR_POSE_FULL_SPEED rig._air_time = 0.0 rig._apply_air_pose(1.0) _check(rig._air_pose_weight > 0.99 and rig._air_pose_weight <= 1.0, "air pose weight clamps at full fall speed") _check(left_hand.position != left_base and right_hand.position != right_base, "air pose offsets both hands") rig._restore_air_pose() _check(left_hand.position.is_equal_approx(left_base) and right_hand.position.is_equal_approx(right_base), "air pose restores exact captured markers") rig._terrain_motion = RIG.TerrainMotion.GROUNDED rig._enter_airborne(0.0) var forward_left_base: Vector2 = rig._air_pose_base["Left_Hand"] var forward_right_base: Vector2 = rig._air_pose_base["Right_Hand"] rig._terrain_air_velocity.y = RIG.AIR_HAND_FORWARD_START_SPEED + 20.0 rig._air_time = 0.0 rig._apply_air_pose(1.0) _check(left_hand.position.x > forward_left_base.x and right_hand.position.x > forward_right_base.x, "hands reach forward before lift engages") _check(is_equal_approx(left_hand.position.y, forward_left_base.y) and is_equal_approx(right_hand.position.y, forward_right_base.y), "early forward reach does not lift hands") rig._terrain_air_velocity.y = RIG.AIR_POSE_FULL_SPEED rig._apply_air_pose(1.0) _check(left_hand.position.y < forward_left_base.y and right_hand.position.y < forward_right_base.y, "hands lift after forward reach") rig._restore_air_pose() rig._terrain_air_velocity = Vector2(300.0, 0.0) rig._terrain_air_velocity.x *= exp(-RIG.AIR_DRAG_X * 0.1) _check(rig._terrain_air_velocity.x > 0.0 and rig._terrain_air_velocity.x < 300.0, "air drag preserves forward momentum while decaying it") func _test_grounded_reset_and_ragdoll_cleanup(rig: StickmanRig) -> void: rig._terrain_following_enabled = true rig._terrain_motion = RIG.TerrainMotion.GROUNDED rig._last_grounded_walk_velocity_x = 999.0 rig._physics_process(0.0) _check(is_zero_approx(rig._last_grounded_walk_velocity_x), "grounded idle frame clears stale walk velocity") rig._enter_airborne(-240.0) rig._terrain_air_velocity.y = 640.0 rig._apply_air_pose(0.1) rig.set_ragdoll(true) _check(rig.state == RIG.RigState.RAGDOLL, "direct ragdoll enters from ordinary airborne motion") _check(rig._terrain_motion == RIG.TerrainMotion.DISABLED and rig._air_pose_base.is_empty(), "direct ragdoll clears airborne terrain ownership") _check(rig._terrain_air_velocity.is_zero_approx() and is_zero_approx(rig._air_pose_weight), "direct ragdoll clears air velocity and pose weight") rig.snap_to_standing() func _test_landing_timeline_and_barrier(rig: StickmanRig) -> void: var torso := rig._get_ik_marker("Torso") var left_leg := rig._get_ik_marker("Left_Leg") var right_leg := rig._get_ik_marker("Right_Leg") rig._enter_airborne(0.0) var base_torso := torso.position var left_hand := rig._get_ik_marker("Left_Hand") var right_hand := rig._get_ik_marker("Right_Hand") var left_hand_base := left_hand.position var right_hand_base := right_hand.position var contacts := { "Left_Leg": {"surface": left_leg.global_position + Vector2(0.0, 1200.0), "surface_valid": true}, "Right_Leg": {"surface": right_leg.global_position + Vector2(0.0, 1300.0), "surface_valid": true}, } rig._air_fall_distance = RIG.HARD_LANDING_MIN_FALL_HEIGHT rig._begin_landing(0.0, {"world_pos": torso.global_position}, contacts) _check(is_equal_approx(rig._landing_compression, RIG.LANDING_COMPRESSION_MIN), "minimum hard fall height maps to minimum compression") _check(rig._is_action_queue_blocked(), "landing blocks primary queue") rig._update_landing_impact(RIG.LANDING_COMPRESS_DURATION) _check(is_equal_approx(torso.position.y, base_torso.y + RIG.LANDING_COMPRESSION_MIN), "impact reaches deepest compression at 0.08s") _check(left_hand.position.y > left_hand_base.y and right_hand.position.y > right_hand_base.y, "hard landing sharply drives hands downward") _check(left_leg.global_position.y < torso.global_position.y + 500.0 and right_leg.global_position.y < torso.global_position.y + 500.0, "landing ignores stale pre-motion solved contacts") rig._update_landing_impact(RIG.LANDING_RECOVER_DURATION) _check(rig._terrain_motion == RIG.TerrainMotion.GROUNDED, "landing returns to GROUNDED after 0.30s") _check(torso.position.is_equal_approx(base_torso), "landing restores torso exactly") _check(left_hand.position.is_equal_approx(left_hand_base) and right_hand.position.is_equal_approx(right_hand_base), "landing restores hand bases exactly") _check(not rig._is_action_queue_blocked(), "queue barrier clears after landing") rig._enter_airborne(0.0) rig._air_fall_distance = RIG.HARD_LANDING_MAX_FALL_HEIGHT rig._begin_landing(0.0, {"world_pos": torso.global_position}, contacts) _check(is_equal_approx(rig._landing_compression, RIG.LANDING_COMPRESSION_MAX), "maximum hard fall height maps to maximum compression") rig._cancel_landing_impact(true) rig._restore_air_pose() func _check(condition: bool, message: String) -> void: _checks += 1 if condition: print("PASS: " + message) else: _failures += 1 print("FAIL: " + message)