Skip to content

Creating your own control characters

ISSOtm edited this page Apr 4, 2025 · 3 revisions

Note that there can only be up to 128 control characters in total, including gb-vwf's built-in ones. But since there are far fewer than 128 built-in control characters, gb-vwf lets you add your own!

  1. Declare the control character in the config file, using the control_char macro.

    Its first argument is the name of the control character's constant/charmap entry; the second argument is the address of the function that evaluates the control character; and any further arguments declare any bytes that the control character may take as arguments.

    Those extra arguments follow .tbl syntax, and are crucial for the auto-linewrapper to function correctly—the auto-linewrapper uses the number of arguments to this macro to properly process control characters.

    (If you're not planning to use .tbl files, it's okay to put dummy values there, but the arguments have to be present.)

    Note that if the control character breaks lines, an extra argument should be prepended, consisting of a single ! character.

  2. Write the control character's handler!

    It is simply a function that gets the input stream pointer in de, and is expected to return a pointer to the following character in de.

    In essence, the function can simply read a byte from [de] and increment de whenever it requires an argument.

    All other registers are fair game to overwrite.

Caveats

  • It follows from the description above that the auto-linewrapper does not support control characters with a variable number of arguments.
  • The auto-linewrapper does not call custom control character handlers. (This also simplifies writing a handler, since it's only called in a single way.)
  • The auto-linewrapper assumes that no control character prints anything.

(If any of those are a dealbreaker to you, feel free to modify gb-vwf accordingly, and/or to contact me; popular enough characters can end up getting built into gb-vwf itself.)

Example

Let's create a control character that prints a 16-bit number stored in RAM. (This could be useful to print how much money the player has, for example.)

  1. Declare the control character in the config file:

    	control_char PRINT_NUM, PrintNumber, low=%X,high=%X
  2. The implementation of the control character itself, placed in any other file:

    PrintNumber::
    	; Read the pointer to the number.
    	ld a, [de] :: inc de ::	ld l, a
    	ld a, [de] :: inc de ::	ld h, a
    	; Read the actual number.
    	ld a, [hli] :: ld b, [hl] :: ld c, a
    	; Save the pointer to return to to a new stack entry.
    	ld hl, wSourceStack.len
    	ld a, [hl] ; Not decrementing means that we'll point at the entry's second byte.
    	inc [hl]
    	add a, a ; Each entry is 2 bytes.
    	add a, l :: ld l, a :: adc a, h :: sub l :: ld h, a
    	ld a, e :: ld [hld], a :: ld [hl], d
    
    	; Write the number in decimal to a buffer.
    	; (How that's done is not very important).
    	ld de, .charBuf :: call WriteDecimalChars
    	ld a, VWF_END :: ld [de], a
    	; Continue reading characters from that buffer.
    	ld de, .charBuf
    	ret
    
    .charBuf
    	ds 6 ; "65535<END>"

    (Note that PrintNumber must be exported, here via ::, so that it's visible within vwf.asm.)

Clone this wiki locally