Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c376349
Complete UTF-8: Allow typing non-ASCII characters (ñ, ç, é, ¿¡ etc) i…
AleWin32 Jul 21, 2026
3e6e06b
Allow loading string subtypes in .tngfx files (#5052)
rainlizard Jul 23, 2026
971bc46
Restore value_stringId usage (#5057)
PieterVdc Jul 24, 2026
f4009bd
Landview overlay no longer has missing edge pixel on high res (#5058)
cerwym Jul 24, 2026
02b48bf
Fix imp desync even more (#5059)
rainlizard Jul 25, 2026
dd36356
Prevent Heart clipping in straight view when zoomed in (#5060)
cerwym Jul 26, 2026
d126833
Added COPY_CREATURE_TYPE script command (#5050)
Loobinex Jul 26, 2026
e99da80
Add also FLAC/MP3/WAV support for music, replace hardcoded "keeperNN.…
AleWin32 Jul 26, 2026
8875eeb
Fix big sprites clipped by floor tiles in straight view (#5062)
RupixTalahone Jul 26, 2026
23d9254
Fix message button drop animation (#5069)
rainlizard Jul 27, 2026
b9b5768
Process local camera controls before logic update (#5067)
jwt27 Jul 27, 2026
96f619a
Fix all sprites vanishing in straight view at max zoom in 4k (#5066)
RupixTalahone Jul 29, 2026
8d79e4f
Fixed units visible through walls in straight view (#5068)
RupixTalahone Jul 29, 2026
1ef7bba
Rewrite bflib_render_gpoly.c (#5071)
jwt27 Jul 30, 2026
de75c5a
Fixed invisible door keys in straight view (#5073)
RupixTalahone Jul 30, 2026
0b6bbe0
Handle camera catchup packets after logic update (#5075)
jwt27 Jul 31, 2026
f8e39bc
Clean up main.cpp (#5064)
PieterVdc Aug 1, 2026
f83d985
Multiplayer: fix ctrl drag-click camera movement (#5078)
rainlizard Aug 2, 2026
2e7a02b
Multiplayer: fixed being unable to chat in lobby (#5079)
rainlizard Aug 2, 2026
ea98b02
Just double frameskip each time. (#5076)
Loobinex Aug 2, 2026
1034ec9
Added 3 new multiplayer maps to classic (#5081)
Loobinex Aug 2, 2026
9f953aa
Load default campaign when none is active (#5082)
rainlizard Aug 2, 2026
7f2180e
Fix linux boot crash (#5084)
PieterVdc Aug 4, 2026
9baef07
Enhance CMake build system with packaging and multi-platform support …
cerwym Aug 4, 2026
78351c0
Make hand rule work on prisoners (#5077)
Loobinex Aug 4, 2026
1f0e2b6
Include keeperfx.exe and keeperfx_hvlog.exe in uploaded package artif…
cerwym Aug 4, 2026
ef2228f
Add debug logging for music track loading
AleWin32 Aug 4, 2026
2cf70d9
Merge branch 'master' into pr/5061
Loobinex Aug 4, 2026
e344559
Small log tweak
Loobinex Aug 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions .github/workflows/build-alpha-patch-unsigned.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
run: |
set -eux
sudo apt update
sudo apt install -y build-essential g++-mingw-w64-i686 libpng16-16t64 7zip
sudo apt install -y build-essential g++-mingw-w64-i686 cmake ninja-build libpng16-16t64 7zip

- name: Build gfx
run: |
Expand All @@ -42,18 +42,30 @@ jobs:
set -eux
BUILD_NUMBER=$(git rev-list --count HEAD)
PACKAGE_SUFFIX=Alpha
make BUILD_NUMBER=$BUILD_NUMBER PACKAGE_SUFFIX=$PACKAGE_SUFFIX heavylog DEBUG=1 -k
make BUILD_NUMBER=$BUILD_NUMBER PACKAGE_SUFFIX=$PACKAGE_SUFFIX standard
make BUILD_NUMBER=$BUILD_NUMBER PACKAGE_SUFFIX=$PACKAGE_SUFFIX package
# Compile both binaries with CMake (MinGW-w64 i686 cross-compile).
cmake -S . -B out -G Ninja -DCMAKE_TOOLCHAIN_FILE=build/cmake/toolchains/mingw32.cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DBUILD_NUMBER=$BUILD_NUMBER -DPACKAGE_SUFFIX=$PACKAGE_SUFFIX
cmake --build out --target keeperfx keeperfx_hvlog -j"$(nproc)"
# Assemble game data with the make pipeline (.dat data); the CMake build
# already provides the binaries and SDL runtime DLLs. Then archive with CPack.
make BUILD_NUMBER=$BUILD_NUMBER PACKAGE_SUFFIX=$PACKAGE_SUFFIX pkg-assemble
cmake --build out --target package
echo "ZIP_NAME=$(basename -s .7z pkg/keeperfx*.7z)" >> $GITHUB_ENV
# CPack stages the binaries (keeperfx.exe, keeperfx_hvlog.exe) and the SDL2
# runtime DLLs only inside the .7z archive, not into the loose pkg/ tree, so
# uploading pkg/** would drop them and leave SignPath with nothing to sign.
# Install the full package layout into dist/ so the uploaded artifact holds
# the binaries + DLLs + game data.
cmake --install out --prefix dist
rm pkg/keeperfx*.7z

- name: Upload artifact
id: upload-artifact
uses: actions/upload-artifact@v4
with:
name: ${{ env.ZIP_NAME }}
path: pkg/**
path: dist/**

outputs:
artifact-id: ${{ steps.upload-artifact.outputs.artifact-id }}
Expand Down
34 changes: 26 additions & 8 deletions .github/workflows/build-prototype.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,43 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: dkfans/setup-cpp@master

- name: Update system
run: |
set -eux
sudo apt update
sudo apt install -y build-essential g++-mingw-w64-i686 libpng16-16t64 7zip
sudo apt install -y build-essential g++-mingw-w64-i686 cmake ninja-build libpng16-16t64 7zip

- name: Build
run: |
set -eux
BUILD_NUMBER=$(git rev-list --count origin/master)
GITHUB_SHA=$(cat $GITHUB_EVENT_PATH | jq -r .pull_request.head.sha)
PACKAGE_SUFFIX=Prototype_$(git rev-parse --short=7 "$GITHUB_SHA")
make BUILD_NUMBER=$BUILD_NUMBER PACKAGE_SUFFIX=$PACKAGE_SUFFIX heavylog DEBUG=1 -k
make BUILD_NUMBER=$BUILD_NUMBER PACKAGE_SUFFIX=$PACKAGE_SUFFIX standard
make BUILD_NUMBER=$BUILD_NUMBER PACKAGE_SUFFIX=$PACKAGE_SUFFIX package
# Compile both binaries with CMake (MinGW-w64 i686 cross-compile).
cmake -S . -B out -G Ninja -DCMAKE_TOOLCHAIN_FILE=build/cmake/toolchains/mingw32.cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DBUILD_NUMBER=$BUILD_NUMBER -DPACKAGE_SUFFIX=$PACKAGE_SUFFIX
cmake --build out --target keeperfx keeperfx_hvlog -j"$(nproc)"
# Assemble game data with the make pipeline (.dat data); the CMake build
# already provides the binaries and SDL runtime DLLs. Then archive with CPack.
make BUILD_NUMBER=$BUILD_NUMBER PACKAGE_SUFFIX=$PACKAGE_SUFFIX pkg-assemble
cmake --build out --target package
echo "ZIP_NAME=$(basename -s .7z pkg/keeperfx*.7z)" >> $GITHUB_ENV
# CPack stages the binaries (keeperfx.exe, keeperfx_hvlog.exe) and the SDL2
# runtime DLLs only inside the .7z archive, not into the loose pkg/ tree, so
# uploading pkg/** would drop them. Install the full package layout into
# dist/ so the uploaded artifact holds the binaries + DLLs + game data.
cmake --install out --prefix dist
rm pkg/keeperfx*.7z

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ env.ZIP_NAME }}
path: pkg/**
path: dist/**

build-prototype-linux:
name: "Build Prototype Linux x86_64"
Expand All @@ -55,6 +66,8 @@ jobs:
sudo apt update
sudo apt install -y \
build-essential \
cmake \
ninja-build \
pkg-config \
curl \
libavcodec-dev \
Expand All @@ -71,6 +84,8 @@ jobs:
libsdl2-net-dev \
libswresample-dev \
libminiupnpc-dev \
libssl-dev \
libzstd-dev \
zlib1g-dev

- name: Build
Expand All @@ -84,10 +99,13 @@ jobs:
PACKAGE_SUFFIX=Prototype_$(git rev-parse --short=7 "$GITHUB_SHA")
LINUX_ARTIFACT_NAME=keeperfx-linux_x86_64-${VER_MAJOR}_${VER_MINOR}_${VER_RELEASE}_${BUILD_NUMBER}_${PACKAGE_SUFFIX}-patch
echo "LINUX_ARTIFACT_NAME=$LINUX_ARTIFACT_NAME" >> $GITHUB_ENV
make BUILD_NUMBER=$BUILD_NUMBER VER_SUFFIX=$PACKAGE_SUFFIX -f linux.mk
# Native Linux build with CMake (pkg-config deps + prebuilt lin64 static libs).
cmake -S . -B out -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DBUILD_NUMBER=$BUILD_NUMBER -DPACKAGE_SUFFIX=$PACKAGE_SUFFIX
cmake --build out --target keeperfx -j"$(nproc)"

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ env.LINUX_ARTIFACT_NAME }}
path: bin/keeperfx
path: out/keeperfx
22 changes: 17 additions & 5 deletions .github/workflows/build-release-patch-unsigned.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
run: |
set -eux
sudo apt update
sudo apt install -y build-essential g++-mingw-w64-i686 libpng16-16t64 7zip
sudo apt install -y build-essential g++-mingw-w64-i686 cmake ninja-build libpng16-16t64 7zip

- name: Build gfx
run: |
Expand All @@ -42,18 +42,30 @@ jobs:
set -eux
BUILD_NUMBER=$(git rev-list --count HEAD)
PACKAGE_SUFFIX=
make BUILD_NUMBER=$BUILD_NUMBER PACKAGE_SUFFIX=$PACKAGE_SUFFIX heavylog DEBUG=1 -k
make BUILD_NUMBER=$BUILD_NUMBER PACKAGE_SUFFIX=$PACKAGE_SUFFIX standard
make BUILD_NUMBER=$BUILD_NUMBER PACKAGE_SUFFIX=$PACKAGE_SUFFIX package
# Compile both binaries with CMake (MinGW-w64 i686 cross-compile).
cmake -S . -B out -G Ninja -DCMAKE_TOOLCHAIN_FILE=build/cmake/toolchains/mingw32.cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DBUILD_NUMBER=$BUILD_NUMBER -DPACKAGE_SUFFIX=$PACKAGE_SUFFIX
cmake --build out --target keeperfx keeperfx_hvlog -j"$(nproc)"
# Assemble game data with the make pipeline (.dat data); the CMake build
# already provides the binaries and SDL runtime DLLs. Then archive with CPack.
make BUILD_NUMBER=$BUILD_NUMBER PACKAGE_SUFFIX=$PACKAGE_SUFFIX pkg-assemble
cmake --build out --target package
echo "ZIP_NAME=$(basename -s .7z pkg/keeperfx*.7z)" >> $GITHUB_ENV
# CPack stages the binaries (keeperfx.exe, keeperfx_hvlog.exe) and the SDL2
# runtime DLLs only inside the .7z archive, not into the loose pkg/ tree, so
# uploading pkg/** would drop them and leave SignPath with nothing to sign.
# Install the full package layout into dist/ so the uploaded artifact holds
# the binaries + DLLs + game data.
cmake --install out --prefix dist
rm pkg/keeperfx*.7z

- name: Upload artifact
id: upload-artifact
uses: actions/upload-artifact@v4
with:
name: ${{ env.ZIP_NAME }}
path: pkg/**
path: dist/**

outputs:
artifact-id: ${{ steps.upload-artifact.outputs.artifact-id }}
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
/config/fxdata/*.dat
/config/fxdata/*.fon
.vs/
build*/
# Build output directories (build/ itself now holds tracked CMake modules under
# build/cmake/, so ignore only alternative output dirs, not build/).
/build-*/
/out/*
*.cache
.vscode
Expand Down
117 changes: 32 additions & 85 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,91 +10,38 @@ project(keeperfx C CXX)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 20)

# Get the abbreviated commit Id of the head.
find_package(Git REQUIRED)
execute_process(COMMAND "${GIT_EXECUTABLE}" describe --always OUTPUT_VARIABLE COMMIT_ID OUTPUT_STRIP_TRAILING_WHITESPACE)

set(VER_MAJOR 1)
set(VER_MINOR 2)
set(VER_RELEASE 0)
set(VER_BUILD 0)
set(VER_STRING "${VER_MAJOR}.${VER_MINOR}.${VER_RELEASE}.${VER_BUILD} ${PACKAGE_SUFFIX}")
set(PACKAGE_SUFFIX "")
set(GIT_REVISION "${COMMIT_ID}")

# CMAKE_BINARY_DIR is defined in CMakePresets.json.
set(KEEPERFX_VER_DEFS_H_IN ${CMAKE_SOURCE_DIR}/ver_defs.h.in)
set(KEEPERFX_VER_DEFS_H_OUT ${CMAKE_SOURCE_DIR}/ver_defs.h)
configure_file(${KEEPERFX_VER_DEFS_H_IN} ${KEEPERFX_VER_DEFS_H_OUT})

find_package(SDL2 CONFIG REQUIRED)
find_package(SDL2_image CONFIG REQUIRED)
find_package(SDL2_mixer CONFIG REQUIRED)
find_package(SDL2_net CONFIG REQUIRED)

# Global definitions.
add_compile_definitions(_CRT_NONSTDC_NO_WARNINGS _CRT_SECURE_NO_WARNINGS)

file(GLOB_RECURSE KEEPERFX_SOURCES_C "src/*.c")
file(GLOB_RECURSE KEEPERFX_SOURCES_CXX "src/*.cpp")

# Global definitions for all targets.
add_compile_definitions("DEBUG=$<IF:$<CONFIG:Debug>,1,0>")
add_compile_definitions("SPNG_STATIC=1")

# Add two executable targets: keeperfx and keeperfx_hvlog.
add_executable(keeperfx ${KEEPERFX_SOURCES_C} ${KEEPERFX_SOURCES_CXX})

target_compile_definitions(keeperfx PUBLIC BFDEBUG_LEVEL=0)
target_sources(keeperfx PRIVATE "res/keeperfx_stdres.rc")

add_executable(keeperfx_hvlog ${KEEPERFX_SOURCES_C} ${KEEPERFX_SOURCES_CXX})

target_compile_definitions(keeperfx_hvlog PUBLIC BFDEBUG_LEVEL=10)
target_sources(keeperfx_hvlog PRIVATE "res/keeperfx_stdres.rc")

message(STATUS "We are using ${CMAKE_CXX_COMPILER_ID}")

# The default bfd linker in MinGW is extremely slow. LLVM linker (LLD) is much much faster.
set_property(TARGET keeperfx PROPERTY LINKER_TYPE LLD)
set_property(TARGET keeperfx_hvlog PROPERTY LINKER_TYPE LLD)

set(WARNFLAGS -Wall -W -Wshadow -Wno-sign-compare -Wno-unused-parameter -Wno-strict-aliasing -Wno-unknown-pragmas -Werror)
set(GNU_COMPILER_FLAG -march=x86-64 -fno-omit-frame-pointer -fmessage-length=0)
set(GNU_LINK_FLAG -mwindows -Wl,--enable-auto-import)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wimplicit")
target_compile_options(keeperfx PRIVATE ${WARNFLAGS} ${GNU_COMPILER_FLAG})
target_compile_options(keeperfx_hvlog PRIVATE ${WARNFLAGS} ${GNU_COMPILER_FLAG})
target_link_options(keeperfx PRIVATE ${GNU_LINK_FLAG} -Wl,-Map,keeperfx.map)
target_link_options(keeperfx_hvlog PRIVATE ${GNU_LINK_FLAG} -Wl,-Map,keeperfx_hvlog.map)
target_link_libraries (keeperfx PUBLIC -static stdc++ winpthread -dynamic)
target_link_libraries (keeperfx_hvlog PUBLIC -static stdc++ winpthread -dynamic)

# System libraries.
target_link_libraries(keeperfx PRIVATE imagehlp dbghelp)
target_link_libraries(keeperfx_hvlog PRIVATE imagehlp dbghelp)

# Go into submodules.
add_subdirectory(deps)
add_subdirectory(tools)

# External libraries.
target_link_libraries(keeperfx
PRIVATE
$<IF:$<TARGET_EXISTS:SDL2::SDL2>,SDL2::SDL2,SDL2::SDL2-static>)
target_link_libraries(keeperfx
PRIVATE $<IF:$<TARGET_EXISTS:SDL2_mixer::SDL2_mixer>,SDL2_mixer::SDL2_mixer,SDL2_mixer::SDL2_mixer-static>)
target_link_libraries(keeperfx
PRIVATE $<IF:$<TARGET_EXISTS:SDL2_net::SDL2_net>,SDL2_net::SDL2_net,SDL2_net::SDL2_net-static>)
target_link_libraries(keeperfx
PRIVATE $<IF:$<TARGET_EXISTS:SDL2_image::SDL2_image>,SDL2_image::SDL2_image,SDL2_image::SDL2_image-static>)

target_link_libraries(keeperfx_hvlog
PRIVATE
$<IF:$<TARGET_EXISTS:SDL2::SDL2>,SDL2::SDL2,SDL2::SDL2-static>)
target_link_libraries(keeperfx_hvlog
PRIVATE $<IF:$<TARGET_EXISTS:SDL2_mixer::SDL2_mixer>,SDL2_mixer::SDL2_mixer,SDL2_mixer::SDL2_mixer-static>)
target_link_libraries(keeperfx_hvlog
PRIVATE $<IF:$<TARGET_EXISTS:SDL2_net::SDL2_net>,SDL2_net::SDL2_net,SDL2_net::SDL2_net-static>)
target_link_libraries(keeperfx_hvlog
PRIVATE $<IF:$<TARGET_EXISTS:SDL2_image::SDL2_image>,SDL2_image::SDL2_image,SDL2_image::SDL2_image-static>)
file(STRINGS "${CMAKE_SOURCE_DIR}/version.mk" _kfx_version_lines)
foreach(_line IN LISTS _kfx_version_lines)
if(_line MATCHES "^(VER_MAJOR|VER_MINOR|VER_RELEASE|VER_BUILD)=([0-9]+)")
set(${CMAKE_MATCH_1} "${CMAKE_MATCH_2}")
endif()
endforeach()
foreach(_v VER_MAJOR VER_MINOR VER_RELEASE VER_BUILD)
if(NOT DEFINED ${_v})
message(FATAL_ERROR "version.mk is missing ${_v}")
endif()
endforeach()
# Override via -DBUILD_NUMBER=<n> -DPACKAGE_SUFFIX=<s>; used for the CPack name.
set(BUILD_NUMBER "${VER_BUILD}" CACHE STRING "Monotonic build number")
set(PACKAGE_SUFFIX "" CACHE STRING "Distribution suffix (e.g. Alpha, Release)")
set(VER_STRING "${VER_MAJOR}.${VER_MINOR}.${VER_RELEASE}.${BUILD_NUMBER} ${PACKAGE_SUFFIX}")
set(GIT_REVISION "${COMMIT_ID}")

# src/version.h includes "ver_defs.h" relative to src/ (matches GENSRC in Makefile).
configure_file(${CMAKE_SOURCE_DIR}/ver_defs.h.in ${CMAKE_SOURCE_DIR}/src/ver_defs.h)

list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/build/cmake/modules)
include(Helpers)
include(Platforms)
include(Dependencies)
include(BuildTargets)

# Windows icon resource is generated by png2ico in tools/.
if(WIN32)
add_subdirectory(tools)
endif()

include(Packaging)
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ obj/game_loop.o \
obj/game_lghtshdw.o \
obj/game_merge.o \
obj/game_saves.o \
obj/game_update.o \
obj/gui_boxmenu.o \
obj/gui_draw.o \
obj/gui_frontbtns.o \
Expand Down Expand Up @@ -350,6 +351,7 @@ obj/thing_physics.o \
obj/thing_shots.o \
obj/thing_stats.o \
obj/thing_traps.o \
obj/timer.o \
obj/value_util.o \
obj/vidfade.o \
obj/vidmode_data.o \
Expand Down
74 changes: 74 additions & 0 deletions build-cmake.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env bash
#
# Build keeperfx with CMake, at parity with the hand Makefiles.
#
# KFX_OS=windows (default) 32-bit MinGW-w64 (i686) Windows binary, using the
# same compiler/flags/prebuilt deps as `make`.
# KFX_OS=linux native x86_64 Linux ELF (pkg-config deps + prebuilt lin64 static libs)
# (system/pkg-config deps + prebuilt lin64 static libs).
#
# Third-party deps are downloaded automatically on first run (into deps/); the
# Windows build needs no vcpkg, the Linux build needs the usual -dev packages.
#
# Usage:
# ./build-cmake.sh # Windows keeperfx (standard log)
# KFX_OS=linux ./build-cmake.sh # Linux keeperfx
# ./build-cmake.sh keeperfx_hvlog # heavy-log variant
# USE_DOCKER=1 ./build-cmake.sh # build in an Ubuntu 24.04 container
# BUILD_DIR=out ./build-cmake.sh # override the build directory
#
# Requirements (native):
# windows: a MinGW-w64 i686 toolchain (Ubuntu: g++-mingw-w64-i686), cmake, ninja
# linux: gcc/g++, cmake, ninja, pkg-config + the SDL2/ffmpeg/openal/luajit/
# spng/minizip/zlib/miniupnpc/natpmp/openssl/zstd -dev packages
#
set -euo pipefail

TARGET="${1:-keeperfx}"
KFX_OS="${KFX_OS:-windows}"
# Output goes to out/ (git-ignored); build/ holds tracked CMake modules.
BUILD_DIR="${BUILD_DIR:-out}"

# Run the whole thing inside a container that mirrors upstream CI (Ubuntu 24.04).
if [ "${USE_DOCKER:-0}" = "1" ]; then
if [ "$KFX_OS" = "linux" ]; then
PKGS="build-essential pkg-config cmake ninja-build git curl ca-certificates \
libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-net-dev \
libavcodec-dev libavformat-dev libavutil-dev libswresample-dev \
libopenal-dev libluajit-5.1-dev libspng-dev libminizip-dev zlib1g-dev \
libminiupnpc-dev libnatpmp-dev libssl-dev libzstd-dev"
else
PKGS="g++-mingw-w64-i686 cmake ninja-build git curl ca-certificates"
fi
exec docker run --rm -v "$PWD:/src" -w /src ubuntu:24.04 bash -c "
set -eux
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq $PKGS
git config --global --add safe.directory /src || true
KFX_OS='$KFX_OS' BUILD_DIR='$BUILD_DIR' bash build-cmake.sh '$TARGET'
"
fi

if [ "$KFX_OS" = "linux" ]; then
cmake -S . -B "$BUILD_DIR" -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo
else
if ! command -v i686-w64-mingw32-gcc >/dev/null 2>&1; then
echo "error: i686-w64-mingw32-gcc not found on PATH." >&2
echo " Install a MinGW-w64 i686 toolchain (Ubuntu: 'sudo apt install g++-mingw-w64-i686')," >&2
echo " or re-run with USE_DOCKER=1, or KFX_OS=linux for a native Linux build." >&2
exit 1
fi
cmake -S . -B "$BUILD_DIR" -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=build/cmake/toolchains/mingw32.cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo
fi

cmake --build "$BUILD_DIR" --target "$TARGET" -j"$(nproc 2>/dev/null || echo 4)"

echo
if [ "$KFX_OS" = "linux" ]; then
echo "Built: $BUILD_DIR/$TARGET"
else
echo "Built: $BUILD_DIR/$TARGET.exe"
fi
Loading