Welcome to VWF Dialogues! Since you got here by yourself, you most likely already know what this patch does, but let me give you a general overview anyways.
The aim of this patch is to give a useful alternative to SMW’s native text boxes. Unlike Romi's VWF Cutscene Tool (which is great, but has very specific use cases only), this patch was designed around easy event creation, easy customization and compatibility with all kinds of languages. The cost of this is that its useage is slightly more advanced and requires more knowledge. However, as long as you read this manual carefully and are somewhat familiar with custom sprites/custom blocks and Asar patches, you should be fine.
I’ve included a single custom block that utilizes this patch. Originally, I wanted to include more blocks and also a few custom sprites, but I figured that any custom block or custom sprite hosted on SMW Central that displays a native SMW message box should already be compatible with the patch as long as you enable the SMW message box hijack (see section 2). The one block I did include gives a general idea on how to address this patch within your own code. It primarily serves as a sample for people who want to write custom code that interfaces with the patch.
In addition to this, I’ve included a few alternative fonts in case you don’t like the default one. Though keep in mind that the default font features the largest (non-Japanese) character set. If you’re making a hack in any language that isn't English and features any special characters that are not yet in the default font, you will have to draw and add the missing glyphs yourself.
Be aware that by default, this patch applies some modifications to your ROM that seem to be unrelated to the patch itself at first and might have unintended side effects. For example: It automatically expands the ROM's SRAM size to 128 KB since it requires roughly around 20 KB of working RAM that normally aren't available in SMW. For all of those cases, there's usually config options that can be used to disable the respective modifications if desired.
During operation, this patch hides, overwrites, and later restores a large chunk of data in layer 3. It's save to use the patch in levels with layer 3 active, however, the original layer image will become invisible for the duration of the text box, so it might not always be a good idea to do so. The patch also overwrites (and later restores) certain colors from the palette in CGRAM, documented in detail throughout this manual. Because of this, some care needs to be taken on which colors to use inside levels that display text boxes.
Anyways, let’s get started with the first steps of setting up the patch.
In order to make use of this patch, you'll need to have downloaded Asar v1.90
or newer. Older versions of Asar won't work, as the patch was designed specifically around newer Asar features for an improved user experience. As for the patch itself, the very first thing you’ll want to do is to take the entire vwf_dialogues
folder and copy it over to your hack’s local patches
directory so that you can make modifications to it as needed. If you only want to see the patch in action, without configuring anything or adding custom text, you may go ahead and patch vwf_dialogues.asm
to your ROM right now. Otherwise, keep reading.
The patch is structured in a way where all data that is meant to be editable by end users is stored inside the data
subdirectory. The most important file here is called vwfconfig.cfg
and it contains all the major settings for the patch. Open it up in a text editor of your choice to edit them. Pay special attention to all the comments in this file, as they explain what most of the options do. This manual will only explain some of the more important ones.
The first options you will find are !vwf_var_ram
, !vwf_backup_ram
and !vwf_gfx_ram
as well as !vwf_var_ram_sa1
, !vwf_backup_ram_sa1
, !vwf_gfx_ram_sa1
and !vwf_palette_backup_ram_sa1
respectively. The first section of variables is used only in non-SA-1 ROMs, with the second one only being used in SA-1 ROMs. These defines configure which areas of RAM VWF Dialogues will use as their working memory. As an average user, you most likely won't ever have to edit any of these. The default settings should work out of the box. Advanced users, who might need more control over their RAM, can make use of them, going by the comments on each define as a rough guide on what they need and how they're being used.
The only thing worth noting is that without further modifications, a non-SA-1 SMW ROM doesn't provide the amount of free RAM VWF Dialogues need. For this reason, the patch uses SRAM as working memory by default. All of the non-SA-1 address defines mentioned above have their default values pointing to areas in SRAM. The patch automatically applies a SRAM expansion patch to make sure enough SRAM is available. This behavior is controlled via the !vwf_patch_sram_expansion
setting. Advanced users can set it to false
to disable SRAM expansion, but will have to use additional patches that provide alternative areas of free RAM. SA-1 ROMs are unaffected by all this, as the SA-1 chip contains its own large area of RAM, which in the case of SMW is more than enough for this patch to work with.
Now for (occasionally not so) quick explanations on some of the more important settings in the Patch Settings
section:
!vwf_bit_mode
: Setting it to VWF_BitMode.8Bit
will make the patch operate in 8-bit mode, whereas setting it to VWF_BitMode.16Bit
will make it operate in 16-bit mode. In 16-bit mode, every text character and ever text box command use two bytes instead of one, meaning higher free space consumption in the ROM. In this mode, any commands that affect the active font are ignored. Instead, the high byte of each character controls which font to use for that particular character. This mode was originally intended for complex languages like Japanese, but in practice, I don't know if it was ever actively used, and its increased free space requirements might not make it worth using. Therefore, you should consider this option deprecated. It will only remain in the patch until someone can come up with a better solution for these languages.!vwf_hijack_message_box
: When set to true
, the patch hijacks SMW's original message boxes so that activating one will display a VWF Dialogue instead. Here's a few quick examples of how SMW message IDs map onto VWF message IDs (more on message IDs later):
SMW Message ID | VWF Dialogues Message ID |
---|---|
000-1 | 0000 |
000-2 | 0001 |
001-1 | 0002 |
001-2 | 0003 |
... | ... |
007-1 | 000E |
007-2 | 000F |
... | ... |
00F-1 | 001E |
00F-2 | 001F |
... | ... |
13B-1 | 00BE |
13B-2 | 00BF |
false
, SMW message boxes and VWF Dialogues can coexist within the same ROM. In this case, you need VWF Dialogue compatible custom sprites or custom blocks in order to use them. One example of those would be wye's NPC sprites.
!vwf_default_advance_button_mask
, !vwf_select_choice_button_mask
, !vwf_skip_message_button_mask
: These settings control which buttons the patch uses for specific functionality. Check the comments on each setting for details. See %vwf_wait_for_custom_button()
for a list of possible buttons, as well as an explanation on how to specify multiple buttons.!vwf_enable_short_aliases
: When set to true
, the patch defines a number of short aliases for most text commands. For example, you may use !str("Hello!")
or !text("Hello!")
instead of %vwf_text("Hello!")
, !font($01)
instead of %vwf_font($01)
or !press_button
instead of %vwf_wait_for_button()
. These short aliases are intended for convenience and to make VWF Dialogues easier to read in code. It's very unlikely that you'll ever need to set this to false
. The only conceivable scenario would be when you include vwf_dialogues.asm
from within another patch via an incsrc
. In that case, disabling this feature might make sense to reduce the likelihood of naming conflicts occuring. Further details on available short aliases will be provided along with the documentation of each text command.
Settings in the Default Settings
sections define the default values/behaviors of various patch functions. I won't explain them in detail here, because most are either self-explanatory or will become apparent once the respective functions they relate to are explained.
The Data Includes
section becomes relevant once you want to add new assets to the patch. That is: New fonts, new message files, new text box frames etc. New fonts and messages files are added within the vwf_define_data()
macro, whereas the vwf_define_frames()
macro lets you specify the properties of your text box frames (currently just the palettes). Once again, these settings should become more apparent when their respective functionality is explained.
This covers all of the patch's basic setup. More advanced functionality will be explained in detail later on. Once you're done configuring vwfconfig.cfg
, you may go ahead and use Asar to patch vwf_dialogues.asm
to your ROM. If everything was set up correctly, Asar's output should look roughly like this:
If that’s what you get, then the patch was applied successfully. Most of these outputs are just for debugging purposes. You can safely ignore them, unless you're modifying the patch itself or coding some advanced feature that makes use of it.
In this section I'll explain all the functionality that is intended for average users of this patch. This includes setting up resources and writing actual message boxes.
VWF Dialogues are designed to be very customizable. This not only includes the dialogue text itself, but also the design of the text box containing it. It's possible to customize all text box frames and backgrounds, as well as all fonts, to your liking, or add new ones entirely. The patch can even switch between them at run-time (though for text box frames and backgrounds, this is only technically supported - no feature is currently provided that makes use of this possibility, so if you want it in your hack, you currently need to write custom code for it). In order to make the most out of these features, you'll have to understand the different types of resources the patch uses, all contained within the
Editing any of these graphics requires a tile editor that supports the 2BPP GB
graphics format. In theory, any such
tile editor will do, but if you plan to edit (or create) fonts, I highly recommend using a recent version of YY-CHR
.
You'll want to be using at least v0.99
, as older versions lack some features that make editing fonts practicable. For the
purpose of this manual, I will assume you're using YY-CHR and will reference it where appropriate.
For starters, let's look at background graphics, which are by far the simplest graphics format. Open data/gfx/vwfbgpatterns.bin
in
YY-CHR and set the graphics format to 2BPP GB
. After tweaking palettes a little, you should see something similiar to this:
Here's what you need to know about background graphics:
vwfbgpatterns.bin
must be divisible by 16. That's exactly the size of one 8x8 tiles in 2BPP GB graphics format in YY-CHR.!vwf_default_text_box_bg_color
in data/vwfconfig.cfg
. In theory, players can override this default setting in-game, but the patch doesn't provide any built-in menu for doing so. Additionally, the setting can be overridden by a message header.!vwf_default_text_box_bg_pattern
in data/vwfconfig.cfg
. A value of $00
represents the first tile in vwfbgpatterns.bin
, a value of $01
the second tile and so forth. In theory, players can override this default setting in-game, but the patch doesn't provide any built-in menu for doing so. Additionally, the setting can be overridden by a message header.$01
of a palette for BG patterns (that is "the second color from left" in a typical 2BPP four-color palette).
The reason for this is that colors $02
and $03
are reserved for fonts.vwfbgpatterns.bin
by 16 bytes (you can use a hex editor for this) and then draw the new pattern into the newly added empty space in YY-CHR.
In order to edit text box frames, open up data/gfx/vwfframes.bin
in YY-CHR and set the graphics format to 2BPP GB
.
Tweak the palettes to your liking, and you should see something like this:
Here's a quick rundown of everything you need to know about text box frames:
vwfframes.bin
make up one text box style. Here is an explanation on how the different tiles of a style are placed to compose a text box:
vwfframes.bin
must be divisible by 144. That's exactly the size of nine 8x8 tile in 2BPP GB graphics format in YY-CHR.!vwf_default_text_box_frame
in data/vwfconfig.cfg
. A value of $00
represents the first nine tiles in vwfframes.bin
, a value of $01
the second nine tiles and so forth. In theory, players can override this default setting in-game, but the patch doesn't provide any built-in menu for doing so. Additionally, the setting can be overridden by a message header.!vwf_frame_palette
in data/vwfconfig.cfg
dictates which section of CGRAM text box frames use for their palette. To give you a better idea of what this means: This define controls which parts of the Lunar Magic palette get overwritten by the text box frame palette while a VWF text box is on screen. Usable values are $00
to $07
. This image illustrates how these values map onto the palette from Lunar Magic:
vwf_define_frames()
macro in vwfconfig.cfg
. Here's a quick example for the format:
macro vwf_define_frames()
; Frame $00
db %00000000,%00000000
dw rgb_15(00, 00, 00), rgb_15(31, 31, 31), rgb_15(00, 00, 00)
; Frame $01
db %00000000,%00000000
dw rgb_15(22, 18, 02), rgb_15(13, 07, 01), rgb_15(04, 02, 00)
; ...
endmacro
Here, each pair of db/dw
represents one text box frame (the order corresponding to the order of frames in vwfframes.bin
). The first line with the db
is reserved for future use and currently unused. Fill it with zeros. The second line defines which colors to write into slots $01
, $02
and $03
of the palette defined by !vwf_frame_palette
. In other words: This line controls the second, third and fourth color of that palette. You can use the rgb_15()
macro to make defining colors a bit easier. The three arguments of this macro represent the R
, G
and B
values of the color, each ranging from 0
to 31
, effectively giving you a 15-bit color palette range.
vwfframes.bin
by 144 bytes (you can use a hex editor for this) and then draw the new text box frame tiles into the newly added empty space in YY-CHR. Add the palette for this new frame to the bottom of vwf_define_frames()
.
Font are the most complex type of resource supported by the patch. It already comes pre-packaged with four of them ready to use (one with support for Japanese text). If you do want to make your own fonts, there's three different types of resource files you need to know about: A .bin file containing character glyph graphics, an .asm file containing the widths of each character, and a second .asm file containing character-to-glyph mappings. You can find all the pre-packaged fonts in data/fonts
. Each folder here contains a vwffont.bin
containing the graphics and a vwffont.asm
containing the character widths. The only exception is the terra_j font, which contains multiple .bin files, because there isn't enough space in a single font to contain the entire Japanese character set. For all pre-packaged fonts, data/fonts/vwftable.asm
can be used as the character-to-glyph mapping file. Here's a list of things to be aware of when working with fonts:
2BPP GB
and also set the pattern to FC/NES x16
. After tweaking the palettes a little, you should se something like this:
$02
and $03
of a palette may be used for the glyphs (that is, the third and fourth color of each palette). Color $01, as mentioned previously, is already reserved for the background pattern. Generally, you'll want to use color $02 for the letters and color $03 for their outlines or drop shadows.;Char00to0F:
db $07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$06,$06
;Char10to1F:
db $07,$07,$05,$07,$08,$06,$09,$08,$07,$07,$07,$07,$06,$07,$07,$07
;...
Each number here represents the pixel width of one glyph from the respective .bin file. The first number is for the first glyph in the .bin file, the second number for the second glyph and so forth. The patch will look up those numbers and use them to determine how many columns of each glyph tile should be rendered, thus creating its variable width text.code/scripts/generate_widths.py
which attempts to generate them for you. Just drop your .bin file onto the script and you should get the width table .asm file as an output. A valid installation of Python 2.7 or Python 3.0 is required for this. Note that you might still have to manually touch up the width table a little bit. For example, I personally find it useful to give all digits in a font a unified width, which makes it easier to create clean layouts with them. You can also use the script to generate a fixed-width table by running it from the command line and passing -f
as an argument. That will use the widest glyph from the font as the width of all characters.'0' = $00
'1' = $01
'2' = $02
'3' = $03
'4' = $04
'5' = $05
'6' = $06
'7' = $07
'8' = $08
'9' = $09
'A' = $0A
'B' = $0B
'C' = $0C
'D' = $0D
'E' = $0E
'F' = $0F
'G' = $10
'H' = $11
'I' = $12
; ...
Given the mapping from the example above, the command %vwf_text("ABC")
would render tiles $0A
, $0B
and $0C
from the current font's .bin file to the text box. In Asar v1.90, only ASCII character mappings are supported, but starting with Asar v2.0, any single-codepoint Unicode characters can be mapped. That makes it possible to even use a mapping for Japanese text (this will likely require running in 16-bit mode). Example:
'あ' = $0100
'い' = $0101
'う' = $0102
'え' = $0103
'お' = $0104
'か' = $0105
'き' = $0106
'く' = $0107
'け' = $0108
; ...
The vwftable.asm
file that is included by default already includes a conditional to automatically add mappings for Japanese characters when Asar v2.0 or newer is used. Note that at this point in time, the patch does not automatically switch mappings when you switch fonts. You need to do so automatically by using the cleartable
and incsrc
commands, like so:
cleartable
incsrc "vwftable_for_my_font.asm"
Having to do this can be avoided by making all your fonts compatible with the same mapping file.vwf_define_data()
macro in vwfconfig.cfg
:
%vwf_add_font("data/fonts/som/vwffont.bin", "data/fonts/som/vwffont.asm", "data/fonts/vwftable.asm")
Where the first argument is the graphics .bin file, the second argument is the width table .asm file, and the third argument is the character-to-glyph mapping .asm file. The order of %vwf_add_font()
calls inside the vwf_define_data()
macro determines the ID of each font. The first %vwf_add_font() will be font $00
, the second %vwf_add_font() will be $01
and so forth. It is crucial that the character-to-glyph mapping file contains at least valid mappings for the characters 0 1 2 3 4 5 6 7 8 9 A B C D E F
for that respective font, because the functionality of all number-related text functions depends on it.
Message files are probably this patch's most important resource, as they contain its actual guts: the messages themselves. The patch comes pre-packaged with a single message file at data/vwfmessages.asm
. It's unlikely you'll ever have to create a new one. For 99% of use cases, just editing the existing file will be sufficient. There's only a few potential scenarios that I can think of where creating additional message files might be useful or even required:
vwf_define_data()
macro in vwfconfig.cfg
:
%vwf_add_messages("data/vwfmessages.asm", "data/fonts/vwftable.asm")
Where the first argument is the path to the message file itself and the second argument is the path to the default character-to-glyph mapping file to use for it (see section Fonts for details).
Adding new messages to this patch is as simple as adding the following lines to one of your message files (usually data/vwfmessages.asm
):
%vwf_message_start(0000)
%vwf_header()
; Message contents go here.
%vwf_message_end()
The number passed to %vwf_message_start()
is the ID of your message. This is what other patches/sprites/blocks use to tell this patch which message to display. It's a four-digit hexadecimal number and must be unique for every message. The easiest way to assure this is to just start from 0000
and increment the ID by 1 for every message you add. In theory, the ID can be any value from 0000
to FFFF
, but in practice, because the patch uses 24-bit pointers for messages and they all need to fit into a single bank, the actual maximum is somewhere around 2AAA
. This shouldn't be an issue for average users, as this still means the patch supports up to 10922 individual messages.
One thing to be aware of when assigning message IDs is that the patch will automatically generate pointers for every single message. Since the pointers are stored as a simple table that is looked up via the message ID, whenever there's a gap in message IDs the patch needs to fill in that gap via dummy pointers. So if you have a message file that only contains two messages with IDs 0000
and 0100
, then the patch will generate dummy pointers for all IDs from 0001
to 00FF
. Since this wastes free space, it is advised to avoid gaps in message IDs altogether. The patch will print a warning once it detects a certain number of gaps.
The %vwf_header()
always needs to be the first line right after the %vwf_message_start()
. This line allows you to override text box settings by passing different arguments to the %vwf_header()
macro. More details on that in section Header Settings.
After the header is where you add your text commands. Without any commands, all you'll get is an empty text box. See section Text Commands for a full list of what commands are available.
Putting everything together, here is a simple example of what a full text box might look like:
%vwf_message_start(001A)
%vwf_header(x_pos(10), y_pos(10), width(5), height(1), text_alignment(TextAlignment.Centered))
!str("What's up, Mario? Hope you have a nice day!")
%vwf_message_end()
When defining your own text boxes, the very first thing you'll want to look at are the header settings. These settings define a number of general properties of your text box, like position, size, sound effects and more. The way this works is by passing optional arguments as function calls to the %vwf_header()
macro in your message. Here's an example:
%vwf_header(vwf_x_pos(0), vwf_y_pos(0), vwf_width(15), vwf_height(13))
When any argument is omitted, its value will be pulled from the default values defined in vwfconfig.cfg
. For example, when you omit the vwf_x_pos
argument, the patch will use the !vwf_default_x_pos
define in its place. Providing no arguments at all will automatically replace the header by a shared header containing all the default values, reducing the total size of your message.
Header arguments, like text commands, support short aliases via the !vwf_enable_short_aliases
setting. When enabled, the vwf_
prefix on all arguments can be omitted. Example:
%vwf_header(x_pos(0), y_pos(0), width(15), height(13))
What follows is a list of all header arguments along with a brief explanation.
Shared headers allow you to define a header in one message and then reuse it in arbitrarily many other other messages. This has a few key advantages:
%vwf_header()
line in one of your mesages by
%vwf_shared_header(message_id)
where message_id
is the ID of the message whose header you want to reuse. Here is a complete example:
%vwf_message_start(001B)
%vwf_shared_header(001A)
!str("Hey, Mario! Nice to see you again!")
%vwf_message_end()
Note that you can only point a shared header to a message that has a physical header itself (aka a message that uses %vwf_header()
instead of %vwf_shared_header()
). While it's technically possible to point shared headers to other shared headers, there's very little use to it over pointing to the origin header directly, and it only runs the risk of causing stack overflows or infinite recursion at run-time, so the patch prevents this use case entirely.
When you try to point a shared header to a message that doesn't have a physical header, you will get an error message similar to the following:
error: (Elabel_not_found): Label 'PhysicalHeader001A' wasn't found. [dw $001A+(PhysicalHeader001A-PhysicalHeader001A)]
The error message is a bit cryptic, because it abuses Asar functionality to work at all. In this example case, it's saying that message 001A
doesn't have a physical header, so it's impossible to use it as a shared header via %vwf_shared_header(001A)
. Fixing this error requires giving either message (001A
or the message referencing it) a physical header.
As a special case, using %vwf_header()
in a message without any arguments will automatically turn the header into a shared header that points to a built-in message containing all your default header settings. This greatly reduces the size of all messages that only use default settings. If you want to use one of your own headers as a shared header, it thus needs to contain at least a single argument to override any header setting and prevent this automatic replacement.
vwf_x_pos()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
x_pos
of 1 moves the text box one 8x8 tile (=8 pixels) the right, an x_pos of 2 two 8x8 tiles etc. Depending on the size of the text box, the patch might automatically clamp this value down to prevent it from going beyond the screen border.
vwf_y_pos()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
y_pos
of 1 moves the text box one 8x8 tile (=8 pixels) down, a y_pos of 2 two 8x8 tiles etc. Depending on the size of the text box, the patch might automatically clamp this value down to prevent it from going beyond the screen border.
vwf_width()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_height()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_text_box_bg_pattern()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_text_box_bg_color()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_text_box_frame()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_box_animation()
Usage |
|
||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Short Aliases |
|
||||||||||||
Parameters |
|
vwf_font()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_add_font()
calls in your vwfconfig.cfg
, starting at 0
. This setting is ignored when running in 16-bit mode. Note that this setting does not affect the active character mapping table, so if you require different tables for different fonts, you'll have to load them manually via an incsrc
. See Fonts for details.
vwf_text_palette()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
!vwf_frame_palette
in vwfconfig.cfg
. Doing so would lead to undefined behavior.
vwf_text_color()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_text_palette()
. You can use the rgb_15()
helper function to specify the color via its RGB components.
vwf_outline_color()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_text_palette()
. You can use the rgb_15()
helper function to specify the color via its RGB components.
vwf_space_width()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_set_text_palette()
command works. It can only modify the text palette per 8x8 tile, not per character or word. Using a wide enough space here assures that if you use this command to recolor a word surrounded by spaces, the palette change will never cut into tiles of surrounding words in a visible way.
vwf_text_margin()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_text_alignment()
Usage |
|
||||||
---|---|---|---|---|---|---|---|
Short Aliases |
|
||||||
Parameters |
|
vwf_freeze_game()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
Specifies whether gameplay should freeze while the text box is open. For non-SA-1 ROMs, the general recommendation is to always set this to true, as the patch is too demanding for them to run gameplay at the same time, leading to slowdown. It's recommended to use an SA-1 ROM instead if you want to make use of this feature. It should be fast enough for a dialog not to slow down gameplay. You can see it in action in this ancient video.
If you absolutely must use a non-SA-1 ROM, here's a few tips for lessening the impact of slowdown:
VWF_BoxAnimation.None
, which disables the text box background entirely and makes the patch skip a good chunk of code.Whenever you do allow gameplay during text boxes, you should try to make sure they close by the time any level transition occurs (like from entering a pipe, touching a goal post or dying). The patch does try to automatically close text boxes to prevent glitches, but there's always a chance for oversights with this feature. You're on the safe side when you only use your text boxes in predictable environments.
vwf_text_speed()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
0
represents the fastest text speed, a value of 63
the slowest.
vwf_auto_wait()
Usage |
|
||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
Short Aliases |
|
||||||||||
Parameters |
|
WaitFrames
setting was 2
and the maximum was 255
, whereas in current versions the supported range is 1
to 255
frames. Keep this in mind if you plan to port text data from an older version to a newer one. Slight adjustments to text box headers might be necessary (you might have to add a frame to all auto-wait settings if frame-perfect timing matters).
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_enable_skipping()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_set_skip_location()
text command within your text box, which will set the skip location to the location of the command. NOTE: This can be done only once per text box. Using the command multiple times within the same text box will generate an error.
vwf_enable_sfx()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_letter_sound()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_wait_sound()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_cursor_sound()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_display_options()
command moves.
vwf_continue_sound()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_display_options()
command.
vwf_enable_message_asm()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
With everything else out of the way, it's time to finally start defining the actual contents of our text boxes. This is done by inserting text commands between a message's %vwf_header()
and %vwf_message_end()
(see section Message Format for details). These text commands usually take the form of macro calls, but can also be defines when using short aliases. Here's a simple example of a message containing some text commands:
%vwf_message_start(0000)
%vwf_header()
; One command per line
%vwf_text("You can write each text command on a separate line like this.")
%vwf_wait_for_button()
%vwf_clear()
; Multiple commands on a single line
%vwf_text("But you can also chain them together on one line via a colon.") : %vwf_wait_for_button() : %vwf_clear()
; These two lines are equivalent, but one uses short aliases, the other doesn't.
%vwf_text("Hello?") : %vwf_wait_for_button() : %vwf_line_break()
!str("Hello?") : !press_button : !n
%vwf_message_end()
Some text commands have parameters tagged as "(optional)
". This means the respective parameter can be omitted, in which case a default value will be used.
%vwf_text()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
$E6
to $FF
when running in 8-bit mode, or $FFE6
to $FFFF
when running in 16-bit mode. Trying to print any character with this command that maps onto one of those values (except for $FE
, which represents the vwf_space() command) will likely result in bugs. Currently, these characters need to be escaped manually using the vwf_char() command. A future version of the patch might automate this process if possible.
%vwf_char()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_char_at_address()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_space()
Usage |
|
---|---|
Short Aliases |
|
%vwf_line_break()
for details. Note that there's no reason to ever use this command under normal circumstances. The default character to glyph mapping tables included with the patch already map the space character to the %vwf_space()
command, so just using the %vwf_text()
command is sufficient and will produce automatic line breaks.
%vwf_non_breaking_space()
Usage |
|
---|---|
Short Aliases |
|
%vwf_char(!vwf_nbsp_char)
, with !vwf_nbsp_char = $00FE
. Basically, this prints character $00FE
(which usually maps to a space) to the text box as a raw character. The purpose of this command is to print a space without invoking the word wrapping processor, similar to the
HTML entity. Useful when you want to prevent two words from being separated and ending up on two different lines. For example, if you want the name "Super Mario" to always appear on a single line, you can assure that by using this command in place of the space.
%vwf_decimal()
Usage |
|
||||||
---|---|---|---|---|---|---|---|
Short Aliases |
|
||||||
Parameters |
|
address_size
parameter, the address is either interpreted to be an 8-bit
number (using a single byte) or a 16-bit
number (using two bytes). When the leading_zeros
parameter is set to true
, leading zeros will be printed. Up to three total places for 8-bit numbers and up to five for 16-bit numbers.
%vwf_hex()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_set_font()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_font()
header setting apply.
%vwf_char_offset()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
$0000
). Here's a simple example:
%vwf_char_offset($0010)
%vwf_char($01) : %vwf_char($02) : %vwf_char($03)
Normally, you would expect this to print characters $01
, $02
and $03
to the text box, but due to the %vwf_char_offset($0010)
, what actually gets printed are characters $11
, $12
and $13
.$00
to $03
(each containing $100
glyphs) and another occupying font slots $04
to $07
. Running the patch in 16-bit mode, you could do something like this:
%vwf_text("Hello world!")
%vwf_char_offset($0400)
%vwf_text("Hello world!")
The first "Hello world!" here would be printed with glyphs starting at font slot $00
, whereas the second "Hello world!" would be printed with glyphs starting at font slot $04
, making it possible to print each of the strings in a different font. In 8-bit mode, this usually wouldn't be necessary, since you could just use %vwf_set_font($04)
instead.
%vwf_change_colors()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
start_color_no
, by passing in a list of color values. The main purpose of this is to follow it up with a call to %vwf_set_text_palette()
to effectively change the text color. Since this command modifies the active palette, using it carelessly will lead to unintended side effects (randomly changing colors on screen). Make sure to only ever overwrite colors that aren't currently visible anywhere on the screen. Once a text box closes, the patch will restore the original state of the palette from before opening any text box. See %vwf_get_color_index_2bpp() for help with specifying start_color_no
.
%vwf_set_text_palette()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
$00
will give you the first four colors of Lunar Magic's palette, a value of $01
the second four colors and so on. Also overwrites color $01
of the selected palette (aka the second color) with the currently active text box background color, so the same restrictions apply as for %vwf_change_colors()
(in other words, make sure not to overwrite any color currently visible on screen). This command is meant to be paired with %vwf_change_colors()
to effectively switch the active text color. Also see vwf_space_width()
for some additional pitfalls related to this command.
%vwf_set_text_color()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_change_colors()
and %vwf_set_text_palette()
and lets you switch the active text color more easily. It sets the text color (color $02
) of palette palette_index
to color text_color_value
, sets the outline color (color $03
) to black, sets the background color (color $01
) to the currently active one, and then automatically switches the active text palette to palette_index
. All restrictions that apply to %vwf_change_colors()
and %vwf_set_text_palette()
also apply to this command.
%vwf_line_break()
Usage |
|
---|---|
Short Aliases |
|
vwf_auto_wait()
header setting dictates how to proceed before automatically clearing the text box.
%vwf_clear()
Usage |
|
---|---|
Short Aliases |
|
%vwf_set_skip_location()
Usage |
|
---|---|
Short Aliases |
|
vwf_enable_skipping()
header setting was set to true
, this text command can be used to mark the destination of skipping. When pressing the Start button, the text box will immediately jump to the location in the message where this command was used. Can only be used once per message.
%vwf_close()
Usage |
|
---|---|
Short Aliases |
|
%vwf_message_end()
already does so automatically. You only need to use it when you want to close a text box early (for example: from a specific choice of a %vwf_display_options()
).
Usage |
|
---|---|
Short Aliases |
|
!vwf_default_advance_button_mask
setting).
%vwf_wait_for_a()
Usage |
|
---|---|
Short Aliases |
|
%vwf_wait_for_button()
or %vwf_wait_for_custom_button()
instead.
Usage |
|
||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Short Aliases |
|
||||||||||||||||||||||||||
Parameters |
|
button_mask
parameter. Multiple buttons can be specified as a bit-mask by using the |
(or) operator. Example:
%vwf_wait_for_custom_button(VWF_ControllerButton.A|VWF_ControllerButton.B)
%vwf_wait_frames()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
num_frames + 1
frames.
%vwf_set_text_speed()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_freeze()
Usage |
|
---|---|
Short Aliases |
|
%vwf_set_text_pointer()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
vwf_inline()
for how to define message data outside the scope of a message.
%vwf_display_message()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
show_open_anim
is set to false
, certain text box settings (such as selected frame, selected background or selected background color) won't be reloaded. Set it to true
if you require them to be reloaded. You can use the VWF_BoxAnimation.Instant
animation style on the new text box to make it appear as though it still appears instantaneously.
%vwf_display_options()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_text()
calls, or multiple text commands wrapped into %vwf_wrap()
calls. Use the %vwf_set_option_location()
command to set the target locations for each option (there must be at least one call to %vwf_set_option_location()
per option passed to %vwf_display_options()
). The !vwf_default_cursor_space
setting in vwfconfig.cfg
lets you control the margin in pixels between the cursor and the option text. The !vwf_default_cursor_char
setting determines what character to use as the cursor. If you need to override either setting for just a single use of %vwf_display_options()
, you can do so by overwriting the respective setting before calling the command and then restoring it to its original value afterwards. Please avoid putting any text commands into option texts that modify the text flow. Generally speaking, using commands from the Text Output, Text Properties or Text Macros categories should be fine, but using anything else will lead to undefined behavior.
%vwf_set_option_location()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_display_options()
command. Upon selecting that choice, the text box will continue at the location where %vwf_set_option_location()
was called. The options_label_name
parameter must be identical to the unique_label_name
passed to %vwf_display_options()
. The option_id
parameter specifies which choice you're setting the location for, starting at 0
. So if you had the following %vwf_display_options()
call
%vwf_display_options(MyOptions, %vwf_text("One"), %vwf_text("Two"), %vwf_text("Three"))
then calling
%vwf_set_option_location(MyOptions, 1)
would set the target location of the Two
choice.
%vwf_play_bgm()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
bgm_id
to $1DFB
. See SMW Central RAM Map for details.
%vwf_setup_teleport_to_level()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_setup_teleport_to_secondary_entrance()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_setup_exit_to_overworld()
Usage |
|
||||||||
---|---|---|---|---|---|---|---|---|---|
Short Aliases |
|
||||||||
Parameters |
|
%vwf_execute_text_macro()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_execute_text_macro_by_indexed_group()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_execute_buffered_text_macro()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
%vwf_execute_subroutine()
Usage |
|
---|---|
Short Aliases |
|
Parameters |
|
jsl
, so it needs to end in an rtl
. Feel free to insert your custom routines directly into vwfmessages.asm
(but always outside of a %vwf_message_start()
/%vwf_message_end()
pair, as the patch might interpret it as text data otherwise). NOTE: The routine is only executed once text rendering itself arrives at the location of this command, not whenever the word wrapping processor sees it. This means running any code inside the routine that will affect what text is being rendered (such as modifying the current text pointer) can lead to unexpected results (such as word wrapping in weird places), as the text being rendered might not match with what the word wrapping processor has previously seen.
This section covers functionality that doesn't really fit into any other category, but can be useful in certain situations. Some helper functions can be used with both header arguments and text commands, others may be be useful when writing code for VWF dialogues. Read the description on each command for hints on how they might be useful.
rgb_15()
Usage |
|
---|---|
Parameters |
|
red
, green
and blue
color channels.
rgb_15_from_24()
Usage |
|
---|---|
Parameters |
|
red
, green
and blue
color channels as 8-bit values. This is useful since RGB24 (which uses 8-bit color channels) is the most common color format around today, so you can easily take color values from existing apps (like Microsoft Paint) and copy them directly into the patch. Note that not all RGB24 color values are expressible in RGB15, so in a lot of cases, the function will pick the closest matching color.
rgb_15_from_f()
Usage |
|
---|---|
Parameters |
|
red
, green
and blue
color channels as decimal values. This is useful in cases where you want to express color channels as a percentage. The function will pick the closest matching color expressible in RGB15 for the given color channel values.
vwf_get_color_index_2bpp()
Usage |
|
||||||
---|---|---|---|---|---|---|---|
Short Aliases |
|
||||||
Parameters |
|
%vwf_change_colors()
. The palette_index
parameters of this function matches the palette_index
parameter of %vwf_set_text_palette()
.
%vwf_wrap()
Usage |
|
---|---|
Parameters |
|
%vwf_display_options()
. Usage example:
!edit_pal(!text_color_5, rgb_15(6, 31, 6), rgb_15(0, 0, 0))
!options(SampleOptions,
%vwf_wrap( !set_pal($05), !char($00AC), !reset_color, !str(" Bullet Point 1") ),
%vwf_wrap( !set_pal($05), !char($00AC), !reset_color, !str(" Bullet Point 2") ),
%vwf_wrap( !set_pal($05), !char($00AC), !reset_color, !str(" Bullet Point 3") ),
%vwf_wrap( !set_pal($05), !char($00AC), !reset_color, !str(" Bullet Point 4") )
)
%vwf_inline()
Usage |
|
---|---|
Parameters |
|
%vwf_message_start()
/%vwf_message_end()
pair. However, when writing custom code for VWF Dialogues, there can be valid reasons for why you'd need to use commands outside of messages (for example: to create Buffered Text Macros). Wrapping commands into a %vwf_inline()
call allows you to do so, by disabling the respective errors.
remap_ram()
Usage |
|
---|---|
Parameters |
|
; This will turn into $7E0DBF in a regular ROM, but into $003DBF in an SA-1 ROM.
!str("Mario's current coins: ") : !dec(remap_ram($7E0DBF), AddressSize.8Bit, true) : !new_line
Text macros are a system for reusing text pieces (like names or commonly used phrases) in multiple places. This has a couple of advantages:
Regular text macros are the simplest form of text macros. They simply wrap an arbitrary number of text commands into a single call. Use the %vwf_register_text_macro()
macro to define a regular text macro.
%vwf_register_text_macro()
Usage |
|
---|---|
Parameters |
|
unique_macro_name
to %vwf_execute_text_macro()
to execute this macro in messages.
%vwf_register_text_macro("Mario", !str("Mario") )
%vwf_register_text_macro("Luigi", !str("Luigi") )
%vwf_message_start(0050) ; Message 104-1
%vwf_header()
!str("My name is ") : !macro("Mario") : !str(" ") : !macro("Mario")
!str(", and this here is my brother ") : !macro("Luigi") : !str(" ") : !macro("Mario") : !str("!")
!press_button
%vwf_message_end()
Text macros can also be nested. In other words, you can register text macros that call other, previously registered text macros, which makes them really flexible and powerful.
Text macro groups are a mechanism for assigning previously registered text macros to groups that can then be indexed via RAM addresses. Put another way: Text macro groups provide a means of turning the value of a RAM address into a text string representing that value. There's many potential use cases for this. A very intuitive one would be some kind of inventory system. Imagine your game featured an inventory where the player could collect different items. In RAM, the items would probably be stored as some kind of table, with one byte specifying the type of each item. You could then use text macro groups to turn the value of said byte into the name of that item. To register a text macro group, use the %vwf_start_text_macro_group()
and %vwf_end_text_macro_group()
macros and insert one or more calls to %vwf_add_text_macro_to_group()
inbetween them.
%vwf_start_text_macro_group()
Usage |
|
---|---|
Parameters |
|
%vwf_add_text_macro_to_group()
macro to add text macros to this group. Pass the unique_group_name
specified here to %vwf_execute_text_macro_by_indexed_group()
to index this group in messages.
%vwf_add_text_macro_to_group()
Usage |
|
---|---|
Parameters |
|
%vwf_add_text_macro_to_group()
calls. The first call will be index 0
, the second call index 1
and so on.
%vwf_end_text_macro_group()
Usage |
|
---|
; Registers text macros for Mario's and Luigi's names
%vwf_register_text_macro("MarioName", !str("Mario") )
%vwf_register_text_macro("LuigiName", !str("Luigi") )
; Registers text macros for the different power-up states of Mario and Luigi
%vwf_register_text_macro("SmallPowerup", !str("Small") )
%vwf_register_text_macro("SuperPowerup", !str("Super") )
%vwf_register_text_macro("CapePowerup", !str("Cape") )
%vwf_register_text_macro("FirePowerup", !str("Fire") )
; Adds Mario's and Luigi's names to a new "PlayerName" group.
%vwf_start_text_macro_group("PlayerName")
%vwf_add_text_macro_to_group("MarioName")
%vwf_add_text_macro_to_group("LuigiName")
%vwf_end_text_macro_group()
; Adds the different powerup states to a new "PlayerPowerup" group.
%vwf_start_text_macro_group("PlayerPowerup")
%vwf_add_text_macro_to_group("SmallPowerup")
%vwf_add_text_macro_to_group("SuperPowerup")
%vwf_add_text_macro_to_group("CapePowerup")
%vwf_add_text_macro_to_group("FirePowerup")
%vwf_end_text_macro_group()
; Registers a convenience macro for indexing the "PlayerName" group.
; $7E0DB3 contains the current player ID.
; 0: Mario
; 1: Luigi
; See SMW Central RAM map for details.
%vwf_register_text_macro("CurrentPlayer", !macro_group("PlayerName", remap_ram($7E0DB3)))
; Registers a convenience macro for indexing both the "PlayerName" and the "PlayerPowerup" groups.
; $7E0019 contains the power-up state of the current player.
; 0: None
; 1: Mushroom
; 2: Cape
; 3: Fire Flower
; See SMW Central RAM map for details.
%vwf_register_text_macro("CurrentPlayerWithPowerup", !macro_group("PlayerPowerup", remap_ram($7E0019)), !nbsp, !macro("CurrentPlayer"))
%vwf_message_start(0050) ; Message 104-1
%vwf_header()
; Let's assume you're currently playing as Luigi and have a Cape power-up. Then this message will read:
; "Hey, aren't you Luigi? Cape Luigi, to be specific."
!str("Hey, aren't you ") : !macro("CurrentPlayer") : !str("? ") : !macro("CurrentPlayerWithPowerup") : !str(", to be specific.")
!press_button
%vwf_message_end()
Buffered text macros function similarly to regular text macros, with the main difference being that they are constructed at runtime and not patched into the ROM. This makes it possible to have dynamic text macros in the game. A classical example for this would be a player name generated from a name entry screen. The name could be stored in a buffered text macro and then displayed via the %vwf_execute_buffered_text_macro()
text command.
Consider this an advanced feature, as it requires some coding knowledge to make meaningful use of. To register buffered text macros, call the shared routines VWF_ResetBufferedTextMacros
, VWF_BeginBufferedTextMacro
, VWF_AddToBufferedTextMacro
and VWF_EndBufferedTextMacro
(their usage is documented in code right next to them, so I'll skip a detailed documentation here).
See Shared Routines for details.
This section is intended for advanced users only. That is, people who want to write custom resources (sprites, blocks, patches etc.) that make use of the patch or who want to use the patch in some complex ways. In other words: If you aren't a coder, you can most likely just ignore this entire section.
While the VWF Dialogues patch provides a pretty powerful text system for your hack, the only built-in method of actually opening text boxes is via the message box hijack. However, not everyone wants to override SMW's default message boxes with VWF text boxes, and some people may want to display VWF text boxes from other places, like interactive NPCs or story events. In other words: There's a number of good reasons for wanting to open VWF text boxes from your custom code, and luckily, the patch makes this very easy to do.
If you're just an end user, you don't need to bother with any of that. I recommend searching SMW Central instead for resources that already offer support for VWF Dialogues. A popular example would be WYE's NPCs sprites. This section is only relevant to you if you're making your own resources and want to open VWF text boxes from them.
As already mentioned, doing so is thankfully very simple and only requires you to call the VWF_DisplayAMessage
shared routine from your own code. See section Shared Routines on details for how to use shared routines. Usage of the routine is documented in code right next to it, but calling it is usually as simple as:
lda.b #MessageNumber
ldx.b #MessageNumber>>8
jsl VWF_DisplayAMessage
MessageASM is an optional feature that allows you to to add code routines to messages. These routines are called every frame as long as a text box with that specific message is open. Think of it as UberASM, but tied to message numbers instead of level numbers. Enabling MessageASM is as simple as setting the vwf_enable_message_asm
setting to true
and adding a routine called MessageASMXXXX
to the code, where XXXX
must be the ID of the message for which MessageASM was enabled. This routine can go into your vwfmessages.asm
file if desired, but never directly inside a message body. It also must end in an rtl
. Here's a simple example:
%vwf_message_start(0050) ; Message 104-1
%vwf_header(enable_message_asm(true), freeze_game(false))
!str("Something is happening right now!")
%vwf_message_end()
MessageASM0050:
inc remap_ram($19)
rtl
Since MessageASM can run any code, there's almost no limits for what can be done with it. You can even use it to mess with the patch directly, either by calling shared routines or by accessing a number of useful defines (some of which are detailed below). To list a few examples of what can be achieved, using MessageASM smartly allows you to create custom menus, display character portraits, automatically display a speaker's name at the start of a text box, or move/animate sprites.
!vwf_message_was_skipped
= Is set to a non-zero value when a message has been skipped with the Start button. Otherwise it's zero.
!vwf_skip_message_flag
= Is non-zero if the current message is allowed to be skipped.
!vwf_l3_priority_flag
= Contains a backup of the layer 3 priority bit before the text box was displayed. Modify this to affect layer 3 once the text box disappears.
!vwf_l3_transparency_flag
= Contains a backup of the layer 3 color math settings before the text box was displayed. Modify this to affect layer 3 once the text box disappears.
!vwf_l3_main_screen_flag
= Contains a backup of the layer 3 mainscreen setting before the text box was displayed. Modify this to affect layer 3 once the text box disappears.
!vwf_l3_sub_screen_flag
= Contains a backup of the layer 3 subscreen setting before the text box was displayed. Modify this to affect layer 3 once the text box disappears.
!vwf_at_start_of_text
= Is set to 01 when a text box is cleared, 00 when text parsing begins. Use this to initialize code related to individual text boxes.
Shared routines are a mechanism for writing routines that can be used by both the VWF Dialogues patch itself, as well as any other resources that want to work with it. The simplest example here would be a routine for displaying a text box, which the patch itself needs for its message box hijack, but which other resources (like an NPC sprite) might also want to call. Currently, the patch uses its own, somewhat ugly implementation for handling shared routines. To do this, it writes a mapping table of routine names and locations into the ROM. A shared .asm file, which reads this table back in, then needs to be included in other resources. There's a few caveats with this solution, so the hope is that a future version of Asar can provide built-in support for shared routines directly and thus remove many of them. Anyways, here's a brief explanation on how to utilize them.
First of all, to use shared routines in another resource, you need to copy the file code/external/vwfsharedroutines.asm
next to it. If the resource in question is for a tool that doesn't use Asar 1.90 or newer yet, copy the file code/external/old_asar/vwfsharedroutines.asm
instead (confirmed to work in Asar 1.81). Now incsrc
the file you copied into your resource. However, since this file reads the locations of routines from ROM, this requires VWF Dialogues to always be patched to it before the other resource. If you plan to release a resource accessing a shared routine, it's a good idea to mention this fact in your Readme. As an additional safety measure, your resource can check for the existence of specific defines, which indicate that a shared routine has been found. Here is a simple example. It demonstrates how to display text boxes from custom code (probably 99% of use cases for shared routines):
incsrc "vwfsharedroutines.asm"
if defined("vwf_shared_routine_VWF_DisplayAMessage_exists")
lda.b #MessageNumber
ldx.b #MessageNumber>>8
jsl VWF_DisplayAMessage
else
; If VWF Dialogues support is optional in your resource,
; you can leave out this error entirely and do something else here.
error "VWF_DisplayAMessage shared routine wasn't found - please patch VWF Dialogues to this ROM first."
endif
If any shared routines were found by the other resource, it will print out some information on them automatically, thanks to the vwfsharedroutines.asm
include. This makes it easier for end users to see when a resource has been inserted correctly. The addresses here should match the addresses printed by the VWF Dialogues patch itself. Here's an example of what it might look like:
To write your own shared routines, or get an overview over all the available ones, open the file vwfroutines.asm
. Each call to the %vwf_register_shared_routine()
macro here defines one shared routine, with the argument to the macro being the name of the routine. You can jsl
to that name either from directly within VWF Dialogues or from your own resources to call the respective routine. The comments above each routine document what they do and how to use them. To add a new routine, simply define it by adding another call to the %vwf_register_shared_routine()
macro at the end of vwfroutines.asm
, ending in an rtl
. However, there's a few pitfalls you need to be aware of:
!vwf_max_num_shared_routines
setting in vwfconfig.cfg
. However, if you ever exceed this number of routines, you'll have to port everything to a new ROM to get around Asar's limitation.This section lists some tips that can help you improve the patch's performance or deal with problems that you might run into while using it. It's a good idea to check it out whenever you're stuck with something.
Ever since version 1.3, the VWF Dialogues patch is operated entirely via macros, functions and defines. The intention of this is primarily to improve usability of the patch, by giving end users readable command names instead of magic hex numbers and by having the patch validate command arguments where possible. However, this also has some drawbacks, which come mainly in the relatively unhelpful way that Asar displays error messages. Whenever Asar throws an error, it only prints the bottom-most and top-most entries of the call stack that led to it. In the case of an incorrect argument passed to a text command macro, an error will be generated inside the macro, so that's the location Asar will display. See the example below:
As you can imagine, this is pretty unhelpful to users of the patch. You will only know what kind of error occurred, but not where. To understand that, you'd need access to a larger part of the error call stack. Thankfully, Asar versions 2.0+ (unreleased as of the writing of this manual) provide a method to get just that. By passing the
--full-error-stack
command line option to Asar when applying the patch, it will display full call stacks whenever an error or warning occurs. Here is what that looks like in practice:
As you can see, with this option enabled, Asar still displays the error to you first, but then gives you a full error call stack that shows you where exactly in
vwfmessages.asm
the offending call can be found (in the case of the screenshot above, line 100
). If Asar version 2.0 or higher are available to you, it's recommended to always operate the patch with this option enabled.
This section attempts to walk you through the process of migrating from older versions of the patch to the current version. This is typically necessary if you have a WIP hack that is already using an older version of VWF Dialogues, but want to use features only found in a newer version.
When I originally started refactoring this patch to make use of Asar 1.90 variadic macros, backwards-compatibility with older patch versions was still one of my main goals. I wanted to make it easy for all version 1.2 (or earlier) users of the patch to migrate to version 1.3+. Over time, as I kept adding more and more improvements to 1.3, this goal kept moving further and further out of reach.
Technically speaking, version 1.3 is binary-compatible with messages from version 1.2, but it just includes so many changes to its general format that writing a straight-forward migration guide became too complex of a task for me. Therefore, I made the decision to declare version 1.3 as incompatible with version 1.2.
So what does this mean for you? Well, if you're making a new hack from scratch or working on a hack that has never used VWF Dialogues before, it doesn't really matter. Just use the newest version of the patch that's available. However, if you're working on a hack that's already using an older version of VWF Dialogues, you now basically have two options. Either you stick with the old patch version (and whatever bugs it might have), or you manually port over everything from the old to the new version, which basically involves recreating all your message boxes and resources in the format of the new version.
As I said, there's unfortunately no easy way of migrating to newer patch versions. However, on the positive side, version 1.3 of the patch was designed in a way that makes it a lot easier to extend in the future without breaking compatibility, so once you go through the effort of migrating, you'll hopefully never have to do it again to that degree for newer versions.
To migrate from version 1.3+ to a newer version of the patch, first open the vwfconfig.cfg
files of both patch versions. Search the newer version for settings missing in the older version and copy all of them over (a diffing tool could help with finding the differences here). Next, take all the contents of the old patch version's data
directory and and copy them into the data
directory of the new version, overwriting all existing files.
You should now be able to continue working in the new version of the patch.
SNES ROMs are stored as banks containing 32768
bytes of memory each. For almost all practical purposes, crossing a bank border with a resource or code is a problem and leads to bugs, so Asar contains built-in checks that detect bank-crossing and throws an error whenever it happens. In the case of VWF Dialogues, the only thing that can potentially cause a bank border to be crossed are resources. Thankfully, this shouldn't be much of a problem with fonts. Since each font only supports 256 glyphs, graphics file should never go above 16384 bytes in size, and width tables will be exponentially smaller than that, so graphics file plus width table should always fit into a single bank. The %vwf_add_font()
macro makes use of Asar's freedata
command, which automatically puts all fonts into their own banks.
That leaves only message files. Since they grow in size with every single message or piece of text added, they have a very real chance of exceeding the bank size limit. An average hack is unlikely to ever run into this limitation, because 32768 bytes amount to a lot of text. However, if you're creating a particularly text- and story-heavy hack, you might run into this issue eventually. This is what it might look like:
Thankfully, the fix for this, too, is pretty simple. Just create a new messages file next to the existing one. Let's say
vwfmessages2.asm
. In vwfconfig.cfg
, include this file inside the vwf_define_data
macro, like so:
%vwf_add_messages("data/vwfmessages2.asm", "data/fonts/vwftable.asm")
And then simply start moving entire messages from your first vwfmessages.asm
file to your second vwfmessages2.asm
file until the error goes aways. From here on out, use vwfmessages2.asm
whenever adding new messages. When you edit a message in vwfmessages.asm
and the error pops up again, move that entire message over to vwfmessages2.asm
.
This patch makes use of DMA transfers. DMA transfers share their channels with HDMA. This means they will influence any HDMA effects that use the same channels as them. In non-SA-1 ROMs, the DMA transfers in this patch use channel 0
(%00000001
) by default. In SA-1 ROMs, they use channel 2
(%00000100
). If you experience problems with HDMA effects while a text box is open, you might be able to resolve them by avoiding to use the respective channels in other patches. If that doesn't help or isn't possible, you can also try tweaking the !vwf_main_dma_channel
and !vwf_main_dma_channel_sa1
settings to move VWF Dialogues DMAs to a different channel (though this could potentially cause conflicts in other places). Possible channels are 0
to 7
. Read an HDMA tutorial for further information on this subject.
The following patches are expected to be compatible:
vwfconfig.cfg
settings, this patch breaks the first two rows of the palette whenever a dialogue is open, usually leading to glitched background colors as demonstrated on this screenshot:
vwfconfig.cfg
file and change the !vwf_enable_bottom_status_bar_color_fix_hack
setting to true
.
!vwf_enable_bottom_status_bar_color_fix_hack
setting to true
. In addition to this, when using an SA-1 ROM, you might experience your dialogues breaking entirely, as demonstrated on these screenshots:
!vwf_enable_smb3_status_bar_layer_3_hdma_fix_hack
setting in vwfconfig.cfg
to true
. Alternatively, changing the !vwf_main_dma_channel_sa1
setting to 0
will also eliminate the issue, since VWF Dialogues now use the same channel for their DMA transfers as the SMB3 Status Bar patch uses for its HDMA effect. However, this might cause some (currently unknown) side effects, so it's recommended to use the !vwf_enable_smb3_status_bar_layer_3_hdma_fix_hack
solution instead.
$008275
. If you patch VWF Dialogues before Remove Status Bar, text boxes will glitch up the screen as demonstrated here:
!vwf_enable_remove_status_bar_compatibility_fix_hack
setting in vwfconfig.cfg
to true
, which will make the VWF Dialogues patch execute Remove Status Bar's missing code.
0
s (FO0) when using level modes where Layer 3 isn’t on the Main-Screen, or the Main-Screen or Sub-Screen registers are updated in such a way that Layer 3 gets shown by another patch while this patch is busy restoring Layer 3.
$00
, because tile $FC
can get overwritten by a characher tile in sufficiently long messages.!vwf_sa1_use_dma_for_gfx_transfer
. When it's set to true
, SA-1 ROMs use DMA transfers to copy graphics instead of MVN transfers, which might provide performance benefits. However, in newer versions of BSNES/Higan (tested in v115) this breaks and produces the following outcome:
false
by default, so unless you change it, you shouldn't run into this bug.
It is unknown whether this is a bug in the SA-1 emulation of sd2snes, or an inaccuracy in emulators (and thus a bug in the patch's code). In any case, the bug can be avoided entirely by never creating buffered text macros directly from data in RAM.
!vwf_backup_duration_in_frames
and !vwf_clear_screen_duration_in_frames
settings, which will reduce the amount of time the patch spends in V-Blank at the cost of some operations (such as text box clears) taking a few frames longer. If you only add a few frames to each setting, the difference shouldn't even be noticeable by players (we're still talking about fractions of seconds here). A few frames alone can already make a world of a difference and could prevent the bug from occuring.Did you find a bug that wasn't listed in the Known Bugs section, or do you have a suggestion or a feature request for the patch? If so, please file an issue on GitHub! (You can also contact me on SMW Central, but filing an issue will make sure your input won't get lost). If you want to contribute to the patch yourself, you can also do so via that repository by submitting a pull request.
!vwf_backup_duration_in_frames
setting, which allows reducing the patch's V-Blank duration in the initialization step at the cost of longer start-up times for text boxes.!vwf_clear_screen_duration_in_frames
setting, which can reduce the amount of time the patch spends in V-Blank during text box clears at the cost of extending their duration to multiple frames.%vwf_wait_for_button()
and %vwf_wait_for_custom_button()
text commands, the VWF_AutoWait.WaitForButton
auto-wait mode, as well as the !vwf_default_advance_button_mask
, !vwf_select_choice_button_mask
and !vwf_skip_message_button_mask
settings, which give finer control over which buttons affect the patch. These features replace the %vwf_wait_for_a()
text command and the VWF_AutoWait.WaitForA
auto-wait mode, which are now deprecated.VWF_AutoWait.WaitFrames
auto-wait mode has been extended from 254
to 255
.vwf_text_box_bg_pattern()
, vwf_text_box_bg_color()
and vwf_text_box_frame()
header settings.rgb_15_from_24()
and rgb_15_from_f()
helper functions.vwfsharedroutines.asm
that's compatible with Asar 1.81 and can be used with NPCs v4.3.vwfconfig.cfg
. Remove Status Bar requires a compatibility setting and needs to be patched before VWF Dialogues. See section Compatibility With Other Patches for further information.
!vwf_var_ram_sa1
. The old setting pointed to an area within the GFX decompression buffer. Decompressing sufficiently large graphics (like player ExGFX) could cause the patch's memory to be trampled, causing it to malfunction.
$EB
(%vwf_freeze()
text command) that forces a textbox to freeze until something modifies the text pointer.$E8
and $E7
for the text macro system and that act like a JSR and RTS to the textbox system, respectively.$EF
(teleport) text command to work with secondary entrances $0200-$1FFF, levels using Lunar Magic 3.00 custom level dimensions, and layer 2 horizontal levels.%vwf_setup_exit_to_overworld()
text command.
vwfmessagepointers.asm
.$F4
to display character $FF
.