Add industrial metal soundtrack with seamless loop
- assets/audio/music/zombie_industrial_loop.ogg: 57.60 s Ogg Vorbis loop generated locally with YuE2-3B on the Tesla V100 (score written for this track; vocals removed with HTDemucs). The loop is spliced at the track's structural repeat with a 0.6 s crossfade: measured seam dip <= 1.6 dB. - scripts/main.gd: "Music" AudioStreamPlayer at -11 dB, started at boot on desktop and on the start click on Web (browser autoplay policy). It forces stream.loop at runtime because the Web staging step re-imports the OGG with loop=false. - tools/test_music.gd: soundtrack test (loop, length, volume, playback, still playing after player death). - docs/MUSIC.md: source, loop construction, verification, licence. - docs/WEB-DEPLOY.md: release ab6054111f5919a8 notes. Initial commit of the project.
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
extends SceneTree
|
||||
var detonation_time := -1
|
||||
func _initialize() -> void:
|
||||
call_deferred("run_test")
|
||||
func run_test() -> void:
|
||||
var world := Node3D.new()
|
||||
root.add_child(world)
|
||||
var room := Node3D.new()
|
||||
room.set_script(load("res://scripts/room.gd"))
|
||||
world.add_child(room)
|
||||
var player := CharacterBody3D.new()
|
||||
player.set_script(load("res://scripts/player.gd"))
|
||||
player.position = Vector3(0, 0.1, 4)
|
||||
world.add_child(player)
|
||||
player.hp = 10000
|
||||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||
await physics_frame
|
||||
var grenade: RigidBody3D = player.throw_grenade()
|
||||
assert(grenade != null)
|
||||
assert(player.throw_grenade() == null)
|
||||
assert(is_equal_approx(player.grenade_cooldown, 15))
|
||||
assert(grenade.physics_material_override.bounce > 0)
|
||||
grenade.detonated.connect(func(): detonation_time = Time.get_ticks_msec())
|
||||
var started := Time.get_ticks_msec()
|
||||
var start := grenade.position
|
||||
await create_timer(0.5).timeout
|
||||
assert(grenade.position.distance_to(start) > 1)
|
||||
assert(grenade.linear_velocity.y < 3)
|
||||
var targets: Array[Node3D] = []
|
||||
for pos in [Vector3(0, 0, -2), Vector3(2, 0, 0), Vector3(0, 0, -7)]:
|
||||
var target := Node3D.new()
|
||||
target.set_script(load("res://tools/grenade_test_target.gd"))
|
||||
target.position = pos
|
||||
world.add_child(target)
|
||||
targets.append(target)
|
||||
var wall := StaticBody3D.new()
|
||||
wall.position = Vector3(1, 1.5, 0)
|
||||
var shape := CollisionShape3D.new()
|
||||
var box := BoxShape3D.new()
|
||||
box.size = Vector3(0.2, 3, 2)
|
||||
shape.shape = box
|
||||
wall.add_child(shape)
|
||||
world.add_child(wall)
|
||||
# Isolate explosion coverage from the projectile's random rotation/bounces.
|
||||
grenade.freeze = true
|
||||
grenade.global_position = Vector3(0, 0.3, 0)
|
||||
await create_timer(3.15).timeout
|
||||
assert(is_instance_valid(grenade) and not grenade.exploded)
|
||||
await create_timer(0.6).timeout
|
||||
assert(detonation_time >= 0)
|
||||
var seconds := (detonation_time - started) / 1000.0
|
||||
assert(seconds >= 3.8 and seconds <= 4.3)
|
||||
assert(targets[0].damage_taken > 0)
|
||||
assert(targets[1].damage_taken == 0) # behind a wall
|
||||
assert(targets[2].damage_taken == 0) # beyond blast radius
|
||||
assert(player.hp < 10000)
|
||||
assert(player.throw_grenade() == null)
|
||||
# Wait until the real cooldown expires, without changing the game timer.
|
||||
await create_timer(player.grenade_cooldown + 0.1).timeout
|
||||
assert(player.grenade_cooldown == 0)
|
||||
assert(player.throw_grenade() != null)
|
||||
var main = load("res://scripts/main.gd").new()
|
||||
assert(main.zombies_for_wave(1) == 6)
|
||||
assert(main.zombies_for_wave(2) == 8)
|
||||
assert(main.zombies_for_wave(11) == 26)
|
||||
main.free()
|
||||
print("PASS: thrown physics/gravity, 4s fuse (", seconds, "), 15s cooldown, blast LOS/range/self-damage, wave growth beyond 24")
|
||||
world.queue_free()
|
||||
await process_frame
|
||||
quit()
|
||||
Reference in New Issue
Block a user