Initial project sync

This commit is contained in:
wxm
2026-07-06 22:55:14 -07:00
commit 8cca00d0da
1066 changed files with 58585 additions and 0 deletions
+91
View File
@@ -0,0 +1,91 @@
extends SceneTree
## Difficulty judgement windows + the dynamic bad-window cap
## (AnchorV1.0 §9.5 / §21.8).
var failures: Array[String] = []
func _init() -> void:
_run.call_deferred()
func _run() -> void:
var settings: Node = load("res://autoload/game_settings.gd").new()
root.add_child(settings)
var rhythm: Node = load("res://autoload/rhythm_manager.gd").new()
rhythm.set("starts_on_ready", false)
root.add_child(rhythm)
await process_frame
# --- §21.8 window tables ---
_expect_vector(settings.call("difficulty_windows", &"easy"), Vector3(0.090, 0.160, 0.260), "easy windows")
_expect_vector(settings.call("difficulty_windows", &"normal"), Vector3(0.060, 0.115, 0.215), "normal windows")
_expect_vector(settings.call("difficulty_windows", &"hard"), Vector3(0.030, 0.070, 0.170), "hard windows")
# --- applying a difficulty rewrites the rhythm manager windows ---
var windows: Vector3 = settings.call("difficulty_windows", &"hard")
rhythm.call("apply_judgement_windows", windows.x, windows.y, windows.z)
_expect_float(float(rhythm.get("perfect_window")), 0.030, "hard perfect window applied")
_expect_float(float(rhythm.get("good_window")), 0.070, "hard good window applied")
_expect_float(float(rhythm.get("bad_window")), 0.170, "hard bad window applied")
# --- default (normal) values live on the manager itself ---
var fresh: Node = load("res://autoload/rhythm_manager.gd").new()
fresh.set("starts_on_ready", false)
root.add_child(fresh)
await process_frame
_expect_float(float(fresh.get("perfect_window")), 0.060, "default perfect window is Normal")
_expect_float(float(fresh.get("good_window")), 0.115, "default good window is Normal")
_expect_float(float(fresh.get("bad_window")), 0.215, "default bad window is Normal")
# --- §9.5 dynamic cap: bad <= beat_interval * 0.48, cascading ---
fresh.set("bpm", 240.0) # beat_time 0.25s → cap 0.12
var effective: Vector3 = fresh.call("effective_windows")
_expect_float(effective.z, 0.12, "bad window capped at 48% of the beat")
_expect_float(effective.y, 0.115, "good window stays when under the cap")
_expect_float(effective.x, 0.060, "perfect window stays when under the cap")
fresh.set("bpm", 600.0) # beat_time 0.1s → cap 0.048: everything collapses
effective = fresh.call("effective_windows")
_expect_float(effective.z, 0.048, "extreme BPM bad cap")
_expect_float(effective.y, 0.048, "good window can never exceed the capped bad window")
_expect_float(effective.x, 0.048, "perfect window can never exceed the capped good window")
# --- the cap is what judgement actually uses ---
fresh.set("bpm", 240.0)
fresh.set("running", true)
var rating: Dictionary = fresh.call("get_rating_for_time", 0.25 + 0.13)
_expect_string(str(rating.get("label")), "miss", "an offset outside the capped bad window judges miss")
rating = fresh.call("get_rating_for_time", 0.25 + 0.118)
_expect_string(str(rating.get("label")), "bad", "an offset between good and the capped bad window judges bad")
settings.free()
rhythm.free()
fresh.free()
_finish()
func _expect_vector(actual: Vector3, expected: Vector3, label: String) -> void:
if (actual - expected).length() > 0.0005:
failures.append("%s: expected %s, got %s" % [label, expected, actual])
func _expect_float(actual: float, expected: float, label: String) -> void:
if absf(actual - expected) > 0.0005:
failures.append("%s: expected %f, got %f" % [label, expected, actual])
func _expect_string(actual: String, expected: String, label: String) -> void:
if actual != expected:
failures.append("%s: expected %s, got %s" % [label, expected, actual])
func _finish() -> void:
if failures.is_empty():
print("PASS difficulty windows")
quit(0)
else:
for failure: String in failures:
push_error(failure)
quit(1)