-
Notifications
You must be signed in to change notification settings - Fork 1
/
infinitas
executable file
·484 lines (431 loc) · 18.4 KB
/
infinitas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
#!/usr/bin/env bash
# Default variables
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
PREFIX_LOCATION="$HOME/.local/share/konaste"
export WINEPREFIX="${PREFIX_LOCATION}"
# Game information
GAME_TITLE='beatmania IIDX INFINITAS'
DIR_TITLE="${GAME_TITLE}"
SIMPLE_NAME="infinitas"
INSTALLER_LINK="https://d1rc4pwxnc0pe0.cloudfront.net/v2/installer/infinitas_installer_2022060800.msi"
LAUNCH_PAGE="https://p.eagate.573.jp/game/infinitas/2/api/login/login.html"
LAUNCHER_NAME='bm2dx_launcher'
URI='bm2dxinf'
KDIALOG="$(command -v kdialog)"
ICOTOOL="$(command -v icotool)"
PW_LOOPBACK="$(command -v pw-loopback)"
WGET="$(command -v wget)"
GAMEMODE="$(command -v gamemoderun)"
GAMESCOPE="$(command -v gamescope)"
WINE="$(command -v wine)"
WINEBOOT="$(command -v wineboot)"
WINESERVER="$(command -v wineserver)"
# Kill the script if being ran from a TTY
if [[ $XDG_SESSION_TYPE != 'x11' && $XDG_SESSION_TYPE != 'wayland' ]]; then
echo "This script requires an active Xorg (X11)/Wayland session"
exit 1
fi
# Kill the script if no dialog box handler is found
[[ -z $KDIALOG ]] && echo "Unable to locate a binary for kdialog" && exit 1
# Function for locating the game files
locate_files() {
# TODO: Improve this.
[[ -n "$LAUNCHER_EXECUTABLE" ]] && return 0
[[ ! -e "${WINEPREFIX}" ]] && return 1
[[ ! -d "${WINEPREFIX}" ]] && return 2
[[ ! -f "${WINEPREFIX}/system.reg" ]] && return 3
[[ ! -f "${WINEPREFIX}/${SIMPLE_NAME}" ]] && return 4
[[ ! -d "${WINEPREFIX}/dosdevices/c:/Games/${DIR_TITLE}" ]] && return 5
[[ ! -d "${WINEPREFIX}/dosdevices/c:/Games/${DIR_TITLE}/Resource" ]] && return 6
[[ ! -f "${WINEPREFIX}/dosdevices/c:/Games/${DIR_TITLE}/launcher/modules/${LAUNCHER_NAME}.exe" ]] && return 7
declare -gr LAUNCHER_EXECUTABLE="C:\\\\Games\\\\${DIR_TITLE}\\\\launcher\\\\modules\\\\${LAUNCHER_NAME}.exe"
return 0
}
# Game launch function
run_game() {
declare -a PRELAUNCH_PARAMS=( )
# The e-amusement Cloud servers always go down daily between 5:00am-7:00am JST for maintenance.
# This is equivalent to 20:00-22:00 (8:00pm-10:00pm) UTC.
# The error message shown in this function will tell you when maintenance will end in your time zone.
if [[ $(date -u +%H) -ge 20 && $(date -u +%H) -lt 22 ]]; then
approx_time=$(printf '%(%l:%M%P %Z)T\n' "$(date +%s -u -d "22:00")")
if [[ "${approx_time:0:1}" == ' ' ]]; then
approx_time="${approx_time:1}"
fi
$KDIALOG \
--title "Maintenance Notice" \
--error "The e-amusement Cloud servers are currently down for maintenance.<br>Please wait until <strong>$approx_time</strong> and try again." 2>/dev/null
exit 255
fi
# Gamescope support
if [[ $IOL_GAMESCOPE -eq 1 || $IOL_GAMESCOPE -eq 2 ]]; then
if [[ -z $GAMESCOPE ]]; then
echo "IOL_GAMESCOPE set to 1, but gamescope was not found on your system." 1>&2
else
echo "Enabling Gamescope..."
PRELAUNCH_PARAMS+=( "${GAMESCOPE}" -w 1920 -h 1080 -r 120 --framerate-limit 120 -f )
# If IOL_GS is set to 1, use the SDL backend for Gamescope
# This is mainly a compatibility feature for those running NVIDIA GPUs, because of a
# core dump issue.
[[ $IOL_GS_NVIDIA -eq 1 ]] && PRELAUNCH_PARAMS+=( --backend sdl )
PRELAUNCH_PARAMS+=( -- )
# Gamescope will use the following parameters:
# - Resolution (-w -h): 1920x1080
# - Refresh rate (-r): 120Hz
# - FPS limit (--framerate-limit): 120fps
# * this is needed because you may get
fi
fi
# Disable DXVK
if [[ -z $IOL_NO_DXVK || $IOL_NO_DXVK -eq 0 ]]; then
# Use DXVK if found
if [[ -d "${WINEPREFIX}/dosdevices/c:/dxvk" || -d /usr/share/dxvk ]]; then
if [[ -d "${WINEPREFIX}/dosdevices/c:/dxvk" ]]; then
DXVK_LOCATION="${WINEPREFIX}/dosdevices/c:/dxvk"
else
DXVK_LOCATION="/usr/share/dxvk"
fi
if [[ -f ${DXVK_LOCATION}/x32/d3d9.dll && -f ${DXVK_LOCATION}/x64/d3d9.dll ]]; then
echo "Located DXVK at ${DXVK_LOCATION}"
export WINEDLLPATH="${DXVK_LOCATION}/x32:${DXVK_LOCATION}/x64"
export DXVK_LOG_LEVEL='error'
export DXVK_FRAME_RATE=120
else
echo "Unable to locate d3d9.dll in ${DXVK_LOCATION}" 1>&2
fi
else
echo "Couldn't locate DXVK directory. Using built-in DirectX..." 1>&2
fi
else
echo "Using built-in DirectX..."
fi
# Disable loopback device (NOT RECOMMENDED!)
if [[ -z $IOL_NO_LOOPBACK || $IOL_NO_LOOPBACK -eq 0 ]]; then
if [[ -z $PW_LOOPBACK ]]; then
echo "No binary for 'pw-loopback' was found. The PipeWire loopback device will not be available."
echo "WARNING: Ensure your audio sample rate is set to 44100Hz, or you will have no sound!" 1>&2
$KDIALOG \
--title "Loopback Warning" \
--sorry "No binary for <code>pw-loopback</code> was found on your system. Infinitas for Linux requires <code>pw-loopback</code> for enabling a virtual output to ease any audio issues with little to no manual audio configuration. Unless your audio sample rate within PipeWire is already set to 44100Hz, <strong><em>you will not have any sound while playing ${GAME_TITLE}.</em></strong>" \
--dontagain "${WINEPREFIX}/.kdialog_ignore:no_pwLoopback" 2>/dev/null
else
# Start PipeWire loopback device
echo "Starting PipeWire loopback device..."
$PW_LOOPBACK -m '[ FL FR ]' --capture-props='media.class=Audio/Sink node.name=konaste node.description=Konaste audio.rate=44100' &
export PULSE_SINK='konaste'
fi
else
echo "PipeWire loopback device has been disabled."
echo "WARNING: Ensure your audio sample rate is set to 44100Hz, or you will have no sound!" 1>&2
$KDIALOG \
--title "Loopback Warning" \
--sorry "You have chosen to disable the PipeWire loopback device. Unless your audio sample rate within PipeWire is already set to 44100Hz, <strong><em>you will not have any sound while playing ${GAME_TITLE}.</em></strong>" \
--dontagain "${WINEPREFIX}/.kdialog_ignore:pwLoopbackDisabled" 2>/dev/null
fi
export WINEDLLOVERRIDES="mscoree"
export WINEDEBUG='fixme-all'
# Detect Wayland and warn the user
if [[ $XDG_SESSION_TYPE == 'wayland' ]]; then
echo "Wayland detected; expect issues" 1>&2
# why the hell does this keep breaking the script
# if [[ -n $KDIALOG ]]; then
# $KDIALOG \
# --title "Wayland Warning" \
# --sorry "You appear to be utilizing a Wayland session provided by '"$XDG_CURRENT_DESKTOP"'. Wayland has a glaring issue of only exposing your current refresh rate to applications, which in turn, causes '"${GAME_TITLE}"' to fail the display initialization process if you are running a non-standard refresh rate, such as 75Hz, 144Hz, 165Hz, etc. Before clicking <strong>OK</strong>, ensure your refresh rate is set to 60Hz (or 120Hz if supported).' \
# --dontagain "${WINEPREFIX}/.kdialog_ignore:waylandWarning" 2>/dev/null
fi
# Alright, we're done here.
${WINESERVER} -p2
"${PRELAUNCH_PARAMS[@]}" ${WINE} start '/high' '/wait' "${LAUNCHER_EXECUTABLE}" "$LOGIN_TOKEN"
${WINESERVER} -w
sleep 1
kill -15 $(jobs -p)
# IIDX EMPRESS has a very goated credits song.
# don't @ me.
echo -e "\n\033[1;95mThank you for playing...\033[0m\n"
}
create_launcher() {
cat > "$HOME/.local/share/applications/${SIMPLE_NAME}.desktop" <<EOF
[Desktop Entry]
Name=${GAME_TITLE}
Type=Application
Categories=Game;
GenericName=Rhythm Game
Icon=$SIMPLE_NAME
Exec=xdg-open $LAUNCH_PAGE
EOF
cat > "$HOME/.local/share/applications/${SIMPLE_NAME}-launcher.desktop" <<EOF
[Desktop Entry]
Name=${GAME_TITLE} Launcher
Type=Application
Icon=$SIMPLE_NAME
Exec=${WINEPREFIX}/${SIMPLE_NAME} %u
MimeType=x-scheme-handler/$URI
NoDisplay=true
EOF
[[ ! -e "$HOME/.local/share/mime/packages" ]] && mkdir "$HOME/.local/share/mime/packages" 2>/dev/null
cat > "$HOME/.local/share/mime/packages/x-scheme-handler-${URI}.xml" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="x-scheme-handler/${URI}">
<comment>${GAME_TITLE}</comment>
<icon name="x-scheme-handler-${URI}"/>
<glob-deleteall/>
<glob pattern="${URI}://*"/>
</mime-type>
</mime-info>
EOF
update-desktop-database "$HOME/.local/share/applications"
update-mime-database "$HOME/.local/share/mime"
}
create_icons() {
[[ -z $ICOTOOL ]] && return 1
[[ -z "${WINEPREFIX}" ]] && {
echo "Wineprefix at ${PREFIX_LOCATION} could not be found"
exit 2
}
[[ ! -f "${WINEPREFIX}/dosdevices/c:/Games/${DIR_TITLE}/${DIR_TITLE}.ico" ]] && {
echo "Unable to locate icon for ${GAME_TITLE}"
exit 3
}
# Get how many icons we need to create
local icon="$(find . -type f -name "${DIR_TITLE}.ico")"
local iconDir="$HOME/.local/share/icons/hicolor"
local numIcons=$($ICOTOOL -l "${icon}" | wc -l)
for i in $(seq 1 $numIcons); do
# Get the size of the icons
local size="$($ICOTOOL -i $i -l "${icon}" | cut -d' ' -f 3 | cut -d'=' -f 2)"
# Create the directory if necessary
[[ ! -e "${iconDir}/${size}x${size}/apps" ]] && mkdir -p "${iconDir}/${size}x${size}/apps" 2>/dev/null
[[ ! -e "${iconDir}/${size}x${size}/mimetypes" ]] && mkdir -p "${iconDir}/${size}x${size}/mimetypes" 2>/dev/null
# Now extract the icon
$ICOTOOL -i $i -x "${icon}" -o "${iconDir}/${size}x${size}/apps/${SIMPLE_NAME}.png"
$ICOTOOL -i $i -x "${icon}" -o "${iconDir}/${size}x${size}/mimetypes/x-scheme-handler-${URI}.png"
done
return
}
# Installation function
run_installer() {
# Show a localization warning for the JP bros
if [[ "${LANG}" == ja_* || "${LANGUAGE}" == ja_* ]]; then
# Original string: Some dialog boxes you see during installation may not appear in Japanese. If necessary, you may need to use a machine translation utility to continue. Do you still want to install ${GAME_TITLE}?
echo "Showing localization warning"
$KDIALOG \
--title "インストールの警告" \
--warningyesno 'インストール中に表示されるダイアログ ボックスの一部は日本語で表示されない場合があります。必要に応じて、機械翻訳ユーティリティを使用して続行する必要があります。<br><br><strong>'"${GAME_TITLE}"' をインストールしますか?</strong>' \
--yes-label 'はい' \
--no-label 'いいえ' 2>/dev/null
if [[ $? -ne 0 ]]; then
exit 1
fi
fi
echo "Showing disclaimer"
# Disclaimer
$KDIALOG \
--title "DISCLAIMER" \
--warningyesno 'Infinitas for Linux is in no way affiliated with, endorsed, nor supported by KONAMI Amusement. It is meant to be used as a way to allow Linux users to play '"${GAME_TITLE}"' on Linux with minimal tweaks. This script does NOT contain any functionality for bypassing any restrictions pertaining to the e-amusement Cloud network, nor does the script developer have any intentions of implementing such features.<br><br>In order to play '"${GAME_TITLE}"' outside of trial mode, an active KONAMI ID is required, as well as the basic course subscription (¥1628/month) associated with it.<br><br>Like many online games today, it is possible to receive bans from the developers for accessing their game outside of what they support. While this script attempts to play it safe with the amount of tweaks to get the game running, the unlikely chance of receiving a ban is possible. Should any ban occur, the script developer is not to be held responsible. <em>Play at your own risk</em>.<br><br><strong>Proceed with installation?</strong>' 2>/dev/null
if [[ $? -eq 1 ]]; then
echo "Quitting installer..." 1>&2
exit 1
fi
# Locate files
if [[ $(locate_files; echo $?) -eq 0 ]]; then
$KDIALOG \
--title "Failed to install ${GAME_TITLE}" \
--error "Installation of ${GAME_TITLE} cannot proceed as existing files were found within the Wineprefix. If you are reinstalling ${GAME_TITLE}, delete the '${DIR_TITLE}' directory within ${PREFIX_LOCATION}." 2>/dev/null
exit 5
else
echo "Existing files were not found. Continuing with installation..."
fi
# Check dependencies
if [[ -z $WINE ]]; then
echo "Unable to locate binary for wine" 1>&2
$KDIALOG \
--title "Missing dependencies" \
--error "The installer was unable to find a binary for Wine. Please install it from your distribution's package manager." 2>/dev/null
exit 10
else
# Check Wine version
echo "$($WINE --version)"
local v="$($WINE --version | cut -d'-' -f2 | cut -d'.' -f1)"
if [[ $v -lt 9 ]]; then
echo "Out of date version of Wine detected"
$KDIALOG \
--title "Outdated Wine build detected!" \
--error "Your version of Wine ( $($WINE --version) ) is not compatible with this script.\nThis script requires a build of Wine based on version 9.0 or later." 2>/dev/null
exit 11
fi
fi
echo "Found wine (${WINE})"
[[ -z $WGET ]] && {
echo "Unable to locate binary for wget" 1>&2
$KDIALOG \
--title "Missing dependencies" \
--error "The installer was unable to find a binary for wget. Please install it from your distribution's package manager." 2>/dev/null
exit 12
}
echo "Found wget (${WGET})"
if [[ -z $ICOTOOL ]]; then
echo "Unable to locate binary for icotool" 1>&2
$KDIALOG \
--title "Missing dependencies" \
--sorry "The installer was unable to find a binary for icotool (icoutils). You will not be able to generate icons for ${GAME_TITLE}." 2>/dev/null
else
echo "Found icoutils (${ICOTOOL})"
fi
if [[ -z $PW_LOOPBACK ]]; then
echo "Unable to locate binary for pw-loopback" 1>&2
$KDIALOG \
--title "Missing dependencies" \
--error "The installer was unable to find a binary for pw-loopback, part of pipewire-audio. Please install it from your distribution's package manager." 2>/dev/null
exit 12
fi
echo "Found pw-loopback (${PW_LOOPBACK})"
# Now that all dependencies are in order, it's time to get started.
if [[ -e "${PREFIX_LOCATION}" && -d "${PREFIX_LOCATION}" ]]; then
if [[ -f "${PREFIX_LOCATION}/system.reg" ]]; then
echo "Existing Wineprefix detected, expect problems."
$WINEBOOT -u 2>/dev/null
else
$WINEBOOT -i 2>/dev/null
fi
else
mkdir -p "${PREFIX_LOCATION}"
$WINEBOOT -i 2>/dev/null
fi
cd "${WINEPREFIX}/dosdevices/c:/"
# Download the installer
echo "Downloading installer for ${GAME_TITLE}"
$WGET -t 3 "$INSTALLER_LINK"
if [[ $? -ne 0 ]]; then
echo "Failed to download installer for ${GAME_TITLE}"
$KDIALOG \
--title "Installation failed!" \
--error "Unable to download installer for ${GAME_TITLE}" 2>/dev/null
exit 15
fi
# Run the installer
echo "Running installer for ${GAME_TITLE}"
echo "NOTE: All CJK characters may render as boxes. This is due to the Wineprefix not having any CJK fonts available."
$WINE msiexec '/i' $(basename -- $INSTALLER_LINK) '/L*' "Z:\\\\tmp\\\\${SIMPLE_NAME}_install.log"
case $? in
1)
$KDIALOG \
--title "Installation failed!" \
--error "The ${GAME_TITLE} installer was terminated unexpectedly." 2>/dev/null
exit 16
;;
66)
$KDIALOG \
--title "Installation failed!" \
--error "The ${GAME_TITLE} installer was cancelled" 2>/dev/null
exit 17
;;
67)
$KDIALOG \
--title "Installation failed!" \
--error 'The '"${GAME_TITLE}"' installer failed to install. Check <code>/tmp/'"${SIMPLE_NAME}"'_install.log</code> to find out what happened.' 2>/dev/null
exit 18
;;
esac
# Set keys
echo "Setting additional registry keys..."
$WINE reg add 'HKLM\SOFTWARE\Microsoft\DirectDraw' /v 'ForceRefreshRate' /t 'REG_DWORD' /d 120 /f '/reg:64' 2>/dev/null
$WINE reg add 'HKCU\SOFTWARE\Wine\X11 Driver' /v 'UseXRandR' /t 'REG_SZ' /d 'Y' /f '/reg:64' 2>/dev/null
$WINE reg add 'HKCU\SOFTWARE\Wine\DllOverrides' /v 'd3d9' /t 'REG_SZ' /d 'native,builtin' /f '/reg:64' 2>/dev/null
# Create launcher and mimetype
echo "Creating launcher and mimetype for ${GAME_TITLE}..."
create_launcher
# Create icons
echo "Creating icons for ${GAME_TITLE}..."
create_icons
# Copy this script to the prefix directory
cp "${SCRIPT_DIR}/$(basename -- $0)" "${WINEPREFIX}/${SIMPLE_NAME}"
chmod +x "${WINEPREFIX}/${SIMPLE_NAME}"
echo "Installation complete!"
if [[ -z "$LOGIN_TOKEN" ]]; then
$KDIALOG \
--title "Installation Complete" \
--yesno "${GAME_TITLE} has been successfully installed. Would you like to open the launch page?" 2>/dev/null
[[ $? -eq 0 ]] && exec env TERM='dumb' xdg-open "$LAUNCH_PAGE"
fi
return 0
}
# And this is where all the fun happens.
if [[ -n "$1" ]]; then
# TODO: turn this into a case statement
if [[ "$1" == ${URI}://* ]]; then
echo "Detected login token for ${GAME_TITLE}: $1"
[[ $TERM != 'dumb' ]] && echo "Avoid passing login tokens directly to this script from a terminal emulator." 1>&2
declare -gr LOGIN_TOKEN="$1"
locate_files; case $? in
0)
run_game; exit $?
;;
1|2|3|4)
echo "${GAME_TITLE} was not found in default prefix location" 1>&2
$KDIALOG \
--title "Failed to launch ${GAME_TITLE}" \
--warningyesno "${GAME_TITLE} is not installed on your system.\nWould you like to install it?" 2>/dev/null
if [[ $? -eq 0 ]]; then
run_installer
# Run game if a login token was already provided
[[ $? -eq 0 ]] && run_game; exit $?
fi
exit 20
;;
5|6)
$KDIALOG \
--title "Failed to launch ${GAME_TITLE}" \
--error "Unable to locate installation and/or resource directory for ${GAME_TITLE} within Wineprefix" 2>/dev/null
exit 21
;;
7)
$KDIALOG \
--title "Failed to launch ${GAME_TITLE}" \
--error "Unable to locate launcher for ${GAME_TITLE} within Wineprefix" 2>/dev/null
exit 22
;;
esac
elif [[ "$1" == 'install' ]]; then
export WINEDLLOVERRIDES="mscoree;mshtml=d;ieframe=d"
run_installer; exit $?
elif [[ "$1" == 'fix-launcher' ]]; then
create_launcher
if [[ -f "${WINEPREFIX}/${SIMPLE_NAME}" ]]; then
echo "Replacing launch script..."
cp -f "${SCRIPT_DIR}/$(basename -- $0)" "${WINEPREFIX}/${SIMPLE_NAME}"
chmod +x "${WINEPREFIX}/${SIMPLE_NAME}"
fi
echo "Done."
exit $?
elif [[ "$1" == 'fix-icons' ]]; then
locate_files
if [[ $? -eq 0 ]]; then
echo "Creating icons..."
cd "${WINEPREFIX}/dosdevices/c:/"
create_icons; exit $?
else
echo "${GAME_TITLE} is not installed."
exit 1
fi
else
echo "Unrecognized argument $1" 1>&2
exit 1
fi
else
if [[ $(locate_files; echo $?) -eq 0 ]]; then
[[ ! $(command -v xdg-open) ]] && echo "This script requires xdg-open (xdg-utils) to open the launcher website for ${GAME_TITLE}." && exit 255
echo "No arguments provided. Opening $LAUNCH_PAGE in a web browser..."
exec xdg-open TERM='dumb' "$LAUNCH_PAGE"
else
echo "${GAME_TITLE} was not found in ~/.local/share/konaste" 1>&2
$KDIALOG \
--title "Not installed" \
--warningyesno "${GAME_TITLE} is not installed on your system.\nWould you like to install it?" 2>/dev/null
if [[ $? -eq 0 ]]; then
run_installer; exit $?
fi
exit 1
fi
fi