• BBS door that plays NES games in SyncTERM using sixel graphics: game li

    From StingRay@1200:1/1 to ALL on Thu Oct 1 11:05:02 2026

    https://github.com/AlexCorris/nesdoor



    NESDOOR v2.8 - NES games over sixel for BBS callers ============================================================================== A game list of the .nes files in roms/, the picture drawn with sixel
    graphics, real key-down/key-up input and the game's own sound in SyncTERM,
    and optional 2-player games between two nodes.

    Callers need a sixel-capable terminal. SyncTERM (syncterm.net) is the one
    to recommend: it also plays the sound and reports held keys. Other terminals get a notice with "Try anyway? (Y/N)".

    FILES
    nesdoor.py the door
    retro.py talks to the emulator core
    fceumm_libretro.so the NES emulator core (Linux x86-64, see NOTES)
    twoplayer.py 2-player link between nodes
    conn.py BBS connection (stdio / DOOR32 socket), terminal check
    sixel.py graphics encoder
    nesdoor.sh Linux launcher (logs to nesdoor.log)
    nesdoor.bat Windows launcher
    nesdoor.ini settings - created on first run
    LICENSE GNU GPL v2
    roms/ your .nes files (you supply these)
    sessions/ open 2-player games - created automatically
    saves/<player>/ each player's saved games - created automatically


    ============================================================================== FRESH LINUX INSTALL (from scratch) ============================================================================== Examples use a Mystic BBS in /home/mystic/mystic running as user "mystic". Change the paths and user name to match your system.

    1. Install the system packages (Debian / Ubuntu; needs sudo once):

    sudo apt update
    sudo apt install python3 python3-venv unzip

    Python 3.10 or newer is fine (check with: python3 --version).

    2. Unpack the door as the BBS user, from the BBS "doors" folder:

    cd /home/mystic/mystic/doors
    unzip -o /home/mystic/nesdoor_v2.zip

    This creates /home/mystic/mystic/doors/nesdoor. Unzip here, NOT inside
    an existing roms/ folder.

    3. Give the door its own Python environment and the one library it needs:

    cd /home/mystic/mystic/doors/nesdoor
    python3 -m venv venv
    ./venv/bin/pip install numpy
    chmod +x nesdoor.sh

    (Optional fallback emulator with no sound, only used if the .so file is
    missing: ./venv/bin/pip install cynes)

    4. Add games: copy .nes files straight into roms/ (not into subfolders).

    mkdir -p roms
    cp /path/to/your/games/*.nes roms/
    ls roms

    File names become titles: Super_Mario_Bros.nes -> "Super Mario Bros".

    5. Check that the emulator loads (replace the file name with one of yours):

    ./venv/bin/python -c "import retro; c = retro.Core( \
    'fceumm_libretro.so', 'roms/Super_Mario_Bros.nes', '.'); \
    print('OK', round(c.fps, 1), 'fps')"

    You should see: OK 60.1 fps
    An error mentioning GLIBC or "cannot open shared object" means the
    included core doesn't suit your Linux - build your own (see NOTES).

    6. Add a menu command in Mystic (MCFG / menu editor):

    Command: (D3) Exec DOOR32 program
    Data: mystic/doors/nesdoor/nesdoor.sh %Pdoor32

    That opens the game list. To jump straight into one game, put its file
    name (without .nes) first: mystic/doors/nesdoor/nesdoor.sh tetris %Pdoor32

    7. Try it from SyncTERM. You should get the game list; pick a game, read the
    controls screen, press ENTER. The first run creates nesdoor.ini.

    8. If anything drops you straight back to the BBS menu:

    tail -20 /home/mystic/mystic/doors/nesdoor/nesdoor.log

    The START line shows what the launcher passed; any Python error follows.

    Synchronet on Linux: same steps 1-5, then in SCFG add an online program with command line /path/to/nesdoor/nesdoor.sh %n , native executable, standard
    I/O intercepted ("Intercept I/O" = Yes), drop file DOOR32.SYS.

    UPDATING LATER
    Zip install: unzip the new version from the doors folder exactly as in
    step 2. Your venv, roms/, saves/, nesdoor.ini and log are left alone.
    Git install: see INSTALL / UPDATE WITH GIT below.


    ============================================================================== INSTALL / UPDATE WITH GIT ============================================================================== Source: https://github.com/AlexCorris/nesdoor
    Git never touches your venv, roms/, saves/, sessions/, nesdoor.ini or logs - they're listed in .gitignore - so "git pull" is a safe one-line update.
    The emulator core (.so) isn't kept in git; it comes from the Releases page.

    NEW INSTALL (replaces steps 1-3 above)

    sudo apt install git python3 python3-venv
    cd /home/mystic/mystic/doors
    git clone https://github.com/AlexCorris/nesdoor.git
    cd nesdoor
    U=https://github.com/AlexCorris/nesdoor/releases/latest/download
    wget $U/fceumm_libretro.so
    python3 -m venv venv
    ./venv/bin/pip install numpy
    mkdir -p roms # then copy your .nes files in

    Then carry on from step 5 (check the emulator) and step 6 (Mystic menu).

    UPDATE

    cd /home/mystic/mystic/doors/nesdoor
    git pull

    Nothing else is needed unless the release notes say the emulator core
    changed; then fetch it again with the two U= / wget lines above, adding
    -O fceumm_libretro.so to the wget line so it overwrites the old file.

    SWITCH AN EXISTING ZIP INSTALL TO GIT (keeps your games, saves and settings)

    cd /home/mystic/mystic/doors/nesdoor
    git init -b main
    git remote add origin https://github.com/AlexCorris/nesdoor.git
    git fetch origin
    git reset --hard origin/main
    git branch --set-upstream-to=origin/main main

    "reset --hard" replaces the door's program files with the GitHub copies.
    Your untracked files (venv, roms, saves, ini, the .so) are not touched.
    From then on, "git pull" updates it.

    IF "git pull" COMPLAINS ABOUT LOCAL CHANGES
    That means a program file (usually nesdoor.sh) was edited by hand. Keep
    your own tweaks in nesdoor.ini where possible. To update anyway:
    git stash # set your edits aside
    git pull
    git stash pop # put them back (fix any conflict it reports)
    Or throw your edits away: git checkout -- nesdoor.sh && git pull


    DROP FILES
    The door reads, in this order:
    1. BBSDEV.DRP - the modern format (https://realdeuce.github.io/bbsdev.drp/).
    Found through the BBSDEV_DRP environment variable the BBS sets, or a
    BBSDEV.DRP file/folder on the command line. Supported I/O types: stdio,
    socket, local. Used from it: the alias, the stable user key (saves stay
    with the player even if they change alias), the forced logoff time (the
    door saves the game and exits on time), and the terminal encoding.
    2. DOOR32.SYS - alias from line 7, socket handle from line 2.
    3. DOOR.SYS - alias from line 36 (or line 10).
    An invalid BBSDEV.DRP is rejected with a note in nesdoor.log and the door
    falls back to the next drop file.


    ============================================================================== PLAYING ============================================================================== GAME LIST UP/DOWN choose, PGUP/PGDN page, HOME/END, ENTER play.
    Just type to search (titles starting with the text come first,
    then titles containing it). BACKSPACE erases, Ctrl+U clears.
    Ctrl+Q (or Esc Esc) leaves the door.

    CONTROLS D-pad = arrows or WASD A = X or Space B = Z
    Start = Enter Select = Tab or Right Shift
    M = sound on/off Ctrl+Q or Esc Esc = back to the list
    Ctrl+S = save your spot Ctrl+L = load it Ctrl+R = reset
    A controls screen with a gamepad picture appears before each game.

    HELD KEYS In SyncTERM the door turns on physical key reporting, so holding
    Right while tapping Jump works like a real controller. Other
    terminals get timed holds (--hold / --carry) and E / Q combo keys
    (jump right / jump left).

    2 PLAYERS On the controls screen press 2 instead of ENTER: you are PLAYER 1
    and the game is offered to the other nodes. It appears at the top
    of their game list as "> JOIN <you> as PLAYER 2: <game>". The
    joiner gets controller 2 and sees and hears the same game. Player
    2 can join or leave any time. Both callers must be on the same
    machine. Needs the libretro core (not the cynes fallback).

    SAVING Three kinds, all per player and per game (saves/<player>/):
    * Leaving a game (Ctrl+Q, Esc Esc, idle, or even hanging up)
    snapshots it. Next time, the controls screen says "You have a
    saved game from <date>": ENTER continues, N starts over.
    * Ctrl+S saves your spot any time; Ctrl+L jumps back to it.
    * Games with a battery save on the cartridge (Zelda, Final Fantasy,
    Dragon Warrior...) keep their in-game save files too, just like
    the real cartridge - even if the player starts over with N.
    Ctrl+R presses the console's RESET button (saves untouched).
    To wipe everything for one game and start from scratch, press R
    on its controls screen and confirm with Y - that erases the
    continue point, the Ctrl+S save and the cartridge save for that
    player only.
    In 2-player games the host's saves are used. Saving needs the
    libretro core (not the cynes fallback).

    IDLE 10 minutes without a key in a game returns to the list; 5 minutes
    idle in the list leaves the door.


    ============================================================================== SETTINGS (nesdoor.ini, created on first run) ============================================================================== [video]
    scale = 1.5 picture height (1.5 x 240 lines fits 80x25)
    terminal_aspect = 1.2 SyncTERM shows 640x400 at 4:3, so pixels are 1.2x
    tall; the picture is widened to cancel it. Use 1.0
    if SyncTERM's aspect correction is turned off.
    pixel_aspect = 1.0 1.0 = square NES pixels; 1.143 = 8:7 "old TV" look

    [sound]
    volume = 70 rate = 16000 chunk = 0.2 gain = 2.5
    load / queue / flush SyncTERM audio command formats. If the sound test
    in a game stays silent in SyncTERM 1.10+, check
    these against the Audio section of the CTerm
    manual (syncterm.net/cterm.html).

    Command-line options (add them to the nesdoor.py line in nesdoor.sh):
    --no-audio --no-keyreport --no-check (skip sixel check) --skip N
    --scale N --row N --col N --hold MS --carry MS --core PATH


    ============================================================================== WINDOWS / SYNCHRONET (Win32) ==============================================================================
    1. Folder, e.g. C:\sbbs\xtrn\nesdoor\ with nesdoor.py, retro.py,
    twoplayer.py, conn.py, sixel.py, nesdoor.bat and a roms\ folder.
    2. Core: download fceumm_libretro.dll.zip from the libretro buildbot
    (buildbot.libretro.com -> nightly -> windows -> x86_64 -> latest) and
    put fceumm_libretro.dll in the folder. 64-bit core needs 64-bit Python.
    3. Either
    a) install Python 3.12 64-bit ("Add to PATH"), then: pip install numpy
    and use nesdoor.bat as the command, or
    b) build one exe: pip install numpy pyinstaller
    pyinstaller --onefile nesdoor.py -> dist\nesdoor.exe
    and put nesdoor.exe next to fceumm_libretro.dll and roms\
    4. SCFG -> External Programs -> Online Programs -> add:
    Command Line ........ C:\sbbs\xtrn\nesdoor\nesdoor.bat %n
    Native Executable ... Yes
    I/O: not intercepted (the door uses the DOOR32 socket handle itself)
    BBS Drop File Type .. DOOR32.SYS
    Option names vary a little between Synchronet versions - see its wiki.


    ============================================================================== NOTES ============================================================================== EMULATOR CORE fceumm_libretro.so was built from
    https://github.com/libretro/libretro-fceumm (GPLv2) on Ubuntu 24.04 x86-64.
    To build your own (needs git and a compiler):
    sudo apt install git build-essential
    git clone --depth 1 https://github.com/libretro/libretro-fceumm
    cd libretro-fceumm && make -j4
    cp fceumm_libretro.so /home/mystic/mystic/doors/nesdoor/

    GAMES Only use ROMs you have the right to use - homebrew games, or dumps of
    cartridges you own.

    VERSION HISTORY
    2.8 BBSDEV.DRP drop file support (stdio, socket, local; logoff deadline)
    2.7.1 save/reset messages moved to the top line
    2.7 Ctrl+R reset button; R on the controls screen erases a game's saves
    2.6 save games: auto-resume, Ctrl+S / Ctrl+L quick save, battery saves
    2.5 correct picture shape for SyncTERM's 4:3 display; sixel check notice
    2.4 Windows / Synchronet fixes (node directory, process check)
    2.3 type-to-search game list, Ctrl+Q to leave, JOIN entries in the list
    2.2 controls screen with gamepad picture; 2-player games
    2.1 scrolling game list; on-screen quit instructions
    2.0 libretro core with sound; SyncTERM key press/release input







    https://github.com/AlexCorris/nesdoor
    --- ANetBBS
    * Origin: ANetBBS - A Modern BBS System (1200:1/1)