Added City of Division.,

This commit is contained in:
Storm Dragon committed 2026-10-26 13:13:57 -04:00
1 parent 62e47a41ae
commit 8244a883b7
4 files changed
+135

No files matched your search

+75
View File
@@ -0,0 +1,75 @@
#!/usr/bin/env bash
recover_city_of_division_window() {
local gamePid="$1"
local attempt gameWindow geometry key value windowX windowY windowWidth windowHeight
local -a gameWindows=()
# Wait for this launch's off-screen pygame window, not another Wine process.
for ((attempt = 0; attempt < 150; attempt++)); do
kill -0 "$gamePid" 2>/dev/null || return 0
mapfile -t gameWindows < <(
xdotool search --all --pid "$gamePid" --name '^City of division,' 2>/dev/null
)
if [[ ${#gameWindows[@]} -eq 1 ]]; then
gameWindow="${gameWindows[0]}"
if [[ "$(xdotool getwindowclassname "$gameWindow" 2>/dev/null)" == "cityofdivision.exe" ]] &&
geometry="$(xdotool getwindowgeometry --shell "$gameWindow" 2>/dev/null)"; then
windowX=""
windowY=""
windowWidth=""
windowHeight=""
# Parse xdotool's data without evaluating it as shell commands.
while IFS='=' read -r key value; do
case "$key" in
X) windowX="$value" ;;
Y) windowY="$value" ;;
WIDTH) windowWidth="$value" ;;
HEIGHT) windowHeight="$value" ;;
esac
done <<< "$geometry"
if [[ "$windowX" =~ ^-[0-9]+$ && "$windowY" =~ ^-[0-9]+$ &&
"$windowWidth" == 1 && "$windowHeight" == 1 ]]; then
if ! xdotool windowmove "$gameWindow" 100 100 \
windowsize "$gameWindow" 640 480 windowmap "$gameWindow"; then
echo "Could not restore City of Division's off-screen window." >&2
return 1
fi
# If its desktop is elsewhere, normal window selection will
# complete focus. Never activate a different workspace here.
xdotool windowfocus "$gameWindow" 2>/dev/null || true
return 0
fi
if [[ "$windowX" =~ ^[0-9]+$ && "$windowY" =~ ^[0-9]+$ &&
"$windowWidth" =~ ^[0-9]+$ && "$windowHeight" =~ ^[0-9]+$ ]] &&
((windowWidth > 1 && windowHeight > 1)); then
return 0
fi
fi
fi
sleep 0.2
done
echo "Timed out waiting to restore City of Division's window." >&2
return 1
}
run_city_of_division() {
if [[ -z "${DISPLAY:-}" ]] || ! command -v xdotool >/dev/null; then
echo "City of Division requires an X11 display and xdotool for its window recovery." >&2
return 1
fi
local -a launchCommand=(wine)
if command -v gamemoderun >/dev/null; then
launchCommand=(gamemoderun wine)
fi
"${launchCommand[@]}" "$@" &
local gamePid=$!
recover_city_of_division_window "$gamePid" &
local focusPid=$!
local gameStatus=0
wait "$gamePid" || gameStatus=$?
# The worker also stops when this process exits; no persistent focus loop.
wait "$focusPid" || true
return "$gameStatus"
}
+26
View File
@@ -0,0 +1,26 @@
# shellcheck shell=bash disable=SC2154 # cache and WINEPREFIX are shared AGM installer state.
export WINEARCH=win64
export winVer="win10"
download "https://blindgames.eu/jeux/city_of_division_setup.exe" || exit 1
install_wine_bottle || exit 1
# Preserve Wine's exit status through the progress wrapper's pipeline.
if ! (
set -o pipefail
install_with_progress wine "Installing City of Division..." \
"${cache}/city_of_division_setup.exe" \
/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- /NOICONS /TASKS= \
/NOCLOSEAPPLICATIONS /NORESTARTAPPLICATIONS \
'/DIR=C:\Program Files\City of Division'
); then
alert "City of Division" "Installation failed. No launcher was added."
exit 1
fi
if [[ ! -s "${WINEPREFIX}/drive_c/Program Files/City of Division/cityofdivision.exe" ]]; then
alert "City of Division" "The game executable was not installed. No launcher was added."
exit 1
fi
add_launcher 'c:\Program Files\City of Division\cityofdivision.exe'
+30
View File
@@ -169,6 +169,36 @@ Run the offline release, installer and updater checks with
`python3 tests/tekken3_setup_tests.py`. These use temporary fixtures and do not
access the network, start Wine or change installed games.
## City of Division
Choose **City of Division** from `./audiogame-manager.sh -i`. The installer
downloads the Windows setup from [BlindGames](https://blindgames.eu/jeux/city-of-division.html)
and runs it silently in the shared Wine64 bottle. The game installs to
`C:\Program Files\City of Division` and uses Windows 10 compatibility.
AGM adds its launcher only after setup succeeds and `cityofdivision.exe` exists.
The bundled NVDA controller DLLs use AGM's existing launch-time speech handling,
including the `-s` option described above.
On X11, AGM uses `xdotool` to move the game's hidden 1-by-1 window on-screen
once per launch. Without this, the language menu can speak but ignore keys,
even after selecting Wine in the window manager. Recovery targets only the
new game process, stops after restoring its window, and does not switch
workspaces. You can then switch away and back using your normal window list.
The window recovery requires `xdotool` and does not run in the `-g` debugger mode.
Before submitting, review the diff and test installation and launch using both
console and graphical menus. Check keyboard navigation, screen-reader speech,
game audio, connecting to the game service, and quitting/relaunching. Confirm an
existing game in the shared Wine64 bottle still launches and speaks. A disposable
Wine installation verified setup and the executable path; live gameplay and
screen-reader behavior still require testing. Run the isolated failure checks
with `bash tests/city_of_division_tests.sh`; these do not start Wine or use the
network or installed games. Run `bash tests/city_of_division_focus_tests.sh` for
the isolated window-recovery and launch checks. For live acceptance, close and
relaunch City of Division twice, check the language menu and main menu keys,
then switch away and back using the window list. Confirm the game accepts keys
after returning and does not pull focus back while you use another window.
## AI-assisted contributions
AI-assisted contributions are welcome. The person submitting the contribution remains responsible for reviewing and testing the changes before submission. Please review the generated diff, run the relevant tests, and describe what changed and how it was tested.
+4
View File
@@ -881,6 +881,10 @@ game_launcher() {
fi
if [[ "$debugGdb" == "1" ]]; then
run_with_optional_gamemode winedbg --gdb "${game[1]##*\\}"
elif [[ "${wineExec,,}" == "cityofdivision.exe" ]]; then
# shellcheck source=.includes/city-of-division.sh
source "${scriptDir}/.includes/city-of-division.sh"
run_city_of_division "${game[1]##*\\}"
else
# Use direct wine execution instead of 'wine start' to ensure clipboard works
# See: https://bugs.winehq.org/show_bug.cgi?id=50598