Version 3.1.0: voice lines linked across all languages from the game data
This commit is contained in:
@@ -19,7 +19,6 @@ import re
|
||||
import struct
|
||||
from collections import defaultdict, namedtuple
|
||||
|
||||
from .upk import Package
|
||||
|
||||
CLASS = "RDialogueEvent"
|
||||
SUBTITLE_CLASS, LOOKUP_CLASS = "RSubtitle", "RSubtitleLookup" # scripted radio/encryption subtitles
|
||||
@@ -29,7 +28,8 @@ T_STRUCT, T_STRING, T_OBJECT = 0x09, 0x0D, 0x10
|
||||
# one subtitle string inside a package: pos = absolute uncompressed offset of the FString length field,
|
||||
# size = bytes of the whole FString (length field included), enc 'a' (cp1252) or 'w' (UTF-16)
|
||||
Field = namedtuple("Field", "lang index text pos size enc")
|
||||
Dialogue = namedtuple("Dialogue", "speech export fields") # speech: name of the referenced speech event
|
||||
# speech: name of the referenced speech event; speaker: the object's speaker field (RDialogueEvent only)
|
||||
Dialogue = namedtuple("Dialogue", "speech export fields speaker", defaults=("",))
|
||||
|
||||
|
||||
class SubtitleError(ValueError):
|
||||
@@ -148,6 +148,15 @@ def parse_dialogue(b, base, names_idx):
|
||||
return fields
|
||||
|
||||
|
||||
def _speaker(b):
|
||||
"""The speaker FString of a dialogue object (property 0x0D at field offset 0x34), '' if none."""
|
||||
m = re.search(rb"\x0d\x00\x34\x00", b)
|
||||
try:
|
||||
return read_fstring(b, m.start() + 4)[0] if m else ""
|
||||
except (struct.error, UnicodeDecodeError, ValueError):
|
||||
return ""
|
||||
|
||||
|
||||
def _speech_ref(b, exports, imports):
|
||||
"""Name of the object referenced by the dialogue's first object property (its speech event)."""
|
||||
m = re.search(rb"\x10\x00\x2c\x00", b)
|
||||
@@ -197,7 +206,14 @@ class Collector:
|
||||
# --- catalog files: SUB_<LANG>.csv (texts) + SUB_locations.csv.gz (every copy) ------------------
|
||||
LOCATIONS = "SUB_locations.csv.gz"
|
||||
TEXT_FIELDS = ["speech", "line", "text", "room", "enc", "sound"]
|
||||
SubLine = namedtuple("SubLine", "lang speech line text room enc sound") # sound: linked WAD sound key
|
||||
class SubLine(namedtuple("SubLine", "lang speech line text room enc sound")):
|
||||
"""A subtitle string. sound: the voice recording(s) its speech event plays in that language (sound keys,
|
||||
';'-separated in the event's order: an event can play one of two versions of a line)."""
|
||||
__slots__ = ()
|
||||
|
||||
@property
|
||||
def sounds(self):
|
||||
return tuple(self.sound.split(";")) if self.sound else ()
|
||||
SubLoc = namedtuple("SubLoc", "lang speech line file pos size enc")
|
||||
|
||||
|
||||
@@ -312,5 +328,5 @@ def scan_package(pkg, data=None, start=None, tables=None):
|
||||
speech = UNRESOLVED % keys[e.index]
|
||||
else:
|
||||
speech = e.name # not in a lookup table: keep the object's name
|
||||
out.append(Dialogue(speech, e.name, fields))
|
||||
out.append(Dialogue(speech, e.name, fields, _speaker(b) if kind == CLASS else ""))
|
||||
return out
|
||||
|
||||
Reference in New Issue
Block a user