• src/doors/syncconquer/door/door_io.c

    From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Wed Jul 8 01:33:28 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/cbea88cb7ee78a73e6657384
    Modified Files:
    src/doors/syncconquer/door/door_io.c
    Log Message:
    syncalert: TODO note 640x384 downscale + the DECSSDT status-line fix

    The engine is 640x400 (80x25) but SyncTERM defaults to an 80x24 / 640x384 canvas (its status line takes the 25th row), so every image tier downscales 0.96x and RA's single-pixel vertical bars drop -- text/gauges degrade;
    crisp only at a true 640x400. Record the proper fix inline: drop the status line with DECSSDT (CSI 0 $ ~), first saving the client's current setting via DECRQSS (DCS $ q $ ~ ST) so door exit can restore it. Notes the separate, smaller one-row sixel reserve too.

    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Fri Jul 10 23:41:56 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/5936da4d1c60ec677eff815a
    Modified Files:
    src/doors/syncconquer/door/door_io.c
    Log Message:
    syncalert: play FMV cutscenes by default (-NOMOVIES now opt-in)

    The door forced -NOMOVIES into the engine argv, which suppressed Red
    Alert's VQA intro/campaign cutscenes. That suppression was intentional
    early on, but the movies actually stream fine over the terminal: the VQA
    frames route through the game page-flip into door_present(), and the
    movie loop keeps pumping the door's input/pacing (so they're skippable
    and don't stall the connection).

    Stop forcing the flag. -NOMOVIES is now injected only when the sysop
    sets the SYNCALERT_NOMOVIES environment variable, so cutscenes play by
    default. The door-arg neutering (sanitizing door-owned tokens out of the engine's view) is unchanged.

    Cutscenes are silent for now -- the no-video build links the null VQA
    audio backend; wiring VQA audio into termgfx is a separate follow-up.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Sat Jul 11 04:50:46 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/bdd485515c8db099897fc76a
    Modified Files:
    src/doors/syncconquer/door/door_io.c
    Log Message:
    syncalert: merge REDALERT.INI instead of clobbering it

    door_setup_engine_paths() rewrote the per-user REDALERT.INI from scratch on every launch with only a [Paths] section. That wiped the engine's own
    persisted settings (music/sound volume, etc.) each session, and left
    [Intro] PlayIntro absent -- so it defaulted true, Special.IsFromInstall
    stayed true, and the door auto-started a Soviet campaign game on Normal
    every session instead of showing the main menu.

    Now merge with xpdev's INI reader/writer: read the existing file, (re)write only the runtime [Paths] UserPath/DataPath, and seed [Intro] PlayIntro=false ONLY when it is absent. So a fresh install boots to the main menu (with the Allies/Soviet and difficulty choosers), a sysop's or the engine's own later values survive, and iniWriteFile() rewinds+truncates so everything else in
    the file is preserved. Existing broken per-user INIs self-heal on the next launch.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Sat Jul 11 18:22:40 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/28800fb9114d146eaf591669
    Modified Files:
    src/doors/syncconquer/door/door_io.c
    Log Message:
    syncalert: fit-toggle fixes and a tighter stats overlay

    Three fixes to the Ctrl-F Aspect<->Fill display toggle and the Ctrl-S
    stats overlay:

    - Clearing: door_fit_toggle() forced a repaint but not a screen clear,
    so switching Fill (full-width) -> Aspect (narrower, centered) left the
    old wider frame's pixels bleeding through the newly-exposed side
    margins. Request a clear, as door_tier_cycle() already does when the
    image re-centers.

    - Fill centering: Fill set the emitted width to the whole canvas width
    and centered on that, but door_emit_sixel then clamps sixel width to
    DOOR_SCALE_MAX. On a canvas wider than the cap the image landed
    flush-left with a lopsided right margin. Apply the same cap in
    door_calc_rect (sixel only) before centering so it stays symmetric.

    - Overlay: add a "fill" token (shown only in Fill mode, like "blob"),
    drop the space before the rate unit, round bytes/frame to KB, and
    remove the redundant trailing space, so the widest line (JXL with
    both blob and fill) fits one 80-column row instead of truncating.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Mon Jul 13 00:36:58 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/54de3085923bf9535feec2ad
    Modified Files:
    src/doors/syncconquer/door/door_io.c
    Log Message:
    syncconquer: write the INI the ENGINE looks for, per title (syncdawn)

    SyncDawn replayed Tiberian Dawn's from-install path on every launch -- the
    long intro, then Choose_Side, then straight into a mission -- instead of reaching the main menu.

    door_setup_engine_paths() hardcoded "REDALERT.INI" as the file it writes into the per-user -home dir, for both titles. But each engine asks PathsClass::Init() for its OWN config filename -- redalert/startup.cpp passes "REDALERT.INI", tiberiandawn/startup.cpp passes "CONQUER.INI" -- and
    PathsClass looks for exactly that name. Under syncdawn the door was therefore writing a file the engine never opens, so [Intro] PlayIntro=false never
    reached it, Get_Bool("Intro", "PlayIntro", true) defaulted true, and Special.IsFromInstall fired every session (tiberiandawn/startup.cpp).

    Add DOOR_ENGINE_INI to the per-title identity block (CONQUER.INI for TD, REDALERT.INI for RA) and write that.

    It hid behind a door that otherwise worked. TD takes its mixes from door_engine_data_dir() rather than the INI's [Paths] DataPath, so the game
    data loaded fine and nothing looked wrong -- while PlayIntro, and the savegame location, silently never reached the engine.

    It also LOOKED platform-specific, and wasn't. With no INI beside argv[0] the engine's ini.Save() falls back to PathsClass::User_Path(): ~/.config/vanilla-conquer/vanillatd on POSIX, %APPDATA%\Vanilla-Conquer\vanillatd on Windows. That write persists for the *nix BBS user -- so from the second run on, Linux found PlayIntro=false and behaved, quietly papering over the bug -- but not for the Windows service account, where every run was thus a first run. That fallback is wrong for a door either way: it is ONE file shared by every caller, the very thing -home exists to prevent, and it is where TD's savegames had been going instead of
    the player's own directory.

    Verified on both hosts: data/user/<n>/tibdawn/CONQUER.INI is now created with our [Paths]/[Intro] plus the engine's own persisted [Mouse]/[Video] settings (the merge-don't-clobber path holding), and syncdawn boots to the main menu. The REDALERT.INI previously left in a tibdawn/ home is inert -- TD never read it -- and can be deleted.
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Tue Jul 14 21:04:14 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/736866fe916b7f150db638f8
    Modified Files:
    src/doors/syncconquer/door/door_io.c
    Log Message:
    syncconquer: scale the image to the exact canvas on any terminal

    The sixel/image size clamp only trusted an XTSMGRAPHICS-derived ceiling (g_canvas_is_gfx), falling back to a conservative 1000px "geometry-less
    xterm" floor otherwise -- so Windows Terminal, which reports an exact pixel canvas via ESC[4;h;wt but doesn't answer XTSMGRAPHICS, had its image
    clamped to 1000px and rendered small in a large window. Trust the exact
    canvas (g_px_exact) whenever any terminal reports it -- WT, SyncTERM, any modern sixel terminal -- keeping the 1000px floor only for genuinely geometry-less terminals (xterm with window-ops off never sends ESC[4t, so g_px_exact stays false and it's still protected). Large pixel canvases
    (e.g. 2700x1440) only ever come from non-SyncTERM terminals anyway, so the prior effectively-SyncTERM-only gating was exactly backwards.

    Also add a geometry-provenance tag to the Ctrl-S stats bar (S/X/G =
    SyncTERM detected / exact-px canvas / XTSMGRAPHICS gfx ceiling), which made this diagnosable at a glance.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Fri Jul 17 02:53:44 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/44e5ea5042f6098243ea2a83
    Modified Files:
    src/doors/syncconquer/door/door_io.c
    Log Message:
    syncconquer: sixel-tier dirty-rect rendering (partial-sixel backend)

    Extend the Phase-2 dirty-rect path to the sixel tier -- the non-JXL
    fallback population: xterm / mlterm / wezterm / Windows Terminal, plus a
    no-JXL SyncTERM. The framebuffer differ + coalescer are hoisted out of
    the WITH_JXL guard into a shared dr_diff_coalesce() that both backends
    call; only the per-tier emit differs.

    Sixel can only be placed at a character cell (unlike a pixel-exact JXL
    blob), so each coalesced box is snapped OUT to cell boundaries and its
    top-left cell is addressed with the cursor, then re-emitted as its own
    partial sixel that composites over the frame the client still holds. The
    box height is rounded up to a 6-px sixel band to dodge SF #258 (SyncTERM mis-decodes a partial last band). On SyncTERM the palette registers
    persist from the prior full frame so boxes ship palette-less; other sixel terminals reset registers per image, so each box re-sends the palette.

    Same data/<door>/dirtyrect flag and ~1.5s live re-check as the JXL path,
    and the same full-frame fallback on a large or over-fragmented change --
    so it is never worse than a full frame. The saving scales with the static (unchanged) fraction: largest on a built-up map, near zero on a sparse animating scene. The ratio is lower than JXL's because sixel is
    cell-snapped and compresses locally rather than globally, and it is
    smallest on a huge canvas (Windows Terminal) where every box inflates and
    the palette re-sends per box. Live-tested in Windows Terminal (sixel
    tier): composites cleanly, frame size swings down with map development.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Sat Jul 18 03:02:48 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/bb8096e4d445077c979888b5
    Modified Files:
    src/doors/syncconquer/door/door_io.c
    Log Message:
    syncconquer: use termgfx's shared mouse handshake

    Delegate the DEC 1003/1006/1016 enable/restore, the SGR-Pixels latch and
    the DECRPM reply to termgfx/mouse instead of open-coding them here. The
    emitted bytes and the coordinate mapping are unchanged -- door_input.c
    and the door_io_* accessors keep their behaviour; only their backing
    state moves into a termgfx_mouse_t. First consumer of the extraction.
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Wed Jul 22 20:38:40 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/8fd7b6f2ca768062cab36f9e
    Modified Files:
    src/doors/syncconquer/door/door_io.c
    Log Message:
    syncconquer: subset the sixel palette on register-resetting terminals

    Select SIXEL_PAL_USED for the full-frame and dirty-box sixel paths on non-SyncTERM clients; SyncTERM keeps FULL-on-change / NONE-reuse
    unchanged. Matches the termgfx present path.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)