feat(client): authored NPC fallback line (§13)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
5
client/content/fallback/npc.json
Normal file
5
client/content/fallback/npc.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"npc": [
|
||||||
|
"The figure looks you over, says nothing you can use, and turns back to their work."
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,37 +1,42 @@
|
|||||||
class_name FallbackLibrary
|
class_name FallbackLibrary
|
||||||
extends RefCounted
|
extends RefCounted
|
||||||
## Authored degraded-DM fallback text (charter §13). The client shows one of
|
## Authored degraded-DM fallback text (charter §13). On ANY failure the client
|
||||||
## these lines on ANY failure, in the Narrator's voice — never an error. If the
|
## shows one of these lines in-voice — never an error. Missing/malformed content
|
||||||
## content file is missing or malformed the library returns a hardcoded
|
## yields a hardcoded constant, so the fallback itself cannot fail.
|
||||||
## constant, so the fallback itself cannot fail.
|
|
||||||
|
|
||||||
const PATH := "res://content/fallback/narrator.json"
|
const PATH := "res://content/fallback/narrator.json"
|
||||||
|
const NPC_PATH := "res://content/fallback/npc.json"
|
||||||
const LAST_RESORT := "The chamber is cold. Something waits in the dark."
|
const LAST_RESORT := "The chamber is cold. Something waits in the dark."
|
||||||
|
const NPC_LAST_RESORT := "The figure regards you in silence, and the moment passes."
|
||||||
|
|
||||||
var _lines: Array = []
|
var _lines: Array = []
|
||||||
|
var _npc_lines: Array = []
|
||||||
|
|
||||||
|
|
||||||
func _init(path := PATH) -> void:
|
func _init(path := PATH, npc_path := NPC_PATH) -> void:
|
||||||
_lines = _load(path)
|
_lines = _load(path, "narrator")
|
||||||
|
_npc_lines = _load(npc_path, "npc")
|
||||||
|
|
||||||
|
|
||||||
func narrator_line() -> String:
|
func narrator_line() -> String:
|
||||||
return str(_lines[0]) if not _lines.is_empty() else LAST_RESORT
|
return str(_lines[0]) if not _lines.is_empty() else LAST_RESORT
|
||||||
|
|
||||||
|
|
||||||
static func _load(path: String) -> Array:
|
func npc_line() -> String:
|
||||||
|
return str(_npc_lines[0]) if not _npc_lines.is_empty() else NPC_LAST_RESORT
|
||||||
|
|
||||||
|
|
||||||
|
static func _load(path: String, key: String) -> Array:
|
||||||
if not FileAccess.file_exists(path):
|
if not FileAccess.file_exists(path):
|
||||||
return []
|
return []
|
||||||
var text := FileAccess.get_file_as_string(path)
|
var text := FileAccess.get_file_as_string(path)
|
||||||
# Use the instance API, not JSON.parse_string(): the static convenience
|
# Instance parse() (not JSON.parse_string) so malformed input returns an
|
||||||
# method pushes an engine-level error on malformed input, which is noisy
|
# Error code instead of pushing an engine error the test config promotes.
|
||||||
# and (in this project's test config) turns a handled failure into a
|
|
||||||
# reported test error. The instance parse() just returns an Error code.
|
|
||||||
var json := JSON.new()
|
var json := JSON.new()
|
||||||
if json.parse(text) != OK:
|
if json.parse(text) != OK:
|
||||||
return []
|
return []
|
||||||
var data = json.get_data()
|
var data = json.get_data()
|
||||||
if typeof(data) != TYPE_DICTIONARY:
|
if typeof(data) != TYPE_DICTIONARY:
|
||||||
return []
|
return []
|
||||||
var lines = data.get("narrator", [])
|
var lines = data.get(key, [])
|
||||||
return lines if typeof(lines) == TYPE_ARRAY else []
|
return lines if typeof(lines) == TYPE_ARRAY else []
|
||||||
|
|||||||
@@ -31,3 +31,15 @@ func test_empty_list_uses_last_resort():
|
|||||||
f.close()
|
f.close()
|
||||||
var lib = FallbackLibrary.new(path)
|
var lib = FallbackLibrary.new(path)
|
||||||
assert_eq(lib.narrator_line(), FallbackLibrary.LAST_RESORT)
|
assert_eq(lib.narrator_line(), FallbackLibrary.LAST_RESORT)
|
||||||
|
|
||||||
|
|
||||||
|
func test_npc_line_falls_back_to_constant_when_missing():
|
||||||
|
var lib = FallbackLibrary.new(
|
||||||
|
"res://content/fallback/does_not_exist.json",
|
||||||
|
"res://content/fallback/does_not_exist.json")
|
||||||
|
assert_eq(lib.npc_line(), FallbackLibrary.NPC_LAST_RESORT)
|
||||||
|
|
||||||
|
|
||||||
|
func test_npc_line_reads_authored_file():
|
||||||
|
var lib = FallbackLibrary.new() # default paths — real content
|
||||||
|
assert_ne(lib.npc_line(), "")
|
||||||
|
|||||||
Reference in New Issue
Block a user