• src/doors/syncretro/main.

    From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Friday, July 10, 2026 01:39:00
    https://gitlab.synchro.net/main/sbbs/-/commit/bd8561267a9eaa29c4c2601a
    Modified Files:
    src/doors/syncretro/main.c syncretro_audio.c syncretro_audio.h syncretro_io.c
    Log Message:
    syncretro: stop the audio dead on exit, and swallow the last keystrokes

    Two things the player sees after quitting.

    The audio kept playing. SyncTERM's do_flush() clears a channel only
    when no fade is asked for; given O=, it queues a silent crossfade
    against the head buffer and leaves the rest of the FIFO in place (syncterm/audio_apc.c). The door runs three chunks deep, so a faded
    flush let ~300 ms of game audio play on after the terminal was handed
    back to the BBS. Flush without a fade. An abrupt stop is what a
    player expects at the moment they quit, and it is the only spelling
    that actually empties the queue.

    The BBS typed at them. The door restores translated-key mode before
    it exits, so any key still held is re-sent as a plain character that
    nothing reads; Synchronet's input thread resumes, finds the bytes,
    and echoes them at its prompt. Build a fort in Utopia, quit, and the
    BBS greets you with "3141". Swallow input for a moment after the
    restore, bounded by a deadline and a byte cap.

    Also: Ctrl-R now flushes the channel, which the design promised and
    the code did not do -- the queued audio belongs to a game that no
    longer exists. Pausing drops any chunks held mid-prime for the same
    reason. And the flush is skipped entirely for a terminal that never
    confirmed libsndfile, so it really does hear nothing from us.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Friday, July 10, 2026 01:39:00
    https://gitlab.synchro.net/main/sbbs/-/commit/e6b9c8adcfa880a43a5420be
    Modified Files:
    src/doors/syncretro/main.c syncretro.h syncretro_config.c syncretro_input.c syncretro_io.c
    Log Message:
    syncretro: answer an unbound key, and trace what a terminal sends

    Two changes to the input path, one a feature and one the tool that
    explains it.

    A player who presses a key that does nothing is asking what the keys
    are, so answer: an unbound printable key now raises the key legend
    instead of being silently dropped. That makes the pause screen and the
    help screen the same screen -- both list the keys, and only the banner
    and the footer differ -- so they collapse into one sr_screen_keys(),
    and '?' behind the pause screen has nothing left to add. The legend
    also carries the two hints a first-time player needs: many cartridges
    read the RIGHT hand controller, and most games start on a keypad digit
    rather than an action button.

    The diagnostic is the more useful half. `keytrace.on` in the door's own directory turns on a log of every inbound byte, tagged with the key
    mode in force, alongside the frame-pacing decisions (sent, dropped,
    de-duped, acked) and a once-a-second sample of the pad the core sees.
    It answers what no amount of source-reading can: what a given terminal
    actually sends for a given key, and whether a frozen picture is a
    stalled door or a core that has the input and draws nothing. Both of
    those questions came up chasing a paddle that moved one tick per
    press-and-hold in Brickout!, and the trace settled each of them after
    static reasoning had guessed wrong three times.

    A touch-file rather than an environment variable because bbs.exec()
    starts a door through execvp() with the BBS's own environment, so a
    sysop cannot set a variable without restarting the BBS -- and under
    EX_BIN the door's stderr is discarded, so the output has to be a file.
    Both paths resolve against the new sr_config_launch_dir() rather than
    cwd: sr_config_apply() has already chdir'd into the per-user sandbox by
    the time a key arrives, so a relative path would quietly land under data/user/NNNN/. The launch directory was already captured there; it
    just had no accessor.

    Off unless the switch file exists -- not even a file handle.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Sunday, July 12, 2026 05:11:00
    https://gitlab.synchro.net/main/sbbs/-/commit/9c924cc2abf225d820686b01
    Modified Files:
    src/doors/syncretro/main.c syncretro_binds.c
    Log Message:
    syncretro: stop the PAUSED badge bleeding red, and make the version legible

    Three fixes to the pause/help screen, all of them visible in a screenshot.

    THE BADGE BLED. A background attribute is STICKY, and the SGR that followed
    the badge (A_FRAME) names only a foreground -- so the red stayed set, and the rule glyphs after the badge, up to and including the corner, were drawn on
    it. Reset before returning to the frame color, and never leave a background live across a glyph. Verified on the wire: zero box glyphs are now emitted while a background attribute is set.

    THE VERSION WAS DARK BLUE ON BLACK, which is to say it was not readable at
    all. Light gray, with synchro.net in cyan.

    THE KEY SEPARATOR WAS '|', WHICH IS A KEY. In a legend that says "press
    this", a pipe between two key names reads as a third thing to press --
    "W A S D | arrows" invites the question. It is now the charset's box-drawing vertical bar, which cannot be misread as something to type.

    That last one is why the separator is not simply a character in the bind tables: it is one byte in CP437 and three in UTF-8, and the tables are shared by both. They carry a marker ('\1') instead, and the help renderer expands it to the client's glyph and counts it as one column, so the padding still lands.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Monday, July 13, 2026 00:36:00
    https://gitlab.synchro.net/main/sbbs/-/commit/3f084da749bab8f33df32ce4
    Modified Files:
    src/doors/syncretro/main.c syncretro.h syncretro_binds.c syncretro_binds.h syncretro_input.c syncretro_io.c
    Log Message:
    syncretro: add the text render tiers and the F4 tier cycle

    SyncRetro drew sixels or nothing. A terminal without them -- conhost, PuTTY, anything old -- got a door it could not play. termgfx already has the block-character renderer the sibling doors use; wire it in, and let F4 walk
    the tiers so a player can pick what looks best on his own screen rather than taking ours.

    The cycle is built from what the CLIENT can do, never from a menu of
    everything we can emit:

    sixel only if DA1 answered param 4. A terminal that did not say so
    starts on TEXT instead of having sixels printed at it as
    garbage.
    half-block one glyph, two pixels. Renders in EITHER charset (CP437 0xDF,
    UTF-8 U+2580), so every client gets it.
    blocks+shades 2x2 detail from the classic CP437 block/shade glyphs only --
    it renders on font-limited terminals where the quadrant
    glyphs come out as missing-glyph boxes.
    quadrant 2x2, exact (U+2596-259F). UTF-8 CLIENTS ONLY.
    sextant 2x3 (U+1FB00). UTF-8 CLIENTS ONLY.

    The last two are withheld from a CP437 client on purpose: cycling SyncTERM through them would step it through two screens of missing-glyph boxes. The charset comes from termgfx/charset.c ($SBBSNODE/terminal.ini), so the door follows the client rather than guessing.

    F4 has no byte form. It arrives as SS3 "ESC O S", as a CSI ending in 'S' (xterm's modified form, and kitty's), as ESC[14~, or -- on SyncTERM with physical-key reports -- as evdev keycode 62 and no escape sequence at all.
    All four spellings land in one place. The tier switch erases the screen and throws away the cell-diff shadow: a sixel is pixels laid over the grid and
    the text tiers write cells, so neither overwrites the other, and a shadow
    that still believes it knows the screen would leave half a picture behind.

    The text path takes the same DSR-ACK backpressure and the same byte
    accounting as the sixel path -- pacing is about what the TERMINAL has drawn, not about what we drew it with -- and reserves the bottom row, which belongs
    to the stats strip.

    The stats strip now names the live tier (it used to say "sixel" always, which with a tier cycle would simply be a lie), and it erases to end-of-line with
    its own background set, so BCE paints the row into a clean full-width bar and wipes the tail of a longer previous readout in the same stroke. Erasing first -- which is what it did -- cleared the row to black and then painted a short cyan stub on it. The sibling doors have always had this the right way round.

    The pause screen sheds ornaments when the terminal is too short: adding F4 to the key list was, by itself, enough to push the bottom border off an 80x24 screen.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Friday, July 17, 2026 21:23:00
    https://gitlab.synchro.net/main/sbbs/-/commit/b226d595468ca7f97f7006da
    Modified Files:
    src/doors/syncretro/main.c syncretro_audio.c syncretro_audio.h src/doors/syncscumm/door/sst_io.c src/doors/termgfx/audio_stream.c audio_stream.h
    Log Message:
    termgfx: make the audio stream dB-native (volume_db, dB stepping)

    The shared PCM stream module still carried its channel level as an int
    0..100 percent, converting to dB only at the A;Volume call -- the last
    percent holdout after the volume-is-dB migration. Move it to a float
    volume_db (0 dB = unity); the mute sentinel moves from `volume <= 0` to `volume_db <= TERMGFX_DB_MUTE`, still stopping the uplink entirely.

    termgfx_stream_volume_step now takes a dB delta and returns dB, capped at
    unity (a pre-mixed stream gets no boost from + / -); stepping down past a near-silent floor (-36 dB) snaps to real mute so the player need not press
    all the way to the -60 dB floor.

    The two stream doors adapt: the sysop [audio] volume knob stays a friendly 0..100 percent (converted to dB at read); the + / - hotkeys step 6 dB; and SyncRetro's on-screen toast now reads dB. Behavior at the defaults is
    unchanged -- SyncSCUMM -6 dB, SyncRetro unity -- the live control simply
    steps in even dB now rather than percent.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Tuesday, July 21, 2026 21:53:00
    https://gitlab.synchro.net/main/sbbs/-/commit/f15366d5db3bfad5bfc56f1a
    Modified Files:
    src/doors/syncretro/main.c
    Log Message:
    syncretro: the key screen says PAUSED however the player opened it

    One screen serves Space, '?' and an unbound key, and the core is stopped
    behind all three of them -- the door does not run it while any screen is
    up, and it pauses the audio too. Only the Space path drew the PAUSED
    badge, so a player who hit '?' saw a key list with no badge on a game
    that had, in fact, stopped: the badge was reporting which key opened the
    screen rather than what the core was doing.

    Draw it unconditionally. The closing prompt still differs, because only
    the Space pause needs a particular key to leave, and that is now the parameter's only job -- renamed from_pause so it cannot drift back into
    meaning "the core is stopped".

    Verified headless (-stdio, fceumm) by scripting '?' then Space and
    decoding the wire bytes: both screens carry the badge, both top rules
    measure 76 visible cells with the closing corner intact, and the prompts
    still read "any key to return" and "Space to resume" respectively. The
    fill arithmetic was re-checked with a long -console name, which is the
    tightest the rule gets.

    Reported by Rob Swindell.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Windows@VERT to Git commit to main/sbbs/m on Tuesday, July 21, 2026 22:33:00
    https://gitlab.synchro.net/main/sbbs/-/commit/3a9fb3c143e7a079afd76189
    Modified Files:
    src/doors/syncretro/main.c retro_core.c retro_core.h syncretro.h syncretro_binds.c syncretro_config.c syncretro_door.c syncretro_profile.c syncretro_profile.h xtrn/syncarcade/lobby.js
    Log Message:
    syncretro: an arcade controller profile, and controller-device selection

    TWO CHANGES, both about input, neither about the wiring.

    The arcade profile binds EXACTLY what `pad` binds -- a control panel is a
    stick and a row of buttons, which is what a RetroPad already is -- and exists for the words. `pad`'s labels are a console's: it calls Backspace "Select"
    when on a cabinet it is the COIN SLOT and nothing happens at all until it is pressed, calls the stick a "d-pad", and names six buttons "B/A/Y/X/L/R" after
    a gamepad's face rather than the six a fighting game has. It also drops the
    Tab controller-swap, which on a cabinet only moves the player onto player
    two's controls -- where his coin and start are different inputs again -- and leaves him with a dead machine and no clue why.

    Buttons are numbered 1-6, not named. MAME 2003-Plus reports what a driver
    wants ("Supports 6 distinct button controls" for Street Fighter II, 0 for Pac-Man) but sends no SET_INPUT_DESCRIPTORS, so the core cannot say WHICH arcade button each RetroPad id became. Numbering them in the core's own order is the most the door can honestly claim; "punch" and "kick" would be a guess, and a wrong guess on a help screen is worse than a vague one.

    Separately, retro_set_controller_port_device() is now resolved and callable.
    It never was, so a core offering alternative controllers stayed on its default forever -- MAME 2003-Plus advertises RetroPad, Fightstick, 8-Button and 6-Button through SET_CONTROLLER_INFO and we could select none of them. Driven by [input] device, defaulting to 0 = say nothing, which is exactly the
    previous behaviour: a wrong device id silently rewires every button, so this
    is opt-in rather than a guess applied to every console.

    Verified: -profile arcade resolves and an unknown profile still falls back to pad with a warning; [input] device = 769 selects 6-Button on sf2 and, with the section absent, the door emits no selection at all.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Friday, July 24, 2026 11:06:00
    https://gitlab.synchro.net/main/sbbs/-/commit/67a84e4e47cc58919b79fb4a
    Modified Files:
    src/doors/syncretro/main.c
    Log Message:
    syncretro: load games.ini at startup for the help screen

    Call sr_games_load() right after sr_profile_select(), passing sr_config_launch_dir() rather than relying on the cwd: by this point sr_config_apply() has already chdir'd into the per-user save sandbox,
    so a relative fopen("games.ini") would silently look in the wrong
    place. This is the last wire connecting the games.ini reader (already
    built and tested) to the running door.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net