Known Issues

Detailed technical issue list maintained in TODO.md. Items are organized by subsystem. This page documents issues and investigation tasks; see Roadmap for prioritized next steps.

Build and Dependencies

Build verification

  • Clean checkout build needs verification after:
    git submodule update --init --recursive
    cmake -S . -B build -DSPEEDY_BLUPI_BACKEND=FREEDIRECT
    cmake --build build -j
  • Confirm default Linux build does not require system-installed SDL packages (FREE_USE_SYSTEM_SDL defaults OFF)
  • Verify FREE_USE_SYSTEM_SDL=ON override still works
  • Confirm free-api and free-direct link SDL as PRIVATE
  • Confirm no game source file directly includes SDL headers
  • Scan: grep -R "#include <SDL" -n src include

CMake cleanup

  • Change target_include_directories for SPEEDY_BLUPI_WINDOWS from PUBLIC to PRIVATE (executables don't need public include dirs)
  • Verify whether /permissive- MSVC flag is appropriate for decompiled C++
  • Keep compiler option changes separate from gameplay/decompilation fixes; non-MSVC flags (-fpermissive -fms-extensions -w -Wno-narrowing) are intentional suppressors for decompiled code
  • cmake/ThirdPartySDL.cmake function name must stay configure_vendored_sdl() — do not reintroduce old names

DirectDraw Initialization

🚨
Three confirmed reasons fullscreen behaves differently on Free Direct vs real DirectX 3
  1. CPixmap::Create() is called twice during startup without releasing previous DirectDraw objects
  2. bTrueColorBack / bTrueColorDecor parameters are inconsistent between declaration, definition, and call sites
  3. CacheAll() contains decompilation artifacts: delete this + member access, suspicious LOWORD/HIWORD usage, nonsensical rectangle initialization

Double CPixmap::Create() call

Startup currently calls CPixmap::Create() twice: once directly in DoInit() and then again inside CacheAll(TRUE, ...). Real DirectDraw 3 may reject the second call with: DDERR_PRIMARYSURFACEALREADYEXISTS, DDERR_EXCLUSIVEMODEALREADYSET, or DDERR_INVALIDPARAMS. Free Direct currently tolerates this.

  • Confirm whether CPixmap::Create() is really called twice
  • Add logging at entry/exit of CPixmap::Create()
  • Log whether m_lpDD, m_lpDDSPrimary already exist before the second call
  • Decide: either DoInit() or CacheAll() should own DirectDraw initialization, not both
  • If recreation is needed, add a proper cleanup path before re-initialization

Parameter swap: bTrueColorBack / bTrueColorDecor

The CPixmap::Create() declaration in pixmap.hpp and the definition in pixmap.cpp have the bTrueColor and bTrueColorDecor parameters in opposite positions, so the wrong value is used for each:

// Declaration (pixmap.hpp)
BOOL Create(HWND hwnd, POINT dim, BOOL bFullScreen, int mouseType,
            BOOL bTrueColor, BOOL bTrueColorDecor);

// Definition (pixmap.cpp) — names are swapped!
BOOL CPixmap::Create(HWND hwnd, POINT dim, BOOL bFullScreen, int mouseType,
                     BOOL bTrueColorDecor, BOOL bTrueColor)
  • Audit all call sites and the intended meaning of each parameter
  • Compare with Planet Blupi source for reference
  • Do not change behavior until logging proves current behavior is wrong
  • Test configurations where background and decor truecolor settings differ

Dangerous delete this in CacheAll(FALSE)

CPixmap::CacheAll(FALSE) contains a delete this followed immediately by reads of m_hWnd, m_bFullScreen, etc. This is undefined behavior — reading object members after destroying the object.

  • Investigate whether this code path is actually executed at runtime
  • Treat as likely decompilation artifact or incorrectly reconstructed logic
  • If object recreation is required, save needed values before destruction
  • Never access object members after delete this

Suspicious rectangle initialization in CacheAll(TRUE)

Decompiled code contains a nonsensical rectangle setup, likely a Ghidra artifact:

// Likely wrong — decompiled artifact
char image[12];
*(char*)image = (LXIMAGE) << 64;   // nonsensical shift
rect.left  = LOWORD(image);         // LOWORD on a local array?
rect.right = HIWORD(image);

// Likely intended
SetRect(&rect, 0, 0, LXIMAGE, LYIMAGE);
  • Investigate in Ghidra and compare with Planet Blupi source
  • Replace only after confirming the intended behavior

Gameplay

  • Many movement and physics behaviors in decblupi.cpp (4,395 lines) need verification against the original game
  • Network synchronization in decnet.cpp is incomplete
  • Level editor in decdesign.cpp has known missing features
  • Save/load in decio.cpp may have version compatibility gaps if DescSave layout has changed

Audio

With #define _BASS FALSE, the active implementation is the DirectSound / MCI path. The setup uses preprocessor conditions:

  • Verify _BASS=FALSE is intentional and README audio notes are current
  • Do not mix audio backend cleanup with DirectDraw fullscreen investigation
  • Consider a future CMake option: FREE_EGGBERT_AUDIO_BACKEND=DSOUND|BASS|STUB

Network

CNetwork::CreateProvider(0) is called at startup but likely fails silently because m_providers.nb starts at 0 (no provider enumeration has been called yet). The return value is ignored, so the game continues in singleplayer mode.

Additionally, CNetwork::Receive() reads into a local buffer but does not copy the data into the caller's destination buffer before returning TRUE — this appears to be a reconstruction bug.

  • Treat networking / DirectPlay as incomplete
  • Audit CNetwork::EnumProviders(), CreateProvider(), and Receive()
  • Consider stubbing network cleanly for singleplayer builds

DirectX SDK / dxsdk3 Submodule

  • dxsdk3 is still listed in .gitmodules even though the build is focused on FREEDIRECT
  • Decide whether dxsdk3 is needed for reference, legacy builds, or real DirectX 3 comparison builds
  • If only historical, document that clearly

Message Loop and Web Support

The native desktop build uses a classic Win32 blocking message loop with a multimedia timer. Emscripten does not work well with this; the web version needs a Free API / launcher-level main-loop adapter.

  • Keep the native Win32-style loop intact for desktop builds
  • For web builds, design an adapter at the Free API or launcher level
  • Do not hack src/blupi.cpp to satisfy Emscripten
  • Keep web work separate from DirectDraw fullscreen debugging

Recommended Debugging Priority

  1. Add detailed logging around DirectDraw initialization in CPixmap::Create()
  2. Verify whether CPixmap::Create() is really called twice
  3. Capture the exact HRESULT from the second DirectDrawCreate, SetCooperativeLevel, SetDisplayMode, and CreateSurface calls
  4. Decide ownership of CPixmap::Create() — either DoInit() or CacheAll(), not both
  5. Clarify the bTrueColorBack / bTrueColorDecor parameter order
  6. Keep unrelated systems separate during investigation
  7. Only after the fullscreen path is understood, continue with web/Android portability