PyLibMS 4.2.4__py3-none-any.whl → 4.2.5__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 (37) hide show
  1. lms/common/field/io.py +17 -6
  2. lms/common/field/lms_datatype.py +4 -6
  3. lms/common/field/lms_field.py +7 -3
  4. lms/common/lms_constants.py +1 -1
  5. lms/common/stream/fileinfo.py +12 -3
  6. lms/common/stream/hashtable.py +6 -1
  7. lms/common/stream/section.py +7 -7
  8. lms/fileio/encoding.py +1 -1
  9. lms/fileio/io.py +1 -1
  10. lms/flowchart/definitions/flowchart.py +11 -6
  11. lms/flowchart/definitions/node.py +125 -91
  12. lms/flowchart/definitions/node_type.py +22 -9
  13. lms/flowchart/flw3.py +111 -47
  14. lms/flowchart/msbf.py +37 -10
  15. lms/flowchart/msbfio.py +30 -20
  16. lms/message/lms_messagetext.py +21 -13
  17. lms/message/msbt.py +27 -18
  18. lms/message/msbtentry.py +10 -10
  19. lms/message/msbtio.py +32 -18
  20. lms/message/section/atr1.py +7 -8
  21. lms/message/section/txt2.py +1 -1
  22. lms/message/tag/io/param_io.py +6 -6
  23. lms/message/tag/io/tag_io.py +17 -16
  24. lms/message/tag/lms_tag.py +26 -16
  25. lms/project/definitions/tag.py +19 -17
  26. lms/project/msbp.py +7 -7
  27. lms/project/msbpread.py +5 -1
  28. lms/titleconfig/config.py +16 -17
  29. lms/titleconfig/definitions/attribute.py +0 -1
  30. lms/titleconfig/definitions/nodes.py +60 -27
  31. lms/titleconfig/definitions/tags.py +4 -2
  32. lms/titleconfig/presets/Tomodachi Life NA-EU.yaml +2 -1
  33. {pylibms-4.2.4.dist-info → pylibms-4.2.5.dist-info}/METADATA +17 -7
  34. {pylibms-4.2.4.dist-info → pylibms-4.2.5.dist-info}/RECORD +37 -37
  35. {pylibms-4.2.4.dist-info → pylibms-4.2.5.dist-info}/WHEEL +0 -0
  36. {pylibms-4.2.4.dist-info → pylibms-4.2.5.dist-info}/licenses/LICENSE +0 -0
  37. {pylibms-4.2.4.dist-info → pylibms-4.2.5.dist-info}/top_level.txt +0 -0
lms/common/field/io.py CHANGED
@@ -1,15 +1,22 @@
1
1
  from typing import Callable
2
2
 
3
- from lms.common.field.lms_datatype import (LMS_DataType, is_bool_datatype,
4
- is_bytes_datatype, is_list_datatype,
5
- is_number_datatype)
3
+ from lms.common.field.lms_datatype import (
4
+ LMS_DataType,
5
+ is_bool_datatype,
6
+ is_bytes_datatype,
7
+ is_list_datatype,
8
+ is_number_datatype,
9
+ )
6
10
  from lms.common.field.lms_field import LMS_Field
7
11
  from lms.fileio.io import FileReader, FileWriter
8
12
  from lms.titleconfig.definitions.value import ValueDefinition
9
13
 
10
14
 
11
- def read_field(reader: FileReader, definition: ValueDefinition,
12
- read_variable_width_value: Callable | None = None) -> LMS_Field:
15
+ def read_field(
16
+ reader: FileReader,
17
+ definition: ValueDefinition,
18
+ read_variable_width_value: Callable | None = None,
19
+ ) -> LMS_Field:
13
20
  # String is excluded as their reading varies between MSBT/MSBF
14
21
  match definition.datatype:
15
22
  case LMS_DataType.UINT8:
@@ -43,7 +50,11 @@ def read_field(reader: FileReader, definition: ValueDefinition,
43
50
  return LMS_Field(value, definition) # type: ignore
44
51
 
45
52
 
46
- def write_field(writer: FileWriter, field: LMS_Field, write_variable_width_value: Callable | None = None) -> None:
53
+ def write_field(
54
+ writer: FileWriter,
55
+ field: LMS_Field,
56
+ write_variable_width_value: Callable | None = None,
57
+ ) -> None:
47
58
  if is_number_datatype(field.value, field.datatype):
48
59
  write_functions: dict[LMS_DataType, Callable] = {
49
60
  LMS_DataType.UINT8: writer.write_uint8,
@@ -119,9 +119,7 @@ class LMS_DataType(Enum):
119
119
  try:
120
120
  return sizes[self]
121
121
  except KeyError:
122
- raise TypeError(
123
- f"Stream size is not defined for '{self.to_string()}'."
124
- )
122
+ raise TypeError(f"Stream size is not defined for '{self.to_string()}'.")
125
123
 
126
124
  @classmethod
127
125
  def from_string(cls, string: str):
@@ -138,8 +136,8 @@ class LMS_DataType(Enum):
138
136
 
139
137
 
140
138
  def verify_number_from_datatype(
141
- value: int | float,
142
- datatype: LMS_DataType,
139
+ value: int | float,
140
+ datatype: LMS_DataType,
143
141
  ):
144
142
  if datatype is LMS_DataType.FLOAT32:
145
143
  max_value = FLOAT32_MAX
@@ -150,7 +148,7 @@ def verify_number_from_datatype(
150
148
  max_value = 2 ** (bits - 1)
151
149
  min_value = -max_value
152
150
  else:
153
- min_value, max_value = 0, (2 ** bits) - 1
151
+ min_value, max_value = 0, (2**bits) - 1
154
152
 
155
153
  if not min_value <= value <= max_value:
156
154
  raise ValueError(
@@ -37,7 +37,9 @@ class LMS_FieldMap:
37
37
  return {field.name: field.value for field in self.fields.values()}
38
38
 
39
39
  @staticmethod
40
- def create_default_dict_map(definitions: list[ValueDefinition]) -> dict[str, FieldValue]:
40
+ def create_default_dict_map(
41
+ definitions: list[ValueDefinition],
42
+ ) -> dict[str, FieldValue]:
41
43
  map = {}
42
44
  for definition in definitions:
43
45
  match definition.datatype:
@@ -101,7 +103,9 @@ class LMS_Field:
101
103
  """
102
104
 
103
105
  def __init__(
104
- self, value: int | str | float | bytes | bool, definition: ValueDefinition,
106
+ self,
107
+ value: int | str | float | bytes | bool,
108
+ definition: ValueDefinition,
105
109
  ):
106
110
  _verify_value_from_definition(value, definition)
107
111
  self._definition = definition
@@ -145,7 +149,7 @@ class LMS_Field:
145
149
 
146
150
 
147
151
  def _verify_value_from_definition(
148
- value: int | str | float | bytes | bool, definition: ValueDefinition
152
+ value: int | str | float | bytes | bool, definition: ValueDefinition
149
153
  ) -> None:
150
154
  datatype = definition.datatype
151
155
 
@@ -3,7 +3,7 @@ PADDING_BYTE = b"\x00"
3
3
 
4
4
  SIZE_OFFSET = 0x12
5
5
  SECTION_DATA_START = 0x20
6
- SECTION_PADDING_BYTE = b"\xAB"
6
+ SECTION_PADDING_BYTE = b"\xab"
7
7
 
8
8
  LITTLE_ENDIAN_BOM = b"\xff\xfe"
9
9
  BIG_ENDIAN_BOM = b"\xfe\xff"
@@ -1,5 +1,10 @@
1
1
  from lms.common import lms_exceptions
2
- from lms.common.lms_constants import BIG_ENDIAN_BOM, SECTION_DATA_START, LITTLE_ENDIAN_BOM, SIZE_OFFSET
2
+ from lms.common.lms_constants import (
3
+ BIG_ENDIAN_BOM,
4
+ SECTION_DATA_START,
5
+ LITTLE_ENDIAN_BOM,
6
+ SIZE_OFFSET,
7
+ )
3
8
  from lms.common.lms_fileinfo import LMS_FileInfo
4
9
  from lms.fileio.encoding import FileEncoding
5
10
  from lms.fileio.io import FileReader, FileWriter
@@ -25,7 +30,9 @@ def read_file_info(reader: FileReader, expected_magic: str) -> LMS_FileInfo:
25
30
  version = reader.read_uint8()
26
31
 
27
32
  if version < 3:
28
- raise lms_exceptions.LMS_UnsupportedFileVersionError("Only version 3+ files are supported!")
33
+ raise lms_exceptions.LMS_UnsupportedFileVersionError(
34
+ "Only version 3+ files are supported!"
35
+ )
29
36
 
30
37
  section_count = reader.read_uint16()
31
38
 
@@ -34,7 +41,9 @@ def read_file_info(reader: FileReader, expected_magic: str) -> LMS_FileInfo:
34
41
 
35
42
  reader.seek(0, 2)
36
43
  if file_size != (real_size := reader.tell()):
37
- raise lms_exceptions.LMS_MisalignedSizeError(f"File size is misaligned!` Got {file_size} expected {real_size}.")
44
+ raise lms_exceptions.LMS_MisalignedSizeError(
45
+ f"File size is misaligned!` Got {file_size} expected {real_size}."
46
+ )
38
47
 
39
48
  reader.seek(SECTION_DATA_START)
40
49
 
@@ -27,7 +27,12 @@ def read_labels(reader: FileReader) -> tuple[dict, int]:
27
27
  return sorted_labels, slot_count
28
28
 
29
29
 
30
- def write_labels(writer: FileWriter, labels: list[str], slot_count: int, index_map: dict[str, int] = None) -> None:
30
+ def write_labels(
31
+ writer: FileWriter,
32
+ labels: list[str],
33
+ slot_count: int,
34
+ index_map: dict[str, int] = None,
35
+ ) -> None:
31
36
  writer.write_uint32(slot_count)
32
37
 
33
38
  hash_slots = {}
@@ -2,12 +2,12 @@ from typing import Any, Callable, Generator
2
2
 
3
3
  from lms.fileio.io import FileReader, FileWriter
4
4
 
5
- SECTION_PADDING_BYTE = b"\xAB"
5
+ SECTION_PADDING_BYTE = b"\xab"
6
6
  SECTION_ALIGNMENT = 16
7
7
 
8
8
 
9
9
  def read_section_data(
10
- reader: FileReader, section_count: int
10
+ reader: FileReader, section_count: int
11
11
  ) -> Generator[tuple[str, int], Any, None]:
12
12
  reader.seek(0x20)
13
13
  for _ in range(section_count):
@@ -24,11 +24,11 @@ def read_section_data(
24
24
 
25
25
 
26
26
  def write_section(
27
- writer: FileWriter,
28
- magic: str,
29
- section_call: Callable,
30
- data: list[Any],
31
- *write_arguments: Any,
27
+ writer: FileWriter,
28
+ magic: str,
29
+ section_call: Callable,
30
+ data: list[Any],
31
+ *write_arguments: Any,
32
32
  ) -> None:
33
33
  writer.write_string(magic)
34
34
  size_offset = writer.tell()
lms/fileio/encoding.py CHANGED
@@ -10,7 +10,7 @@ class FileEncoding(IntEnum):
10
10
  UTF32 = 0x02
11
11
 
12
12
  def to_string_format(
13
- self, is_big_endian: bool = False
13
+ self, is_big_endian: bool = False
14
14
  ) -> Literal["UTF-8", "UTF-16-BE", "UTF-16-LE", "UTF-32-BE", "UTF-32-LE"]:
15
15
  """Converts the FileEncoding to string format."""
16
16
  match self:
lms/fileio/io.py CHANGED
@@ -106,7 +106,7 @@ class FileReader:
106
106
  def read_encoded_string(self):
107
107
  message = b""
108
108
  while (
109
- raw_char := self.read_bytes(self.encoding.width)
109
+ raw_char := self.read_bytes(self.encoding.width)
110
110
  ) != self.encoding.terminator:
111
111
  message += raw_char
112
112
  return message.decode(self.encoding.to_string_format(self.is_big_endian))
@@ -7,7 +7,9 @@ from lms.flowchart.definitions.node import LMS_EntryNode, LMS_BranchNode, LMS_Ba
7
7
  class LMS_Flowchart:
8
8
  """Class that represents a flowchart in a MSBF file."""
9
9
 
10
- def __init__(self, entry_point: LMS_EntryNode, id_generator: Callable[[], int]) -> None:
10
+ def __init__(
11
+ self, entry_point: LMS_EntryNode, id_generator: Callable[[], int]
12
+ ) -> None:
11
13
  self._entry_node = entry_point
12
14
  self._nodes: dict[int, LMS_BaseNode] = {}
13
15
  self._id_generator = id_generator
@@ -16,7 +18,6 @@ class LMS_Flowchart:
16
18
  for node in entry_point.get_descendents():
17
19
  self._nodes[node.id] = node
18
20
 
19
-
20
21
  def __iter__(self) -> Iterator[LMS_BaseNode]:
21
22
  return iter(self._nodes.values())
22
23
 
@@ -28,7 +29,7 @@ class LMS_Flowchart:
28
29
 
29
30
  @property
30
31
  def name(self) -> str:
31
- """The name of the flowchart. """
32
+ """The name of the flowchart."""
32
33
  return self._entry_node.flowchart_name
33
34
 
34
35
  @name.setter
@@ -41,7 +42,7 @@ class LMS_Flowchart:
41
42
  return self._entry_node
42
43
 
43
44
  @property
44
- def nodes(self) -> MappingProxyType[LMS_BaseNode]:
45
+ def nodes(self) -> MappingProxyType[int, LMS_BaseNode]:
45
46
  """All nodes in the flowchart instance."""
46
47
  return MappingProxyType(self._nodes)
47
48
 
@@ -52,10 +53,14 @@ class LMS_Flowchart:
52
53
  :param node: the node to add.
53
54
  """
54
55
  if not isinstance(node, LMS_BaseNode):
55
- raise TypeError(f"Node type '{type(node).__name__}' is not a child of LMS_BaseNode!")
56
+ raise TypeError(
57
+ f"Node type '{type(node).__name__}' is not a child of LMS_BaseNode!"
58
+ )
56
59
 
57
60
  if node in self._nodes.values():
58
- raise ValueError(f"Node of ID '{node.id}' is already registered to this flowchart!")
61
+ raise ValueError(
62
+ f"Node of ID '{node.id}' is already registered to this flowchart!"
63
+ )
59
64
 
60
65
  node.id = self._id_generator()
61
66
  self._nodes[node.id] = node
@@ -21,15 +21,17 @@ NO_NEXT_NODE = -1
21
21
 
22
22
  class LMS_BaseNode:
23
23
  """
24
- Class that represents common structure and methods for a LMS_Node.
24
+ Class that represents common structure and methods for any LMS_Node.
25
25
  """
26
26
 
27
- def __init__(self,
28
- id: int | None,
29
- node_type: LMS_NodeType,
30
- parameter_type: LMS_NodeParameterType,
31
- parameter_value: LMS_NodeParameter | None):
32
- self.id = id
27
+ def __init__(
28
+ self,
29
+ node_id: int,
30
+ node_type: LMS_NodeType,
31
+ parameter_type: LMS_NodeParameterType,
32
+ parameter_value: LMS_NodeParameter | None,
33
+ ):
34
+ self.id = node_id
33
35
  self._node_type = node_type
34
36
 
35
37
  self._parameter_type = parameter_type
@@ -68,13 +70,19 @@ class LMS_BaseNode:
68
70
  @parameter_value.setter
69
71
  def parameter_value(self, value: LMS_NodeParameter):
70
72
  if self._parameter_type == LMS_NodeParameterType.NONE:
71
- raise TypeError("Unable to set parameter values when there is no parameter!")
73
+ raise TypeError(
74
+ "Unable to set parameter values when there is no parameter!"
75
+ )
72
76
 
73
77
  if isinstance(self._parameter_value, LMS_FieldMap):
74
- raise ValueError("Edit a parameter value through the value property of a field!")
78
+ raise ValueError(
79
+ "Edit a parameter value through the value property of a field!"
80
+ )
75
81
 
76
82
  if not isinstance(value, self._parameter_type.builtin_type):
77
- raise TypeError(f"Wrong value provided! Expected {self._parameter_type.builtin_type} got {type(value)}")
83
+ raise TypeError(
84
+ f"Wrong value provided! Expected {self._parameter_type.builtin_type} got {type(value)}"
85
+ )
78
86
 
79
87
  match self._parameter_type:
80
88
  case LMS_NodeParameterType.STRING:
@@ -84,15 +92,19 @@ class LMS_BaseNode:
84
92
  self._parameter_value = value
85
93
  case _:
86
94
  for i, parameter in enumerate(value):
87
- verify_number_from_datatype(parameter,
88
- self._parameter_type.sliced_datatype[self._parameter_type][i])
95
+ verify_number_from_datatype(
96
+ parameter,
97
+ self._parameter_type.sliced_datatype[self._parameter_type][i],
98
+ )
89
99
 
90
100
  self._parameter_value = value
91
101
 
92
102
  def set_next_node(self, node: LMS_BaseNode | None) -> LMS_BaseNode | None:
93
- """Set the next node for the instance.
103
+ """
104
+ Set the next node for the instance.
94
105
 
95
- :param node: the node object, None for no next node."""
106
+ :param node: the node object, None for no next node.
107
+ """
96
108
  self._next_node = node
97
109
  return node
98
110
 
@@ -129,17 +141,18 @@ class LMS_BaseNode:
129
141
 
130
142
  class LMS_MessageNode(LMS_BaseNode):
131
143
  """
132
- Class that represents a message node. Node utilized in juction with MSBT entries.
144
+ Class that represents a message node. Node utilized in junction with MSBT entries.
133
145
  """
134
146
 
135
- def __init__(self,
136
- id: int | None,
137
- msbt_index: int,
138
- label_index: int,
139
- msbt: MSBT | None = None
140
- ):
147
+ def __init__(
148
+ self,
149
+ node_id: int,
150
+ msbt_index: int,
151
+ label_index: int,
152
+ msbt: MSBT | None = None,
153
+ ):
141
154
  super().__init__(
142
- id,
155
+ node_id,
143
156
  LMS_NodeType.MESSAGE,
144
157
  LMS_NodeParameterType.NONE,
145
158
  None,
@@ -189,14 +202,16 @@ class LMS_BranchNode(LMS_BaseNode):
189
202
  Class that represents a branch node.
190
203
  """
191
204
 
192
- def __init__(self,
193
- id: int,
194
- parameter_type: LMS_NodeParameterType,
195
- parameter_value: LMS_NodeParameter,
196
- condition_id: int,
197
- definition: NodeDefinition | None = None):
205
+ def __init__(
206
+ self,
207
+ node_id,
208
+ parameter_type: LMS_NodeParameterType,
209
+ parameter_value: LMS_NodeParameter,
210
+ condition_id: int,
211
+ definition: NodeDefinition | None = None,
212
+ ):
198
213
  super().__init__(
199
- id,
214
+ node_id,
200
215
  LMS_NodeType.BRANCH,
201
216
  parameter_type,
202
217
  parameter_value,
@@ -212,14 +227,17 @@ class LMS_BranchNode(LMS_BaseNode):
212
227
  return f"{self._definition.name}({ {field.name: field.value for field in self._parameter_value} } {self.id}"
213
228
 
214
229
  def set_next_node(self, node: LMS_BaseNode | None) -> LMS_BaseNode | None:
215
- raise NotImplementedError("Use function set_branch_case to alter the flow of a branch node!")
230
+ raise NotImplementedError(
231
+ "Use function set_branch_case to alter the flow of a branch node!"
232
+ )
216
233
 
217
234
  @classmethod
218
- def new(cls,
235
+ def new(
236
+ cls,
219
237
  parameter_type: LMS_NodeParameterType,
220
238
  parameter_value: LMS_NodeParameter,
221
239
  condition_id: int,
222
- ):
240
+ ):
223
241
  """
224
242
  Instantiates a new branch node.
225
243
 
@@ -230,18 +248,23 @@ class LMS_BranchNode(LMS_BaseNode):
230
248
  return cls(None, parameter_type, parameter_value, condition_id)
231
249
 
232
250
  @classmethod
233
- def new_from_definition(cls,
234
- definition: NodeDefinition,
235
- **parameter_values: str | bool | float | bytes,
236
- ):
251
+ def new_from_definition(
252
+ cls,
253
+ definition: NodeDefinition,
254
+ **parameter_values: str | bool | float | bytes,
255
+ ):
237
256
  """
238
257
  Instantiates a new branch node from a definition.
239
258
 
240
259
  :param definition: the node definition.
241
260
  :param parameter_values: keyword arguments of parameters.
242
261
  """
243
- converted = LMS_FieldMap.from_dict(parameter_values, definition.parameter_definitions)
244
- return cls(None, definition.parameter_type, converted, definition.id)
262
+ converted = LMS_FieldMap.from_dict(
263
+ parameter_values, definition.parameter_definitions
264
+ )
265
+ return cls(
266
+ None, definition.parameter_type, converted, definition.id, definition
267
+ )
245
268
 
246
269
  @property
247
270
  def definition(self) -> NodeDefinition | None:
@@ -252,7 +275,9 @@ class LMS_BranchNode(LMS_BaseNode):
252
275
  def name(self) -> str:
253
276
  """Returns the name of the node. Must have provided a node configuration when reading the file."""
254
277
  if self._definition is None:
255
- raise LMS_Error("Unable to access the name of the node without a definition set!")
278
+ raise LMS_Error(
279
+ "Unable to access the name of the node without a definition set!"
280
+ )
256
281
 
257
282
  return self._definition.name
258
283
 
@@ -271,12 +296,13 @@ class LMS_BranchNode(LMS_BaseNode):
271
296
  """The node branches."""
272
297
  return MappingProxyType(self._branches)
273
298
 
274
- def get_case_options(self, compress_shared_references: bool = False) -> list[
275
- tuple[tuple[int, ...], str, LMS_BaseNode | None]]:
299
+ def get_case_options(
300
+ self, compress_shared_references: bool = False
301
+ ) -> list[tuple[tuple[int, ...], str, LMS_BaseNode | None]]:
276
302
  """
277
303
  Retrieves the cases from this node formatted with the proper messages.
278
304
 
279
- If a definition is provided, and either ``case_format`` or ``case_options`` are provied, the resulting
305
+ If a definition is provided, and either ``case_format`` or ``case_options`` are provided, the resulting
280
306
  message will utilize those values to format the message.
281
307
 
282
308
  :param compress_shared_references: whether to compress shared references into one case.
@@ -287,10 +313,11 @@ class LMS_BranchNode(LMS_BaseNode):
287
313
  case_map.setdefault(branch, []).append(case)
288
314
 
289
315
  if self.definition is not None:
290
-
291
316
  if self.definition.case_options:
292
317
  for case, branch in self._branches.items():
293
- case_message = self.definition.case_options.get(case, f"Case {case}")
318
+ case_message = self.definition.case_options.get(
319
+ case, f"Case {case}"
320
+ )
294
321
 
295
322
  result.append(((case,), case_message, branch))
296
323
 
@@ -299,7 +326,9 @@ class LMS_BranchNode(LMS_BaseNode):
299
326
  if self.definition.case_format is not None:
300
327
  if compress_shared_references:
301
328
  for branch, cases in case_map.items():
302
- case_message = self._format_case_message(merge_shared_cases(cases))
329
+ case_message = self._format_case_message(
330
+ merge_shared_cases(cases)
331
+ )
303
332
  result.append((tuple(cases), case_message, branch))
304
333
  else:
305
334
  for case, branch in self._branches.items():
@@ -310,7 +339,11 @@ class LMS_BranchNode(LMS_BaseNode):
310
339
 
311
340
  if compress_shared_references:
312
341
  for branch, cases in case_map.items():
313
- case_message = f"Case {cases[0]}" if len(cases) == 1 else f"Cases {merge_shared_cases(cases)}"
342
+ case_message = (
343
+ f"Case {cases[0]}"
344
+ if len(cases) == 1
345
+ else f"Cases {merge_shared_cases(cases)}"
346
+ )
314
347
  result.append((tuple(cases), case_message, branch))
315
348
  else:
316
349
  for case, branch in self._branches.items():
@@ -327,7 +360,8 @@ class LMS_BranchNode(LMS_BaseNode):
327
360
  string_map = {}
328
361
  for param_definition in self.definition.parameter_definitions:
329
362
  string_map[param_definition.name] = self.parameter_value[
330
- param_definition.name].value
363
+ param_definition.name
364
+ ].value
331
365
 
332
366
  string_map["case"] = case_prefix
333
367
  return prefix.substitute(**string_map)
@@ -397,18 +431,15 @@ class LMS_EventNode(LMS_BaseNode):
397
431
  Class that represents an event node. Node utilized for in-game actions.
398
432
  """
399
433
 
400
- def __init__(self,
401
- id: int,
402
- parameter_type: LMS_NodeParameterType,
403
- parameter_value: LMS_FieldMap | int | str | tuple[int, ...],
404
- event_id: int,
405
- definition: NodeDefinition | None = None,
406
- ):
407
- super().__init__(
408
- id,
409
- LMS_NodeType.EVENT,
410
- parameter_type,
411
- parameter_value)
434
+ def __init__(
435
+ self,
436
+ node_id: int,
437
+ parameter_type: LMS_NodeParameterType,
438
+ parameter_value: LMS_FieldMap | int | str | tuple[int, ...],
439
+ event_id: int,
440
+ definition: NodeDefinition | None = None,
441
+ ):
442
+ super().__init__(node_id, LMS_NodeType.EVENT, parameter_type, parameter_value)
412
443
 
413
444
  self._event_id = event_id
414
445
  self._definition = definition
@@ -419,7 +450,12 @@ class LMS_EventNode(LMS_BaseNode):
419
450
  return f"{self._definition.name}({ {field.name: field.value for field in self._parameter_value} } {self.id}"
420
451
 
421
452
  @classmethod
422
- def new(cls, parameter_type: LMS_NodeParameterType, parameter_value: int | str | tuple[int, ...], event_id: int):
453
+ def new(
454
+ cls,
455
+ parameter_type: LMS_NodeParameterType,
456
+ parameter_value: int | str | tuple[int, ...],
457
+ event_id: int,
458
+ ):
423
459
  """
424
460
  Instantiates a new event node.
425
461
 
@@ -432,18 +468,23 @@ class LMS_EventNode(LMS_BaseNode):
432
468
  return cls(None, parameter_type, parameter_value, event_id)
433
469
 
434
470
  @classmethod
435
- def new_from_definition(cls,
436
- definition: NodeDefinition,
437
- **parameter_values: str | int | str | tuple[int, ...],
438
- ):
471
+ def new_from_definition(
472
+ cls,
473
+ definition: NodeDefinition,
474
+ **parameter_values: str | int | str | tuple[int, ...],
475
+ ):
439
476
  """
440
477
  Instantiates a new event node from a definition.
441
478
 
442
479
  :param definition: the node definition.
443
480
  :param parameter_values: keyword arguments of parameters.
444
481
  """
445
- converted = LMS_FieldMap.from_dict(parameter_values, definition.parameter_definitions)
446
- return cls(None, definition.parameter_type, converted, definition.id)
482
+ converted = LMS_FieldMap.from_dict(
483
+ parameter_values, definition.parameter_definitions
484
+ )
485
+ return cls(
486
+ None, definition.parameter_type, converted, definition.id, definition
487
+ )
447
488
 
448
489
  @property
449
490
  def definition(self) -> NodeDefinition | None:
@@ -469,12 +510,8 @@ class LMS_EntryNode(LMS_BaseNode):
469
510
  Class that represents an entry node. Node that is at the start of a flowchart.
470
511
  """
471
512
 
472
- def __init__(self, id: int, flowchart_name: str = ""):
473
- super().__init__(
474
- id,
475
- LMS_NodeType.ENTRY,
476
- LMS_NodeParameterType.NONE,
477
- None)
513
+ def __init__(self, node_id: int, flowchart_name: str = ""):
514
+ super().__init__(node_id, LMS_NodeType.ENTRY, LMS_NodeParameterType.NONE, None)
478
515
 
479
516
  self.flowchart_name = flowchart_name
480
517
 
@@ -484,14 +521,10 @@ class LMS_JumpNode(LMS_BaseNode):
484
521
  Class that represents a jump node. Node that jumps to another flowchart.
485
522
  """
486
523
 
487
- def __init__(self, id: int, unknown_short0a: int):
488
- super().__init__(
489
- id,
490
- LMS_NodeType.JUMP,
491
- LMS_NodeParameterType.NONE,
492
- None)
524
+ def __init__(self, node_id: int, unknown_short0a: int, next_entry_point: LMS_EntryNode = None):
525
+ super().__init__(node_id, LMS_NodeType.JUMP, LMS_NodeParameterType.NONE, None)
493
526
 
494
- self.next_flowchart: LMS_EntryNode | None = None
527
+ self.next_flowchart = next_entry_point
495
528
 
496
529
  # TODO: Document this unknown value at 0xA in the node
497
530
  # This value is usually -1 in TL 3DS but is a set value in other games
@@ -505,17 +538,12 @@ class LMS_JumpNode(LMS_BaseNode):
505
538
  :param next_entry_point: the next entry point.
506
539
  :param unknown_short0a: unknown short value. -1 if there is no value.
507
540
  """
508
- node = cls(None, unknown_short0a)
509
- node.next_flowchart = next_entry_point
510
- return node
541
+ return cls(None, unknown_short0a, next_entry_point)
511
542
 
512
543
  @property
513
- def next_flowchart_id(self) -> int:
544
+ def next_flowchart_id(self) -> int | None:
514
545
  """The ID of the next flowchart."""
515
- if self.next_flowchart is not None:
516
- return self.next_flowchart.id
517
-
518
- return self._stream_next_id
546
+ return None if self.next_flowchart is None else self.next_flowchart.id
519
547
 
520
548
  def set_next_node(self, node: LMS_BaseNode | None) -> LMS_BaseNode | None:
521
549
  super().set_next_node(node)
@@ -524,18 +552,24 @@ class LMS_JumpNode(LMS_BaseNode):
524
552
  return node
525
553
 
526
554
 
527
- def verify_parameter_structure(value: int | tuple[int, ...] | str, parameter_type: LMS_NodeParameterType) -> None:
555
+ def verify_parameter_structure(
556
+ value: int | tuple[int, ...] | str, parameter_type: LMS_NodeParameterType
557
+ ) -> None:
528
558
  if parameter_type is LMS_NodeParameterType.NONE:
529
- raise node_exceptions.LMS_NodeInvalidParameterTypeError("There must be a parameter type!")
559
+ raise node_exceptions.LMS_NodeInvalidParameterTypeError(
560
+ "There must be a parameter type!"
561
+ )
530
562
 
531
563
  if not isinstance(value, parameter_type.builtin_type):
532
564
  raise node_exceptions.LMS_NodeInvalidParameterValueError(
533
565
  f"Parameter type {parameter_type} expects type {parameter_type.builtin_type},"
534
- f" but got {type(value)}.")
566
+ f" but got {type(value)}."
567
+ )
535
568
 
536
569
  if isinstance(value, tuple) and len(value) != parameter_type.value_count:
537
570
  raise node_exceptions.LMS_NodeMissingParameterValueError(
538
- f"Parameter type {parameter_type} expects {parameter_type.value_count} parameter values, got {len(value)}!")
571
+ f"Parameter type {parameter_type} expects {parameter_type.value_count} parameter values, got {len(value)}!"
572
+ )
539
573
 
540
574
 
541
575
  def merge_shared_cases(cases: list[int]) -> str: