Files
Blockline/tests/shooting_polish.gd
T

67 lines
2.8 KiB
GDScript

extends SceneTree
var failures := 0
var checks := 0
func _initialize() -> void: call_deferred("run")
func check(ok: bool, message: String) -> void:
checks += 1
if not ok: failures += 1
print("PASS " if ok else "FAIL ", message)
func run() -> void:
var audio := ArenaAudio.new()
root.add_child(audio)
for local in [true,false]:
for i in 8: audio.play_shot("shot_0", Vector3.ZERO, local)
check(audio.shot_players.size() == 2, "shot players reused rather than allocated per shot")
for player in audio.shot_players.values():
check(player.max_polyphony == 3 and player.pitch_scale >= 0.95 and player.pitch_scale <= 1.05, "polyphony and pitch limits")
var limited := false
for i in AudioServer.get_bus_effect_count(0): limited = limited or AudioServer.get_bus_effect(0,i) is AudioEffectLimiter
check(limited, "master limiter installed")
for profile in WeaponHandling.DATA:
var states := []
for rate in [60,240]:
var state: Array[Vector2] = [Vector2.ZERO, Vector2(profile.kick,profile.rise)*profile.spring*2.1]
for tick in rate: state = WeaponHandling.settle(state[0],state[1],profile.spring,1.0/rate)
states.append(state)
check(states[0][0].distance_to(states[1][0]) < 0.00001, "recoil trajectory endpoint matches at 60/240 Hz")
var stop := HitStop.new()
root.add_child(stop)
var started := Time.get_ticks_usec()
stop.trigger()
check(Engine.time_scale == 0.05, "hit-stop applies five percent")
while stop.running: await process_frame
var elapsed := (Time.get_ticks_usec()-started)/1000.0
check(Engine.time_scale == 1.0 and elapsed >= 29 and elapsed < 100, "hit-stop restores on real-time deadline; ms="+str(elapsed))
stop.trigger()
stop.restore()
check(Engine.time_scale == 1.0, "leaving restores time immediately")
await create_timer(0.5, true, false, true).timeout
var stage := Node3D.new()
root.add_child(stage)
var fighter := Fighter.new()
fighter.add_child(fighter.movement)
fighter.add_child(fighter.weapon_controller)
fighter.add_child(fighter.replication_state)
fighter.set_process(false)
fighter.set_physics_process(false)
stage.add_child(fighter)
fighter.process_mode = Node.PROCESS_MODE_DISABLED
var target := StaticBody3D.new()
target.position = Vector3(0,0,-5)
var box := BoxShape3D.new()
var collider := CollisionShape3D.new()
collider.shape = box
target.add_child(collider)
stage.add_child(target)
await physics_frame
await physics_frame
var hit := HitscanRay.cast(fighter, Vector3.ZERO, Vector3(0,0,-10), 1)
check(hit.get("collider") == target and fighter.get_node("HitscanRay") is RayCast3D, "RayCast3D hits world cover immediately")
check(HitscanRay.cast(fighter, Vector3.ZERO, Vector3(0,5,-10), 1).is_empty(), "RayCast3D clears previous hit on miss")
stage.queue_free()
audio.queue_free()
stop.queue_free()
await process_frame
print("POLISH RESULT ", checks-failures,"/",checks)
quit(1 if failures else 0)