Initial commit

This commit is contained in:
2026-10-09 02:48:24 +02:00
commit e05d973a8d
133 changed files with 101507 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
@echo off
rem Double-click to install Unheard City for your user (no admin rights needed).
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0install.ps1" %*
echo.
pause

View File

@@ -0,0 +1,79 @@
# Unheard City - per-user installer (no admin rights needed). Run "Install.cmd" next to this file.
# install.ps1 [-Target DIR] [-Desktop yes|no] [-Quiet]
# Copies the app to %LOCALAPPDATA%\Programs\UnheardCity, adds a Start menu (and optionally desktop) shortcut and
# an "Unheard City" entry in Settings > Apps for uninstalling. Running it again upgrades in place.
param(
[string]$Target = (Join-Path $env:LOCALAPPDATA "Programs\UnheardCity"),
[ValidateSet("ask", "yes", "no")][string]$Desktop = "ask",
[switch]$Quiet
)
$ErrorActionPreference = "Stop"
$Name = "Unheard City"
$Exe = "UnheardCity.exe"
$Version = "@VERSION@"
$Src = $PSScriptRoot
$RegKey = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\UnheardCity"
$StartLnk = Join-Path ([Environment]::GetFolderPath("Programs")) "$Name.lnk"
$DesktopLnk = Join-Path ([Environment]::GetFolderPath("Desktop")) "$Name.lnk"
function Say($msg) { if (-not $Quiet) { Write-Host $msg } }
function Shortcut($path, $target, $workdir) {
$s = (New-Object -ComObject WScript.Shell).CreateShortcut($path)
$s.TargetPath = $target
$s.WorkingDirectory = $workdir
$s.IconLocation = "$target,0"
$s.Description = "Replace voice lines, music and ambience in Batman: Arkham City"
$s.Save()
}
try {
if (-not (Test-Path (Join-Path $Src $Exe))) { throw "$Exe not found next to this script. Unzip the whole download first." }
$Target = [IO.Path]::GetFullPath($Target)
if ([IO.Path]::GetFullPath($Src).TrimEnd('\') -ieq $Target.TrimEnd('\')) { throw "This copy is already the installed one." }
$running = Get-Process -Name "UnheardCity" -ErrorAction SilentlyContinue | Where-Object { $_.Path -and $_.Path.StartsWith($Target, [StringComparison]::OrdinalIgnoreCase) }
if ($running) { throw "$Name is running. Close it and run the installer again." }
Say "Installing $Name $Version to $Target ..."
if (Test-Path $Target) {
# upgrade: replace the program files only (user data lives in %APPDATA%\UnheardCity, not here)
$isOurs = (Test-Path (Join-Path $Target $Exe)) -or -not (Get-ChildItem -LiteralPath $Target -Force)
if (-not $isOurs) { throw "$Target exists and is not an $Name installation; choose another folder." }
Get-ChildItem -LiteralPath $Target -Force | Remove-Item -Recurse -Force
} else {
New-Item -ItemType Directory -Path $Target | Out-Null
}
Get-ChildItem -LiteralPath $Src -Force | Where-Object { $_.Name -notin @("Install.cmd", "install.ps1") } |
Copy-Item -Destination $Target -Recurse -Force
$exePath = Join-Path $Target $Exe
Shortcut $StartLnk $exePath $Target
$wantDesktop = $Desktop -eq "yes"
if ($Desktop -eq "ask" -and -not $Quiet) {
$wantDesktop = (Read-Host "Add a desktop shortcut? [Y/n]") -notmatch '^(n|no)$'
}
if ($wantDesktop) { Shortcut $DesktopLnk $exePath $Target }
$kb = [int]((Get-ChildItem -LiteralPath $Target -Recurse -File | Measure-Object Length -Sum).Sum / 1KB)
$uninst = Join-Path $Target "uninstall.ps1"
New-Item -Path $RegKey -Force | Out-Null
$props = @{
DisplayName = $Name; DisplayVersion = $Version; Publisher = "Unheard City"; DisplayIcon = "$exePath,0"
InstallLocation = $Target; EstimatedSize = $kb; NoModify = 1; NoRepair = 1
UninstallString = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"$uninst`""
QuietUninstallString = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"$uninst`" -Quiet"
}
foreach ($k in $props.Keys) {
$type = if ($props[$k] -is [int]) { "DWord" } else { "String" }
New-ItemProperty -Path $RegKey -Name $k -Value $props[$k] -PropertyType $type -Force | Out-Null
}
Say ""
Say "$Name is installed. Start it from the Start menu$(if ($wantDesktop) { ' or the desktop' })."
Say "Uninstall: Settings > Apps > Installed apps > $Name."
if (-not $Quiet -and (Read-Host "Start $Name now? [Y/n]") -notmatch '^(n|no)$') { Start-Process $exePath -WorkingDirectory $Target }
exit 0
} catch {
Write-Host ""
Write-Host "Installation failed: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}

View File

@@ -0,0 +1,46 @@
# Unheard City - uninstaller (registered in Settings > Apps by install.ps1).
# uninstall.ps1 [-Quiet] [-RemoveUserData]
# Removes the program folder, the shortcuts and the Apps entry. Your user data (%APPDATA%\UnheardCity: originals
# store, notes, settings) is kept unless you choose to remove it - it is what "Revert" uses to restore the game.
param([switch]$Quiet, [switch]$RemoveUserData)
$ErrorActionPreference = "Stop"
$Name = "Unheard City"
$Target = $PSScriptRoot
$RegKey = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\UnheardCity"
$Links = @((Join-Path ([Environment]::GetFolderPath("Programs")) "$Name.lnk"),
(Join-Path ([Environment]::GetFolderPath("Desktop")) "$Name.lnk"))
$Data = @((Join-Path $env:APPDATA "UnheardCity"), (Join-Path $env:LOCALAPPDATA "UnheardCity"))
function Say($msg) { if (-not $Quiet) { Write-Host $msg } }
function Modified-Count {
# sounds still changed in the game, according to the originals stores
$n = 0
Get-ChildItem -Path (Join-Path $Data[0] "stores\*\store.json") -ErrorAction SilentlyContinue | ForEach-Object {
try { $n += @((Get-Content -Raw -LiteralPath $_.FullName | ConvertFrom-Json).entries.PSObject.Properties).Count } catch {}
}
return $n
}
try {
if (Get-Process -Name "UnheardCity" -ErrorAction SilentlyContinue) { throw "$Name is running. Close it first." }
$mods = Modified-Count
if ($mods -gt 0 -and -not $Quiet) {
Write-Host "$mods sound(s) are still modified in the game. To restore the originals, open $Name and use"
Write-Host "'Revert all' BEFORE uninstalling (your originals store is kept either way)."
if ((Read-Host "Uninstall anyway? [y/N]") -notmatch '^(y|yes)$') { exit 1 }
}
if (-not $Quiet -and -not $RemoveUserData -and $mods -eq 0 -and (Test-Path $Data[0])) {
$RemoveUserData = (Read-Host "Also delete your settings, notes and backups in $($Data[0])? [y/N]") -match '^(y|yes)$'
}
foreach ($l in $Links) { if (Test-Path $l) { Remove-Item -LiteralPath $l -Force } }
if (Test-Path $RegKey) { Remove-Item -Path $RegKey -Recurse -Force }
if ($RemoveUserData -and $mods -eq 0) { foreach ($d in $Data) { if (Test-Path $d) { Remove-Item -LiteralPath $d -Recurse -Force } } }
# the folder holding this script is removed after it exits
Start-Process -FilePath "cmd.exe" -ArgumentList "/c ping 127.0.0.1 -n 3 >nul & rmdir /s /q `"$Target`"" -WindowStyle Hidden
Say "$Name has been uninstalled."
exit 0
} catch {
Write-Host "Uninstall failed: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}