extends Node var checks: int = 0 var failures: Array[String] = [] func check(ok: bool, label: String) -> void: checks += 1 if not ok: failures.append(label) printerr("RIG_FAIL: ", label) func _ready() -> void: call_deferred("run") func run() -> void: var a: Node3D = AssetLibrary.instantiate_fighter("w10") var b: Node3D = AssetLibrary.instantiate_fighter("w10") add_child(a) add_child(b) check(a.skeleton.get_bone_count() == 17, "17 imported bones") check(a.player != b.player and a.skeleton != b.skeleton, "independent skeleton and playback") for clip: String in ["idle", "start", "walk", "stop", "attack_a", "attack_b", "hit", "ability", "death"]: check(a.clips.has(clip), "imported clip " + clip) check(a.clip_length(clip) > .3, "clip duration " + clip) var arm: int = a.skeleton.find_bone("UpperArm.L") var rest: Quaternion = b.skeleton.get_bone_pose_rotation(arm) a.preview("walk", .40) check(a.skeleton.find_bone("Thigh.L") >= 0, "has legs") a.preview("attack_a", .90) check(a.skeleton.get_bone_pose_rotation(arm).angle_to(rest) > .05, "left tendril attack moves arm") a.preview("ability", .80) check(a.current_clip == "ability" or a.clips.has("ability"), "multi-heal clip") a.preview("idle", 0) check(a.skeleton.get_bone_pose_rotation(arm).is_equal_approx(b.skeleton.get_bone_pose_rotation(arm)), "idle restores arms") a.update_combat(1.0 / 60, 0, true, .6, 0, 0, 0, true) check(a.current_clip == "attack_a", "combat left attack") a.update_combat(1.0 / 60, 0, true, 0, 1, 0, 0, true) check(absf(a.player.current_animation_position - .9) < .001, "contact frame") a.update_combat(1.0 / 60, 0, true, .65, 1, 0, 0, true) check(a.current_clip == "attack_b", "alternating right attack") a.update_combat(1.0 / 60, 0, false, 0, 1, 0, 0, false) check(a.dead and a.current_clip == "death", "death clip") a.free() b.free() var f := FileAccess.open("res://docs/phase16-rig-verification.json", FileAccess.WRITE) f.store_string(JSON.stringify({"checks": checks, "failures": failures}, "\t")) f.close() print("RIG_PASS: ", checks, " checks; ", failures.size(), " failures") await Soundscape.quit_game(0 if failures.is_empty() else 1)