99 lines
3.9 KiB
GDScript
99 lines
3.9 KiB
GDScript
extends SceneTree
|
|
|
|
## Result-screen statistics + Rank formula (AnchorV1.0 §19.6 / §21.10).
|
|
|
|
var failures: Array[String] = []
|
|
|
|
|
|
func _init() -> void:
|
|
_run.call_deferred()
|
|
|
|
|
|
func _run() -> void:
|
|
var stats: Node = load("res://autoload/game_stats.gd").new()
|
|
root.add_child(stats)
|
|
await process_frame
|
|
|
|
stats.call("start_run")
|
|
|
|
# --- fact subscription through a synthetic bus feed ---
|
|
stats.call("_on_judgement_made", &"perfect", 0.0, 1)
|
|
stats.call("_on_judgement_made", &"good", 20.0, 2)
|
|
stats.call("_on_judgement_made", &"bad", 90.0, 3)
|
|
stats.call("_on_judgement_made", &"miss", 300.0, 4)
|
|
stats.call("_on_time_anchor_resolved", {"beat": 4}, true, {"label": "perfect"})
|
|
stats.call("_on_time_anchor_resolved", {"beat": 8}, false, {})
|
|
stats.call("_on_time_phase_changed", &"past", &"future", &"time_anchor_broken")
|
|
stats.call("_on_time_phase_changed", &"past", &"future", &"chart_init")
|
|
stats.call("_on_streak_changed", 12)
|
|
stats.call("_on_streak_changed", 3)
|
|
|
|
_expect_int(int(stats.get("perfect_count")), 1, "perfect count")
|
|
_expect_int(int(stats.get("good_count")), 1, "good count")
|
|
_expect_int(int(stats.get("bad_count")), 1, "bad count")
|
|
_expect_int(int(stats.get("miss_count")), 1, "miss count")
|
|
_expect_int(int(stats.get("anchor_success_count")), 1, "anchor success only on held")
|
|
_expect_int(int(stats.get("phase_shift_count")), 1, "chart_init phase change must not count as a shift")
|
|
_expect_int(int(stats.get("max_combo")), 12, "max combo keeps the highest streak")
|
|
|
|
# --- accuracy: (1*1.00 + 1*0.85 + 1*0.55 + 0) / 4 * 65 ---
|
|
_expect_float(float(stats.call("accuracy_score")), (1.0 + 0.85 + 0.55) / 4.0 * 65.0, "accuracy score formula")
|
|
# --- anchor: 1 success / (1 + 1 shift) * 20 ---
|
|
_expect_float(float(stats.call("anchor_score")), 10.0, "anchor control score formula")
|
|
# --- combo: min(12/80, 1) * 15 ---
|
|
_expect_float(float(stats.call("combo_score")), 12.0 / 80.0 * 15.0, "combo stability score formula")
|
|
|
|
# --- rank bands (§19.6) ---
|
|
_expect_string(str(stats.call("rank_for_score", 95.0)), "S", "rank S from 90")
|
|
_expect_string(str(stats.call("rank_for_score", 90.0)), "S", "rank S boundary")
|
|
_expect_string(str(stats.call("rank_for_score", 85.0)), "A", "rank A band")
|
|
_expect_string(str(stats.call("rank_for_score", 70.0)), "B", "rank B band")
|
|
_expect_string(str(stats.call("rank_for_score", 55.0)), "C", "rank C band")
|
|
_expect_string(str(stats.call("rank_for_score", 20.0)), "D", "rank D band")
|
|
|
|
# --- anchor_total = 0 → full anchor score (§19.6) ---
|
|
stats.call("reset")
|
|
_expect_float(float(stats.call("anchor_score")), 20.0, "no anchors at all should give the full 20 anchor points")
|
|
|
|
# --- perfect run: full 100 / S ---
|
|
stats.call("start_run")
|
|
for index: int in range(80):
|
|
stats.call("_on_judgement_made", &"perfect", 0.0, index)
|
|
stats.call("_on_streak_changed", 80)
|
|
stats.call("_on_time_anchor_resolved", {"beat": 4}, true, {"label": "perfect"})
|
|
_expect_float(float(stats.call("total_score")), 100.0, "perfect run should score 100")
|
|
_expect_string(str(stats.call("current_rank")), "S", "perfect run rank")
|
|
|
|
# --- tracking stops after stop_tracking ---
|
|
stats.call("stop_tracking")
|
|
stats.call("_on_judgement_made", &"miss", 0.0, 99)
|
|
_expect_int(int(stats.get("miss_count")), 0, "no counting after stop_tracking")
|
|
|
|
stats.free()
|
|
_finish()
|
|
|
|
|
|
func _expect_int(actual: int, expected: int, label: String) -> void:
|
|
if actual != expected:
|
|
failures.append("%s: expected %d, got %d" % [label, expected, actual])
|
|
|
|
|
|
func _expect_float(actual: float, expected: float, label: String) -> void:
|
|
if absf(actual - expected) > 0.001:
|
|
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 game stats rank")
|
|
quit(0)
|
|
else:
|
|
for failure: String in failures:
|
|
push_error(failure)
|
|
quit(1)
|