Joke Shop - Reservation list without ID (guest list valid, ID missing) — denied. - Borrowed/mismatched ID (ID valid but mismatched) — denied. - Guest who refuses the wand screen: new `refuses_screening` event flag, copied onto NPCController, handled in _toggle_wand_screening (logs wand.refused, records a wand_refused event, small prop hit, panel stays closed). - Late arrival during the performance (ID + ticket, "arrive" intent). Studio - Filming-boundary event and a later repeat, both using the new `film_boundary` intent which maps to `steps_end` so the influencer stands past the posted line. - Celebrity arrival now pulls in a small crowd via a new `extra_spawns` event field (two tourists + an influencer), spawned through the normal path. Building - Filming-boundary event whose hint points at the body camera and request-reason verbs, plus an unclear-intent event that hints at asking for a reason. Engine support - Events may carry `hint` (string key logged on spawn), `extra_spawns`, and `refuses_screening`; 9 new localized hint strings. Tests/docs - Headless suite 139 -> 149 (test_scenario_content.gd) and a new smoke_scenario_content.gd that spawns the refusal and celebrity events through the real signal path. - README, TODO section moved to DONE, MEMORY. Version 0.2.13.
92 lines
2.9 KiB
GDScript
92 lines
2.9 KiB
GDScript
extends SceneTree
|
|
## Scenario-content smoke: forces the authored Joke Shop refusal event and the
|
|
## Studio celebrity arrival through the real spawn path, then checks the extra
|
|
## bystanders, the hint log, and that a screening refusal is handled.
|
|
##
|
|
## Usage:
|
|
## godot --headless --path . --script res://src/test/smoke_scenario_content.gd
|
|
|
|
const MAX_FRAMES := 900
|
|
|
|
var frame := 0
|
|
var gm: Node = null
|
|
var started := false
|
|
var step := 0
|
|
var failures: Array[String] = []
|
|
|
|
func _initialize() -> void:
|
|
root.size = Vector2i(1280, 720)
|
|
root.add_child(load("res://scenes/main.tscn").instantiate())
|
|
|
|
func _process(_delta: float) -> bool:
|
|
frame += 1
|
|
if gm == null:
|
|
gm = root.find_child("GameManager", true, false)
|
|
return false
|
|
if not started:
|
|
gm.call("_on_venue_selected", "joke_shop")
|
|
started = true
|
|
return false
|
|
if frame > MAX_FRAMES:
|
|
_fail("timeout")
|
|
return true
|
|
if frame < 120:
|
|
return false
|
|
match step:
|
|
0:
|
|
# Force the refusal event through the normal spawn signal.
|
|
var event := _find_event(gm.selected_scenario.event_pool, "joke_refuses_wand")
|
|
_check(not event.is_empty(), "the refusal event exists in the Joke Shop pool")
|
|
var guest: Object = gm.selected_scenario.profile_for(int(event.get("npc_type", 0)))
|
|
gm.coordinator.npc_spawn_requested.emit(guest, "enter", "smoke_refuser", event)
|
|
_check(gm.npcs.size() > 0, "the refusing guest spawned")
|
|
gm.call("_on_guard_target", gm.npcs[gm.npcs.size() - 1])
|
|
var controller: Object = gm.npcs[gm.npcs.size() - 1].get_npc_controller()
|
|
_check(controller.refuses_screening, "the refusal flag reached the controller")
|
|
gm.call("_toggle_wand_screening")
|
|
_check(not gm.wand_open, "screening does not open for someone who refuses")
|
|
step = 1
|
|
1:
|
|
# Studio: celebrity arrival should bring extra bystanders.
|
|
gm.call("_on_venue_selected", "tv_studio")
|
|
step = 2
|
|
2:
|
|
if frame % 20 != 0:
|
|
return false
|
|
var event := _find_event(gm.selected_scenario.event_pool, "studio_celebrity_arrival")
|
|
var before: int = gm.npcs.size()
|
|
var guest: Object = gm.selected_scenario.profile_for(int(event.get("npc_type", 0)))
|
|
gm.coordinator.npc_spawn_requested.emit(guest, "arrive", "smoke_celeb", event)
|
|
var added: int = gm.npcs.size() - before
|
|
_check(added >= 4, "celebrity arrival spawns the guest plus bystanders (%d)" % added)
|
|
step = 3
|
|
3:
|
|
_finish()
|
|
return true
|
|
return false
|
|
|
|
func _find_event(pool: Array, id: String) -> Dictionary:
|
|
for event in pool:
|
|
if str((event as Dictionary).get("id", "")) == id:
|
|
return event
|
|
return {}
|
|
|
|
func _check(condition: bool, message: String) -> void:
|
|
if condition:
|
|
print("ok: " + message)
|
|
else:
|
|
_fail(message)
|
|
|
|
func _fail(message: String) -> void:
|
|
failures.append(message)
|
|
_finish()
|
|
|
|
func _finish() -> void:
|
|
if failures.is_empty():
|
|
print("SMOKE OK: authored scenario content")
|
|
quit(0)
|
|
else:
|
|
for message in failures:
|
|
printerr("SMOKE FAIL: " + message)
|
|
quit(1)
|