mirror of
https://gitlab.com/the-no-frauds-club/cosmonarchy-bw-prerelease.git
synced 2026-09-17 01:01:12 +00:00
Ported from cosmonarchy-bw-release 46d191e, minus plugins/gptp.qdp:
this repo's gptp.qdp is its own newer build (last rebuilt in c7cee7f7)
and the release binary would regress it.
230 lines
8.8 KiB
Bash
Executable File
230 lines
8.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Prepare a Bottles/Wine prefix so Fraud Launcher 2 and Cosmonarchy BW will run.
|
|
#
|
|
# Fixes two things that a stock Wine prefix gets wrong:
|
|
#
|
|
# 1. Fraud Launcher 2 (.NET 8 WPF) aborts at startup because Wine's icu.dll
|
|
# forwards to icuuc68.dll, which does not exist:
|
|
# err:module:find_forwarded_export module not found for forward
|
|
# 'icuuc68.u_charsToUChars_68' used by L"C:\\windows\\system32\\icu.dll"
|
|
# Setting DOTNET_SYSTEM_GLOBALIZATION_USENLS=1 makes .NET use Windows NLS
|
|
# instead of ICU. (DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 also works but
|
|
# throws away culture support, so prefer NLS.)
|
|
#
|
|
# 2. aize_debug.qdp initialises its console with FreeType against two Windows
|
|
# system fonts that Wine does not ship, and dies with "Fonts could not be
|
|
# loaded":
|
|
# %systemroot%\fonts\lucon.ttf (Lucida Console)
|
|
# %systemroot%\fonts\arialuni.ttf (Arial Unicode MS)
|
|
# FreeType opens these by path, not by name, so any monospace / wide-coverage
|
|
# TTF dropped in under those filenames satisfies it.
|
|
#
|
|
# 3. Cosmonarchy ships cnc-ddraw (ddraw.dll beside StarCraft.exe), but Wine
|
|
# loads its own builtin ddraw.dll unless told otherwise, so cnc-ddraw is
|
|
# silently ignored. StarCraft then performs a real exclusive-fullscreen
|
|
# 640x480 DirectDraw mode switch, which on a multi-monitor X11 desktop
|
|
# shows up as an entirely black screen. Overriding ddraw to native,builtin
|
|
# makes Wine load cnc-ddraw so the game renders in a normal window.
|
|
#
|
|
# 4. With cnc-ddraw actually loaded, its default renderer=auto still draws a
|
|
# black window here; renderer=gdi renders correctly. The bundled GLSL
|
|
# shader only applies to the OpenGL renderer, so it is cleared alongside.
|
|
# (Both were changed together, so which one mattered is not isolated - if
|
|
# you want the shader back, try renderer=opengl first.)
|
|
#
|
|
# Usage:
|
|
# tools/linux/setup-bottle.sh [--check] [--bottle NAME | --prefix PATH]
|
|
#
|
|
# --check report what is missing, change nothing
|
|
# --bottle NAME Bottles bottle name (default: Blizzard)
|
|
# --prefix PATH a plain WINEPREFIX, instead of a Bottles bottle
|
|
# --game-dir PATH the StarCraft directory holding ddraw.ini
|
|
# (default: read from the prefix's registry InstallPath)
|
|
#
|
|
set -euo pipefail
|
|
|
|
BOTTLE=Blizzard
|
|
PREFIX=
|
|
GAMEDIR=
|
|
CHECK=0
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--check) CHECK=1; shift ;;
|
|
--bottle) BOTTLE="${2:?--bottle needs a name}"; shift 2 ;;
|
|
--prefix) PREFIX="${2:?--prefix needs a path}"; shift 2 ;;
|
|
--game-dir) GAMEDIR="${2:?--game-dir needs a path}"; shift 2 ;;
|
|
-h|--help) sed -n '2,30p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
|
*) echo "unknown argument: $1" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "$PREFIX" ]; then
|
|
for base in \
|
|
"$HOME/.var/app/com.usebottles.bottles/data/bottles/bottles" \
|
|
"$HOME/.local/share/bottles/bottles"
|
|
do
|
|
if [ -d "$base/$BOTTLE" ]; then PREFIX="$base/$BOTTLE"; break; fi
|
|
done
|
|
fi
|
|
|
|
if [ -z "$PREFIX" ] || [ ! -d "$PREFIX/drive_c" ]; then
|
|
echo "error: no Wine prefix found (bottle '$BOTTLE')." >&2
|
|
echo " pass --bottle NAME or --prefix /path/to/prefix" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "prefix: $PREFIX"
|
|
rc=0
|
|
|
|
note() { if [ "$CHECK" = 1 ]; then echo " MISSING $1"; rc=1; else echo " fixed $1"; fi; }
|
|
ok() { echo " ok $1"; }
|
|
|
|
# --- 1. fonts -----------------------------------------------------------------
|
|
# Each entry is "target-filename<TAB>candidate source paths, first match wins".
|
|
install_font() {
|
|
local target="$1"; shift
|
|
local fontdir dest src
|
|
fontdir="$PREFIX/drive_c/windows/Fonts"
|
|
[ -d "$fontdir" ] || fontdir="$PREFIX/drive_c/windows/fonts"
|
|
mkdir -p "$fontdir"
|
|
dest="$fontdir/$target"
|
|
|
|
if [ -s "$dest" ]; then ok "$target"; return 0; fi
|
|
|
|
if [ "$CHECK" = 1 ]; then note "$target"; return 0; fi
|
|
|
|
for src in "$@"; do
|
|
if [ -s "$src" ]; then
|
|
cp -- "$src" "$dest"
|
|
note "$target <- $(basename "$src")"
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
# last resort: ask fontconfig for anything matching
|
|
if command -v fc-match >/dev/null 2>&1; then
|
|
src=$(fc-match -f '%{file}' "${FC_QUERY:-sans}" 2>/dev/null || true)
|
|
if [ -n "$src" ] && [ -s "$src" ]; then
|
|
cp -- "$src" "$dest"
|
|
note "$target <- $(basename "$src") (fontconfig)"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
echo " FAILED $target - no source font found; install fonts-dejavu" >&2
|
|
rc=1
|
|
}
|
|
|
|
echo "fonts (for aize_debug.qdp's FreeType console):"
|
|
FC_QUERY=monospace install_font lucon.ttf \
|
|
/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf \
|
|
/usr/share/fonts/dejavu/DejaVuSansMono.ttf \
|
|
/usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf \
|
|
/usr/share/fonts/liberation/LiberationMono-Regular.ttf
|
|
FC_QUERY=sans install_font arialuni.ttf \
|
|
/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf \
|
|
/usr/share/fonts/dejavu/DejaVuSans.ttf \
|
|
/usr/share/fonts/truetype/noto/NotoSans-Regular.ttf \
|
|
/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf
|
|
|
|
# --- 2. .NET globalization (Fraud Launcher 2) ---------------------------------
|
|
echo ".NET globalization (for Fraud Launcher 2):"
|
|
VAR=DOTNET_SYSTEM_GLOBALIZATION_USENLS
|
|
YML="$PREFIX/bottle.yml"
|
|
|
|
if [ -f "$YML" ]; then
|
|
if grep -q "^ *$VAR:" "$YML"; then
|
|
ok "$VAR set in bottle.yml"
|
|
elif [ "$CHECK" = 1 ]; then
|
|
note "$VAR in bottle.yml"
|
|
else
|
|
cp -- "$YML" "$YML.bak-$(date +%Y%m%d%H%M%S)"
|
|
python3 - "$YML" "$VAR" <<'PY'
|
|
import re, sys
|
|
path, var = sys.argv[1], sys.argv[2]
|
|
s = open(path, encoding='utf-8').read()
|
|
line = " %s: '1'\n" % var
|
|
if re.search(r'^Environment_Variables:\s*\{\}\s*$', s, re.M):
|
|
s = re.sub(r'^Environment_Variables:\s*\{\}\s*$',
|
|
"Environment_Variables:\n" + line.rstrip('\n'), s, count=1, flags=re.M)
|
|
elif re.search(r'^Environment_Variables:\s*$', s, re.M):
|
|
s = re.sub(r'^(Environment_Variables:\s*\n)', r'\1' + line, s, count=1, flags=re.M)
|
|
else:
|
|
raise SystemExit("could not find Environment_Variables: in %s" % path)
|
|
open(path, 'w', encoding='utf-8').write(s)
|
|
PY
|
|
note "$VAR in bottle.yml (backup written alongside)"
|
|
fi
|
|
else
|
|
# plain WINEPREFIX: no bottle.yml to edit, so tell the caller how to export it
|
|
if [ "$CHECK" = 1 ]; then
|
|
note "$VAR (no bottle.yml; export it yourself)"
|
|
else
|
|
echo " note no bottle.yml here - run the launcher with:"
|
|
echo " $VAR=1 wine 'Fraud Launcher 2.exe'"
|
|
fi
|
|
fi
|
|
|
|
# --- 3. ddraw override, so Wine loads cnc-ddraw rather than its own builtin ----
|
|
echo "ddraw override (cnc-ddraw):"
|
|
REG="$PREFIX/user.reg"
|
|
HELPER="$(dirname "$0")/add-dll-override.py"
|
|
if [ ! -f "$REG" ]; then
|
|
echo " FAILED no user.reg in $PREFIX" >&2
|
|
rc=1
|
|
elif grep -q '^"ddraw"=' "$REG"; then
|
|
ok "ddraw = $(grep -m1 '^\"ddraw\"=' "$REG" | cut -d= -f2- | tr -d '\"')"
|
|
elif [ "$CHECK" = 1 ]; then
|
|
note "ddraw=native,builtin in user.reg"
|
|
elif pgrep -f "wineserver" >/dev/null 2>&1 && pgrep -af wineserver | grep -qF "$PREFIX"; then
|
|
echo " SKIPPED a wineserver is live for this prefix - close the game and re-run" >&2
|
|
rc=1
|
|
elif [ ! -f "$HELPER" ]; then
|
|
echo " FAILED helper not found: $HELPER" >&2
|
|
rc=1
|
|
else
|
|
cp -- "$REG" "$REG.bak-$(date +%Y%m%d%H%M%S)"
|
|
python3 "$HELPER" "$REG" ddraw native,builtin >/dev/null
|
|
note "ddraw=native,builtin in user.reg (backup written alongside)"
|
|
fi
|
|
|
|
|
|
# --- 4. cnc-ddraw renderer ----------------------------------------------------
|
|
echo "cnc-ddraw renderer:"
|
|
if [ -z "$GAMEDIR" ]; then
|
|
# HKLM\Software\Wow6432Node\Blizzard Entertainment\Starcraft -> InstallPath
|
|
winpath=$(grep -a -m1 '^"InstallPath"=' "$PREFIX/system.reg" 2>/dev/null \
|
|
| sed 's/^"InstallPath"="//; s/"$//')
|
|
if [ -n "$winpath" ]; then
|
|
rel=$(printf '%s' "$winpath" | sed 's/\\\\/\//g; s|^[A-Za-z]:||; s|/*$||')
|
|
GAMEDIR="$PREFIX/drive_c$rel"
|
|
fi
|
|
fi
|
|
|
|
INI="$GAMEDIR/ddraw.ini"
|
|
PATCHER="$(dirname "$0")/patch-ddraw-ini.py"
|
|
if [ -z "$GAMEDIR" ] || [ ! -f "$INI" ]; then
|
|
echo " SKIPPED no ddraw.ini found${GAMEDIR:+ at $GAMEDIR}; pass --game-dir" >&2
|
|
elif [ ! -f "$PATCHER" ]; then
|
|
echo " FAILED helper not found: $PATCHER" >&2
|
|
rc=1
|
|
elif python3 "$PATCHER" --check "$INI" renderer=gdi shader= >/dev/null 2>&1; then
|
|
ok "renderer=gdi in $(basename "$GAMEDIR")/ddraw.ini"
|
|
elif [ "$CHECK" = 1 ]; then
|
|
note "renderer=gdi in $(basename "$GAMEDIR")/ddraw.ini"
|
|
else
|
|
cp -- "$INI" "$INI.bak-$(date +%Y%m%d%H%M%S)"
|
|
python3 "$PATCHER" "$INI" renderer=gdi shader= >/dev/null
|
|
note "renderer=gdi, shader= in $(basename "$GAMEDIR")/ddraw.ini (backup written alongside)"
|
|
fi
|
|
|
|
|
|
echo
|
|
if [ "$CHECK" = 1 ] && [ "$rc" != 0 ]; then
|
|
echo "check failed: run without --check to apply."
|
|
elif [ "$rc" = 0 ]; then
|
|
echo "bottle ready."
|
|
fi
|
|
exit $rc
|