Local Doors — Native v86 Emulation

Native DOS Emulation via v86

ENiGMA½ includes a built-in x86/DOS emulator powered by v86 — a JavaScript x86 emulator that runs entirely within Node.js. The v86_door module boots a FreeDOS disk image and bridges COM1 directly to the user’s connection, with no external emulator installed on the server.

:information_source: The emulator runs in a dedicated worker thread, so it does not block ENiGMA½’s event loop. Each active session gets its own isolated emulator instance.


How It Works

  1. ENiGMA½ generates the appropriate drop file for the user (DORINFO, DOOR.SYS, etc.)
  2. The drop file is written into a small in-memory FAT12 floppy image — no temp files on disk
  3. v86 boots the op-supplied FreeDOS disk image from the hard drive (C:)
  4. The drop file floppy is mounted as A: in FreeDOS
  5. The door’s AUTOEXEC.BAT copies the drop file from A: and launches the game
  6. COM1 serial I/O is bridged directly between v86 and the user’s connection
  7. When the door exits and FreeDOS powers off, the session ends cleanly

Prerequisites

BIOS Files

v86 requires SeaBIOS and a VGA BIOS image. The ENiGMA½ installer (misc/install.sh) downloads these automatically to misc/v86_bios/. To download manually:

mkdir -p misc/v86_bios
curl -fL https://github.com/copy/v86/raw/master/bios/seabios.bin -o misc/v86_bios/seabios.bin
curl -fL https://github.com/copy/v86/raw/master/bios/vgabios.bin -o misc/v86_bios/vgabios.bin

Disk Image

You need a raw FreeDOS disk image (.img) with your door game pre-installed. Raw .img images are fully compatible between QEMU, DOSBox-X, and v86 — set up your image with QEMU or DOSBox-X, then point v86_door at it on the production server.


Configuration

Item Required Description
name :+1: Door name. Used as a key for tracking concurrent sessions.
image :+1: Path to the raw FreeDOS disk image (.img).
dropFileType :-1: Drop file to generate and inject onto the A: floppy: DORINFO, DOOR, or DOOR32. Omit if the door needs no drop file.
runBatch :-1: Multi-line batch script written to A:\RUN.BAT at runtime. Supports variable substitution. See One Image, Multiple Doors.
nodeMax :-1: Max concurrent sessions. 0 = unlimited.
tooManyArt :-1: Art spec to display when nodeMax is exceeded.
memoryMb :-1: Guest RAM in MB. Default: 64.
biosPath :-1: Path to SeaBIOS image. Default: misc/v86_bios/seabios.bin.
vgaBiosPath :-1: Path to VGA BIOS image. Default: misc/v86_bios/vgabios.bin.

Drop File Filenames on A:

dropFileType Filename on A:
DORINFO DORINFOx.DEF (x = node-based suffix per spec)
DOOR DOOR.SYS
DOOR32 door32.sys

runBatch Variables

When runBatch is set, ENiGMA replaces the following variables before writing RUN.BAT:

Variable Description Example
{dropFile} Drop file filename DORINFO1.DEF
{node} Node number 1
{baud} Baud rate 57600

Example Menu Entries

Single-player door (PimpWars):

doorPimpWars: {
    desc: Playing PimpWars
    module: v86_door
    config: {
        name: PimpWars
        image: /path/to/images/freedos_doors.img
        dropFileType: DORINFO
        nodeMax: 1
        tooManyArt: DOORMANY
        runBatch:
            '''
            @ECHO OFF
            C:\FOSSIL\X00.SYS
            COPY A:\{dropFile} C:\DOORS\PW\
            CD C:\DOORS\PW
            PW.EXE {node}
            ECHO Returning to BBS, please wait... > COM1
            '''
    }
}

Multi-node door with shared game state (TradeWars 2002):

doorTradeWars2002: {
    desc: TradeWars 2002
    module: v86_door
    config: {
        name: TradeWars2002
        image: /path/to/images/tw2002.img
        dropFileType: DORINFO
        nodeMax: 4
        tooManyArt: DOORMANY
        runBatch:
            '''
            @ECHO OFF
            C:\FOSSIL\X00.SYS
            C:\FREEDOS\BIN\SHARE.COM
            COPY A:\{dropFile} C:\DOORS\TW2\{dropFile}
            CD C:\DOORS\TW2
            TW2.EXE
            C:\FREEDOS\BIN\FDAPM POWEROFF
            '''
    }
}

:information_source: ANSI color with DORINFO: ENiGMA½ sets the DORINFO graphics field to 2 (ANSI color), which is the value required by RBBS-mode doors such as TradeWars 2002. A value of 1 enables IBM high-bit characters but not color in strict RBBS mode.


Image Preparation

Your disk image must contain:

  • A working FreeDOS installation
  • Your door game(s) installed (e.g. C:\DOORS\PIMPWARS\)
  • Optionally, a FOSSIL driver such as X00 — required by most classic DOS doors
  • An AUTOEXEC.BAT (or FDAUTO.BAT) that calls A:\RUN.BAT and powers off

AUTOEXEC.BAT Convention

Set up your image’s AUTOEXEC.BAT once. ENiGMA writes RUN.BAT to A: at runtime with the door-specific launch commands:

CALL A:\RUN.BAT
ECHO Shutting down, please wait... > COM1
FDAPM POWEROFF
  • CALL A:\RUN.BAT — executes the per-door launch script ENiGMA injects at runtime
  • ECHO ... > COM1 — sends a message to the user’s terminal while FreeDOS shuts down (can take a few seconds)
  • FDAPM POWEROFF — shuts FreeDOS down cleanly; placed after the CALL so it always fires even if the door crashes

One Image, Multiple Doors

Because RUN.BAT is generated at runtime, a single FreeDOS image can host multiple doors. Each door has its own menu entry pointing at the same image path with a different runBatch:

doorPimpWars: {
    module: v86_door
    config: {
        name: PimpWars
        image: /path/to/images/freedos_doors.img
        dropFileType: DORINFO
        nodeMax: 1
        runBatch:
            '''
            COPY A:\{dropFile} C:\DOORS\PW\
            C:\FOSSIL\X00.SYS
            CD C:\DOORS\PW
            PW.EXE {node}
            ECHO Returning to BBS, please wait... > COM1
            '''
    }
}

doorSmurfCombat: {
    module: v86_door
    config: {
        name: SmurfCombat
        image: /path/to/images/freedos_doors.img   // same image
        dropFileType: DOOR
        nodeMax: 1
        runBatch:
            '''
            COPY A:\{dropFile} C:\DOORS\SMURF\
            C:\FOSSIL\X00.SYS
            CD C:\DOORS\SMURF
            SMURF.EXE {node}
            ECHO Returning to BBS, please wait... > COM1
            '''
    }
}

:information_source: All concurrent sessions for the same image path share a single in-memory disk buffer (SharedArrayBuffer). Guest writes from one session are immediately visible to others — exactly as they would be with a real shared disk. Use nodeMax: 1 for single-player doors that have no locking. For multi-node games that rely on file/record locking (e.g. TradeWars 2002), load a FOSSIL-aware SHARE driver (C:\FOSSIL\X00.SYS plus C:\FREEDOS\BIN\SHARE.COM) in runBatch — the game handles concurrent access the same way it would on a real BBS.

FOSSIL Driver

Most classic DOS doors use the FOSSIL serial interface for COM1 I/O. If your door fails to start or falls back to local mode, a FOSSIL driver is needed. X00 works well with v86.

Load it from runBatch (per-door, recommended) rather than FDCONFIG.SYS (global):

C:\FOSSIL\X00.SYS

Or in FDCONFIG.SYS if all doors on the image need it:

DEVICE=C:\FOSSIL\X00.SYS

Creating and Configuring Images with oputil v86

ENiGMA½ ships two oputil subcommands for working with disk images without needing QEMU or DOSBox-X installed on the server:

oputil.js v86 console <image.img>   Boot and wire COM1 to this terminal (interactive)
oputil.js v86 desktop <image.img>   Boot in a full VGA browser session

console — best for doors that output entirely through COM1 (most doors). Use CTTY COM1 in the image’s FDAUTO.BAT to redirect all I/O. Ctrl+] exits and saves changes back to the image file automatically.

desktop — boots the image in a small local HTTP server and opens your browser to a full VGA canvas. Use this for setup programs that write directly to VGA (e.g. door configuration wizards). Click Save Image to write changes back to the image file on the server — no browser download dialog appears.

# Interactive COM1 terminal
node core/oputil/oputil_main.js v86 console /path/to/tw2002.img

# Full VGA browser session (opens browser automatically)
node core/oputil/oputil_main.js v86 desktop /path/to/tw2002.img --port 18086

See also: oputil.js fat for listing and copying files into images without booting them.

Creating the Image with QEMU

# Create a 500MB raw image
qemu-img create -f raw freedos_mygame.img 500M

# Install FreeDOS (boot from CD)
qemu-system-i386 -hda freedos_mygame.img -cdrom FD14CD.iso -boot d

# Boot into FreeDOS to install your door
qemu-system-i386 -hda freedos_mygame.img

# Transfer files from host using QEMU's vfat driver — files appear on D:
qemu-system-i386 -hda freedos_mygame.img -hdb fat:/path/to/door/files

DOSBox-X is a graphical alternative for image setup on Windows, macOS, and Linux. See the DOSBox-X documentation for imgmount.

FreeDOS Boot Configuration for Fast Startup

For ~5 second boot times, configure FreeDOS to use Emergency Mode (no memory managers, no networking). In FDCONFIG.SYS:

MENUDEFAULT=5,0

Ensure the 5? config block loads your FOSSIL driver:

5?DEVICE=C:\FOSSIL\X00.SYS
5?SHELL=C:\FreeDOS\BIN\COMMAND.COM C:\FreeDOS\BIN /E:1024 /P=C:\FDAUTO.BAT

See Also