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,53 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any, BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import func_call, quoted_string
|
|
5
|
+
from tfbscript.binary import write_u8
|
|
6
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
7
|
+
from tfbscript.payload import PayloadReader
|
|
8
|
+
from tfbscript.reference import Reference
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@opcode("print")
|
|
12
|
+
@dataclass
|
|
13
|
+
class OpPrint(Opcode):
|
|
14
|
+
target: Reference = field(default_factory=Reference)
|
|
15
|
+
content: str = ""
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
@override
|
|
19
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpPrint":
|
|
20
|
+
target = reader.readRef()
|
|
21
|
+
content = reader.read_string(reader.read_u8())
|
|
22
|
+
return cls(target=target, content=content)
|
|
23
|
+
|
|
24
|
+
@override
|
|
25
|
+
def source_line(self, inline: bool = False) -> str:
|
|
26
|
+
return func_call("print", str(self.target), quoted_string(self.content))
|
|
27
|
+
|
|
28
|
+
@override
|
|
29
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
30
|
+
return {
|
|
31
|
+
"fields": [
|
|
32
|
+
{
|
|
33
|
+
"type": "op-label",
|
|
34
|
+
"value": "print",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"type": "ref",
|
|
38
|
+
"name": "target",
|
|
39
|
+
"ref": self.target,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"type": "string",
|
|
43
|
+
"name": "content",
|
|
44
|
+
"value": self.content,
|
|
45
|
+
},
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@override
|
|
50
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
51
|
+
self.target.write(f)
|
|
52
|
+
write_u8(f, len(self.content))
|
|
53
|
+
f.write(self.content.encode("latin1"))
|
|
@@ -0,0 +1,43 @@
|
|
|
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("remove")
|
|
11
|
+
@dataclass
|
|
12
|
+
class OpRemove(Opcode):
|
|
13
|
+
target: Reference = field(default_factory=Reference)
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
@override
|
|
17
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpRemove":
|
|
18
|
+
return cls(target=reader.readRef())
|
|
19
|
+
|
|
20
|
+
@override
|
|
21
|
+
def source_line(self, inline: bool = False) -> str:
|
|
22
|
+
return f"{self.target}.{method('remove')}{parentheses('()')};"
|
|
23
|
+
|
|
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": "remove",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"type": "ref",
|
|
36
|
+
"ref": self.target,
|
|
37
|
+
},
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@override
|
|
42
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
43
|
+
self.target.write(f)
|
|
@@ -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("reset")
|
|
11
|
+
@dataclass
|
|
12
|
+
class OpReset(Opcode):
|
|
13
|
+
target: Reference = field(default_factory=Reference)
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
@override
|
|
17
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpReset":
|
|
18
|
+
return cls(target=reader.readRef())
|
|
19
|
+
|
|
20
|
+
@override
|
|
21
|
+
def source_line(self, inline: bool = False) -> str:
|
|
22
|
+
return f"{self.target}.{method('reset')}{parentheses('()')};"
|
|
23
|
+
|
|
24
|
+
@override
|
|
25
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
26
|
+
return {
|
|
27
|
+
"hasBody": True,
|
|
28
|
+
"fields": [
|
|
29
|
+
{
|
|
30
|
+
"type": "op-label",
|
|
31
|
+
"value": "reset",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"type": "ref",
|
|
35
|
+
"ref": self.target,
|
|
36
|
+
},
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@override
|
|
41
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
42
|
+
self.target.write(f)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import func_call
|
|
5
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
6
|
+
from tfbscript.payload import PayloadReader
|
|
7
|
+
from tfbscript.reference import Reference
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@opcode("run as player")
|
|
11
|
+
@dataclass
|
|
12
|
+
class OpRunAsPlayer(Opcode):
|
|
13
|
+
actor_ref: Reference = field(default_factory=Reference)
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
@override
|
|
17
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpRunAsPlayer":
|
|
18
|
+
return cls(actor_ref=reader.readRef())
|
|
19
|
+
|
|
20
|
+
@override
|
|
21
|
+
def source_line(self, inline: bool = False) -> str:
|
|
22
|
+
return func_call("runAsPlayer", str(self.actor_ref))
|
|
23
|
+
|
|
24
|
+
@override
|
|
25
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
26
|
+
self.actor_ref.write(f)
|
|
@@ -0,0 +1,53 @@
|
|
|
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.payload import PayloadReader
|
|
8
|
+
from tfbscript.reference import Reference
|
|
9
|
+
from tfbscript.rhs import Rhs
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@opcode("send message")
|
|
13
|
+
@dataclass
|
|
14
|
+
class OpSendMessage(Opcode):
|
|
15
|
+
message_ref: Reference = field(default_factory=Reference)
|
|
16
|
+
reciver_Ref: Reference = field(default_factory=Reference)
|
|
17
|
+
value: Rhs = field(default_factory=Rhs)
|
|
18
|
+
# The byte at payload+8 is the RHS record's own rec+8 field -- the same one
|
|
19
|
+
# `check message` reads as its relational operator (both opcodes hand it to
|
|
20
|
+
# FUN_0042FC60 before readRHS). Send's execute never looks at it, but it is
|
|
21
|
+
# not always zero on disk ({0: 20, 2: 636} across the corpus), so it is kept
|
|
22
|
+
# verbatim rather than assumed.
|
|
23
|
+
_rec8: int = 0
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
@override
|
|
27
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpSendMessage":
|
|
28
|
+
message_ref = reader.readRef()
|
|
29
|
+
reciver_ref = reader.readRef()
|
|
30
|
+
rec8 = reader.read_u8()
|
|
31
|
+
value = reader.readRHS()
|
|
32
|
+
return cls(
|
|
33
|
+
message_ref=message_ref,
|
|
34
|
+
reciver_Ref=reciver_ref,
|
|
35
|
+
value=value,
|
|
36
|
+
_rec8=rec8,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
@override
|
|
40
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
41
|
+
self.message_ref.write(f)
|
|
42
|
+
self.reciver_Ref.write(f)
|
|
43
|
+
write_u8(f, self._rec8)
|
|
44
|
+
self.value.write(f)
|
|
45
|
+
|
|
46
|
+
@override
|
|
47
|
+
def source_line(self, inline: bool = False) -> str:
|
|
48
|
+
return func_call(
|
|
49
|
+
"sendMessage",
|
|
50
|
+
str(self.message_ref),
|
|
51
|
+
f"to: {self.reciver_Ref}",
|
|
52
|
+
f"value: {self.value}",
|
|
53
|
+
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any, BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import func_call
|
|
5
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
6
|
+
from tfbscript.payload import PayloadReader
|
|
7
|
+
from tfbscript.reference import Reference
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@opcode("set behavior")
|
|
11
|
+
@dataclass
|
|
12
|
+
class OpSetBehavior(Opcode):
|
|
13
|
+
behavior: Reference = field(default_factory=Reference)
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
@override
|
|
17
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpSetBehavior":
|
|
18
|
+
return cls(behavior=reader.readRef())
|
|
19
|
+
|
|
20
|
+
@override
|
|
21
|
+
def source_line(self, inline: bool = False) -> str:
|
|
22
|
+
return func_call("setBehavior", str(self.behavior))
|
|
23
|
+
|
|
24
|
+
@override
|
|
25
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
26
|
+
return {
|
|
27
|
+
"fields": [
|
|
28
|
+
{
|
|
29
|
+
"type": "op-label",
|
|
30
|
+
"value": "set behavior",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"type": "ref",
|
|
34
|
+
"ref": self.behavior,
|
|
35
|
+
},
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@override
|
|
40
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
41
|
+
self.behavior.write(f)
|
|
@@ -0,0 +1,52 @@
|
|
|
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("set reference")
|
|
11
|
+
@dataclass
|
|
12
|
+
class OpSetReference(Opcode):
|
|
13
|
+
dest_ref: Reference = field(default_factory=Reference)
|
|
14
|
+
src_ref: Reference = field(default_factory=Reference)
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
@override
|
|
18
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpSetReference":
|
|
19
|
+
return cls(dest_ref=reader.readRef(), src_ref=reader.readRef())
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@override
|
|
23
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
24
|
+
self.dest_ref.write(f)
|
|
25
|
+
self.src_ref.write(f)
|
|
26
|
+
|
|
27
|
+
@override
|
|
28
|
+
def source_line(self, inline: bool = False) -> str:
|
|
29
|
+
return f"{keyword('set reference')} *{self.dest_ref} = {self.src_ref};"
|
|
30
|
+
|
|
31
|
+
@override
|
|
32
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
33
|
+
return {
|
|
34
|
+
"fields": [
|
|
35
|
+
{
|
|
36
|
+
"type": "op-label",
|
|
37
|
+
"value": "set *reference",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"type": "ref",
|
|
41
|
+
"ref": self.dest_ref,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"type": "label",
|
|
45
|
+
"content": "to",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"type": "ref",
|
|
49
|
+
"ref": self.src_ref,
|
|
50
|
+
},
|
|
51
|
+
]
|
|
52
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Any, BinaryIO, override
|
|
3
|
+
|
|
4
|
+
from tfbscript.ansi import keyword, operator
|
|
5
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
6
|
+
from tfbscript.payload import PayloadReader
|
|
7
|
+
from tfbscript.reference import Reference
|
|
8
|
+
from tfbscript.rhs import Rhs
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@opcode("set value")
|
|
12
|
+
@dataclass
|
|
13
|
+
class OpSetValue(Opcode):
|
|
14
|
+
lhs: Reference = field(default_factory=Reference)
|
|
15
|
+
rhs: Rhs = field(default_factory=Rhs)
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
@override
|
|
19
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpSetValue":
|
|
20
|
+
return cls(lhs=reader.readRef(), rhs=reader.readRHS())
|
|
21
|
+
|
|
22
|
+
@override
|
|
23
|
+
def source_line(self, inline: bool = False) -> str:
|
|
24
|
+
return f"{keyword('set')} {self.lhs} {operator('=')} {self.rhs};"
|
|
25
|
+
|
|
26
|
+
@override
|
|
27
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
28
|
+
return {
|
|
29
|
+
"fields": [
|
|
30
|
+
{
|
|
31
|
+
"type": "op-label",
|
|
32
|
+
"value": "set value",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"type": "ref",
|
|
36
|
+
"ref": self.lhs,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"type": "label",
|
|
40
|
+
"content": "=",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"type": "rhs",
|
|
44
|
+
"rhs": self.rhs,
|
|
45
|
+
},
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@override
|
|
50
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
51
|
+
self.lhs.write(f)
|
|
52
|
+
self.rhs.write(f)
|
|
@@ -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 OpShutdown(BlockOpcode):
|
|
9
|
+
@override
|
|
10
|
+
def block_name(self) -> str:
|
|
11
|
+
return "SHUTDOWN"
|
|
12
|
+
|
|
13
|
+
@override
|
|
14
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
15
|
+
return {
|
|
16
|
+
"fields": [
|
|
17
|
+
{
|
|
18
|
+
"type": "block-label",
|
|
19
|
+
"value": "SHUTDOWN",
|
|
20
|
+
},
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@override
|
|
25
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
26
|
+
pass # Shutdown has no payload
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import override
|
|
3
|
+
|
|
4
|
+
from typing import BinaryIO
|
|
5
|
+
|
|
6
|
+
from tfbscript.ansi import func_call
|
|
7
|
+
from tfbscript.binary import write_u32
|
|
8
|
+
from tfbscript.opcodes.base import Opcode, opcode
|
|
9
|
+
from tfbscript.payload import PayloadReader
|
|
10
|
+
from tfbscript.reference import Reference
|
|
11
|
+
from tfbscript.rhs import Rhs
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@opcode("slide value")
|
|
15
|
+
@dataclass
|
|
16
|
+
class OpSlideValue(Opcode):
|
|
17
|
+
lhs: Reference = field(default_factory=Reference)
|
|
18
|
+
target_value: Rhs = field(default_factory=Rhs)
|
|
19
|
+
interpolation_time: Rhs = field(default_factory=Rhs)
|
|
20
|
+
|
|
21
|
+
# Plain u32s, not references: slide value's parse (FUN_00430210) reads
|
|
22
|
+
# them with FUN_00432990 -- a thunk to FUN_00432920, a raw 4-byte LE read --
|
|
23
|
+
# not with FUN_004346f0, which is what every actual reference operand goes
|
|
24
|
+
# through. Disk order is ease_out (obj+0x28) then ease_in (obj+0x24).
|
|
25
|
+
ease_out: int = 0
|
|
26
|
+
ease_in: int = 0
|
|
27
|
+
# Whatever is left when the trailer is not the expected 8 bytes. That only
|
|
28
|
+
# happens when the RHS reader took an operator tail that was not really
|
|
29
|
+
# there (see Rhs._tail_follows -- the byte test is sound but not complete),
|
|
30
|
+
# so the fields above are unreliable for those; keeping the raw bytes lets
|
|
31
|
+
# the file round-trip exactly regardless.
|
|
32
|
+
_trailing: bytes = b""
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
@override
|
|
36
|
+
def parse_payload(cls, reader: PayloadReader) -> Opcode:
|
|
37
|
+
lhs = reader.readRef()
|
|
38
|
+
target_value = reader.readRHS()
|
|
39
|
+
interpolation_time = reader.readRHS()
|
|
40
|
+
|
|
41
|
+
# Normally exactly 8 bytes remain.
|
|
42
|
+
if reader.size_remaining() >= 8:
|
|
43
|
+
return cls(
|
|
44
|
+
lhs=lhs,
|
|
45
|
+
target_value=target_value,
|
|
46
|
+
interpolation_time=interpolation_time,
|
|
47
|
+
ease_out=reader.read_u32(),
|
|
48
|
+
ease_in=reader.read_u32(),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
return cls(
|
|
52
|
+
lhs=lhs,
|
|
53
|
+
target_value=target_value,
|
|
54
|
+
interpolation_time=interpolation_time,
|
|
55
|
+
_trailing=reader.read_bytes(reader.size_remaining()),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
@override
|
|
59
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
60
|
+
self.lhs.write(f)
|
|
61
|
+
self.target_value.write(f)
|
|
62
|
+
self.interpolation_time.write(f)
|
|
63
|
+
if self._trailing:
|
|
64
|
+
f.write(self._trailing)
|
|
65
|
+
else:
|
|
66
|
+
write_u32(f, self.ease_out)
|
|
67
|
+
write_u32(f, self.ease_in)
|
|
68
|
+
|
|
69
|
+
@override
|
|
70
|
+
def source_line(self, inline: bool = False) -> str:
|
|
71
|
+
return (
|
|
72
|
+
str(self.lhs)
|
|
73
|
+
+ "."
|
|
74
|
+
+ func_call(
|
|
75
|
+
"slide",
|
|
76
|
+
f"to {self.target_value!s}",
|
|
77
|
+
f"over {self.interpolation_time!s}",
|
|
78
|
+
f"ease in {self.ease_out!s}",
|
|
79
|
+
f"ease out {self.ease_in!s}",
|
|
80
|
+
)
|
|
81
|
+
)
|
|
@@ -0,0 +1,96 @@
|
|
|
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.payload import PayloadReader
|
|
8
|
+
from tfbscript.reference import Reference
|
|
9
|
+
from tfbscript.rhs import Rhs
|
|
10
|
+
|
|
11
|
+
# TODO: RESEARCH REMAINING BYTE PURPOSE
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@opcode("spawn actor")
|
|
15
|
+
@dataclass
|
|
16
|
+
class OpSpawnActor(Opcode):
|
|
17
|
+
clone_ref: Reference = field(default_factory=Reference)
|
|
18
|
+
at_ref: Reference = field(default_factory=Reference)
|
|
19
|
+
facing_rhs: Rhs = field(default_factory=Rhs)
|
|
20
|
+
remaining: int | None = None
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
@override
|
|
24
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpSpawnActor":
|
|
25
|
+
clone_ref = reader.readRef()
|
|
26
|
+
at_ref = reader.readRef()
|
|
27
|
+
facing_rhs = reader.readRHS()
|
|
28
|
+
|
|
29
|
+
if reader.size_remaining() > 0:
|
|
30
|
+
return cls(
|
|
31
|
+
clone_ref=clone_ref,
|
|
32
|
+
at_ref=at_ref,
|
|
33
|
+
facing_rhs=facing_rhs,
|
|
34
|
+
remaining=reader.read_u8(),
|
|
35
|
+
)
|
|
36
|
+
return cls(clone_ref=clone_ref, at_ref=at_ref, facing_rhs=facing_rhs)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@override
|
|
40
|
+
def source_line(self, inline: bool = False) -> str:
|
|
41
|
+
if self.remaining is not None:
|
|
42
|
+
return f"{keyword(f'spawn actor ({self.clone_ref}, at: {self.at_ref}, facing: {self.facing_rhs}, unknown: {self.remaining})')};"
|
|
43
|
+
else:
|
|
44
|
+
return f"{keyword(f'spawn actor ({self.clone_ref}, at: {self.at_ref}, facing: {self.facing_rhs})')};"
|
|
45
|
+
|
|
46
|
+
@override
|
|
47
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
48
|
+
return {
|
|
49
|
+
"fields": [
|
|
50
|
+
{
|
|
51
|
+
"type": "op-label",
|
|
52
|
+
"value": "clone",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"type": "label",
|
|
56
|
+
"content": "actor",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"type": "ref",
|
|
60
|
+
"name": "clone_ref",
|
|
61
|
+
"ref": self.clone_ref,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"type": "label",
|
|
65
|
+
"content": "at",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"type": "ref",
|
|
69
|
+
"name": "at_ref",
|
|
70
|
+
"ref": self.at_ref,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"type": "label",
|
|
74
|
+
"content": "facing",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"type": "rhs",
|
|
78
|
+
"name": "facing_rhs",
|
|
79
|
+
"rhs": self.facing_rhs,
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"type": "label",
|
|
83
|
+
"content": "degrees",
|
|
84
|
+
},
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@override
|
|
89
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
90
|
+
self.clone_ref.write(f)
|
|
91
|
+
self.at_ref.write(f)
|
|
92
|
+
self.facing_rhs.write(f)
|
|
93
|
+
# The trailing byte is only there in some files; parse records its
|
|
94
|
+
# absence as None so writing can leave it out again.
|
|
95
|
+
if self.remaining is not None:
|
|
96
|
+
write_u8(f, self.remaining)
|
|
@@ -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 OpStartup(BlockOpcode):
|
|
9
|
+
@override
|
|
10
|
+
def block_name(self) -> str:
|
|
11
|
+
return "STARTUP"
|
|
12
|
+
|
|
13
|
+
@override
|
|
14
|
+
def editor_repr(self) -> dict[str, Any]:
|
|
15
|
+
return {
|
|
16
|
+
"fields": [
|
|
17
|
+
{
|
|
18
|
+
"type": "block-label",
|
|
19
|
+
"value": "STRARTUP",
|
|
20
|
+
},
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@override
|
|
25
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
26
|
+
pass # Startup has no payload
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import 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("stop sound")
|
|
11
|
+
@dataclass
|
|
12
|
+
class OpStopSound(Opcode):
|
|
13
|
+
sound: Reference = field(default_factory=Reference)
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
@override
|
|
17
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpStopSound":
|
|
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('stop')}{parentheses('()')};"
|
|
@@ -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 SetDirection
|
|
8
|
+
from tfbscript.payload import PayloadReader
|
|
9
|
+
from tfbscript.reference import Reference
|
|
10
|
+
from tfbscript.rhs import Rhs
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@opcode("teleport to")
|
|
14
|
+
@dataclass
|
|
15
|
+
class OpTeleportTo(Opcode):
|
|
16
|
+
target_ref: Reference = field(default_factory=Reference)
|
|
17
|
+
set_direction: SetDirection = field(default=SetDirection.forward)
|
|
18
|
+
facing: Rhs = field(default_factory=Rhs)
|
|
19
|
+
|
|
20
|
+
duration: Rhs = field(default_factory=Rhs)
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
@override
|
|
24
|
+
def parse_payload(cls, reader: PayloadReader) -> "OpTeleportTo":
|
|
25
|
+
return cls(
|
|
26
|
+
target_ref=reader.readRef(),
|
|
27
|
+
set_direction=SetDirection(reader.read_u8()),
|
|
28
|
+
facing=reader.readRHS(),
|
|
29
|
+
duration=reader.readRHS(),
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
@override
|
|
33
|
+
def source_line(self, inline: bool = False) -> str:
|
|
34
|
+
return func_call(
|
|
35
|
+
"teleportTo",
|
|
36
|
+
str(self.target_ref),
|
|
37
|
+
f"facing {self.facing}",
|
|
38
|
+
f"direction: {self.set_direction}",
|
|
39
|
+
f"over {self.duration} seconds",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
@override
|
|
43
|
+
def write_payload(self, f: BinaryIO) -> None:
|
|
44
|
+
self.target_ref.write(f)
|
|
45
|
+
write_u8(f, self.set_direction)
|
|
46
|
+
self.facing.write(f)
|
|
47
|
+
self.duration.write(f)
|