Author the missing scenario content from the PLAN lists
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.
This commit is contained in:
1 parent
922a990c7a
commit
a2a0ded527
12 files changed
+426
-18
No files matched your search
@@ -343,6 +343,28 @@ static func hollywood_building() -> VenueScenario:
|
||||
_building_routine("staff_entry", Rules.NpcType.AUTHORIZED_STAFF, "enter", Vector2(0, 600), 0.35),
|
||||
_building_routine("guest_entry", Rules.NpcType.AUTHORIZED_GUEST, "enter", Vector2(0, 900), 0.25),
|
||||
_building_routine("performer_show", Rules.NpcType.PERFORMER, "perform", Vector2(300, 800), 0.24),
|
||||
{
|
||||
"id": "building_filming_boundary",
|
||||
"phase": Rules.Phase.MIDDAY,
|
||||
"kind": "scripted",
|
||||
"npc_type": Rules.NpcType.INFLUENCER,
|
||||
"intent": "film",
|
||||
"time_range_s": Vector2(300, 600),
|
||||
"probability": 0.4,
|
||||
"base_weight": 1.0,
|
||||
"hint": "hint.body_camera_reason",
|
||||
},
|
||||
{
|
||||
"id": "building_unclear_intent",
|
||||
"phase": Rules.Phase.EVENING,
|
||||
"kind": "scripted",
|
||||
"npc_type": Rules.NpcType.CONFUSED_VISITOR,
|
||||
"intent": "enter",
|
||||
"time_range_s": Vector2(600, 780),
|
||||
"probability": 0.4,
|
||||
"base_weight": 1.0,
|
||||
"hint": "hint.ask_reason",
|
||||
},
|
||||
_building_routine("influencer_film", Rules.NpcType.INFLUENCER, "film", Vector2(300, 900), 0.26),
|
||||
_building_routine("intoxicated_wander", Rules.NpcType.INTOXICATED, "wander", Vector2(600, 900), 0.15),
|
||||
_building_routine("trespass_test", Rules.NpcType.TRESPASSER, "trespass", Vector2(300, 900), 0.16),
|
||||
@@ -437,6 +459,67 @@ static func joke_shop() -> VenueScenario:
|
||||
_joke_guest("guest_no_ticket", false, true, Vector2(0, 900), 0.18),
|
||||
_joke_guest("guest_expired_id", true, true, Vector2(0, 900), 0.12, {"id_status": Rules.ArtifactStatus.EXPIRED}),
|
||||
_joke_guest("guest_no_id", true, false, Vector2(0, 900), 0.12),
|
||||
{
|
||||
"id": "joke_guest_reservation_no_id",
|
||||
"phase": Rules.Phase.EVENING,
|
||||
"kind": "scripted",
|
||||
"npc_type": Rules.NpcType.AUTHORIZED_GUEST,
|
||||
"intent": "enter",
|
||||
"time_range_s": Vector2(620, 860),
|
||||
"probability": 0.45,
|
||||
"base_weight": 1.0,
|
||||
"override_access": {
|
||||
"has_guest_list": true, "guest_list_status": Rules.ArtifactStatus.VALID,
|
||||
"has_id": false, "has_ticket": false,
|
||||
},
|
||||
"hint": "hint.reservation_no_id",
|
||||
},
|
||||
{
|
||||
"id": "joke_borrowed_id",
|
||||
"phase": Rules.Phase.MIDDAY,
|
||||
"kind": "scripted",
|
||||
"npc_type": Rules.NpcType.AUTHORIZED_GUEST,
|
||||
"intent": "enter",
|
||||
"time_range_s": Vector2(320, 700),
|
||||
"probability": 0.4,
|
||||
"base_weight": 1.0,
|
||||
"override_access": {
|
||||
"has_id": true, "id_status": Rules.ArtifactStatus.MISMATCHED,
|
||||
"has_ticket": true, "ticket_status": Rules.ArtifactStatus.VALID,
|
||||
},
|
||||
"hint": "hint.borrowed_id",
|
||||
},
|
||||
{
|
||||
"id": "joke_refuses_wand",
|
||||
"phase": Rules.Phase.EVENING,
|
||||
"kind": "scripted",
|
||||
"npc_type": Rules.NpcType.AUTHORIZED_GUEST,
|
||||
"intent": "enter",
|
||||
"time_range_s": Vector2(650, 880),
|
||||
"probability": 0.4,
|
||||
"base_weight": 1.0,
|
||||
"refuses_screening": true,
|
||||
"override_access": {
|
||||
"has_id": true, "id_status": Rules.ArtifactStatus.VALID,
|
||||
"has_ticket": true, "ticket_status": Rules.ArtifactStatus.VALID,
|
||||
},
|
||||
"hint": "hint.refuses_wand",
|
||||
},
|
||||
{
|
||||
"id": "joke_late_arrival",
|
||||
"phase": Rules.Phase.EVENING,
|
||||
"kind": "scripted",
|
||||
"npc_type": Rules.NpcType.AUTHORIZED_GUEST,
|
||||
"intent": "arrive",
|
||||
"time_range_s": Vector2(700, 860),
|
||||
"probability": 0.35,
|
||||
"base_weight": 1.0,
|
||||
"override_access": {
|
||||
"has_id": true, "id_status": Rules.ArtifactStatus.VALID,
|
||||
"has_ticket": true, "ticket_status": Rules.ArtifactStatus.VALID,
|
||||
},
|
||||
"hint": "hint.late_arrival",
|
||||
},
|
||||
_joke_staff_entry(Vector2(0, 900), 0.25),
|
||||
_joke_routine("performer_show", Rules.NpcType.PERFORMER, "perform", Vector2(300, 800), 0.15),
|
||||
_joke_routine("influencer_film", Rules.NpcType.INFLUENCER, "film", Vector2(300, 900), 0.15),
|
||||
@@ -515,6 +598,45 @@ static func tv_studio() -> VenueScenario:
|
||||
"base_weight": 1.0,
|
||||
"override_access": {"wristband_status": Rules.ArtifactStatus.COUNTERFEIT, "credential_status": Rules.ArtifactStatus.COUNTERFEIT},
|
||||
},
|
||||
{
|
||||
"id": "studio_film_boundary",
|
||||
"phase": Rules.Phase.MIDDAY,
|
||||
"kind": "scripted",
|
||||
"npc_type": Rules.NpcType.INFLUENCER,
|
||||
"intent": "film_boundary",
|
||||
"time_range_s": Vector2(330, 560),
|
||||
"probability": 0.5,
|
||||
"base_weight": 1.0,
|
||||
"hint": "hint.film_boundary",
|
||||
},
|
||||
{
|
||||
"id": "studio_film_boundary_repeat",
|
||||
"phase": Rules.Phase.EVENING,
|
||||
"kind": "scripted",
|
||||
"npc_type": Rules.NpcType.INFLUENCER,
|
||||
"intent": "film_boundary",
|
||||
"time_range_s": Vector2(640, 830),
|
||||
"probability": 0.45,
|
||||
"base_weight": 1.0,
|
||||
"hint": "hint.film_boundary_repeat",
|
||||
},
|
||||
{
|
||||
"id": "studio_celebrity_arrival",
|
||||
"phase": Rules.Phase.EVENING,
|
||||
"kind": "scripted",
|
||||
"npc_type": Rules.NpcType.AUTHORIZED_GUEST,
|
||||
"intent": "arrive",
|
||||
"time_range_s": Vector2(620, 760),
|
||||
"probability": 0.5,
|
||||
"base_weight": 1.0,
|
||||
"override_access": {"has_guest_list": true, "guest_list_status": Rules.ArtifactStatus.VALID},
|
||||
"extra_spawns": [
|
||||
{"npc_type": Rules.NpcType.TOURIST, "intent": "photo"},
|
||||
{"npc_type": Rules.NpcType.TOURIST, "intent": "photo"},
|
||||
{"npc_type": Rules.NpcType.INFLUENCER, "intent": "film"},
|
||||
],
|
||||
"hint": "hint.celebrity_arrival",
|
||||
},
|
||||
{
|
||||
"id": "studio_follow_through",
|
||||
"phase": Rules.Phase.EVENING,
|
||||
@@ -587,6 +709,10 @@ static func _joke_routine(id: String, npc_type: int, intent: String, time_range:
|
||||
static func _studio_routine(id: String, npc_type: int, intent: String, time_range: Vector2, prob: float) -> Dictionary:
|
||||
return _building_routine(id, npc_type, intent, time_range, prob)
|
||||
|
||||
## Scripted film-boundary intent: the influencer stands past the posted line.
|
||||
static func _film_boundary_spot() -> String:
|
||||
return "steps_end"
|
||||
|
||||
static func _phase_for_range(time_range: Vector2, duration: float) -> int:
|
||||
var start := time_range.x / duration
|
||||
if start < 0.34:
|
||||
|
||||
Reference in new issue
Block a user