feat: ATL durations in brackets, offset and GPU hints; screen for-index, glued strings and onlayer
ATL: `ease(1.0) zoom 1.3`, `ease (0.1)xpos 0.5`, `ease(0.1)rotate 5` and `pause(1.5)` take the duration
in brackets; `offset (x, y)` becomes xoffset/yoffset; lines starting with shader, mesh, u_*, blend or
transform_anchor are skipped as GPU hints. thelewdesthouse drops from about 1400 to 111 rejections.
Screens: `for x index k in seq`, `add"x"` without a space, and `onlayer name` after show/call screen
(the layer is ignored, every screen lives in one layer). Transforms named with a capital letter and
declared in another file are resolved by the prescan, and `__("Name") "text"` is a translatable speaker.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
25bd39dd43
commit
5c1e1aee01
4 files changed
+84
-5
No files matched your search
@@ -152,6 +152,9 @@ class ScriptData:
|
||||
self.warning_examples[kind] = where
|
||||
|
||||
|
||||
TRANSLATED_SPEAKER = re.compile(r"""^_{1,2}\(\s*("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')\s*\)(?=\s+["'])""")
|
||||
|
||||
|
||||
class RpyParser:
|
||||
def __init__(self, data: ScriptData, filename: str):
|
||||
self.d = data
|
||||
@@ -1274,7 +1277,7 @@ class RpyParser:
|
||||
spec["atl"] = fname
|
||||
spec["args"], spec["kw"] = e["a"], e["kw"]
|
||||
return spec
|
||||
if "." not in fname and fname[:1].islower() and fname not in KNOWN_FACTORIES:
|
||||
if "." not in fname and (fname[:1].islower() or fname in self.d.transform_names) and fname not in KNOWN_FACTORIES:
|
||||
# parameterised transform defined later (or in another file); the player resolves it by name
|
||||
self.use_transform(fname)
|
||||
return {"name": fname, "atl": fname, "args": e["a"], "kw": e["kw"]}
|
||||
@@ -1343,6 +1346,8 @@ class RpyParser:
|
||||
def screen_call(self, c: Cursor, line: Line) -> Node | None:
|
||||
"""``name(args)`` after `call/show screen`; trailing `nopredict` and `with` are ignored."""
|
||||
source = re.split(r"\s+(?:nopredict|with)\b", c.rest(), maxsplit=1)[0].strip()
|
||||
# `onlayer name` only picks the stacking layer; the player keeps every screen in one layer
|
||||
source = re.sub(r"\s+onlayer\s+\w+\s*$", "", source)
|
||||
call = self.expr(source, line) if source else None
|
||||
if call is None:
|
||||
self.d.warn("Не разобран вызов screen", self.where(line))
|
||||
@@ -1623,6 +1628,9 @@ class RpyParser:
|
||||
# say ------------------------------------------------------------------------------
|
||||
|
||||
def say(self, line: Line) -> list[Node] | None:
|
||||
# `__("Girl") "Hello"`: a translatable speaker name; the name is looked up by its text anyway
|
||||
if wrapped := TRANSLATED_SPEAKER.match(line.text):
|
||||
line = replace(line, text=wrapped[1] + line.text[wrapped.end():])
|
||||
c = self.cursor(line)
|
||||
who: str | None = None
|
||||
who_str: str | None = None
|
||||
|
||||
Reference in new issue
Block a user