a5ec8db5f7
build / build (push) Failing after 5s
dependency (SDL2, SDL2_mixer, fluidsynth-lite, a MIDI soundfont) prebuilt, so compiling the engine needs no network access - just the image and the engine source. Add res/assets/extract_assets.sh to pull the game's data files out of a purchased GOG installer, and a Makefile that assembles a runnable dist/ from the two. Also add `make package`, which builds a redistributable tarball that omits the proprietary game assets (shipping res/GET_ASSETS.txt instead) plus license information for both the MIT tooling and the GPLv3 engine, and a Gitea Actions workflow that builds and publishes it to dl.ladkau.de on every push.
98 lines
4.1 KiB
Bash
Executable File
98 lines
4.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Extracts the game data Shockolate needs out of a purchased System Shock:
|
|
# Enhanced Edition installer from gog.com, into ./ss_ee/{data,sound}.
|
|
#
|
|
# Usage:
|
|
# 1. Buy System Shock: Enhanced Edition on gog.com and download the
|
|
# offline installer (a Windows .exe, e.g.
|
|
# setup_system_shock_enhanced_edition_1.2.16_(64bit)_(44378).exe).
|
|
# 2. Drop it in this directory (res/assets/).
|
|
# 3. Run this script: ./extract_assets.sh
|
|
#
|
|
# The installer is an Inno Setup package; the actual game data lives
|
|
# inside it in sshock.kpf, which is just a zip file. Its res/pc/hd/ and
|
|
# res/pc/cdrom/ trees together hold every classic-game data/sound file
|
|
# Shockolate's res/ folder expects (res/pc/hd wins the couple of
|
|
# filenames present in both: intro.res, objprop.dat). Needs innoextract
|
|
# and unzip; if they're not installed locally, this script does the
|
|
# extraction inside a throwaway Ubuntu container instead (needs docker in
|
|
# that case, nothing else).
|
|
set -euo pipefail
|
|
|
|
cd "$(dirname "${BASH_SOURCE[0]}")"
|
|
ASSETS_DIR="$(pwd)"
|
|
OUT_DIR="$ASSETS_DIR/ss_ee"
|
|
|
|
fail() { echo "PREFLIGHT FAIL: $*" >&2; exit 1; }
|
|
|
|
shopt -s nullglob
|
|
installers=(setup_system_shock_enhanced_edition*.exe)
|
|
shopt -u nullglob
|
|
case "${#installers[@]}" in
|
|
0) fail "no setup_system_shock_enhanced_edition*.exe found in $ASSETS_DIR - buy System Shock: Enhanced Edition on gog.com, download the offline installer, and drop it here" ;;
|
|
1) ;;
|
|
*) fail "multiple installer .exe files found in $ASSETS_DIR - keep only one: ${installers[*]}" ;;
|
|
esac
|
|
INSTALLER="${installers[0]}"
|
|
|
|
# Extracts sshock.kpf from $1 (an installer .exe) and assembles $2 (an
|
|
# ss_ee output directory) from its res/pc/{hd,cdrom} trees. Defined as a
|
|
# function so the exact same logic can run either natively or, via
|
|
# `declare -f`, inside a throwaway container.
|
|
run_extraction() {
|
|
set -euo pipefail
|
|
local installer="$1" out_dir="$2"
|
|
# Deliberately not `local`: an EXIT trap set here fires when the whole
|
|
# shell process exits, which is after this function - and this
|
|
# function's own scope - has already returned, so a `local` var would
|
|
# already be unset by then (unbound-variable error under `set -u`).
|
|
work="$(mktemp -d)"
|
|
trap 'rm -rf "${work:-}"' EXIT
|
|
|
|
echo "== Extracting sshock.kpf from installer =="
|
|
innoextract --silent --include sshock.kpf -d "$work/installer" "$installer"
|
|
|
|
echo "== Unpacking sshock.kpf (data/sound trees only) =="
|
|
mkdir -p "$work/kpf"
|
|
unzip -q "$work/installer/sshock.kpf" \
|
|
'res/pc/hd/data/*' 'res/pc/hd/sound/*' 'res/pc/cdrom/data/*' \
|
|
-d "$work/kpf"
|
|
|
|
echo "== Assembling $out_dir =="
|
|
rm -rf "$out_dir"
|
|
mkdir -p "$out_dir/data" "$out_dir/sound"
|
|
# cdrom/data first (cutscenes, audio logs, and shared tables only it
|
|
# has), then hd/data on top (wins the 2 overlapping filenames:
|
|
# intro.res, objprop.dat - the hd install's own copies).
|
|
cp -a "$work/kpf/res/pc/cdrom/data/." "$out_dir/data/"
|
|
cp -a "$work/kpf/res/pc/hd/data/." "$out_dir/data/"
|
|
cp -a "$work/kpf/res/pc/hd/sound/." "$out_dir/sound/"
|
|
}
|
|
|
|
if command -v innoextract >/dev/null 2>&1 && command -v unzip >/dev/null 2>&1; then
|
|
echo "== Using local innoextract/unzip =="
|
|
run_extraction "$ASSETS_DIR/$INSTALLER" "$OUT_DIR"
|
|
else
|
|
echo "== innoextract/unzip not found locally - using a throwaway docker container =="
|
|
command -v docker >/dev/null 2>&1 \
|
|
|| fail "docker not found in PATH (needed since innoextract/unzip aren't installed locally)"
|
|
docker run --rm \
|
|
-v "$ASSETS_DIR:/assets" \
|
|
-e HOST_UID="$(id -u)" \
|
|
-e HOST_GID="$(id -g)" \
|
|
ubuntu:22.04 \
|
|
bash -c "
|
|
set -euo pipefail
|
|
apt-get update -qq >/dev/null
|
|
apt-get install -y -qq innoextract unzip >/dev/null
|
|
$(declare -f run_extraction)
|
|
run_extraction '/assets/$INSTALLER' '/assets/ss_ee'
|
|
chown -R \"\$HOST_UID:\$HOST_GID\" /assets/ss_ee
|
|
"
|
|
fi
|
|
|
|
echo "== Done =="
|
|
echo "Assets extracted to $OUT_DIR"
|
|
echo "Note: mfdfrn.res/mfdger.res (French/German MFD art) are not present in this"
|
|
echo "installer and are only needed for those localizations - not for English play."
|