Add a language option to the VR menu, and fix a crash switching to it
build / build (push) Successful in 2m22s
build / build (push) Successful in 2m22s
- New "Language" row on the Main Menu tab (English/French/German), backed by a new "general" group in questshock.config.json - Fixes a device-reproduced crash: switching language used to call language_dealfunc(), whose render_run()/opanel_redraw() repaint assumes the game's own in-game options panel is on screen - crashes (SIGSEGV) when triggered from our independent VR overlay instead. Now calls language_change() directly, which is all that's actually needed to reload resources and refresh the inventory/MFD/side-icon UI - Fixes a second crash: this data set ships frnstrng.res/gerstrng.res but not mfdfrn.res/mfdger.res, and language_change() closes the current resource files before discovering the new ones don't exist - leaving no valid resource file open and crashing on the next lookup. Now checks both files exist before ever switching, refusing the change (with an in-headset popup) instead of corrupting resource state - extract_assets.sh can now also pull mfdfrn.res/mfdger.res out of a System Shock: Classic installer (which includes them, unlike Enhanced Edition) if one is present in res/assets/ - entirely optional - Documented all of the above in README.md/CONFIG.md
This commit is contained in:
@@ -13,10 +13,23 @@
|
||||
# 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).
|
||||
# filenames present in both: intro.res, objprop.dat), EXCEPT
|
||||
# mfdfrn.res/mfdger.res (French/German MFD art - see CONFIG.md/README.md),
|
||||
# which that installer doesn't include at all - see "Optional: French/
|
||||
# German MFD art" below for where those instead come from. 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).
|
||||
#
|
||||
# Optional: French/German MFD art
|
||||
# The Enhanced Edition installer's data set doesn't include
|
||||
# mfdfrn.res/mfdger.res, so French/German are otherwise missing their
|
||||
# MFD (Multi-Function Display) art and the game refuses to switch to
|
||||
# them (see CONFIG.md). System Shock: Classic (also gog.com) does
|
||||
# include both files. If you also own it, drop its offline installer
|
||||
# (e.g. setup_system_shock_classic_2.0.0.3.exe) in this directory too -
|
||||
# entirely optional, this script still runs fine without it - and this
|
||||
# script pulls just those two files out of it into ss_ee/data/ as well.
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||
@@ -27,6 +40,7 @@ fail() { echo "PREFLIGHT FAIL: $*" >&2; exit 1; }
|
||||
|
||||
shopt -s nullglob
|
||||
installers=(setup_system_shock_enhanced_edition*.exe)
|
||||
classic_installers=(setup_system_shock_classic*.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" ;;
|
||||
@@ -35,6 +49,15 @@ case "${#installers[@]}" in
|
||||
esac
|
||||
INSTALLER="${installers[0]}"
|
||||
|
||||
# Optional - see "Optional: French/German MFD art" above. Empty (not
|
||||
# missing/failed) when absent; only a genuine ambiguity (more than one
|
||||
# candidate file) is a hard failure.
|
||||
case "${#classic_installers[@]}" in
|
||||
0) CLASSIC_INSTALLER="" ;;
|
||||
1) CLASSIC_INSTALLER="${classic_installers[0]}" ;;
|
||||
*) fail "multiple setup_system_shock_classic*.exe files found in $ASSETS_DIR - keep only one: ${classic_installers[*]}" ;;
|
||||
esac
|
||||
|
||||
# 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
|
||||
@@ -69,9 +92,38 @@ run_extraction() {
|
||||
cp -a "$work/kpf/res/pc/hd/sound/." "$out_dir/sound/"
|
||||
}
|
||||
|
||||
# Extracts mfdfrn.res/mfdger.res from $1 (a System Shock: Classic installer
|
||||
# .exe) into $2 (an existing ss_ee output directory's data/ subfolder) -
|
||||
# see "Optional: French/German MFD art" above. Unlike the Enhanced Edition
|
||||
# installer, Classic's data files sit directly in the Inno Setup package
|
||||
# (no intermediate zip), so this is just a targeted innoextract --include,
|
||||
# no unzip step needed. Same declare -f-into-docker structure as
|
||||
# run_extraction() above.
|
||||
run_classic_mfd_extraction() {
|
||||
set -euo pipefail
|
||||
local installer="$1" out_dir="$2"
|
||||
work="$(mktemp -d)"
|
||||
trap 'rm -rf "${work:-}"' EXIT
|
||||
|
||||
echo "== Extracting mfdfrn.res/mfdger.res from classic installer =="
|
||||
innoextract --silent \
|
||||
--include 'app/SSHOCK/DATA/MFDFRN.RES' --include 'app/SSHOCK/DATA/MFDGER.RES' \
|
||||
-d "$work/classic" "$installer"
|
||||
|
||||
# Original DOS-era filenames are uppercase; Shockolate's resource
|
||||
# loader expects the lowercase names already used for every other
|
||||
# res/data/*.res file (case-sensitive on Linux, unlike the DOS/Windows
|
||||
# filesystems these came from).
|
||||
cp "$work/classic/app/SSHOCK/DATA/MFDFRN.RES" "$out_dir/data/mfdfrn.res"
|
||||
cp "$work/classic/app/SSHOCK/DATA/MFDGER.RES" "$out_dir/data/mfdger.res"
|
||||
}
|
||||
|
||||
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"
|
||||
if [ -n "$CLASSIC_INSTALLER" ]; then
|
||||
run_classic_mfd_extraction "$ASSETS_DIR/$CLASSIC_INSTALLER" "$OUT_DIR"
|
||||
fi
|
||||
else
|
||||
echo "== innoextract/unzip not found locally - using a throwaway docker container =="
|
||||
command -v docker >/dev/null 2>&1 \
|
||||
@@ -86,12 +138,18 @@ else
|
||||
apt-get update -qq >/dev/null
|
||||
apt-get install -y -qq innoextract unzip >/dev/null
|
||||
$(declare -f run_extraction)
|
||||
$(declare -f run_classic_mfd_extraction)
|
||||
run_extraction '/assets/$INSTALLER' '/assets/ss_ee'
|
||||
$([ -n "$CLASSIC_INSTALLER" ] && echo "run_classic_mfd_extraction '/assets/$CLASSIC_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."
|
||||
if [ -n "$CLASSIC_INSTALLER" ]; then
|
||||
echo "Also extracted mfdfrn.res/mfdger.res (French/German MFD art) from $CLASSIC_INSTALLER."
|
||||
else
|
||||
echo "Note: mfdfrn.res/mfdger.res (French/German MFD art) are not present - only needed for"
|
||||
echo "French/German (see CONFIG.md); drop a System Shock: Classic installer here too to get them."
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user