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.
Files changed (72) hide show
  1. tfbscript/__init__.py +21 -0
  2. tfbscript/__main__.py +52 -0
  3. tfbscript/ansi.py +203 -0
  4. tfbscript/arena.py +119 -0
  5. tfbscript/binary.py +84 -0
  6. tfbscript/debug.py +14 -0
  7. tfbscript/editor/__init__.py +3 -0
  8. tfbscript/editor/app.py +141 -0
  9. tfbscript/editor/fonts/ms-sans-serif/MS Sans Serif.ttf +0 -0
  10. tfbscript/editor/fonts/ms-sans-serif/license.txt +4 -0
  11. tfbscript/editor/fonts/ms-sans-serif/readme.txt +26 -0
  12. tfbscript/editor/fonts/ms-sans-serif-bold/MS Sans Serif Bold.ttf +0 -0
  13. tfbscript/editor/fonts/ms-sans-serif-bold/license.txt +4 -0
  14. tfbscript/editor/fonts/ms-sans-serif-bold/readme.txt +26 -0
  15. tfbscript/editor/fonts.py +98 -0
  16. tfbscript/editor/search.py +200 -0
  17. tfbscript/editor/style.py +141 -0
  18. tfbscript/editor/widgets.py +321 -0
  19. tfbscript/opcodes/__init__.py +104 -0
  20. tfbscript/opcodes/base.py +362 -0
  21. tfbscript/opcodes/block.py +34 -0
  22. tfbscript/opcodes/enums.py +219 -0
  23. tfbscript/opcodes/op_behavior_implementation.py +39 -0
  24. tfbscript/opcodes/op_change_membership.py +62 -0
  25. tfbscript/opcodes/op_check_fov.py +73 -0
  26. tfbscript/opcodes/op_check_membership.py +41 -0
  27. tfbscript/opcodes/op_check_message.py +79 -0
  28. tfbscript/opcodes/op_check_reference.py +61 -0
  29. tfbscript/opcodes/op_check_value.py +66 -0
  30. tfbscript/opcodes/op_comment.py +43 -0
  31. tfbscript/opcodes/op_control.py +80 -0
  32. tfbscript/opcodes/op_create_variable.py +42 -0
  33. tfbscript/opcodes/op_cut_scene.py +44 -0
  34. tfbscript/opcodes/op_dec_value.py +43 -0
  35. tfbscript/opcodes/op_displace.py +111 -0
  36. tfbscript/opcodes/op_find_subset.py +49 -0
  37. tfbscript/opcodes/op_find_variable.py +28 -0
  38. tfbscript/opcodes/op_for_each.py +65 -0
  39. tfbscript/opcodes/op_if_else.py +105 -0
  40. tfbscript/opcodes/op_inc_value.py +43 -0
  41. tfbscript/opcodes/op_loop_value.py +28 -0
  42. tfbscript/opcodes/op_move_from.py +47 -0
  43. tfbscript/opcodes/op_move_to.py +99 -0
  44. tfbscript/opcodes/op_play_animation.py +46 -0
  45. tfbscript/opcodes/op_play_sound.py +42 -0
  46. tfbscript/opcodes/op_prescript.py +26 -0
  47. tfbscript/opcodes/op_print.py +53 -0
  48. tfbscript/opcodes/op_remove.py +43 -0
  49. tfbscript/opcodes/op_reset.py +42 -0
  50. tfbscript/opcodes/op_run_as_player.py +26 -0
  51. tfbscript/opcodes/op_send_message.py +53 -0
  52. tfbscript/opcodes/op_set_behavior.py +41 -0
  53. tfbscript/opcodes/op_set_reference.py +52 -0
  54. tfbscript/opcodes/op_set_value.py +52 -0
  55. tfbscript/opcodes/op_shutdown.py +26 -0
  56. tfbscript/opcodes/op_slide_value.py +81 -0
  57. tfbscript/opcodes/op_spawn_actor.py +96 -0
  58. tfbscript/opcodes/op_startup.py +26 -0
  59. tfbscript/opcodes/op_stop_sound.py +26 -0
  60. tfbscript/opcodes/op_teleport_to.py +47 -0
  61. tfbscript/opcodes/op_turn_to.py +33 -0
  62. tfbscript/opcodes/op_use_camera.py +68 -0
  63. tfbscript/payload.py +40 -0
  64. tfbscript/reference.py +926 -0
  65. tfbscript/rhs.py +326 -0
  66. tfbscript/script.py +160 -0
  67. tfbscript/string_table.py +101 -0
  68. tfbscript-0.1.0.dist-info/METADATA +116 -0
  69. tfbscript-0.1.0.dist-info/RECORD +72 -0
  70. tfbscript-0.1.0.dist-info/WHEEL +4 -0
  71. tfbscript-0.1.0.dist-info/entry_points.txt +2 -0
  72. 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
+ }