tfbscript 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tfbscript/__init__.py +21 -0
- tfbscript/__main__.py +52 -0
- tfbscript/ansi.py +203 -0
- tfbscript/arena.py +119 -0
- tfbscript/binary.py +84 -0
- tfbscript/debug.py +14 -0
- tfbscript/editor/__init__.py +3 -0
- tfbscript/editor/app.py +141 -0
- tfbscript/editor/fonts/ms-sans-serif/MS Sans Serif.ttf +0 -0
- tfbscript/editor/fonts/ms-sans-serif/license.txt +4 -0
- tfbscript/editor/fonts/ms-sans-serif/readme.txt +26 -0
- tfbscript/editor/fonts/ms-sans-serif-bold/MS Sans Serif Bold.ttf +0 -0
- tfbscript/editor/fonts/ms-sans-serif-bold/license.txt +4 -0
- tfbscript/editor/fonts/ms-sans-serif-bold/readme.txt +26 -0
- tfbscript/editor/fonts.py +98 -0
- tfbscript/editor/search.py +200 -0
- tfbscript/editor/style.py +141 -0
- tfbscript/editor/widgets.py +321 -0
- tfbscript/opcodes/__init__.py +104 -0
- tfbscript/opcodes/base.py +362 -0
- tfbscript/opcodes/block.py +34 -0
- tfbscript/opcodes/enums.py +219 -0
- tfbscript/opcodes/op_behavior_implementation.py +39 -0
- tfbscript/opcodes/op_change_membership.py +62 -0
- tfbscript/opcodes/op_check_fov.py +73 -0
- tfbscript/opcodes/op_check_membership.py +41 -0
- tfbscript/opcodes/op_check_message.py +79 -0
- tfbscript/opcodes/op_check_reference.py +61 -0
- tfbscript/opcodes/op_check_value.py +66 -0
- tfbscript/opcodes/op_comment.py +43 -0
- tfbscript/opcodes/op_control.py +80 -0
- tfbscript/opcodes/op_create_variable.py +42 -0
- tfbscript/opcodes/op_cut_scene.py +44 -0
- tfbscript/opcodes/op_dec_value.py +43 -0
- tfbscript/opcodes/op_displace.py +111 -0
- tfbscript/opcodes/op_find_subset.py +49 -0
- tfbscript/opcodes/op_find_variable.py +28 -0
- tfbscript/opcodes/op_for_each.py +65 -0
- tfbscript/opcodes/op_if_else.py +105 -0
- tfbscript/opcodes/op_inc_value.py +43 -0
- tfbscript/opcodes/op_loop_value.py +28 -0
- tfbscript/opcodes/op_move_from.py +47 -0
- tfbscript/opcodes/op_move_to.py +99 -0
- tfbscript/opcodes/op_play_animation.py +46 -0
- tfbscript/opcodes/op_play_sound.py +42 -0
- tfbscript/opcodes/op_prescript.py +26 -0
- tfbscript/opcodes/op_print.py +53 -0
- tfbscript/opcodes/op_remove.py +43 -0
- tfbscript/opcodes/op_reset.py +42 -0
- tfbscript/opcodes/op_run_as_player.py +26 -0
- tfbscript/opcodes/op_send_message.py +53 -0
- tfbscript/opcodes/op_set_behavior.py +41 -0
- tfbscript/opcodes/op_set_reference.py +52 -0
- tfbscript/opcodes/op_set_value.py +52 -0
- tfbscript/opcodes/op_shutdown.py +26 -0
- tfbscript/opcodes/op_slide_value.py +81 -0
- tfbscript/opcodes/op_spawn_actor.py +96 -0
- tfbscript/opcodes/op_startup.py +26 -0
- tfbscript/opcodes/op_stop_sound.py +26 -0
- tfbscript/opcodes/op_teleport_to.py +47 -0
- tfbscript/opcodes/op_turn_to.py +33 -0
- tfbscript/opcodes/op_use_camera.py +68 -0
- tfbscript/payload.py +40 -0
- tfbscript/reference.py +926 -0
- tfbscript/rhs.py +326 -0
- tfbscript/script.py +160 -0
- tfbscript/string_table.py +101 -0
- tfbscript-0.1.0.dist-info/METADATA +116 -0
- tfbscript-0.1.0.dist-info/RECORD +72 -0
- tfbscript-0.1.0.dist-info/WHEEL +4 -0
- tfbscript-0.1.0.dist-info/entry_points.txt +2 -0
- tfbscript-0.1.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any, BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import func_call
|
|
5
|
+
from tfbscript.binary import write_u8
|
|
6
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
7
|
+
from tfbscript.opcodes.enums import CombineMode
|
|
8
|
+
from tfbscript.payload import PayloadReader
|
|
9
|
+
from tfbscript.reference import Reference
|
|
10
|
+
from tfbscript.rhs import Rhs
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@opcode("displace")
|
|
14
|
+
@dataclass
|
|
15
|
+
class OpDisplace(Opcode):
|
|
16
|
+
target: Reference = field(default_factory=Reference)
|
|
17
|
+
combine_mode: CombineMode = field(default=CombineMode.relative)
|
|
18
|
+
|
|
19
|
+
length: Rhs = field(default_factory=Rhs)
|
|
20
|
+
heading: Rhs = field(default_factory=Rhs)
|
|
21
|
+
pitch: Rhs = field(default_factory=Rhs)
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
@override
|
|
25
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpDisplace":
|
|
26
|
+
target = reader.readRef() # the object being displaced
|
|
27
|
+
combine_mode = CombineMode(
|
|
28
|
+
reader.read_u8()
|
|
29
|
+
) # TODO : May actually be a SetDirection
|
|
30
|
+
|
|
31
|
+
length = reader.readRHS()
|
|
32
|
+
heading = reader.readRHS()
|
|
33
|
+
pitch = reader.readRHS()
|
|
34
|
+
|
|
35
|
+
return cls(
|
|
36
|
+
target=target,
|
|
37
|
+
combine_mode=combine_mode,
|
|
38
|
+
length=length,
|
|
39
|
+
heading=heading,
|
|
40
|
+
pitch=pitch,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
@override
|
|
44
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
45
|
+
self.target.write(f)
|
|
46
|
+
write_u8(f, self.combine_mode)
|
|
47
|
+
self.length.write(f)
|
|
48
|
+
self.heading.write(f)
|
|
49
|
+
self.pitch.write(f)
|
|
50
|
+
|
|
51
|
+
@override
|
|
52
|
+
def source_line(self, inline: bool = False) -> str:
|
|
53
|
+
return f"{self.target}." + func_call(
|
|
54
|
+
"displace",
|
|
55
|
+
str(self.combine_mode),
|
|
56
|
+
"length: " + str(self.length),
|
|
57
|
+
"heading: " + str(self.heading),
|
|
58
|
+
"pitch: " + str(self.pitch),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
@override
|
|
62
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
63
|
+
return {
|
|
64
|
+
"fields": [
|
|
65
|
+
{
|
|
66
|
+
"type": "op-label",
|
|
67
|
+
"value": "displace",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"type": "ref",
|
|
71
|
+
"name": "clone_ref",
|
|
72
|
+
"ref": self.target,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"type": "enum",
|
|
76
|
+
"name": "combine_mode",
|
|
77
|
+
"entry": self.combine_mode,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"type": "label",
|
|
81
|
+
"content": "LENGTH:",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"type": "rhs",
|
|
85
|
+
"name": "length",
|
|
86
|
+
"rhs": self.length,
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"type": "label",
|
|
90
|
+
"content": "feet HEADING:",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"type": "rhs",
|
|
94
|
+
"name": "length",
|
|
95
|
+
"rhs": self.heading,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"type": "label",
|
|
99
|
+
"content": "degrees PITCH:",
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"type": "rhs",
|
|
103
|
+
"name": "length",
|
|
104
|
+
"rhs": self.pitch,
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"type": "label",
|
|
108
|
+
"content": "degrees",
|
|
109
|
+
},
|
|
110
|
+
]
|
|
111
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import (
|
|
5
|
+
comparison,
|
|
6
|
+
func_call,
|
|
7
|
+
variable,
|
|
8
|
+
)
|
|
9
|
+
from tfbscript.binary import write_u8
|
|
10
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
11
|
+
from tfbscript.opcodes.enums import RelOp
|
|
12
|
+
from tfbscript.payload import PayloadReader
|
|
13
|
+
from tfbscript.reference import Reference
|
|
14
|
+
from tfbscript.rhs import Rhs
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@opcode("find subset")
|
|
18
|
+
@dataclass
|
|
19
|
+
class OpFindSubset(Opcode):
|
|
20
|
+
"""Filters a set by a condition; yields the subset of items that match."""
|
|
21
|
+
|
|
22
|
+
set_ref: Reference = field(default_factory=Reference)
|
|
23
|
+
rel_op: RelOp = RelOp.Eq
|
|
24
|
+
rhs: Rhs = field(default_factory=Rhs)
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
@override
|
|
28
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpFindSubset":
|
|
29
|
+
set_ref = reader.readRef()
|
|
30
|
+
rel_op = RelOp(reader.read_u8())
|
|
31
|
+
rhs = reader.readRHS()
|
|
32
|
+
return cls(set_ref=set_ref, rel_op=rel_op, rhs=rhs)
|
|
33
|
+
|
|
34
|
+
@override
|
|
35
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
36
|
+
self.set_ref.write(f)
|
|
37
|
+
write_u8(f, self.rel_op)
|
|
38
|
+
self.rhs.write(f)
|
|
39
|
+
|
|
40
|
+
@override
|
|
41
|
+
def source_line(self, inline: bool = False) -> str:
|
|
42
|
+
# Rendered as: set.filter(val <op> rhs )
|
|
43
|
+
val = variable("val")
|
|
44
|
+
lambda_src = (
|
|
45
|
+
f"{val} {comparison(self.rel_op.symbol())} {self.rhs}"
|
|
46
|
+
)
|
|
47
|
+
set_ref_str = str(self.set_ref)
|
|
48
|
+
|
|
49
|
+
return f"{set_ref_str}.{func_call('filter', lambda_src)}"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import keyword
|
|
5
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
6
|
+
from tfbscript.payload import PayloadReader
|
|
7
|
+
from tfbscript.reference import Reference
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@opcode("find variable")
|
|
11
|
+
@dataclass
|
|
12
|
+
class OpFindVariable(Opcode):
|
|
13
|
+
var_ref: Reference = field(default_factory=Reference)
|
|
14
|
+
owner_ref: Reference = field(default_factory=Reference)
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
@override
|
|
18
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpFindVariable":
|
|
19
|
+
return cls(var_ref=reader.readRef(), owner_ref=reader.readRef())
|
|
20
|
+
|
|
21
|
+
@override
|
|
22
|
+
def source_line(self, inline: bool = False) -> str:
|
|
23
|
+
return f"{keyword('find variable (')} {self.var_ref} in {self.owner_ref} {keyword(')')}"
|
|
24
|
+
|
|
25
|
+
@override
|
|
26
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
27
|
+
self.var_ref.write(f)
|
|
28
|
+
self.owner_ref.write(f)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any, BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import keyword
|
|
5
|
+
from tfbscript.binary import write_u8
|
|
6
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
7
|
+
from tfbscript.opcodes.enums import SetDirection
|
|
8
|
+
from tfbscript.payload import PayloadReader
|
|
9
|
+
from tfbscript.reference import Reference
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@opcode(
|
|
13
|
+
"for each",
|
|
14
|
+
"Loops over a set in the order of set_direction, stores the current element in [^each]",
|
|
15
|
+
)
|
|
16
|
+
@dataclass
|
|
17
|
+
class OpForEach(Opcode):
|
|
18
|
+
set_ref: Reference = field(default_factory=Reference)
|
|
19
|
+
set_direction: SetDirection = field(default=SetDirection.forward)
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
@override
|
|
23
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpForEach":
|
|
24
|
+
return cls(
|
|
25
|
+
set_ref=reader.readRef(),
|
|
26
|
+
set_direction=SetDirection(reader.read_u8()),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
@override
|
|
30
|
+
def source_line(self, inline: bool = False) -> str:
|
|
31
|
+
return f"{keyword('for each [~each] in ')} {self.set_ref} {keyword('')}"
|
|
32
|
+
|
|
33
|
+
@override
|
|
34
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
35
|
+
self.set_ref.write(f)
|
|
36
|
+
write_u8(f, self.set_direction)
|
|
37
|
+
|
|
38
|
+
@override
|
|
39
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
40
|
+
return {
|
|
41
|
+
"fields": [
|
|
42
|
+
{
|
|
43
|
+
"type": "op-label",
|
|
44
|
+
"value": "for each",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"type": "label",
|
|
48
|
+
"content": "in",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"type": "ref",
|
|
52
|
+
"name": "set_ref",
|
|
53
|
+
"ref": self.set_ref,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"type": "label",
|
|
57
|
+
"content": "moving",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"type": "enum",
|
|
61
|
+
"name": "set_direction",
|
|
62
|
+
"entry": self.set_direction,
|
|
63
|
+
},
|
|
64
|
+
]
|
|
65
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any, BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import flow_control, keyword
|
|
5
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
6
|
+
from tfbscript.payload import PayloadReader
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@opcode("if/else")
|
|
10
|
+
@dataclass
|
|
11
|
+
class OpIfElse(Opcode):
|
|
12
|
+
# No payload of its own. The first child is the condition opcode; the
|
|
13
|
+
# condition's own children are the "then" branch, and any remaining
|
|
14
|
+
# children of the if/else are the "else" branch.
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
@override
|
|
18
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpIfElse":
|
|
19
|
+
return cls()
|
|
20
|
+
|
|
21
|
+
@override
|
|
22
|
+
def print_tree(self, indent: int = 0, chained: bool = False) -> None:
|
|
23
|
+
if not self.children:
|
|
24
|
+
return
|
|
25
|
+
|
|
26
|
+
pad = " " * indent
|
|
27
|
+
condition = self.children[0]
|
|
28
|
+
|
|
29
|
+
keyword_str = "} else if (" if chained else "if ("
|
|
30
|
+
|
|
31
|
+
print(
|
|
32
|
+
f"{pad}{keyword(keyword_str)} {condition.source_line(inline=True)} {keyword(') {')}"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
context = self.context
|
|
36
|
+
if context is not None:
|
|
37
|
+
context.open_opcodes.append(self)
|
|
38
|
+
try:
|
|
39
|
+
if context is not None:
|
|
40
|
+
context.open_opcodes.append(condition)
|
|
41
|
+
try:
|
|
42
|
+
for then_child in condition.children:
|
|
43
|
+
then_child.print_tree(indent + 1)
|
|
44
|
+
finally:
|
|
45
|
+
if context is not None:
|
|
46
|
+
context.open_opcodes.pop()
|
|
47
|
+
|
|
48
|
+
print(
|
|
49
|
+
f"{' ' * (indent + 1)}{keyword('flow ')}{flow_control(self.flags.flow_control_str())}"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
else_children = self.children[1:]
|
|
53
|
+
|
|
54
|
+
# None
|
|
55
|
+
if not else_children:
|
|
56
|
+
print(pad + keyword("}"))
|
|
57
|
+
# ELSE IF
|
|
58
|
+
elif len(else_children) == 1 and isinstance(else_children[0], OpIfElse):
|
|
59
|
+
fist_child = else_children[0]
|
|
60
|
+
fist_child.print_tree(indent, chained=True) # type: ignore
|
|
61
|
+
# ELSE
|
|
62
|
+
else:
|
|
63
|
+
print(pad + keyword("} else {"))
|
|
64
|
+
for else_child in else_children:
|
|
65
|
+
else_child.print_tree(indent + 1)
|
|
66
|
+
|
|
67
|
+
print(
|
|
68
|
+
f"{' ' * (indent + 1)}{keyword('flow ')}{flow_control(self.flags.flow_control_str())}"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
print(pad + keyword("}"))
|
|
72
|
+
finally:
|
|
73
|
+
if context is not None:
|
|
74
|
+
context.open_opcodes.pop()
|
|
75
|
+
|
|
76
|
+
@override
|
|
77
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
78
|
+
# The row is the condition itself; its body is the "true" branch and
|
|
79
|
+
# the remaining children are the "else" branch.
|
|
80
|
+
if not self.children:
|
|
81
|
+
return {"fields": [{"type": "op-label", "value": "if/else"}]}
|
|
82
|
+
|
|
83
|
+
condition = self.children[0]
|
|
84
|
+
else_children = self.children[1:]
|
|
85
|
+
|
|
86
|
+
groups: list[dict[str, Any]] = [
|
|
87
|
+
{
|
|
88
|
+
"label": "true",
|
|
89
|
+
"children": condition.children,
|
|
90
|
+
"scope": [condition],
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
if else_children:
|
|
95
|
+
groups.append({"label": "else", "children": else_children})
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
"row": condition,
|
|
99
|
+
"groups": groups,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@override
|
|
103
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
104
|
+
# If/Else has no payload
|
|
105
|
+
pass
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any, BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import operator
|
|
5
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
6
|
+
from tfbscript.payload import PayloadReader
|
|
7
|
+
from tfbscript.reference import Reference
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@opcode("inc value")
|
|
11
|
+
@dataclass
|
|
12
|
+
class OpIncValue(Opcode):
|
|
13
|
+
lhs: Reference = field(default_factory=Reference)
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
@override
|
|
17
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpIncValue":
|
|
18
|
+
return cls(lhs=reader.readRef())
|
|
19
|
+
|
|
20
|
+
@override
|
|
21
|
+
def source_line(self, inline: bool = False) -> str:
|
|
22
|
+
return f"{self.lhs} {operator('++')};"
|
|
23
|
+
|
|
24
|
+
@override
|
|
25
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
26
|
+
return {
|
|
27
|
+
"hasBody": False,
|
|
28
|
+
"fields": [
|
|
29
|
+
{
|
|
30
|
+
"type": "op-label",
|
|
31
|
+
"value": "increment value",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"type": "ref",
|
|
35
|
+
"name": "lhs",
|
|
36
|
+
"ref": self.lhs,
|
|
37
|
+
},
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@override
|
|
42
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
43
|
+
self.lhs.write(f)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import keyword
|
|
5
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
6
|
+
from tfbscript.payload import PayloadReader
|
|
7
|
+
from tfbscript.rhs import Rhs
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@opcode("loop value", "Loops X amount of times, stores the current index in [^each]")
|
|
11
|
+
@dataclass
|
|
12
|
+
class OpLoopValue(Opcode):
|
|
13
|
+
loop_amount: Rhs = field(default_factory=Rhs)
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
@override
|
|
17
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpLoopValue":
|
|
18
|
+
return cls(
|
|
19
|
+
loop_amount=reader.readRHS(),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
@override
|
|
23
|
+
def source_line(self, inline: bool = False) -> str:
|
|
24
|
+
return f"{keyword('loop value (')} {self.loop_amount} {keyword(')')}"
|
|
25
|
+
|
|
26
|
+
@override
|
|
27
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
28
|
+
self.loop_amount.write(f)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import func_call
|
|
5
|
+
from tfbscript.binary import write_u8
|
|
6
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
7
|
+
from tfbscript.opcodes.enums import AnimationMapping
|
|
8
|
+
from tfbscript.payload import PayloadReader
|
|
9
|
+
from tfbscript.reference import Reference
|
|
10
|
+
from tfbscript.rhs import Rhs
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@opcode("move from")
|
|
14
|
+
@dataclass
|
|
15
|
+
class OpMoveFrom(Opcode):
|
|
16
|
+
target_ref: Reference = field(default_factory=Reference)
|
|
17
|
+
with_anim: AnimationMapping = field(default=AnimationMapping.ambient)
|
|
18
|
+
until_beyond: Rhs = field(default_factory=Rhs)
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
@override
|
|
22
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpMoveFrom":
|
|
23
|
+
return cls(
|
|
24
|
+
target_ref=reader.readRef(),
|
|
25
|
+
with_anim=AnimationMapping(reader.read_u8()),
|
|
26
|
+
until_beyond=reader.readRHS(),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
@override
|
|
30
|
+
def source_line(self, inline: bool = False) -> str:
|
|
31
|
+
base = func_call(
|
|
32
|
+
"moveFrom",
|
|
33
|
+
str(self.target_ref),
|
|
34
|
+
f"animation: {self.with_anim}",
|
|
35
|
+
f"until_beyond: {self.until_beyond}",
|
|
36
|
+
add_semicolon=not self.children,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
if self.children:
|
|
40
|
+
return f"when {base} is done, do:"
|
|
41
|
+
return base
|
|
42
|
+
|
|
43
|
+
@override
|
|
44
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
45
|
+
self.target_ref.write(f)
|
|
46
|
+
write_u8(f, self.with_anim)
|
|
47
|
+
self.until_beyond.write(f)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any, BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import func_call
|
|
5
|
+
from tfbscript.binary import write_u8
|
|
6
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
7
|
+
from tfbscript.opcodes.enums import AnimationMapping, SetDirection
|
|
8
|
+
from tfbscript.payload import PayloadReader
|
|
9
|
+
from tfbscript.reference import Reference
|
|
10
|
+
from tfbscript.rhs import Rhs
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@opcode("move to")
|
|
14
|
+
@dataclass
|
|
15
|
+
class OpMoveTo(Opcode):
|
|
16
|
+
target_ref: Reference = field(default_factory=Reference)
|
|
17
|
+
set_direction: SetDirection = field(default=SetDirection.forward)
|
|
18
|
+
with_anim: AnimationMapping = field(default=AnimationMapping.ambient)
|
|
19
|
+
until_within: Rhs = field(default_factory=Rhs)
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
@override
|
|
23
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpMoveTo":
|
|
24
|
+
return cls(
|
|
25
|
+
target_ref=reader.readRef(),
|
|
26
|
+
set_direction=SetDirection(reader.read_u8()),
|
|
27
|
+
with_anim=AnimationMapping(reader.read_u8()),
|
|
28
|
+
until_within=reader.readRHS(),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
@override
|
|
32
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
33
|
+
self.target_ref.write(f)
|
|
34
|
+
write_u8(f, self.set_direction)
|
|
35
|
+
write_u8(f, self.with_anim)
|
|
36
|
+
self.until_within.write(f)
|
|
37
|
+
|
|
38
|
+
@override
|
|
39
|
+
def source_line(self, inline: bool = False) -> str:
|
|
40
|
+
base = func_call(
|
|
41
|
+
"moveTo",
|
|
42
|
+
str(self.target_ref),
|
|
43
|
+
f"set_dir: {self.set_direction}",
|
|
44
|
+
f"animation: {self.with_anim}",
|
|
45
|
+
f"until_within: {self.until_within}",
|
|
46
|
+
add_semicolon=not self.children,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
if self.children:
|
|
50
|
+
return f"when {base} is done, do:"
|
|
51
|
+
return base
|
|
52
|
+
|
|
53
|
+
@override
|
|
54
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
55
|
+
return {
|
|
56
|
+
"hasBody": True,
|
|
57
|
+
"fields": [
|
|
58
|
+
{
|
|
59
|
+
"type": "op-label",
|
|
60
|
+
"value": "move to",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"type": "ref",
|
|
64
|
+
"name": "target_ref",
|
|
65
|
+
"ref": self.target_ref,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"type": "op-label",
|
|
69
|
+
"value": "set direction: ",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"type": "enum",
|
|
73
|
+
"name": "set_direction",
|
|
74
|
+
"entry": self.set_direction,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"type": "op-label",
|
|
78
|
+
"value": "with animation: ",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"type": "enum",
|
|
82
|
+
"name": "with_anim",
|
|
83
|
+
"entry": self.with_anim,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"type": "op-label",
|
|
87
|
+
"value": "until within: ",
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"type": "rhs",
|
|
91
|
+
"name": "until_within",
|
|
92
|
+
"rhs": self.until_within,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"type": "op-label",
|
|
96
|
+
"value": "ft",
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any, BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import func_call, method, parentheses
|
|
5
|
+
from tfbscript.binary import write_u8
|
|
6
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
7
|
+
from tfbscript.opcodes.enums import AnimationMapping
|
|
8
|
+
from tfbscript.payload import PayloadReader
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@opcode("play animation")
|
|
12
|
+
@dataclass
|
|
13
|
+
class OpPlayAnimation(Opcode):
|
|
14
|
+
animation: AnimationMapping = field(default=AnimationMapping.ambient)
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
@override
|
|
18
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpPlayAnimation":
|
|
19
|
+
return cls(animation=AnimationMapping(reader.read_u8()))
|
|
20
|
+
|
|
21
|
+
@override
|
|
22
|
+
def source_line(self, inline: bool = False) -> str:
|
|
23
|
+
if self.children:
|
|
24
|
+
return f"when {method('playAnimation')}{parentheses('(')}{self.animation!s}{parentheses(')')} is done playing, do:"
|
|
25
|
+
return func_call("playAnimation", str(self.animation))
|
|
26
|
+
|
|
27
|
+
@override
|
|
28
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
29
|
+
return {
|
|
30
|
+
"hasBody": False,
|
|
31
|
+
"fields": [
|
|
32
|
+
{
|
|
33
|
+
"type": "op-label",
|
|
34
|
+
"value": "play animation",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"type": "enum",
|
|
38
|
+
"name": "animation",
|
|
39
|
+
"entry": self.animation,
|
|
40
|
+
},
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@override
|
|
45
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
46
|
+
write_u8(f, self.animation)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any, BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import method, parentheses
|
|
5
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
6
|
+
from tfbscript.payload import PayloadReader
|
|
7
|
+
from tfbscript.reference import Reference
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@opcode("play sound")
|
|
11
|
+
@dataclass
|
|
12
|
+
class OpPlaySound(Opcode):
|
|
13
|
+
sound: Reference = field(default_factory=Reference)
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
@override
|
|
17
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpPlaySound":
|
|
18
|
+
return cls(sound=reader.readRef())
|
|
19
|
+
|
|
20
|
+
@override
|
|
21
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
22
|
+
self.sound.write(f)
|
|
23
|
+
|
|
24
|
+
@override
|
|
25
|
+
def source_line(self, inline: bool = False) -> str:
|
|
26
|
+
return f"{self.sound}.{method('play')}{parentheses('()')};"
|
|
27
|
+
|
|
28
|
+
@override
|
|
29
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
30
|
+
return {
|
|
31
|
+
"fields": [
|
|
32
|
+
{
|
|
33
|
+
"type": "op-label",
|
|
34
|
+
"value": "play sound",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"type": "ref",
|
|
38
|
+
"name": "sound",
|
|
39
|
+
"ref": self.sound,
|
|
40
|
+
},
|
|
41
|
+
]
|
|
42
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any, BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.opcodes.block import BlockOpcode
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class OpPrescript(BlockOpcode):
|
|
9
|
+
@override
|
|
10
|
+
def block_name(self) -> str:
|
|
11
|
+
return "PRESCRIPT"
|
|
12
|
+
|
|
13
|
+
@override
|
|
14
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
15
|
+
pass # Prescript has no payload
|
|
16
|
+
|
|
17
|
+
@override
|
|
18
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
19
|
+
return {
|
|
20
|
+
"fields": [
|
|
21
|
+
{
|
|
22
|
+
"type": "block-label",
|
|
23
|
+
"value": "PRESCRIPT",
|
|
24
|
+
},
|
|
25
|
+
]
|
|
26
|
+
}
|