ShitboxInfinity/tests/smoke.gd
type-two 9a4d96ae54 MINI MERK, MAXI MERK (6 wheels), HARDON SHAGGEN panel van
New moke body style: open slab tub, no doors, exposed seats, windscreen,
rip-off det_roof canopy on posts, optional extra visual axles (physics stays
4-ray). New van style: cargo box from cab to tail with det_tailgate. Smoke
test ram made deterministic (re-aim loop instead of blind throttle).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 21:48:37 +10:00

83 lines
3.0 KiB
GDScript

extends SceneTree
## Headless smoke test:
## /Applications/Godot.app/Contents/MacOS/Godot --headless --path . --script tests/smoke.gd
## Registry finds content; each mode boots and simulates; the car drives; traffic
## gets smashed when driven through.
func _initialize() -> void:
_run()
func _run() -> void:
var cars := Registry.cars()
var levels := Registry.levels()
assert(not cars.is_empty(), "no cars found")
assert(not levels.is_empty(), "no levels found")
for p in cars.values():
var s: CarStats = load(p)
assert(s != null and s.engine_power > 0.0, "bad stats: %s" % p)
if s.model_path != "":
assert(load(s.model_path) is PackedScene, "bad model: %s" % s.model_path)
Game.car_path = cars.values()[0]
Game.level_path = levels.values()[0]
# cruise: throttle 3s, car must move
var game: Game = await _boot("cruise")
if game.car.stats.model_path != "":
assert(game.car._parts.size() >= 8, "model has no detachable det_* parts")
var start: Vector3 = game.car.global_position
Input.action_press("throttle")
for i in 180:
await physics_frame
var dist := start.distance_to(game.car.global_position)
assert(dist > 5.0, "car didn't move (%.1f m)" % dist)
Input.action_release("throttle")
game.free()
# crash mode: traffic spawned, ram the nearest one, score must rise
game = await _boot("crash")
assert(game.traffic.size() == Game.TRAFFIC_COUNT["crash"], "traffic missing")
var victim: TrafficCar = game.traffic[0]
await physics_frame # traffic takes position on its first physics tick
Input.action_press("throttle")
for attempt in 8: # re-aim: victim keeps moving along the loop
if not victim.live:
break
var to_victim := (victim.global_position - game.car.global_position)
game.car.global_position = victim.global_position - victim.global_basis.z * 8.0
game.car.look_at(victim.global_position)
to_victim = (victim.global_position - game.car.global_position).normalized()
game.car.linear_velocity = to_victim * 18.0
for i in 30:
await physics_frame
if not victim.live:
break
Input.action_release("throttle")
assert(not victim.live, "rammed traffic never went dynamic")
assert(game.score > 0.0, "crash mode scored nothing")
var crash_score := game.score
game.free()
# race: rivals spawn and make progress along the path
game = await _boot("race")
assert(game.rivals.size() == Game.RIVAL_COUNT, "rivals missing")
var p0: float = game.rivals[0].progress
for i in 240:
await physics_frame
var moved := false
for r in game.rivals:
if absf(r.progress - p0) > 3.0 or r.linear_velocity.length() > 3.0:
moved = true
assert(moved, "no rival is driving")
game.free()
print("smoke ok: %d cars, %d levels | cruise %.1f m | crash $%d | race AI driving" %
[cars.size(), levels.size(), dist, int(crash_score)])
quit(0)
func _boot(mode: String) -> Game:
Game.mode = mode
var game: Game = (load("res://src/game.tscn") as PackedScene).instantiate()
root.add_child(game)
await process_frame # _ready is deferred until the main loop runs
return game