Files
security-game/content/venues/joke_shop.tres
T
zwitschi f763cff744
Full build / Import + headless tests (push) Successful in 34s
Full build / Full desktop build + optional release (push) Successful in 3m51s
Export venues as editor-authorable .tres resources
- tools/export_venues.gd (SceneTree script) saves the three factory scenarios to
  content/venues/<id>.tres via ResourceSaver. The factory stays the source of truth;
  the exported files are what an editor workflow would edit and ship.
- New tests load the files back and check that id, name, event pool, profiles,
  policy (ID/wand), equipment, door-staff lines, shift phases, and locations all
  survive. They also fail when the exported files are missing or stale, so the
  export is re-run after content changes.
- GUT is consciously not adopted: the custom headless runner already covers 157
  assertions without an editor plugin and keeps CI dependency-free. Recorded in
  DONE.md.
- TODO: the planned backlog is complete; only optional future ideas remain.
- README/MEMORY updated. Version 0.2.16.
2026-10-31 22:16:55 +01:00

591 lines
9.3 KiB
Plaintext

[gd_resource type="Resource" script_class="VenueScenario" load_steps=13 format=3]
[ext_resource type="Script" path="res://src/core/access_policy.gd" id="1_lxsgk"]
[ext_resource type="Script" path="res://src/core/npc_profile.gd" id="2_wfc6m"]
[ext_resource type="Script" path="res://src/core/venue_scenario.gd" id="3_8xm7a"]
[sub_resource type="Resource" id="Resource_xha77"]
script = ExtResource("1_lxsgk")
required_artifacts = {
2: true,
3: true
}
grant_if_any_required = false
minimum_age = 21
require_id = true
wand_screening_required = true
policy_summary = "Government ID and a valid ticket or reservation required. Carry items are screened."
[sub_resource type="Resource" id="Resource_8ksyk"]
script = ExtResource("2_wfc6m")
id = "tourist"
display_name = "Tourist"
npc_type = 0
temperament = 0.1
base_compliance = 0.9
return_probability = 0.0
reactions_by_level = {}
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["Oh sure, sorry, just taking a picture.", "Is there a better spot to stand?", "Understood, moving."])
carried_items = Array[String]([])
[sub_resource type="Resource" id="Resource_wt1op"]
script = ExtResource("2_wfc6m")
id = "confused_visitor"
display_name = "Confused Visitor"
npc_type = 3
temperament = 0.2
base_compliance = 0.85
return_probability = 0.0
reactions_by_level = {}
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["Wait, this isn't the entrance?", "Sorry about that, I'm a bit lost."])
carried_items = Array[String]([])
[sub_resource type="Resource" id="Resource_g1jr2"]
script = ExtResource("2_wfc6m")
id = "influencer"
display_name = "Influencer"
npc_type = 2
temperament = 0.5
base_compliance = 0.5
return_probability = 0.0
reactions_by_level = {
1: {
0: 40,
2: 10,
3: 30,
4: 20
},
2: {
0: 30,
2: 20,
4: 35,
8: 15
},
3: {
0: 10,
1: 15,
2: 20,
4: 30,
8: 25
}
}
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["This is public sidewalk, you can't stop me from filming."])
carried_items = Array[String]([])
[sub_resource type="Resource" id="Resource_ys0b0"]
script = ExtResource("2_wfc6m")
id = "intoxicated"
display_name = "Intoxicated Pedestrian"
npc_type = 4
temperament = 0.6
base_compliance = 0.4
return_probability = 0.0
reactions_by_level = {
1: {
0: 30,
2: 20,
3: 50
},
2: {
0: 40,
2: 35,
3: 15,
4: 10
}
}
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 1.8
dialogue_lines = Array[String]([])
carried_items = Array[String]([])
[sub_resource type="Resource" id="Resource_bv0jw"]
script = ExtResource("2_wfc6m")
id = "trespasser"
display_name = "Trespasser"
npc_type = 5
temperament = 0.55
base_compliance = 0.35
return_probability = 0.6
reactions_by_level = {
1: {
0: 30,
2: 25,
3: 45
},
2: {
0: 40,
2: 35,
6: 25
},
3: {
1: 35,
2: 25,
6: 15,
7: 10,
8: 15
},
4: {
1: 70,
7: 30
},
5: {
1: 30,
5: 50,
7: 20
}
}
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["I'm just here to see a friend, come on.", "I'll be inside for ten seconds."])
carried_items = Array[String]([])
[sub_resource type="Resource" id="Resource_7vgx3"]
script = ExtResource("2_wfc6m")
id = "violent_threat"
display_name = "Violent Threat"
npc_type = 6
temperament = 0.95
base_compliance = 0.05
return_probability = 0.0
reactions_by_level = {
1: {
2: 25,
3: 45,
5: 30
},
2: {
2: 30,
5: 45,
7: 25
},
3: {
1: 20,
5: 45,
7: 35
},
4: {
1: 15,
5: 30,
7: 55
},
5: {
1: 30,
5: 40,
7: 30
}
}
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String]([])
carried_items = Array[String]([])
[sub_resource type="Resource" id="Resource_x43ed"]
script = ExtResource("2_wfc6m")
id = "authorized_staff"
display_name = "Staff Member"
npc_type = 8
temperament = 0.15
base_compliance = 1.0
return_probability = 0.0
reactions_by_level = {}
default_reactions = {
1: {
0: 100
}
}
reaction_delay = 0.6
dialogue_lines = Array[String]([])
carried_items = Array[String]([])
[sub_resource type="Resource" id="Resource_07lsg"]
script = ExtResource("2_wfc6m")
id = "authorized_guest"
display_name = "Authorized Guest"
npc_type = 9
temperament = 0.2
base_compliance = 0.95
return_probability = 0.0
reactions_by_level = {}
default_reactions = {
1: {
0: 92,
2: 8
},
2: {
0: 88,
2: 12
}
}
reaction_delay = 0.6
dialogue_lines = Array[String]([])
carried_items = Array[String]([])
[resource]
script = ExtResource("3_8xm7a")
id = "joke_shop"
display_name = "The Joke Shop"
description = "Comedy club door: IDs, reservations, and wand screening."
access_policy = SubResource("Resource_xha77")
equipment = Array[String](["id_check", "guest_list", "wand", "radio"])
locations = {
"door_area": Vector3(0, 0, 3),
"entrance": Vector3(0, 0, 1),
"guard_post": Vector3(0, 0, -3),
"queue_area": Vector3(0, 0, 9),
"sidewalk": Vector3(0, 0, 9),
"steps_end": Vector3(0, 0, 3)
}
npc_profiles = Array[ExtResource("2_wfc6m")]([SubResource("Resource_8ksyk"), SubResource("Resource_wt1op"), SubResource("Resource_g1jr2"), SubResource("Resource_ys0b0"), SubResource("Resource_bv0jw"), SubResource("Resource_7vgx3"), SubResource("Resource_x43ed"), SubResource("Resource_07lsg")])
event_pool = Array[Dictionary]([{
"base_weight": 1.0,
"id": "guest_valid",
"intent": "enter",
"kind": "routine",
"npc_type": 9,
"override_access": {
"has_id": true,
"has_ticket": true
},
"phase": 0,
"probability": 0.3,
"time_range_s": Vector2(0, 900)
}, {
"base_weight": 1.0,
"id": "guest_no_ticket",
"intent": "enter",
"kind": "routine",
"npc_type": 9,
"override_access": {
"has_id": true,
"has_ticket": false
},
"phase": 0,
"probability": 0.18,
"time_range_s": Vector2(0, 900)
}, {
"base_weight": 1.0,
"id": "guest_expired_id",
"intent": "enter",
"kind": "routine",
"npc_type": 9,
"override_access": {
"has_id": true,
"has_ticket": true,
"id_status": 1
},
"phase": 0,
"probability": 0.12,
"time_range_s": Vector2(0, 900)
}, {
"base_weight": 1.0,
"id": "guest_no_id",
"intent": "enter",
"kind": "routine",
"npc_type": 9,
"override_access": {
"has_id": false,
"has_ticket": true
},
"phase": 0,
"probability": 0.12,
"time_range_s": Vector2(0, 900)
}, {
"base_weight": 1.0,
"hint": "hint.reservation_no_id",
"id": "joke_guest_reservation_no_id",
"intent": "enter",
"kind": "scripted",
"npc_type": 9,
"override_access": {
"guest_list_status": 0,
"has_guest_list": true,
"has_id": false,
"has_ticket": false
},
"phase": 2,
"probability": 0.45,
"time_range_s": Vector2(620, 860)
}, {
"base_weight": 1.0,
"hint": "hint.borrowed_id",
"id": "joke_borrowed_id",
"intent": "enter",
"kind": "scripted",
"npc_type": 9,
"override_access": {
"has_id": true,
"has_ticket": true,
"id_status": 3,
"ticket_status": 0
},
"phase": 1,
"probability": 0.4,
"time_range_s": Vector2(320, 700)
}, {
"base_weight": 1.0,
"hint": "hint.refuses_wand",
"id": "joke_refuses_wand",
"intent": "enter",
"kind": "scripted",
"npc_type": 9,
"override_access": {
"has_id": true,
"has_ticket": true,
"id_status": 0,
"ticket_status": 0
},
"phase": 2,
"probability": 0.4,
"refuses_screening": true,
"time_range_s": Vector2(650, 880)
}, {
"base_weight": 1.0,
"hint": "hint.late_arrival",
"id": "joke_late_arrival",
"intent": "arrive",
"kind": "scripted",
"npc_type": 9,
"override_access": {
"has_id": true,
"has_ticket": true,
"id_status": 0,
"ticket_status": 0
},
"phase": 2,
"probability": 0.35,
"time_range_s": Vector2(700, 860)
}, {
"base_weight": 1.0,
"id": "joke_staff",
"intent": "enter",
"kind": "routine",
"npc_type": 8,
"phase": 0,
"probability": 0.25,
"time_range_s": Vector2(0, 900)
}, {
"base_weight": 1.0,
"id": "performer_show",
"intent": "perform",
"kind": "routine",
"npc_type": 1,
"phase": 0,
"probability": 0.15,
"time_range_s": Vector2(300, 800)
}, {
"base_weight": 1.0,
"id": "influencer_film",
"intent": "film",
"kind": "routine",
"npc_type": 2,
"phase": 0,
"probability": 0.15,
"time_range_s": Vector2(300, 900)
}, {
"base_weight": 1.0,
"id": "joke_disruptive",
"intent": "force_entry",
"kind": "scripted",
"npc_type": 4,
"phase": 2,
"probability": 0.5,
"time_range_s": Vector2(650, 830)
}])
shift_phases = {
0: {
"start_s": 0.0
},
1: {
"start_s": 300.0
},
2: {
"start_s": 600.0
},
3: {
"start_s": 700.0
}
}
shift_duration_s = 900.0
policy_summary = ""
door_staff_lines = {
"id_check": ["May I see your ID, please?", "Could you show me some identification?"],
"prohibited_item": ["I can't allow that item inside. Please leave it outside.", "That item isn't permitted in the venue."],
"refusal": ["I'm sorry, I can't let you in without that.", "Without a valid ID, I can't admit you tonight."],
"ticket_check": ["Your ticket or reservation, please.", "Do you have a ticket for tonight's show?"],
"wand_check": ["Please step forward for the wand check.", "Arms out, please — just a quick screening."]
}