mvbg

VM_INVOKE

VM_INVOKE is a GBVM instruction that allows you to call specific, pre-defined C functions within the Game Boy engine until they signal completion (return true). This provides a bridge between your GBVM script and lower-level engine functionalities written in C.

Purpose: While GBVM provides a robust scripting environment, certain complex or performance-critical operations are often implemented directly in C for efficiency and direct hardware control. VM_INVOKE is used to:

Syntax:

VM_INVOKE BANK, ADDR, N, PARAMS

Usage Example: Implementing a Camera Shake Effect

Let’s say you want to shake the camera when the player takes damage or a significant event occurs. The engine provides a _camera_shake C function for this.

; In your damage routine or event script:

; Assume _camera_shake expects 1 argument: the number of shakes
; Push the number of shakes onto the stack
VM_PUSH_CONST 5 ; Shake the camera 5 times

; Invoke the _camera_shake C function
VM_INVOKE BANK(_camera_shake), _camera_shake, 1, 0
; BANK(_camera_shake): The bank where _camera_shake is located.
; _camera_shake: The address of the function.
; 1: The number of arguments (5) to remove from the stack after invocation.
; 0: (PARAMS) This indicates that the parameters are on the stack.

; ... continue script after camera shake completes ...

; Example of how _camera_shake might be defined in C (conceptual):
; // In a C source file (e.g., src/core/camera.c)
; #include <gb/gb.h>
; #include "vm.h"
; UBYTE camera_shake_count;
; UBYTE camera_shake_timer;
; UBYTE camera_shake_active = FALSE;
;
; // This function is called by VM_INVOKE
; UBYTE _camera_shake(SCRIPT_CTX * THIS) { // SCRIPT_CTX is the VM context
;   if (!camera_shake_active) {
;     camera_shake_count = SCRIPT_POP_BYTE(THIS); // Get argument from stack
;     camera_shake_timer = 0;
;     camera_shake_active = TRUE;
;   }
;
;   // Logic to move camera based on camera_shake_count and camera_shake_timer
;   // ...
;
;   if (camera_shake_count == 0) {
;     camera_shake_active = FALSE;
;     return TRUE; // Signal completion
;   } else {
;     return FALSE; // Not yet complete
;   }
; }

In this example, VM_PUSH_CONST 5 places the argument for _camera_shake onto the stack. VM_INVOKE then calls the C function. The GBVM script will pause at this point, and _camera_shake will execute frame by frame until its internal logic determines it’s finished (by returning TRUE). Once it returns TRUE, VM_INVOKE removes the argument from the stack, and the GBVM script resumes execution.

Analogy to other programming languages: This is analogous to using a Foreign Function Interface (FFI) in languages like Python (ctypes) or Java (JNA) to call functions written in C or C++. You are explicitly telling the high-level scripting environment to temporarily hand over control to a low-level, pre-compiled function, often passing arguments and expecting a return value or a completion signal.