ndspy.bmg
: BMG (messages)¶
The ndspy.bmg
module provides support for loading and saving BMG files.
In games that use them, BMG files generally contain most or all of the text that can be displayed to the player (apart from text embedded into images). Games contain one or more BMG files for each language they support, and will load the appropriate one depending on the console’s language setting. Each “message” is referenced by index.
Some BMG files – namely, those used in the DS Zelda games – can contain scripts that control game progression in addition to text. ndspy can read and save the file blocks that contain these scripts (FLW1 and FLI1), but decoding and encoding the instructions themselves is very game-specific and therefore out of its scope.
Examples¶
Load a BMG from a ROM and inspect its messages and scripts:
>>> import ndspy.rom, ndspy.bmg
>>> rom = ndspy.rom.NintendoDSRom.fromFile('Zelda - Spirit Tracks.nds')
>>> bmgData = rom.getFileByName('English/Message/castle_town.bmg')
>>> bmg = ndspy.bmg.BMG(bmgData)
>>> print(bmg)
<bmg id=12 (159 messages, 26 scripts)>
>>> print(bmg.messages[2])
What took you so long,
[254:0000]?
Did you keep me waiting
just so you could change
clothes?
>>> bmg.messages[2].stringParts
['What took you so long,\n', Escape(254, bytearray(b'\x00\x00')), '?\n\nDid you keep me waiting\njust so you could change\nclothes?']
>>> bmg.scripts[:5]
[(6553601, 9), (6553602, 140), (6553604, 117), (6553605, 124), (6553609, 183)]
>>> bmg.labels[:5]
[(12, 28), (-1, -1), (12, 0), (12, 68), (12, 73)]
>>> bmg.instructions[:5]
[bytearray(b'\x033\x00\x00e\x00\x00\x00'), bytearray(b'\x03\n\x01\x00\n\x00\r\x00'), bytearray(b'\x033\x02\x00\x03\x00\x00\x00'), bytearray(b'\x033\x03\x00\x02\x00\x00\x00'), bytearray(b'\x033\x04\x00\x04\x00\x00\x00')]
>>>
Load a BMG from a file, edit a message, and save it back into a ROM:
>>> import ndspy.bmg, ndspy.rom
>>> bmg = ndspy.bmg.BMG.fromFile('course.bmg')
>>> print(bmg.messages[15])
Welcome to the secret
Challenge mode. Think you can
reach the goal? If you get
stuck, press START and choose
Return to Map.
>>> bmg.messages[15].stringParts = ["Welcome to the secret\nChallenge mode where it's\nvery easy to softlock."]
>>> print(bmg.messages[15])
Welcome to the secret
Challenge mode where it's
very easy to softlock.
>>> rom = ndspy.rom.NintendoDSRom.fromFile('nsmb.nds')
>>> rom.setFileByName('script/course.bmg', bmg.save())
>>> rom.saveToFile('nsmb_edited.nds')
>>>
Create a new BMG using the cp1252
encoding, and save it to a file:
>>> import ndspy.bmg
>>> message1 = ndspy.bmg.Message(b'', ['Want to save your game?'])
>>> message2 = ndspy.bmg.Message(b'', ["Sure!\nNo thanks."])
>>> bmg = ndspy.bmg.BMG.fromMessages([message1, message2])
>>> bmg.encoding = 'cp1252'
>>> bmg.saveToFile('savegame-en-us.bmg')
>>>
API¶
- class ndspy.bmg.BMG([data, ]*[, id=0])¶
A BMG file.
- Parameters:
- encoding¶
The encoding that should be used for storing strings in the BMG. Choosing an encoding is a trade-off between space efficiency, time efficiency, and the amount and choice of characters that can be encoded.
Valid encodings are
cp1252
,utf-16
,shift-jis
, andutf-8
.See also
fullEncoding
– a read-only mirror of this property that includes endianness information, intended for use withstr.encode()
andbytes.decode()
.- Type:
- Default:
'utf-16'
- fullEncoding¶
A mirror property for
encoding
that takesendianness
into account. This can be used withstr.encode()
orbytes.decode()
, if for some reason you need to encode or decode raw string data matching this BMG’s encoding.The value of this attribute will always be the same as that of
encoding
, unless that attribute has the valueutf-16
. In that case, this property will be eitherutf-16le
orutf-16be
, depending onendianness
.This attribute is read-only.
See also
encoding
– a writable property you can use to modify the BMG’s encoding.- Type:
- Default:
'utf-16le'
- endianness¶
Whether values in the BMG should be stored using big- or little-endian byte order. Since the Nintendo DS is by default a little-endian console, almost every game uses little-endian BMG files. An exception to this is Super Princess Peach.
'<'
and'>'
(representing little-endian and big-endian, respectively) are the only values this attribute is allowed to take.- Type:
- Default:
'<'
- id¶
This BMG’s ID number. In at least some games, every BMG has a unique ID. This makes it possible to refer to specific messages by specifying the desired BMG ID and the message index within that BMG.
- Type:
- Default:
0
- instructions¶
The script instructions in this BMG, if it has a FLW1 block. Instructions will be
bytes
objects by default, but when saving, any object that implements a.save() -> bytes
method is acceptable in place ofbytes
. (This is to let you implement custom classes for instructions if you want to.)
- labels¶
The script instruction labels in this BMG, if it has a FLW1 block.
- scripts¶
The starting instruction indices for each script ID defined in this BMG, if it has a FLI1 block.
See also
ndspy.indexInNamedList()
,ndspy.findInNamedList()
,ndspy.setInNamedList()
– helper functions you can use to find and replace values in this list.
- classmethod fromMessages(messages, [instructions, [labels, [scripts, ]]]*[, id=0])¶
Create a BMG from a list of messages.
- Parameters:
messages – The initial value for the
messages
attribute.instructions – The initial value for the
instructions
attribute.labels – The initial value for the
labels
attribute.scripts – The initial value for the
scripts
attribute.id – The initial value for the
id
attribute.
- Returns:
The BMG object.
- Return type:
- classmethod fromFile(filePath[, ...])¶
Load a BMG from a filesystem file. This is a convenience function.
- Parameters:
filePath (
str
or other path-like object) – The path to the BMG file to open.
Further parameters are the same as those of the default constructor.
- Returns:
The BMG object.
- Return type:
- save()¶
Generate file data representing this BMG.
FLW1 and FLI1 sections will be created only if any script instructions or scripts exist, respectively.
- Returns:
The BMG file data.
- Return type:
- saveToFile(filePath)¶
Generate file data representing this BMG, and save it to a filesystem file. This is a convenience function.
FLW1 and FLI1 sections will be created only if any script instructions or scripts exist, respectively.
- Parameters:
filePath (
str
or other path-like object) – The path to the BMG file to save to.
- class ndspy.bmg.Message([info[, stringParts[, isNull]]])¶
A single message in a BMG file.
BMG messages are more than simple strings; they contain escape sequences that can specify font formatting and allow text to be inserted at runtime. For this reason, the message data is represented as a list of strings and
Escape
s instead of as a string.- Parameters:
info – The initial value for the
info
attribute.stringParts – The initial value of the
stringParts
attribute. If you pass a bare string for this parameter, it will be automatically wrapped in a list for you.isNull – The initial value for the
isNull
attribute.
- info¶
A value containing message metadata, which comes from the BMG’s INF1 block.
The meaning of this value is completely game-dependent, and some games just leave this empty and don’t use it at all.
Warning
While the amount of metadata per message varies from game to game, it’s always required that all messages in a BMG have the same amount of metadata. If you violate this, you’ll experience errors when trying to save!
- Type:
- Default:
b''
- isNull¶
This is
True
if the message is null; that is, if its data offset value in INF1 is 0. A null message should have an emptystringParts
list.Note
Message
s with this attribute set toTrue
are used to represent empty messages instead ofNone
because empty messages can still have non-emptyinfo
values.- Type:
- Default:
False
- stringParts¶
A list of strings and escape sequences that together form the message. Empty strings are allowed but discouraged.
- class Message.Escape([type[, data]])¶
An escape sequence within a BMG message.
Escape sequences have a type and optional parameter data. Currently, the parameter data is left raw and unparsed; this may change in the future.
- Parameters:
- save(encoding)¶
Generate binary data representing this escape sequence.