Wikifang:Network Translation Patchsite/BugVM: Difference between revisions

From Wikifang, a definitive guide to Telefang, Dino Device and Bugsite
Jump to navigation Jump to search
No edit summary
(Document the WINDIALOG ($5A), WINFRARROW ($AD), and WINARROW ($F4) opcodes)
 
(47 intermediate revisions by the same user not shown)
Line 26: Line 26:
|-
|-
| $12 || $C424 || W_BugVM_StringArena || Stores the current location of the end of the string-builder arena, used by the DB opcode to store embedded string data.
| $12 || $C424 || W_BugVM_StringArena || Stores the current location of the end of the string-builder arena, used by the DB opcode to store embedded string data.
|-
| $172 || $C6E4 || W_MainScript_PortraitID || Stores the currently selected character portrait, if any.
|-
| $580 - $59F || $CF00-$CF3F || W_Battle_AttrStaging || Stores the most recently loaded RPG Attribute Table entry.
|}
|}


== Linkage Directory ==
== Linkage Directory (BugFS) ==
Code and graphical resources exist entirely within sections, which can be referred to by their 16-bit linkage identifier. The linkage identifier indexes a directory starting from $A:$4000, with $800 8-byte directory entries per bank. In practice, while the directory could extend all the way across 8 banks, only 2 are used for the directory. (Effectively, linkages above $1000 are invalid and will horribly crash the game.) Directory entries appear to be stored in order of where their data is stored in ROM.
Bugsite contains a filesystem which almost pervasively enumerates all resources within the game. Each file is exclusively referred to with it's 16-bit linkage identifier; there are no file names and only one directory. Almost all resource loads, except some game data tables, are mediated through BugFS. Graphics and tilemaps are loaded by ID and BugVM code can farjump/farcall to the start of another section by ID.


Each directory index contains a bank index, byte offset into that bank (0 means a pointer of $4000), and total size; with at least graphical resource loads capable of handling sections that span multiple banks. The remaining three bytes are padding and are always zero. There appear to be about 36 unused directory entries from linkage $FDC all pointing to $7F:$70FF with a size of zero.
The directory's structure is that of an array of entry structures. The directory array starts at $A:$4000, and the ID indexes this array by 8 bytes. Directory entries appear to be stored in the same order as where their data is stored in ROM. The directory spans $1000 entries, across 2 banks; though it could be extended further if the referenced data were to be moved to a later bank. Approximately 40 entries at the end of the directory are zero-size files (pointing to ROM $7F:70FF) and may be unused filler entries.
 
{| class="wikitable"
|-
! Offset !! Name !! Type !!
|-
| $0 || Bank || 8-bit bank index ||
|-
| $1 || Offset || 16-bit offset || Offset is relative to $4000, not a pointer
|-
| $3 || Size || 16-bit size ||
|}
 
Each directory entry is 5 bytes long. Fields include a bank index, byte offset into that bank (0 means a pointer of $4000), and total size. Much like the directory itself, files are allowed and expected to span across bank boundaries. Native code that reads BugFS files will need to account for bank switching. Directory entries are stored with an 8-byte alignment (3 padding bytes).
 
== RPG Attribute Tables ==
 
Certain tables of game attributes are not stored as BugFS files. These data tables include listings for monsters, battle moves, chips, key items, and encounters. Not much is known about these tables, except for the fact that they are universally arrays of $40 bytes and often contain a name string at offset $30. Specialized BugVM instructions exist to load a single table entry into W_Battle_AttrStaging and to print the name at offset $30.
 
{| class="wikitable"
|-
! Location !! Size !! Contents !!
|-
| $4:4000, $5:4000 || $4000 || Bugs || Instructions that read from the monster table will select bank $4 for Alpha Version and bank $5 for Beta Version. Beta's table is present and unmodified in Alpha, and vice versa.
|-
| $6:4000 || $4000 || Moves ||
|-
| $7:4000 || $A80 || Chips || After the entry at $7:4A40 none of the remaining items in this table appear to have valid name data and are thus likely to be something else.
|-
| $7:6000 || $1240 || Key Items || After the entry at $7:7200 none of the remaining items in this table appear to have valid name data and are thus likely to be something else.
|-
| $8:4000, $9:4000 || $4000 || Encounters || Instructions that read from the encounter table will select bank $8 for Alpha Version and bank $9 for Beta Version. Beta's table is present and unmodified in Alpha, and vice versa.
|}


== Initial State ==
== Initial State ==
Line 44: Line 80:
|-
|-
! 0x
! 0x
| NOP <br> [[#op_5E9|$5E9]] || ENOP $01 <br> [[#op_5E9|$5E9]] || ENOP $02 <br> [[#op_5E9|$5E9]] || ??? <br> $671 || ENOP $04 <br> [[#op_5E9|$5E9]] || ENOP $05 <br> [[#op_5E9|$5E9]] || STR <br> [[#op_68C|$68C]] || SUML <br> [[#op_6C0|$6C0]] || ANDL <br> [[#op_6CA|$6CA]] || OR <br> [[#op_6D7|$6D7]] || XOR <br> [[#op_6E2|$6E2]] || AND <br> [[#op_6ED|$6ED]] || CMP_EQ <br> [[#op_6F8|$6F8]] || CMP_NEQ <br> [[#op_705|$705]] || CMP_LT <br> [[#op_712|$712]] || CMP_LEQ <br> [[#op_723|$723]]
| NOP <br> [[#op_5E9|$5E9]] || ENOP $01 <br> [[#op_5E9|$5E9]] || ENOP $02 <br> [[#op_5E9|$5E9]] || ARFREE <br> [[#op_671|$671]] || ENOP $04 <br> [[#op_5E9|$5E9]] || ENOP $05 <br> [[#op_5E9|$5E9]] || STR <br> [[#op_68C|$68C]] || SUML <br> [[#op_6C0|$6C0]] || ANDL <br> [[#op_6CA|$6CA]] || OR <br> [[#op_6D7|$6D7]] || XOR <br> [[#op_6E2|$6E2]] || AND <br> [[#op_6ED|$6ED]] || CMP_EQ <br> [[#op_6F8|$6F8]] || CMP_NEQ <br> [[#op_705|$705]] || CMP_LT <br> [[#op_712|$712]] || CMP_LEQ <br> [[#op_723|$723]]
|-
|-
! 1x
! 1x
Line 56: Line 92:
|-
|-
! 4x
! 4x
| || || || || || || || || || || || || || || ||
| WINWAIT <br> [[#op_A12|$A12]] || || || || || || || || || || || || PRINT <br> [[#op_A84|$A84]] || || ||
|-
|-
! 5x
! 5x
| || || || || || || || || || || || || || || ||
| SCRCURS <br> [[#op_C54|$C54]] || || || || || || || || || || WINDIALOG <br> [[#op_AED|$AED]] || WINCLR <br> [[#op_97C|$97C]] || || || || RESLD <br> [[#op_9C6|$9C6]]
|-
|-
! 6x
! 6x
| || || || || || || || || || || || FARJMP <br> [[#op_83B|$83B]] || || || ||
| || SPRINPUT <br> [[#op_A29|$A29]] || || || || || || || || || FARCALL <br> [[#op_91B|$91B]] || FARJMP <br> [[#op_83B|$83B]] || || || SPRANIM <br> [[#op_2775|$2775]] || SPRPOSPLAY <br> [[#op_2788|$2788]]
|-
|-
! 7x
! 7x
| || || || || || || || || || || || || || || ||
| WINCHOICE <br> [[#op_13B4|$13B4]] || || TILELD <br> [[#op_1BAC|$1BAC]] || || || PALLD <br> [[#op_2F0E|$2F0E]] || || || SPRCHOREO <br> [[#op_3269|$3269]] || || || || || WINCOORD <br> [[#op_C24|$C24]] || WINCURS <br> [[#op_C63|$C63]] ||
|-
|-
! 8x
! 8x
| || || || || || || || || || || || || || || ||
| || || WINBRK <br> [[#op_ADA|$ADA]] || || || || TMAPSAV <br> [[#op_1C92|$1C92]] || || || || || || SPRDIR <br> [[#op_324F|$324F]] || || SPRWIPE <br> [[#op_289C|$289C]] ||
|-
|-
! 9x
! 9x
| || || || || || || || || || || || || || || ||
| || || SPRPLAY <br> [[#op_27B3|$27B3]] || || || || || || || || || || || || || PRKEY <br> [[#op_165A|$165A]]
|-
|-
! Ax
! Ax
| || || || || || || || || || || || || || || ||
| BLKKEY <br> [[#op_42A|$42A]] || PRMOVE <br> [[#op_1668|$1668]] || BLKMOVE <br> [[#op_3FE|$3FE]] || || || PRNAME <br> [[#op_162A|$162A]] || SPRCTRL <br> [[#op_235E|$235E]] || SPRFINISH <br> [[#op_2386|$2386]] || || || || || || WINFRARROW <br> [[#op_B05|$B05]] || || PRMON <br> [[#op_1622|$1622]]
|-
|-
! Bx
! Bx
| || || || || || || || || || || || || || || ||
| NTSTR <br> [[#op_1677|$1677]] || NTPRINT <br> [[#op_1670|$1670]] || WINOPEN <br> [[#op_B2D|$B2D]] || WINFRAME <br> [[#op_AFC|$AFC]] || || || || || || || || BLKMON <br> [[#op_39C|$39C]] || || || ||
|-
|-
! Cx
! Cx
| || || || || || || || || || || || || || || ||
| || || || || || || SPRWAIT <br> [[#op_27BB|$27BB]] || || || || || SPRFREEZE <br> [[#op_32C7|$32C7]] || SPRTHAW <br> [[#op_32D5|$32D5]] || || || SPRHIDE <br> [[#op_2877|$2877]]
|-
|-
! Dx
! Dx
| || || || || || || || || || || || || || || ||
| || || SPRHOLD <br> [[#op_A39|$A39]] || || || || || || || WININPUT <br> [[#op_A1D|$A1D]] || || || || || ||
|-
|-
! Ex
! Ex
| || || || || || || || || || || || || || || ||
| || || BLKCHIP <br> [[#op_456|$456]] || PRCHIP <br> [[#op_1661|$1661]] || || PRNICK <br> [[#op_1638|$1638]] || || || || || || || || || ||
|-
|-
! Fx
! Fx
| || || || || || || || || || || || || || || ||
| || BLKENC <br> [[#op_3CD|$3CD]] || || || WINARROW <br> [[#op_B10|$B10]] || || || || || || || || || || ||
|}
|}


Line 166: Line 202:
| PRED <br> (PREDicate) || $1E || $820 || None || immed (TOP) -> &pred (TOP) || Cast the value '''immed''' into a predicate memory index &'''pred'''.
| PRED <br> (PREDicate) || $1E || $820 || None || immed (TOP) -> &pred (TOP) || Cast the value '''immed''' into a predicate memory index &'''pred'''.
|- id='op_831'
|- id='op_831'
| POPALL <br> (POP ALL) || $2C || $831 || None || anything (TOP) -> (EMPTY) || Empty the stack.
| POPALL <br> (POP ALL) || $2C || $831 || None || (...) -> (EMPTY) || Empty the stack.
|- id='op_8DE'
|- id='op_8DE'
| IMMED <br> (IMMEDiate) || $3D || $8DE || immed (16b) || (TOP) -> immed (TOP) || Push '''immed''' onto the data stack as an immediate value.
| IMMED <br> (IMMEDiate) || $3D || $8DE || immed (16b) || (TOP) -> immed (TOP) || Push '''immed''' onto the data stack as an immediate value.
Line 173: Line 209:


The address of the newly copied string data will be pushed onto the data stack as an immediate value.
The address of the newly copied string data will be pushed onto the data stack as an immediate value.
|- id='op_671'
| ARFREE <br> (ARena FREE) || $03 || $671 || None || None || Free the data in the string arena (or set up the string arena if it hasn't already been done).
This opcode should be used as soon as possible after you are done with the data in the string arena. The arena has a maximum capacity of 255 bytes, and memory is not reclaimed from use by a [[#op_941|DB]] opcode until you ARFREE the entire arena.
|- id='op_1677'
| NTSTR <br> (Name Temporary SToRe) || $B0 || $1677 || None || srcaddr (TOP) -> (TOP) || Store string data in the naming temporary string area.
This is primarily used by naming / password screens which need to redraw themselves while retaining the user's input data. srcaddr is the address of a string, usually provided by the DB opcode.
The naming temporary area has a maximum size of $E bytes, not counting the mandatory null terminator.
|}
|}


=== Execution Control ===
=== Execution Control ===
Execution Control opcodes control the address of the next instruction to execute, determined by BugVM's program counter. It consists of a '''bank address''', '''base address''', and '''offset address'''. The linkage directory determines what the bank and base addresses of a section are. The offset address is added to the base in order to calculate the address of the next instruction.
Caution: Parameters named "offset" for jump instructions refer to the program counter offset address, and do not imply the existence of PC-relative jumps instructions within Bugsite.


{| class='wikitable'
{| class='wikitable'
Line 188: Line 237:
|- id='op_8F0'
|- id='op_8F0'
| JAL <br> (Jump And Link) || $3F || $8F0 || offset (16b) || None || Jump to a new offset within the current linkage section. Store the offset of the next instruction on the link stack.
| JAL <br> (Jump And Link) || $3F || $8F0 || offset (16b) || None || Jump to a new offset within the current linkage section. Store the offset of the next instruction on the link stack.
|- id='op_91B'
| FARCALL || $6A || $91B || None || linkage_index (TOP) -> (TOP) || Jump to the start of a new linkage section. Store the offset of the next instruction on the stack.
|- id='op_83B'
|- id='op_83B'
| FARJMP <br> (FAR JuMP) || $6B || $83B || None || linkage_index (TOP) -> (TOP) || Jump to the start of a new linkage section, erasing the link stack in the process.
| FARJMP <br> (FAR JuMP) || $6B || $83B || None || linkage_index (TOP) -> (TOP) || Jump to the start of a new linkage section, erasing the link stack in the process.
Line 238: Line 289:
|- id='op_8DB'
|- id='op_8DB'
| PNOP $3C <br> (Probable Null OPeration) || $3C || $8DB || None || None || Does nothing.
| PNOP $3C <br> (Probable Null OPeration) || $3C || $8DB || None || None || Does nothing.
|}
=== Graphics Functions ===
{| class='wikitable'
|-
! Opcode !! Encoding(s) !! Native Impl. !! Operand Args !! Stack Args !! Description
|- id='op_1BAC'
| TILELD <br> (TILE LoaD) || $72 || $1BAC || None || linkage_index, tile_x, tile_y, base_tile, base_attr (TOP) -> (TOP) || Load a precomposed tilemap from BugFS file linkage_index into the first tilemap in VRAM ($9800).
The base_tile and base_attr parameters allow the user to add a dynamic tile index and palette index offset to the tilemap. For example, if you loaded the tilemap's graphics into slot $30 on the second VRAM tile bank, with color data starting at BG palette 3, you could set base_tile to $30 and base_attr to Bank 1, Palette 3.
Tile X and Y coordinates allow you to control where the tilemap data is written. These coordinates are in tile units and are relative to the first visible tile on the screen (based on the current screen scroll).
Each tilemap's data starts with the width and height of the tilemap, followed by two bytes for each tile's ID and attributes, starting from the top-left of the tilemap and continuing right until the end, then the next line down. These IDs and attributes are relative to the base parameters as described above.
|- id='op_9C6'
| RESLD <br> (RESource LoaD) || $5F || $9C6 || None || linkage_index, copy_start, copy_len, target_addr, target_bank (TOP) -> (TOP) || Load graphics resources from BugFS file linkage_index into tile memory.
copy_start determines how far into the resource to copy from, and copy_len determines how much to copy from that point. Both of these are in units of 32 bytes - exactly the size of a single tile.
target_addr and target_bank determines where to place the copied resources in VRAM. They are native memory pointers, not indexed to anything.
|- id='op_2F0E'
| PALLD <br> (PALette LoaD) || $75 || $2F0E || None || linkage_index, is_bgpal, source_palette, target_palette (TOP) -> (TOP) || Copy a color palette into color palette memory.
Palette color data will be copied from source_palette palettes into the file at linkage_index, into color memory at the given target_palette. If is_bgpal is True then the color data will be loaded into background palette memory; otherwise, color data will load into object palette memory.
source_palette and target_palette are both palette indices; it is not possible to copy part of a palette, or unaligned data from the filesystem.
|- id='op_C54'
| SCRCURS <br> (SCReen CURSor) || $7E || $C54 || None || x, y (TOP) -> (TOP) || Set the tile cursor relative to the screen.
The tile cursor is a screen offset in increments of 8x8 pixels, used to control the positioning of various graphical operations on the screen, such as [[#op_A84|PRINT]]ing text.
|- id='op_A84'
| PRINT <br> (PRINT) || $4C || $A84 || None || string_addr (TOP) -> (TOP) || Print tile text onto the screen.
Printed text will appear on screen at the current tile cursor - usually set by an opcode like [[#op_C54|SCRCURS]], [[#op_C63|WINCURS]], or [[#op_C24|WINCOORD]].
string_addr points to a null-terminated string in unbanked memory - usually some portion of the string arena that is written to by [[#op_941|DB]]. Since that opcode returns an unbanked memory pointer on stack, one can print to the screen using just DB and PRINT opcodes.
The character $7F is special-cased in this function to print the player's name at $C9F0.
PRINT uses tile text in order to draw letters. A tile font must have been previously loaded in VRAM at tile location 0; it's encoded character value will be used as a tile index to draw with.
|- id='op_1670'
| NTPRINT <br> (Name Temporary PRINT) || $B0 || $1677 || None || None || Print stored string data in the naming temporary area.
|- id='op_1C92'
| TMAPSAV <br> (Tile MAP SAVe) || $86 || $1C92 || None || None || Copy the contents of tile map 1 ($9800) to tile map 2 ($9C00).
|}
=== Window Management ===
Windows are regions of the background layer adorned with a border, intended to be drawn over the active playfield to represent dialogue or certain kinds of menus.
{| class='wikitable'
|-
! Opcode !! Encoding(s) !! Native Impl. !! Operand Args !! Stack Args !! Description
|- id='op_C24'
| WINCOORD <br> (WINdow COORDinate) || $7D || $C24 || None || xmin, ymin, xmax, ymax (TOP) -> (TOP) || Set the coordinates of the current window.
xmin, ymin, xmax, ymax are the screen pixel coordinates of the left, top, right, and bottom edges of the window, respectively; including the frame. They will be used to configure Window Manager variables for other WINnn opcodes.
The tile cursor will be set to the X and Y coordinates of the ''contents'' of the specified window, so you can [[#op_A84|PRINT]] to it immediately. This is equivalent to [[#op_C63|WINCURS]] with an x and y of zero.
|- id='op_AFC'
| WINFRAME <br> (WINdow FRAME) || $B3 || $AFC || None || None || Draw the current window's frame.
You must have an active window style loaded into VRAM.
If this window is a menu, and the item counts are configured correctly, WINFRAME will also draw the overflow arrows.
|- id='op_B05'
| WINFRARROW <br> (WINdow FRame ARROW) || $AD || $B05 || None || arrow_position (TOP) -> (TOP) || Draw the current window's frame, with overflow arrows.
This is equivalent to [[#op_AFC|WINFRAME]] + [[#op_B10|WINARROW]] all at once.
|- id='op_B2D'
| WINOPEN <br> (WINdow OPEN) || $B2 || $B2D || None || None || Animate the current window opening.
This animation requires that the window span the whole width of the screen and that [[#op_1C92|TMAPSAV]] had been used to copy the screen before the window frame was drawn (e.g. with [[#op_AFC|WINFRAME]]). Execution of BugVM code is halted until the animation completes.
|- id='op_AED'
| WINDIALOG <br> (WINdow DIALOG) || $5A || $AED || None || None || Draw and open the current window.
This is equivalent to [[#op_1C92|TMAPSAV]] + [[#op_AFC|WINFRAME]] + [[#op_B2D|WINOPEN]] all at once.
|- id='op_97C'
| WINCLR <br> (WINdow CLeaR) || $5B || $97C || None || None || Clear the active window region.
Tiles will be set to $20, which is the encoded byte for a space. In any loaded font, this tile is intended to be blank.
|- id='op_C63'
| WINCURS <br> (WINdow CURSor) || $7E || $C63 || None || x, y (TOP) -> (TOP) || Set the tile cursor relative to the window.
|- id='op_13B4'
| WINCHOICE <br> (WINdow CHOICE) || $70 || $13B4 || None || choice, choice, (...) -> (EMPTY) || Print a series of menu choices.
Each choice will be prefixed with a space, to make room for the selection cursor. They will also be printed single-spaced, as opposed to normal line printing which is double-spaced.
The choice arguments are string pointers (e.g. from [[#op_941|DB]]); this opcode consumes all pointers on the data stack.
|- id='op_B10'
| WINARROW <br> (WINdow ARROW) || $F4 || $B10 || None || arrow_position (TOP) -> (TOP) || Draw overflow arrows for a given menu position.
''arrow_position'' is the index of a particular selected menu choice. Overflow arrows will be drawn on top of the window frame based on this value.
|- id='op_A12'
| WINWAIT <br> (WINdow WAIT) || $60 || $A12 || None || None || Wait for user input.
BugVM execution will halt until the user presses the "A" button on the system. A blinking A-button prompt will be displayed at the bottom-right of the window range.
|- id='op_A1D'
| WININPUT <br> (WINdow INPUT) || $D9 || $A1D || None || (TOP) -> input_changed (TOP) || Wait for user input.
BugVM execution will halt until the user presses any button on the system. A blinking A-button prompt will be displayed at the bottom-right of the window range.
The state of which buttons were pressed to continue is returned on the stack. The format for input data is that of eight bit-flags; from highest to lowest: Start, Select, Button B, Button A, Down, Up, Left, and Right. The upper 8 bits of data are always zero.
|- id='op_97C'
| WINBRK <br> (WINdow BReaK) || $82 || $ADA || None || None || Insert a 'page break' of sorts between two full windows' worth of text.
Internally this is equivalent to a WINWAIT followed by a WINCLR.
|}
=== Sprite Management ===
BugVM contains a fully featured metaspriting and animation system, which we've nicknamed Sprite Manager.
{| class='wikitable'
|-
! Opcode !! Encoding(s) !! Native Impl. !! Operand Args !! Stack Args !! Description
|- id='op_324F'
| SPRDIR <br> (SPRite DIRection) || $8C || $324F || None || slot, direction (TOP) -> (TOP) || Set the facing direction of a given sprite.
''slot'' refers to the sprite to control (0 thru 7) and ''direction'' is the direction to make it face. If either are invalid, then nothing will happen. Consult [[Wikifang:Network Translation Patchsite/SpriteManager#Metasprite_Data_Structure|SpriteManager documentation]] for more information on which direction numbers are valid.
|- id='op_235E'
| SPRCTRL <br> (SPRite ConTRoL) || $A6 || $235E || None || slot, input (TOP) -> (TOP) || Control a given sprite with user or simulated input.
''slot'' refers to the sprite to control (0 thru 7) and ''input'' is the input state or simulated input state to send to the sprite.
The given sprite will have a movement animation queued on it if and only if the space for the sprite to move to is free. Otherwise, no action will be taken. Queued sprite animations can be played with other SPR opcodes.
Consult [[#op_A1D|WININPUT]] for information about the format of input state.
|- id='op_3269'
| SPRCHOREO <br> (SPRite CHOREOgraphy) || $78 || $3269 || None || file_id, slot (TOP) -> (TOP) || Place a sprite under control of a choreography script.
''file_id'' refers to the BugFS file containing the choreography script and ''slot'' is the sprite to be placed under it's control. The sprite in ''slot'' will have the choreography script installed, and then frozen in place for later execution.
The choreography script will be copied into one of eight choreography script slots. Each slot is 128 bytes max; and lives in an array starting at $2:DC00. This means choreography scripts may not exceed 64 instructions.
|- id='op_2775'
| SPRANIM <br> (SPRite ANIMate) || $6E || $2775 || None || file_id, ctxt_slot, slot (TOP) -> (TOP) || Load an animation into a sprite animation context for a given sprite.
''file_id'' is the BugFS file ID for a sprite animation to play.
''ctxt_slot'' refers to the animation context that will execute the animation script; while ''slot'' refers to the sprite to be animated. Usually both indices are the same; for example, idle-sprite choreography assumes that sprite 5's animations must always be loaded into animation context 5.
|- id='op_2788'
| SPRPOSPLAY <br> (SPRite POSition and PLAY) || $6F || $2788 || None || slot, x, y (TOP) -> (TOP) || Position and then play a previously loaded animation on a given sprite.
''slot'' refers to the sprite being played (0 thru 7). It must already have an animation queued. It's origin will be placed at the coordinates (''x'', ''y'').
Additionally, all active sprite animations will be evaluated for one frame.
|- id='op_27B3'
| SPRPLAY <br> (SPRite PLAY) || $92 || $27B3 || None || slot (TOP) -> (TOP) || Play a previously-loaded animation on a given sprite.
''slot'' refers to the sprite being played (0 thru 7). It must already have an animation queued.
This opcode is not in use in Network Adventure Bugsite.
|- id='op_27D8'
| SPRWAIT <br> (SPRite WAIT) || $C6 || $27D8 || None || slot, should_clear (TOP) -> (TOP) || Wait for sprite animation to finish.
BugVM execution will halt until the given sprite in ''slot'' finishes animating. Optionally, if ''should_clear'' is TRUE, then we will also clear any deactivated sprites from the screen.
|- id='op_27D8'
| SPRWAITALL <br> (SPRite WAIT ALL) || $79 || $27BB || None || None || Wait for all sprite animations to finish.
BugVM execution will halt until all sprite animations finish, then any deactivated sprites will be cleared from the screen.
This opcode is not in use in Network Adventure Bugsite.
|- id='op_A29'
| SPRINPUT <br> (SPRite INPUT) || $61 || $A29 || None || (TOP) -> input_changed (TOP) || Wait for user input.
BugVM execution will halt until the user presses any button on the system. Sprite animations will continue to execute during this period of halted execution.
Consult [[#op_A1D|WININPUT]] for information about this opcode's output format.
|- id='op_A39'
| SPRHOLD <br> (SPRite HOLD) || $D2 || $A39 || None || (TOP) -> input_held (TOP) || Wait for user input.
BugVM execution will halt until the user presses, or is already holding, any button on the system. Sprite animations will continue to execute during this period of halted execution.
Consult [[#op_A1D|WININPUT]] for information about this opcode's output format.
|- id='op_2386'
| SPRFINISH <br> (SPRite FINISH) || $A7 || $2386 || None || None || Wait for sprites to finish moving.
BugVM execution will halt until all sprites have finished moving.
|- id='op_2877'
| SPRHIDE <br> (SPRite HIDE) || $CF || $2877 || None || slot (TOP) -> (TOP) || Deactivate sprite in ''slot''.
|- id='op_289C'
| SPRWIPE <br> (SPRite WIPE) || $8E || $289C || None || None || Deactivate all sprites and clear them from the screen.
|- id='op_32C7'
| SPRFREEZE <br> (SPRite FREEZE) || $CB || $32C7 || None || slot (TOP) -> (TOP) || Manually freeze sprite in ''slot''.
This opcode is not in use in Network Adventure Bugsite.
|- id='op_32D5'
| SPRTHAW <br> (SPRite THAW) || $CB || $32D5 || None || slot (TOP) -> (TOP) || Manually unfreeze sprite in ''slot''.
This does not revert the freeze caused by [[#op_3269|SPRCHOREO]] - SPRFREEZE and SPRCHOREO freezes are treated separately.
This opcode is not in use in Network Adventure Bugsite.
|}
=== Attribute Table Utilities ===
{| class='wikitable'
|-
! Opcode !! Encoding(s) !! Native Impl. !! Operand Args !! Stack Args !! Description
|- id='op_165A'
| PRKEY <br> (PRint KEY item) || $9F || $165A || None || attr_index (TOP) -> (TOP) || Read the given Key Item's Attribute Table block and print it's name.
|- id='op_42A'
| BLKKEY <br> (BLocK KEY item) || $A0 || $42A || None || attr_index (TOP) -> (TOP) || Read the given Key Item's Attribute Table block into W_Battle_AttrStaging.
|- id='op_1668'
| PRMOVE <br> (PRint MOVE) || $A1 || $1668 || None || attr_index (TOP) -> (TOP) || Read the given Battle Move's Attribute Table block and print it's name.
|- id='op_3FE'
| BLKMOVE <br> (BLocK MOVE) || $A2 || $3FE || None || attr_index (TOP) -> (TOP) || Read the given Battle Move's Attribute Table block into W_Battle_AttrStaging.
|- id='op_1622'
| PRMON <br> (PRint MONster) || $AF || $1622 || None || attr_index (TOP) -> (TOP) || Read the given Bug's Attribute Table block and print it's name.
|- id='op_39C'
| BLKMON <br> (BLocK MONster) || $BB || $39C || None || attr_index (TOP) -> (TOP) || Read the given Bug's Attribute Table block into W_Battle_AttrStaging.
This instruction switches between two different Attribute Tables based on the value of W_System_GameVersion.
|- id='op_1661'
| PRCHIP <br> (PRint CHIP) || $E3 || $1661 || None || attr_index (TOP) -> (TOP) || Read the given Chip's Attribute Table block and print it's name.
|- id='op_456'
| BLKCHIP <br> (BLocK CHIP) || $E2 || $456 || None || attr_index (TOP) -> (TOP) || Read the given Chip's Attribute Table block into W_Battle_AttrStaging.
|- id='op_3CD'
| BLKENC <br> (BLocK ENCounter) || $F1 || $3CD || None || attr_index (TOP) -> (TOP) || Read the given Encounter's Attribute Table block into W_Battle_AttrStaging.
There does not appear to be a PRENC instruction.
This instruction switches between two different Attribute Tables based on the value of W_System_GameVersion.
|- id='op_162A'
| PRNAME <br> (PRint NAME) || $A5 || $162A || None || None || Print the name of the currently loaded Attribute Table block.
All PRint instructions that reference Attribute Table data execute this opcode. It prints data from $CF30, which is an offset into W_Battle_AttrStaging that appears to be a standard offset for this kind of data.
|- id='op_1670'
| PRNICK <br> (PRint NICKname) || $E5 || $1638 || None || None || Print the name of the currently loaded Nickname block.
Like PRNAME, this opcode prints the name section of a datablock. However, it prints data stored in the Nickname datablock area, $CC30, which is an offset into the W_NameInput_NicknameDataBlock area. The name "nickname data block area" is assumed; it is not currently known what semantic purpose this area serves other than use by the naming screens.
|}
=== Variable Width Font Rendering ===
These opcodes are exclusive to the English patch of Bugsite and represent new opcodes. They overlap existing ENOP instructions starting from $1F and thus can only be used if you are using BugTools' auto-optimize feature to remove existing ENOP instructions.
{| class='wikitable'
|-
! Opcode !! Encoding(s) !! Native Impl. !! Operand Args !! Stack Args !! Description
|- id='op_VWFCONFIG'
| VWFCONFIG <br> (VWF CONFIG) || $1F || (varies) || None || font, metrics, bg (TOP) -> (TOP) || Configure the font used for VWF text rendering.
''font'' and ''metrics'' refers to the file IDs of the font character data and metrics data, respectively. Character data is stored similarly to FWF fonts, but left-aligned; while metrics data is an array of one byte per character indicating width of each character.
This instruction only configures the font in use by VWF; it does not enable VWF.
|- id='op_VWFENABLE'
| VWFENABLE <br> (VWF ENABLE) || $20 || (varies) || None || ring_start, ring_end (TOP) -> (TOP) || Enable VWF rendering.
When enabled, [[#op_A84|PRINT]] instructions will use the VWF font rendering path. A font should have already been configured via VWFCONFIG before enabling VWF.
''ring_start'' and ''ring_end'' are a range of tiles to use for VWF rendering. Tiles from $100 onward indicate tiles in the second VRAM bank. This range of tiles will constitute a ring buffer of free tiles to be overwritten with VWF text, with drawn tiles starting from the first tile in the ring. Most importantly, new text will overwrite old tiles if the ring runs out of space, so you must ensure text that you don't intend to overwrite occupies it's own rings.
|- id='op_VWFDISABLE'
| VWFDISABLE <br> (VWF DISABLE) || $21 || (varies) || None || None || Disable VWF rendering.
Rendering will return to tile based fonts, using the same tiles normally used for tile text. Note that if you have overwritten these tiles, you will need to reload the FWF font equivalents.
|}
|}

Latest revision as of 11:08, 7 January 2018

Bugsite contains a virtual machine which executes all (non-IRQ) game logic. It is a stack-based virtual machine with a large number of opcodes specific to the game.

Data and Link Stacks[edit]

Two stacks are managed by the VM: a link stack and a data stack. The link stack ($C100) supports up to $3F call frames of 4 bytes each, which is manipulated entirely by the call, jump-far, and return opcodes. The data stack ($C200) supports up to $55 data items of 3 bytes each. Each data item consists of a little-endian 16-bit word followed by a tag byte, which specifies if it's...

  • $3D an immediate value
  • $1D a word index into the indirect memory array
  • $1E a bit index into the predicate array

Data items are pushed onto the stack as immediate values and then cast to indirect or predicate offsets as necessary. Both stacks grow upwards from their base address.

Indirect & Predicate Memory[edit]

BugVM allows direct access (read and write) to indirect and predicate memory. Indirect memory covers WRAM3:$C400 to WRAM3:$D7FF, and is indexed using word offsets. Predicate memory covers WRAM3:$D800 to WRAM3:$DFFF and is indexed as a massive bitfield.

Indirect and predicate memory can be saved to and loaded from SRAM using opcodes $47 and $48, along with additional data in SRAM.

Known Indirect Memory Slots[edit]

Index WRAM Addr. Name Purpose
$01 $C402 W_System_GameVersion Stores the version of the game the user is playing.

0 is Alpha version, 1 is Beta version

$12 $C424 W_BugVM_StringArena Stores the current location of the end of the string-builder arena, used by the DB opcode to store embedded string data.
$172 $C6E4 W_MainScript_PortraitID Stores the currently selected character portrait, if any.
$580 - $59F $CF00-$CF3F W_Battle_AttrStaging Stores the most recently loaded RPG Attribute Table entry.

Linkage Directory (BugFS)[edit]

Bugsite contains a filesystem which almost pervasively enumerates all resources within the game. Each file is exclusively referred to with it's 16-bit linkage identifier; there are no file names and only one directory. Almost all resource loads, except some game data tables, are mediated through BugFS. Graphics and tilemaps are loaded by ID and BugVM code can farjump/farcall to the start of another section by ID.

The directory's structure is that of an array of entry structures. The directory array starts at $A:$4000, and the ID indexes this array by 8 bytes. Directory entries appear to be stored in the same order as where their data is stored in ROM. The directory spans $1000 entries, across 2 banks; though it could be extended further if the referenced data were to be moved to a later bank. Approximately 40 entries at the end of the directory are zero-size files (pointing to ROM $7F:70FF) and may be unused filler entries.

Offset Name Type
$0 Bank 8-bit bank index
$1 Offset 16-bit offset Offset is relative to $4000, not a pointer
$3 Size 16-bit size

Each directory entry is 5 bytes long. Fields include a bank index, byte offset into that bank (0 means a pointer of $4000), and total size. Much like the directory itself, files are allowed and expected to span across bank boundaries. Native code that reads BugFS files will need to account for bank switching. Directory entries are stored with an 8-byte alignment (3 padding bytes).

RPG Attribute Tables[edit]

Certain tables of game attributes are not stored as BugFS files. These data tables include listings for monsters, battle moves, chips, key items, and encounters. Not much is known about these tables, except for the fact that they are universally arrays of $40 bytes and often contain a name string at offset $30. Specialized BugVM instructions exist to load a single table entry into W_Battle_AttrStaging and to print the name at offset $30.

Location Size Contents
$4:4000, $5:4000 $4000 Bugs Instructions that read from the monster table will select bank $4 for Alpha Version and bank $5 for Beta Version. Beta's table is present and unmodified in Alpha, and vice versa.
$6:4000 $4000 Moves
$7:4000 $A80 Chips After the entry at $7:4A40 none of the remaining items in this table appear to have valid name data and are thus likely to be something else.
$7:6000 $1240 Key Items After the entry at $7:7200 none of the remaining items in this table appear to have valid name data and are thus likely to be something else.
$8:4000, $9:4000 $4000 Encounters Instructions that read from the encounter table will select bank $8 for Alpha Version and bank $9 for Beta Version. Beta's table is present and unmodified in Alpha, and vice versa.

Initial State[edit]

Execution of BugVM always starts from the beginning of linkage $0. Indirect and predicate memory is set to $0 upon game initialization.

Instruction Set[edit]

BugVM takes instructions as 8-bit opcodes which can optionally accept additional parameters. Most opcodes take arguments from the stack, rather than from the instruction stream. Native implementations for a particular opcode are referenced from the opcode table at $3E00, reproduced below:

x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF
0x NOP
$5E9
ENOP $01
$5E9
ENOP $02
$5E9
ARFREE
$671
ENOP $04
$5E9
ENOP $05
$5E9
STR
$68C
SUML
$6C0
ANDL
$6CA
OR
$6D7
XOR
$6E2
AND
$6ED
CMP_EQ
$6F8
CMP_NEQ
$705
CMP_LT
$712
CMP_LEQ
$723
1x CMP_GT
$752
CMP_GEQ
$763
???
$772
SLA
$784
SUB
$796
ADD
$7A1
MOD
$7A9
DIV
$7C3
MUL
$7ED
PNOP $19
$80B
PNOP $1A
$80C
PNOP $1B
$80D
PNOP $1C
$80E
INDIR
$80F
PRED
$820
ENOP $1F
$5E9
2x ENOP $20
$5E9
ENOP $21
$5E9
ENOP $22
$5E9
ENOP $23
$5E9
ENOP $24
$5E9
ENOP $25
$5E9
ENOP $26
$5E9
ENOP $27
$5E9
ENOP $28
$5E9
ENOP $29
$5E9
ENOP $2A
$5E9
ENOP $2B
$5E9
POPALL
$831
ENOP $2D
$5E9
ENOP $2E
$5E9
PNOP $2F
$835
3x PNOP $30
$836
PNOP $31
$837
PNOP $32
$838
PNOP $33
$839
PNOP $34
$83A
PNOP $35
$87B
NPREF
$87C
JMPT
$887
JMP
$8AC
RET
$8BB
PNOP $3A
$8DB
PNOP $3B
$8DC
PNOP $3C
$8DD
IMMED
$8DE
DB
$941
JAL
$8F0
4x WINWAIT
$A12
PRINT
$A84
5x SCRCURS
$C54
WINDIALOG
$AED
WINCLR
$97C
RESLD
$9C6
6x SPRINPUT
$A29
FARCALL
$91B
FARJMP
$83B
SPRANIM
$2775
SPRPOSPLAY
$2788
7x WINCHOICE
$13B4
TILELD
$1BAC
PALLD
$2F0E
SPRCHOREO
$3269
WINCOORD
$C24
WINCURS
$C63
8x WINBRK
$ADA
TMAPSAV
$1C92
SPRDIR
$324F
SPRWIPE
$289C
9x SPRPLAY
$27B3
PRKEY
$165A
Ax BLKKEY
$42A
PRMOVE
$1668
BLKMOVE
$3FE
PRNAME
$162A
SPRCTRL
$235E
SPRFINISH
$2386
WINFRARROW
$B05
PRMON
$1622
Bx NTSTR
$1677
NTPRINT
$1670
WINOPEN
$B2D
WINFRAME
$AFC
BLKMON
$39C
Cx SPRWAIT
$27BB
SPRFREEZE
$32C7
SPRTHAW
$32D5
SPRHIDE
$2877
Dx SPRHOLD
$A39
WININPUT
$A1D
Ex BLKCHIP
$456
PRCHIP
$1661
PRNICK
$1638
Fx BLKENC
$3CD
WINARROW
$B10

Boolean Logic & Comparison Operators[edit]

As convention for this table we treat zero as boolean TRUE and one as boolean FALSE. Other non-zero values are treated as FALSE, but boolean opcodes will not return nonstandard values.

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
SUML
(SUM Logical)
$07 $6C0 None arg1, arg2 (TOP) -> bool (TOP) Add arg1 and arg2. Push TRUE if result is zero, FALSE if non-zero.
ANDL
(AND Logical)
$08 $6CA None arg1, arg2 (TOP) -> bool (TOP) Bitwise-AND arg1 and arg2. Push TRUE if result is zero, FALSE if non-zero.
CMP_EQ
(CoMParison EQual)
$0C $6F8 None arg1, arg2 (TOP) -> bool (TOP) Compare arg1 and arg2. Push TRUE if both arguments are equal, FALSE otherwise.
CMP_NEQ
(CoMParison Not EQual)
$0D $705 None arg1, arg2 (TOP) -> bool (TOP) Compare arg1 and arg2. Push TRUE if both arguments are not equal, FALSE otherwise.
CMP_LT
(CoMParison Less Than)
$0E $712 None arg1, arg2 (TOP) -> bool (TOP) Compare arg1 and arg2. Push TRUE if arg1 is less than arg2, FALSE otherwise.
CMP_LEQ
(CoMParison Less or EQual)
$0F $723 None arg1, arg2 (TOP) -> bool (TOP) Compare arg1 and arg2. Push TRUE if arg1 is less than or equal to arg2, FALSE otherwise.
CMP_GT
(CoMParison Greater Than)
$10 $752 None arg1, arg2 (TOP) -> bool (TOP) Compare arg1 and arg2. Push TRUE if arg1 is greater than arg2, FALSE otherwise.
CMP_GEQ
(CoMParison Greater or EQual)
$11 $763 None arg1, arg2 (TOP) -> bool (TOP) Compare arg1 and arg2. Push TRUE if arg1 is greater than or equal to arg2, FALSE otherwise.

Bitwise logic[edit]

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
OR
(bitwise OR)
$09 $6D7 None arg1, arg2 (TOP) -> value (TOP) Bitwise-OR arg1 and arg2 as the return value.
XOR
(bitwise eXclusive OR)
$0A $6E2 None arg1, arg2 (TOP) -> value (TOP) Bitwise-XOR arg1 and arg2 as the return value.
AND
(bitwise AND)
$0B $6ED None arg1, arg2 (TOP) -> value (TOP) Bitwise-AND arg1 and arg2 as the return value.
SLA
(Shift-Left Arithmetic)
$13 $784 None bits, shift (TOP) -> value (TOP) Shift bits left, shift times, while inserting zero bits, to produce value.

Arithmetic[edit]

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
SUB
(SUBtraction)
$14 $796 None minuend, subtrahend (TOP) -> difference (TOP) Subtract subtrahend from minuend to produce difference.
ADD
(ADDition)
$15 $7A1 None addend1, addend2 (TOP) -> sum (TOP) Add addend1 to addend2 to produce sum.
MOD
(MODulo)
$16 $7A9 None dividend, divisor (TOP) -> remainder (TOP) Integer-divide dividend by divisor and return only the remainder.
DIV
(DIVide)
$17 $7C3 None dividend, divisor (TOP) -> quotient (TOP) Integer-divide dividend by divisor and return only the quotient.
MUL
(MULtiply)
$18 $7ED None multiplicand, multiplier (TOP) -> product (TOP) Multiply multiplicand by multiplier to produce the product.

Memory & Stack Manipulation[edit]

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
STR
(SToRe)
$06 $68C None &address, value (TOP) -> (TOP) Store the value at the memory location referenced by &address. The exact memory operations performed depend on the target of *address.

If address is an indirect index, the memory location referenced by *address will be set to value.

If address is a predicate index, the bit referenced by *address will be set or reset based on if value is zero or non-zero.

It is illegal to STR into an immediate value, and doing so will cause the VM to halt operation.

INDIR
(INDIRect)
$1D $80F None immed (TOP) -> &address (TOP) Cast the value immed into an indirect memory index &address.
PRED
(PREDicate)
$1E $820 None immed (TOP) -> &pred (TOP) Cast the value immed into a predicate memory index &pred.
POPALL
(POP ALL)
$2C $831 None (...) -> (EMPTY) Empty the stack.
IMMED
(IMMEDiate)
$3D $8DE immed (16b) (TOP) -> immed (TOP) Push immed onto the data stack as an immediate value.
DB
(Declare Bytes)
$3E $941 string (null-terminated) (TOP) -> straddr (TOP) Copy null-terminated string data from the instruction stream into the string-building arena referred to by $C424.

The address of the newly copied string data will be pushed onto the data stack as an immediate value.

ARFREE
(ARena FREE)
$03 $671 None None Free the data in the string arena (or set up the string arena if it hasn't already been done).

This opcode should be used as soon as possible after you are done with the data in the string arena. The arena has a maximum capacity of 255 bytes, and memory is not reclaimed from use by a DB opcode until you ARFREE the entire arena.

NTSTR
(Name Temporary SToRe)
$B0 $1677 None srcaddr (TOP) -> (TOP) Store string data in the naming temporary string area.

This is primarily used by naming / password screens which need to redraw themselves while retaining the user's input data. srcaddr is the address of a string, usually provided by the DB opcode.

The naming temporary area has a maximum size of $E bytes, not counting the mandatory null terminator.

Execution Control[edit]

Execution Control opcodes control the address of the next instruction to execute, determined by BugVM's program counter. It consists of a bank address, base address, and offset address. The linkage directory determines what the bank and base addresses of a section are. The offset address is added to the base in order to calculate the address of the next instruction.

Caution: Parameters named "offset" for jump instructions refer to the program counter offset address, and do not imply the existence of PC-relative jumps instructions within Bugsite.

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
JMPT
(JuMP if True)
$37 $887 offset (16b) bool (TOP) -> (TOP) Jump to a new offset within the current linkage section if bool is TRUE.
JMP
(JuMP)
$38 $8AC offset (16b) None Jump to a new offset within the current linkage section.
RET
(RETurn)
$39 $8BB None None Return to the previously linked return address.
JAL
(Jump And Link)
$3F $8F0 offset (16b) None Jump to a new offset within the current linkage section. Store the offset of the next instruction on the link stack.
FARCALL $6A $91B None linkage_index (TOP) -> (TOP) Jump to the start of a new linkage section. Store the offset of the next instruction on the stack.
FARJMP
(FAR JuMP)
$6B $83B None linkage_index (TOP) -> (TOP) Jump to the start of a new linkage section, erasing the link stack in the process.

The previous linkage section is stored for later use.

NOP and NOP-alikes[edit]

BugVM contains a number of opcodes which do nothing, including both a single implementation of a NOP opcode used to fill in blank spots in the table as well as individual implementations which presumably did something in the past.

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
NOP
(Null OPeration),
ENOP $nn (Effective Null OPeration)
Too many to list $5E9 None None Does nothing.

This particular null-op implementation is used many times to fill space in the opcode table.

PNOP $19
(Probable Null OPeration)
$19 $80B None None Does nothing.
PNOP $1A
(Probable Null OPeration)
$1A $80C None None Does nothing.
PNOP $1B
(Probable Null OPeration)
$1B $80D None None Does nothing.
PNOP $1C
(Probable Null OPeration)
$1C $80E None None Does nothing.
PNOP $2F
(Probable Null OPeration)
$2F $835 None None Does nothing.
PNOP $30
(Probable Null OPeration)
$30 $836 None None Does nothing.
PNOP $31
(Probable Null OPeration)
$31 $837 None None Does nothing.
PNOP $32
(Probable Null OPeration)
$32 $838 None None Does nothing.
PNOP $33
(Probable Null OPeration)
$33 $839 None None Does nothing.
PNOP $34
(Probable Null OPeration)
$34 $83A None None Does nothing.
PNOP $35
(Probable Null OPeration)
$35 $87B None None Does nothing.
NPREF
(Null PREFix)
$36 $87C opcode, ??? None Executes the next opcode as normal.

This would appear to be just another NOP, but it's native implementation actually loads and executes the next byte as an opcode. Hence, it works like a prefix byte that does nothing.

Perhaps in a previous revision of the game, NPREF had a use.

PNOP $3A
(Probable Null OPeration)
$3A $8DB None None Does nothing.
PNOP $3B
(Probable Null OPeration)
$3B $8DC None None Does nothing.
PNOP $3C
(Probable Null OPeration)
$3C $8DB None None Does nothing.

Graphics Functions[edit]

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
TILELD
(TILE LoaD)
$72 $1BAC None linkage_index, tile_x, tile_y, base_tile, base_attr (TOP) -> (TOP) Load a precomposed tilemap from BugFS file linkage_index into the first tilemap in VRAM ($9800).

The base_tile and base_attr parameters allow the user to add a dynamic tile index and palette index offset to the tilemap. For example, if you loaded the tilemap's graphics into slot $30 on the second VRAM tile bank, with color data starting at BG palette 3, you could set base_tile to $30 and base_attr to Bank 1, Palette 3.

Tile X and Y coordinates allow you to control where the tilemap data is written. These coordinates are in tile units and are relative to the first visible tile on the screen (based on the current screen scroll).

Each tilemap's data starts with the width and height of the tilemap, followed by two bytes for each tile's ID and attributes, starting from the top-left of the tilemap and continuing right until the end, then the next line down. These IDs and attributes are relative to the base parameters as described above.

RESLD
(RESource LoaD)
$5F $9C6 None linkage_index, copy_start, copy_len, target_addr, target_bank (TOP) -> (TOP) Load graphics resources from BugFS file linkage_index into tile memory.

copy_start determines how far into the resource to copy from, and copy_len determines how much to copy from that point. Both of these are in units of 32 bytes - exactly the size of a single tile.

target_addr and target_bank determines where to place the copied resources in VRAM. They are native memory pointers, not indexed to anything.

PALLD
(PALette LoaD)
$75 $2F0E None linkage_index, is_bgpal, source_palette, target_palette (TOP) -> (TOP) Copy a color palette into color palette memory.

Palette color data will be copied from source_palette palettes into the file at linkage_index, into color memory at the given target_palette. If is_bgpal is True then the color data will be loaded into background palette memory; otherwise, color data will load into object palette memory.

source_palette and target_palette are both palette indices; it is not possible to copy part of a palette, or unaligned data from the filesystem.

SCRCURS
(SCReen CURSor)
$7E $C54 None x, y (TOP) -> (TOP) Set the tile cursor relative to the screen.

The tile cursor is a screen offset in increments of 8x8 pixels, used to control the positioning of various graphical operations on the screen, such as PRINTing text.

PRINT
(PRINT)
$4C $A84 None string_addr (TOP) -> (TOP) Print tile text onto the screen.

Printed text will appear on screen at the current tile cursor - usually set by an opcode like SCRCURS, WINCURS, or WINCOORD.

string_addr points to a null-terminated string in unbanked memory - usually some portion of the string arena that is written to by DB. Since that opcode returns an unbanked memory pointer on stack, one can print to the screen using just DB and PRINT opcodes.

The character $7F is special-cased in this function to print the player's name at $C9F0.

PRINT uses tile text in order to draw letters. A tile font must have been previously loaded in VRAM at tile location 0; it's encoded character value will be used as a tile index to draw with.

NTPRINT
(Name Temporary PRINT)
$B0 $1677 None None Print stored string data in the naming temporary area.
TMAPSAV
(Tile MAP SAVe)
$86 $1C92 None None Copy the contents of tile map 1 ($9800) to tile map 2 ($9C00).

Window Management[edit]

Windows are regions of the background layer adorned with a border, intended to be drawn over the active playfield to represent dialogue or certain kinds of menus.

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
WINCOORD
(WINdow COORDinate)
$7D $C24 None xmin, ymin, xmax, ymax (TOP) -> (TOP) Set the coordinates of the current window.

xmin, ymin, xmax, ymax are the screen pixel coordinates of the left, top, right, and bottom edges of the window, respectively; including the frame. They will be used to configure Window Manager variables for other WINnn opcodes.

The tile cursor will be set to the X and Y coordinates of the contents of the specified window, so you can PRINT to it immediately. This is equivalent to WINCURS with an x and y of zero.

WINFRAME
(WINdow FRAME)
$B3 $AFC None None Draw the current window's frame.

You must have an active window style loaded into VRAM.

If this window is a menu, and the item counts are configured correctly, WINFRAME will also draw the overflow arrows.

WINFRARROW
(WINdow FRame ARROW)
$AD $B05 None arrow_position (TOP) -> (TOP) Draw the current window's frame, with overflow arrows.

This is equivalent to WINFRAME + WINARROW all at once.

WINOPEN
(WINdow OPEN)
$B2 $B2D None None Animate the current window opening.

This animation requires that the window span the whole width of the screen and that TMAPSAV had been used to copy the screen before the window frame was drawn (e.g. with WINFRAME). Execution of BugVM code is halted until the animation completes.

WINDIALOG
(WINdow DIALOG)
$5A $AED None None Draw and open the current window.

This is equivalent to TMAPSAV + WINFRAME + WINOPEN all at once.

WINCLR
(WINdow CLeaR)
$5B $97C None None Clear the active window region.

Tiles will be set to $20, which is the encoded byte for a space. In any loaded font, this tile is intended to be blank.

WINCURS
(WINdow CURSor)
$7E $C63 None x, y (TOP) -> (TOP) Set the tile cursor relative to the window.
WINCHOICE
(WINdow CHOICE)
$70 $13B4 None choice, choice, (...) -> (EMPTY) Print a series of menu choices.

Each choice will be prefixed with a space, to make room for the selection cursor. They will also be printed single-spaced, as opposed to normal line printing which is double-spaced.

The choice arguments are string pointers (e.g. from DB); this opcode consumes all pointers on the data stack.

WINARROW
(WINdow ARROW)
$F4 $B10 None arrow_position (TOP) -> (TOP) Draw overflow arrows for a given menu position.

arrow_position is the index of a particular selected menu choice. Overflow arrows will be drawn on top of the window frame based on this value.

WINWAIT
(WINdow WAIT)
$60 $A12 None None Wait for user input.

BugVM execution will halt until the user presses the "A" button on the system. A blinking A-button prompt will be displayed at the bottom-right of the window range.

WININPUT
(WINdow INPUT)
$D9 $A1D None (TOP) -> input_changed (TOP) Wait for user input.

BugVM execution will halt until the user presses any button on the system. A blinking A-button prompt will be displayed at the bottom-right of the window range.

The state of which buttons were pressed to continue is returned on the stack. The format for input data is that of eight bit-flags; from highest to lowest: Start, Select, Button B, Button A, Down, Up, Left, and Right. The upper 8 bits of data are always zero.

WINBRK
(WINdow BReaK)
$82 $ADA None None Insert a 'page break' of sorts between two full windows' worth of text.

Internally this is equivalent to a WINWAIT followed by a WINCLR.

Sprite Management[edit]

BugVM contains a fully featured metaspriting and animation system, which we've nicknamed Sprite Manager.

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
SPRDIR
(SPRite DIRection)
$8C $324F None slot, direction (TOP) -> (TOP) Set the facing direction of a given sprite.

slot refers to the sprite to control (0 thru 7) and direction is the direction to make it face. If either are invalid, then nothing will happen. Consult SpriteManager documentation for more information on which direction numbers are valid.

SPRCTRL
(SPRite ConTRoL)
$A6 $235E None slot, input (TOP) -> (TOP) Control a given sprite with user or simulated input.

slot refers to the sprite to control (0 thru 7) and input is the input state or simulated input state to send to the sprite.

The given sprite will have a movement animation queued on it if and only if the space for the sprite to move to is free. Otherwise, no action will be taken. Queued sprite animations can be played with other SPR opcodes.

Consult WININPUT for information about the format of input state.

SPRCHOREO
(SPRite CHOREOgraphy)
$78 $3269 None file_id, slot (TOP) -> (TOP) Place a sprite under control of a choreography script.

file_id refers to the BugFS file containing the choreography script and slot is the sprite to be placed under it's control. The sprite in slot will have the choreography script installed, and then frozen in place for later execution.

The choreography script will be copied into one of eight choreography script slots. Each slot is 128 bytes max; and lives in an array starting at $2:DC00. This means choreography scripts may not exceed 64 instructions.

SPRANIM
(SPRite ANIMate)
$6E $2775 None file_id, ctxt_slot, slot (TOP) -> (TOP) Load an animation into a sprite animation context for a given sprite.

file_id is the BugFS file ID for a sprite animation to play.

ctxt_slot refers to the animation context that will execute the animation script; while slot refers to the sprite to be animated. Usually both indices are the same; for example, idle-sprite choreography assumes that sprite 5's animations must always be loaded into animation context 5.

SPRPOSPLAY
(SPRite POSition and PLAY)
$6F $2788 None slot, x, y (TOP) -> (TOP) Position and then play a previously loaded animation on a given sprite.

slot refers to the sprite being played (0 thru 7). It must already have an animation queued. It's origin will be placed at the coordinates (x, y).

Additionally, all active sprite animations will be evaluated for one frame.

SPRPLAY
(SPRite PLAY)
$92 $27B3 None slot (TOP) -> (TOP) Play a previously-loaded animation on a given sprite.

slot refers to the sprite being played (0 thru 7). It must already have an animation queued.

This opcode is not in use in Network Adventure Bugsite.

SPRWAIT
(SPRite WAIT)
$C6 $27D8 None slot, should_clear (TOP) -> (TOP) Wait for sprite animation to finish.

BugVM execution will halt until the given sprite in slot finishes animating. Optionally, if should_clear is TRUE, then we will also clear any deactivated sprites from the screen.

SPRWAITALL
(SPRite WAIT ALL)
$79 $27BB None None Wait for all sprite animations to finish.

BugVM execution will halt until all sprite animations finish, then any deactivated sprites will be cleared from the screen.

This opcode is not in use in Network Adventure Bugsite.

SPRINPUT
(SPRite INPUT)
$61 $A29 None (TOP) -> input_changed (TOP) Wait for user input.

BugVM execution will halt until the user presses any button on the system. Sprite animations will continue to execute during this period of halted execution.

Consult WININPUT for information about this opcode's output format.

SPRHOLD
(SPRite HOLD)
$D2 $A39 None (TOP) -> input_held (TOP) Wait for user input.

BugVM execution will halt until the user presses, or is already holding, any button on the system. Sprite animations will continue to execute during this period of halted execution.

Consult WININPUT for information about this opcode's output format.

SPRFINISH
(SPRite FINISH)
$A7 $2386 None None Wait for sprites to finish moving.

BugVM execution will halt until all sprites have finished moving.

SPRHIDE
(SPRite HIDE)
$CF $2877 None slot (TOP) -> (TOP) Deactivate sprite in slot.
SPRWIPE
(SPRite WIPE)
$8E $289C None None Deactivate all sprites and clear them from the screen.
SPRFREEZE
(SPRite FREEZE)
$CB $32C7 None slot (TOP) -> (TOP) Manually freeze sprite in slot.

This opcode is not in use in Network Adventure Bugsite.

SPRTHAW
(SPRite THAW)
$CB $32D5 None slot (TOP) -> (TOP) Manually unfreeze sprite in slot.

This does not revert the freeze caused by SPRCHOREO - SPRFREEZE and SPRCHOREO freezes are treated separately.

This opcode is not in use in Network Adventure Bugsite.

Attribute Table Utilities[edit]

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
PRKEY
(PRint KEY item)
$9F $165A None attr_index (TOP) -> (TOP) Read the given Key Item's Attribute Table block and print it's name.
BLKKEY
(BLocK KEY item)
$A0 $42A None attr_index (TOP) -> (TOP) Read the given Key Item's Attribute Table block into W_Battle_AttrStaging.
PRMOVE
(PRint MOVE)
$A1 $1668 None attr_index (TOP) -> (TOP) Read the given Battle Move's Attribute Table block and print it's name.
BLKMOVE
(BLocK MOVE)
$A2 $3FE None attr_index (TOP) -> (TOP) Read the given Battle Move's Attribute Table block into W_Battle_AttrStaging.
PRMON
(PRint MONster)
$AF $1622 None attr_index (TOP) -> (TOP) Read the given Bug's Attribute Table block and print it's name.
BLKMON
(BLocK MONster)
$BB $39C None attr_index (TOP) -> (TOP) Read the given Bug's Attribute Table block into W_Battle_AttrStaging.

This instruction switches between two different Attribute Tables based on the value of W_System_GameVersion.

PRCHIP
(PRint CHIP)
$E3 $1661 None attr_index (TOP) -> (TOP) Read the given Chip's Attribute Table block and print it's name.
BLKCHIP
(BLocK CHIP)
$E2 $456 None attr_index (TOP) -> (TOP) Read the given Chip's Attribute Table block into W_Battle_AttrStaging.
BLKENC
(BLocK ENCounter)
$F1 $3CD None attr_index (TOP) -> (TOP) Read the given Encounter's Attribute Table block into W_Battle_AttrStaging.

There does not appear to be a PRENC instruction.

This instruction switches between two different Attribute Tables based on the value of W_System_GameVersion.

PRNAME
(PRint NAME)
$A5 $162A None None Print the name of the currently loaded Attribute Table block.

All PRint instructions that reference Attribute Table data execute this opcode. It prints data from $CF30, which is an offset into W_Battle_AttrStaging that appears to be a standard offset for this kind of data.

PRNICK
(PRint NICKname)
$E5 $1638 None None Print the name of the currently loaded Nickname block.

Like PRNAME, this opcode prints the name section of a datablock. However, it prints data stored in the Nickname datablock area, $CC30, which is an offset into the W_NameInput_NicknameDataBlock area. The name "nickname data block area" is assumed; it is not currently known what semantic purpose this area serves other than use by the naming screens.

Variable Width Font Rendering[edit]

These opcodes are exclusive to the English patch of Bugsite and represent new opcodes. They overlap existing ENOP instructions starting from $1F and thus can only be used if you are using BugTools' auto-optimize feature to remove existing ENOP instructions.

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
VWFCONFIG
(VWF CONFIG)
$1F (varies) None font, metrics, bg (TOP) -> (TOP) Configure the font used for VWF text rendering.

font and metrics refers to the file IDs of the font character data and metrics data, respectively. Character data is stored similarly to FWF fonts, but left-aligned; while metrics data is an array of one byte per character indicating width of each character.

This instruction only configures the font in use by VWF; it does not enable VWF.

VWFENABLE
(VWF ENABLE)
$20 (varies) None ring_start, ring_end (TOP) -> (TOP) Enable VWF rendering.

When enabled, PRINT instructions will use the VWF font rendering path. A font should have already been configured via VWFCONFIG before enabling VWF.

ring_start and ring_end are a range of tiles to use for VWF rendering. Tiles from $100 onward indicate tiles in the second VRAM bank. This range of tiles will constitute a ring buffer of free tiles to be overwritten with VWF text, with drawn tiles starting from the first tile in the ring. Most importantly, new text will overwrite old tiles if the ring runs out of space, so you must ensure text that you don't intend to overwrite occupies it's own rings.

VWFDISABLE
(VWF DISABLE)
$21 (varies) None None Disable VWF rendering.

Rendering will return to tile based fonts, using the same tiles normally used for tile text. Note that if you have overwritten these tiles, you will need to reload the FWF font equivalents.