--- layout: page title: Local Doors — Native v86 Emulation --- ## Native DOS Emulation via v86 ENiGMA½ includes a built-in x86/DOS emulator powered by [v86](https://github.com/copy/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: ```bash 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](#runbatch-variables). See [One Image, Multiple Doors](#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):** ```hjson 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):** ```hjson 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](http://pcmicro.com/xtalk/x00.html) — 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: ```bat 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`: ```hjson 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](https://en.wikipedia.org/wiki/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](http://pcmicro.com/xtalk/x00.html) works well with v86. Load it from `runBatch` (per-door, recommended) rather than `FDCONFIG.SYS` (global): ```bat 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 Boot and wire COM1 to this terminal (interactive) oputil.js v86 desktop 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. ```bash # 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 ```bash # 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](https://dosbox-x.com/) 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 * [Local Doors](local-doors.md) * [External DOS Emulators](local-doors-dos-emulation.md) * [Scripts & Native Binaries](local-doors-abracadabra.md) * [v86](https://github.com/copy/v86) — upstream JavaScript x86 emulator