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,62 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Any, BinaryIO, override
3
+
4
+ from tfbscript.ansi import method, parentheses
5
+ from tfbscript.binary import write_u8
6
+ from tfbscript.opcodes.base import Opcode, opcode
7
+ from tfbscript.opcodes.enums import MembershipCombiner
8
+ from tfbscript.payload import PayloadReader
9
+ from tfbscript.reference import Reference
10
+
11
+
12
+ @opcode("change membership")
13
+ @dataclass
14
+ class OpChangeMembership(Opcode):
15
+ ref: Reference = field(default_factory=Reference)
16
+ membershipCombiner: MembershipCombiner = field(default=MembershipCombiner.add)
17
+ ref2: Reference = field(default_factory=Reference)
18
+
19
+ @classmethod
20
+ @override
21
+ def parse_payload(cls, reader: PayloadReader) -> "OpChangeMembership":
22
+ ref = reader.readRef()
23
+ membershipCombiner = MembershipCombiner(reader.read_u8())
24
+ ref2 = reader.readRef()
25
+ return cls(ref=ref, membershipCombiner=membershipCombiner, ref2=ref2)
26
+
27
+ @override
28
+ def source_line(self, inline: bool = False) -> str:
29
+ return f"{self.ref}.{method(self.membershipCombiner.symbol())}{parentheses('(')}{self.ref2}{parentheses(')')};"
30
+
31
+ @override
32
+ def write_payload(self, f: BinaryIO) -> None:
33
+ self.ref.write(f)
34
+ write_u8(f, self.membershipCombiner)
35
+ self.ref2.write(f)
36
+
37
+ @override
38
+ def editor_repr(self) -> dict[str, Any]:
39
+ return {
40
+ "fields": [
41
+ {
42
+ "type": "op-label",
43
+ "value": "set [set]",
44
+ },
45
+ {
46
+ "type": "ref",
47
+ "ref": self.ref,
48
+ },
49
+ {
50
+ "type": "label",
51
+ "content": "to",
52
+ },
53
+ {
54
+ "type": "enum",
55
+ "value": self.membershipCombiner,
56
+ },
57
+ {
58
+ "type": "ref",
59
+ "ref": self.ref2,
60
+ },
61
+ ]
62
+ }
@@ -0,0 +1,73 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import BinaryIO, override
3
+
4
+ from tfbscript.ansi import comparison, keyword, number
5
+ from tfbscript.binary import write_u8
6
+ from tfbscript.opcodes.base import Opcode, opcode
7
+ from tfbscript.opcodes.enums import CheckFOVMode, RelOp
8
+ from tfbscript.payload import PayloadReader
9
+ from tfbscript.reference import Reference
10
+ from tfbscript.rhs import Rhs
11
+
12
+
13
+ @opcode(
14
+ "check fov",
15
+ """
16
+ Is there an actor from target_ref within arc_width°
17
+ of angle_base, whose distance to me satisfies
18
+ "distance {range_relop} range",
19
+ and if mode == consider_obstructions,
20
+ i have a clear line of sight to them?
21
+ """,
22
+ )
23
+ @dataclass
24
+ class OpCheckFOV(Opcode):
25
+ angle_base: Rhs = field(default_factory=Rhs)
26
+ arc_width: Rhs = field(default_factory=Rhs)
27
+
28
+ target_ref: Reference = field(default_factory=Reference)
29
+
30
+ range_relop: RelOp = RelOp.Eq
31
+ range: Rhs = field(default_factory=Rhs)
32
+
33
+ mode: CheckFOVMode = CheckFOVMode.ignore_obstructions
34
+
35
+ @classmethod
36
+ @override
37
+ def parse_payload(cls, reader: PayloadReader) -> "OpCheckFOV":
38
+ angle_base = reader.readRHS()
39
+ arc_width = reader.readRHS()
40
+
41
+ target_ref = reader.readRef()
42
+
43
+ range_relop = RelOp(reader.read_u8())
44
+ range = reader.readRHS()
45
+
46
+ checkfov_mode = CheckFOVMode(reader.read_u8())
47
+
48
+ return cls(
49
+ angle_base=angle_base,
50
+ arc_width=arc_width,
51
+ target_ref=target_ref,
52
+ range_relop=range_relop,
53
+ range=range,
54
+ mode=checkfov_mode,
55
+ )
56
+
57
+ @override
58
+ def source_line(self, inline: bool = False) -> str:
59
+ condition = f"{self.target_ref} is within a {number(self.arc_width)}° cone centered on heading {number(self.angle_base)}, distance {comparison(self.range_relop.symbol())} {self.range}, {self.mode}"
60
+
61
+ # Normally we would have a check for inline here,
62
+ # but its nice to know that this is a FOV check
63
+
64
+ return f"{keyword('check fov (')} {condition} {keyword(')')}"
65
+
66
+ @override
67
+ def write_payload(self, f: BinaryIO) -> None:
68
+ self.angle_base.write(f)
69
+ self.arc_width.write(f)
70
+ self.target_ref.write(f)
71
+ write_u8(f, self.range_relop)
72
+ self.range.write(f)
73
+ write_u8(f, self.mode)
@@ -0,0 +1,41 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import BinaryIO, override
3
+
4
+ from tfbscript.ansi import comparison, keyword
5
+ from tfbscript.binary import write_u8
6
+ from tfbscript.opcodes.base import Opcode, opcode
7
+ from tfbscript.opcodes.enums import MembershipTest
8
+ from tfbscript.payload import PayloadReader
9
+ from tfbscript.reference import Reference
10
+
11
+
12
+ @opcode("check membership")
13
+ @dataclass
14
+ class OpCheckMembership(Opcode):
15
+ ref1: Reference = field(default_factory=Reference)
16
+ membershipTest: MembershipTest = MembershipTest.includes
17
+ ref2: Reference = field(default_factory=Reference)
18
+
19
+ @classmethod
20
+ @override
21
+ def parse_payload(cls, reader: PayloadReader) -> "OpCheckMembership":
22
+ ref1 = reader.readRef()
23
+ membershipTest = MembershipTest(reader.read_u8())
24
+ ref2 = reader.readRef()
25
+ return cls(ref1=ref1, membershipTest=membershipTest, ref2=ref2)
26
+
27
+ @override
28
+ def source_line(self, inline: bool = False) -> str:
29
+ condition = (
30
+ f"{self.ref1} {comparison(self.membershipTest.symbol())} {self.ref2}"
31
+ )
32
+ if inline:
33
+ return condition
34
+
35
+ return f"{keyword('check membership (')} {condition} {keyword(')')}"
36
+
37
+ @override
38
+ def write_payload(self, f: BinaryIO) -> None:
39
+ self.ref1.write(f)
40
+ write_u8(f, self.membershipTest)
41
+ self.ref2.write(f)
@@ -0,0 +1,79 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import 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 RelOp
8
+ from tfbscript.payload import PayloadReader
9
+ from tfbscript.reference import Reference
10
+ from tfbscript.rhs import Rhs
11
+
12
+
13
+ @opcode("check message")
14
+ @dataclass
15
+ class OpCheckMessage(Opcode):
16
+ message_ref: Reference = field(default_factory=Reference)
17
+
18
+ sender_ref: Reference = field(default_factory=Reference)
19
+ rel_op: RelOp = field(default=RelOp.Eq)
20
+ value: Rhs = field(default_factory=Rhs)
21
+
22
+ _is_extended: bool = field(
23
+ default=False
24
+ ) # has sender_ref, rel_op, value determined if payload > 4
25
+
26
+ @classmethod
27
+ @override
28
+ def parse_payload(cls, reader: PayloadReader) -> "OpCheckMessage":
29
+ message_ref = reader.readRef()
30
+
31
+ # Three shapes only, 4 / 14 / 20 bytes, so this threshold cannot be
32
+ # straddled. The engine's own test is not reproducible from the .ai:
33
+ # parse (FUN_0043AE30) asks the message's descriptor
34
+ # DAT_0061f870->vt[0x18]() and stops right after the message ref when
35
+ # that is <= 0 -- an operand count that comes from the message's
36
+ # per-level declaration in the level hub, not from this file. The two
37
+ # `message` vtables differ only there: 005CDC08 returns 0, 005CE590
38
+ # returns 2. Verified as a per-declaration property: of 88 message
39
+ # symbols, 79 are always extended and 8 always plain; the one that is
40
+ # both (`ledge nearby`) is plain in 8 levels and extended in `battle`.
41
+ #
42
+ # Ref: 4b
43
+ # RelOp: 1b
44
+ # Rhs: min. 5b
45
+ if reader.size_remaining() >= 4 + 1 + 5:
46
+ sender_ref = reader.readRef()
47
+
48
+ rel_op = RelOp(reader.read_u8())
49
+ value = reader.readRHS()
50
+
51
+ return cls(
52
+ message_ref=message_ref,
53
+ sender_ref=sender_ref,
54
+ rel_op=rel_op,
55
+ value=value,
56
+ _is_extended=True,
57
+ )
58
+
59
+ return cls(
60
+ message_ref=message_ref,
61
+ _is_extended=False,
62
+ )
63
+
64
+ @override
65
+ def write_payload(self, f: BinaryIO) -> None:
66
+ self.message_ref.write(f)
67
+ if not self._is_extended:
68
+ return
69
+ self.sender_ref.write(f)
70
+ write_u8(f, self.rel_op)
71
+ self.value.write(f)
72
+
73
+ @override
74
+ def source_line(self, inline: bool = False) -> str:
75
+ if self._is_extended:
76
+ condition = f"value {self.rel_op} {self.value}"
77
+ return f"{keyword('check message (')} {self.message_ref}, sent by: {self.sender_ref}, where: {condition} {keyword(')')}"
78
+ else:
79
+ return f"{keyword('check message (')} {self.message_ref} {keyword(')')}"
@@ -0,0 +1,61 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Any, 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("check reference")
11
+ @dataclass
12
+ class OpCheckReference(Opcode):
13
+ ref1: Reference = field(default_factory=Reference)
14
+ ref2: Reference = field(default_factory=Reference)
15
+
16
+ @classmethod
17
+ @override
18
+ def parse_payload(cls, reader: PayloadReader) -> "OpCheckReference":
19
+ ref1 = reader.readRef()
20
+ ref2 = reader.readRef()
21
+
22
+ return cls(ref1=ref1, ref2=ref2)
23
+
24
+ @override
25
+ def write_payload(self, f: BinaryIO) -> None:
26
+ self.ref1.write(f)
27
+ self.ref2.write(f)
28
+
29
+ @override
30
+ def source_line(self, inline: bool = False) -> str:
31
+ condition = f"*{self.ref1} is reference to {self.ref2}"
32
+ if inline:
33
+ return condition
34
+
35
+ return f"{keyword('check reference (')} {condition} {keyword(')')}"
36
+
37
+ @override
38
+ def editor_repr(self) -> dict[str, Any]:
39
+ return {
40
+ "hasBody": True,
41
+ "fields": [
42
+ {
43
+ "type": "op-label",
44
+ "value": "check reference",
45
+ },
46
+ {
47
+ "type": "ref",
48
+ "name": "ref1",
49
+ "ref": self.ref1,
50
+ },
51
+ {
52
+ "type": "op-label",
53
+ "value": "is reference to",
54
+ },
55
+ {
56
+ "type": "ref",
57
+ "name": "ref2",
58
+ "ref": self.ref2,
59
+ },
60
+ ],
61
+ }
@@ -0,0 +1,66 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Any, BinaryIO, override
3
+
4
+ from tfbscript.ansi import comparison, keyword
5
+ from tfbscript.binary import write_u8
6
+ from tfbscript.opcodes.base import Opcode, opcode
7
+ from tfbscript.opcodes.enums import RelOp
8
+ from tfbscript.payload import PayloadReader
9
+ from tfbscript.reference import Reference
10
+ from tfbscript.rhs import Rhs
11
+
12
+
13
+ @opcode("check value")
14
+ @dataclass
15
+ class OpCheckValue(Opcode):
16
+ lhs: Reference = field(default_factory=Reference)
17
+ rel_op: RelOp = RelOp.Eq
18
+ rhs: Rhs = field(default_factory=Rhs)
19
+
20
+ @classmethod
21
+ @override
22
+ def parse_payload(cls, reader: PayloadReader) -> "OpCheckValue":
23
+ lhs = reader.readRef()
24
+ rel_op = RelOp(reader.read_u8())
25
+ rhs = reader.readRHS()
26
+ return cls(lhs=lhs, rel_op=rel_op, rhs=rhs)
27
+
28
+ @override
29
+ def source_line(self, inline: bool = False) -> str:
30
+ condition = f"{self.lhs} {comparison(self.rel_op.symbol())} {self.rhs}"
31
+ if inline:
32
+ return condition
33
+
34
+ return f"{keyword('check value (')} {condition} {keyword(')')}"
35
+
36
+
37
+ @override
38
+ def editor_repr(self) -> dict[str, Any]:
39
+ return {
40
+ "hasBody": True,
41
+ "fields": [
42
+ {
43
+ "type": "op-label",
44
+ "value": "check value",
45
+ },
46
+ {
47
+ "type": "ref",
48
+ "ref": self.lhs,
49
+ },
50
+ {
51
+ "type": "enum",
52
+ "name": "rel_op",
53
+ "entry": self.rel_op,
54
+ },
55
+ {
56
+ "type": "rhs",
57
+ "rhs": self.rhs,
58
+ },
59
+ ]
60
+ }
61
+
62
+ @override
63
+ def write_payload(self, f: BinaryIO) -> None:
64
+ self.lhs.write(f)
65
+ write_u8(f, self.rel_op.value)
66
+ self.rhs.write(f)
@@ -0,0 +1,43 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, BinaryIO, override
3
+
4
+ from tfbscript.ansi import comment
5
+ from tfbscript.binary import write_u8
6
+ from tfbscript.opcodes.base import Opcode, opcode
7
+ from tfbscript.payload import PayloadReader
8
+
9
+
10
+ @opcode("comment:")
11
+ @dataclass
12
+ class OpComment(Opcode):
13
+ content: str = ""
14
+
15
+ @classmethod
16
+ @override
17
+ def parse_payload(cls, reader: PayloadReader) -> "OpComment":
18
+ content = reader.read_string(reader.read_u8())
19
+ return cls(content=content)
20
+
21
+ @override
22
+ def source_line(self, inline: bool = False) -> str:
23
+ return comment(f"// {self.content}")
24
+
25
+ @override
26
+ def editor_repr(self) -> dict[str, Any]:
27
+ return {
28
+ "fields": [
29
+ {
30
+ "type": "label",
31
+ "content": "comment:",
32
+ },
33
+ {
34
+ "type": "string",
35
+ "value": self.content,
36
+ },
37
+ ]
38
+ }
39
+
40
+ @override
41
+ def write_payload(self, f: BinaryIO) -> None:
42
+ write_u8(f, len(self.content))
43
+ f.write(self.content.encode("latin1"))
@@ -0,0 +1,80 @@
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 ControlRequirement
8
+ from tfbscript.payload import PayloadReader
9
+ from tfbscript.reference import Reference
10
+
11
+
12
+ @opcode("control")
13
+ @dataclass
14
+ class OpControl(Opcode):
15
+ target: Reference = field(default_factory=Reference)
16
+ script_control: ControlRequirement = field(default=ControlRequirement.Allow)
17
+
18
+ # Whether the payload carries the script_control byte. The byte is there
19
+ # for an actor target, but the target's type is the wrong thing to ask:
20
+ # resolving it only works while the read traversal is still inside the
21
+ # enclosing ops (see ParserContext.open_opcodes), so writing -- which
22
+ # happens outside any traversal -- got a different answer and dropped the
23
+ # byte. The payload length says it outright, there being only two shapes,
24
+ # 4 bytes for the reference alone and 5 with the byte. Measured over the
25
+ # corpus: 12,376 control ops, 965 of them 4 bytes and 11,411 of them 5,
26
+ # nothing else -- and the type test disagreed with the bytes 72 times.
27
+ _has_script_control: bool = True
28
+
29
+ @classmethod
30
+ @override
31
+ def parse_payload(cls, reader: PayloadReader) -> "OpControl":
32
+ target = reader.readRef()
33
+
34
+ script_control = ControlRequirement.Allow
35
+ has_script_control = reader.size_remaining() >= 1
36
+
37
+ if has_script_control:
38
+ script_control = ControlRequirement(reader.read_u8())
39
+
40
+ return cls(
41
+ target=target,
42
+ script_control=script_control,
43
+ _has_script_control=has_script_control,
44
+ )
45
+
46
+ @override
47
+ def source_line(self, inline: bool = False) -> str:
48
+ return f"{keyword('control (')} {self.target}, {self.script_control} {keyword(')')}"
49
+
50
+ @override
51
+ def write_payload(self, f: BinaryIO) -> None:
52
+ self.target.write(f)
53
+ if self._has_script_control:
54
+ write_u8(f, self.script_control)
55
+
56
+ @override
57
+ def editor_repr(self) -> dict[str, Any]:
58
+ return {
59
+ "hasBody": True,
60
+ "fields": [
61
+ {
62
+ "type": "op-label",
63
+ "value": "control",
64
+ },
65
+ {
66
+ "type": "ref",
67
+ "name": "target",
68
+ "ref": self.target,
69
+ },
70
+ {
71
+ "type": "op-label",
72
+ "value": "script control: ",
73
+ },
74
+ {
75
+ "type": "enum",
76
+ "name": "script_control",
77
+ "entry": self.script_control,
78
+ },
79
+ ],
80
+ }
@@ -0,0 +1,42 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Any, BinaryIO, override
3
+
4
+ from tfbscript.ansi import keyword, type_
5
+ from tfbscript.opcodes.base import Opcode, opcode
6
+ from tfbscript.payload import PayloadReader
7
+ from tfbscript.reference import Reference
8
+
9
+
10
+ @opcode("create variable")
11
+ @dataclass
12
+ class OpCreateVariable(Opcode):
13
+ variable: Reference = field(default_factory=Reference)
14
+
15
+ @classmethod
16
+ @override
17
+ def parse_payload(cls, reader: PayloadReader) -> "OpCreateVariable":
18
+ return cls(variable=reader.readRef())
19
+
20
+ @override
21
+ def source_line(self, inline: bool = False) -> str:
22
+ var_type = self.variable.entry.type if self.variable.entry else "unknown"
23
+ return f"{keyword('var')} {self.variable} : {type_(var_type)};"
24
+
25
+ @override
26
+ def editor_repr(self) -> dict[str, Any]:
27
+ return {
28
+ "fields": [
29
+ {
30
+ "type": "op-label",
31
+ "value": "create variable",
32
+ },
33
+ {
34
+ "type": "ref",
35
+ "ref": self.variable,
36
+ },
37
+ ]
38
+ }
39
+
40
+ @override
41
+ def write_payload(self, f: BinaryIO) -> None:
42
+ self.variable.write(f)
@@ -0,0 +1,44 @@
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 CutsceneCommand
8
+ from tfbscript.payload import PayloadReader
9
+
10
+ @opcode("cut-scene")
11
+ @dataclass
12
+ class OpCutScene(Opcode):
13
+ cutscene_command: CutsceneCommand = field(default=CutsceneCommand.Begin)
14
+
15
+ @classmethod
16
+ @override
17
+ def parse_payload(cls, reader: PayloadReader) -> "OpCutScene":
18
+ cutscene_cmd = CutsceneCommand(reader.read_u8())
19
+ return cls(cutscene_command=cutscene_cmd)
20
+
21
+ @override
22
+ def source_line(self, inline: bool = False) -> str:
23
+ return func_call("cutScene", str(self.cutscene_command))
24
+
25
+ @override
26
+ def editor_repr(self) -> dict[str, Any]:
27
+ return {
28
+ "hasBody": False,
29
+ "fields": [
30
+ {
31
+ "type": "op-label",
32
+ "value": "cut-scene",
33
+ },
34
+ {
35
+ "type": "enum",
36
+ "name": "cutscene_command",
37
+ "entry": self.cutscene_command,
38
+ },
39
+ ]
40
+ }
41
+
42
+ @override
43
+ def write_payload(self, f: BinaryIO) -> None:
44
+ write_u8(f, self.cutscene_command)
@@ -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("dec value")
11
+ @dataclass
12
+ class OpDecValue(Opcode):
13
+ lhs: Reference = field(default_factory=Reference)
14
+
15
+ @classmethod
16
+ @override
17
+ def parse_payload(cls, reader: PayloadReader) -> "OpDecValue":
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": "decrement 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)