diff --git a/FCHost.bat b/FCHost.bat
new file mode 100644
index 0000000000000000000000000000000000000000..400243fc2b65360a807712f2986eb8c2ca6517ab
--- /dev/null
+++ b/FCHost.bat
@@ -0,0 +1,25 @@
+@ECHO off
+:: Free Cities FCHost Launcher - Windows
+
+:: run dependencyCheck.bat
+CALL .\devTools\scripts\dependencyCheck.bat
+SET CODE=%ERRORLEVEL%
+
+IF %CODE% EQU 69 (
+	:: if exit code is 69, then we don't have all the dependencies we need
+	ECHO.
+	ECHO Dependencies not met.
+    ECHO.
+	EXIT /b 0
+) ELSE IF %CODE% EQU 0 (
+	:: if exit code is 0, run FCHostInstallAndRun.js
+	CALL node devTools\scripts\FCHostInstallAndRun.js
+	EXIT /b 0
+) ELSE (
+	:: if exit code is not 0, print error message
+	ECHO.
+	ECHO dependencyCheck.bat exited with code: %CODE%
+	ECHO Dependency check failed unexpectedly.
+    ECHO.
+    EXIT /b 0
+)
diff --git a/FCHost.sh b/FCHost.sh
new file mode 100755
index 0000000000000000000000000000000000000000..8464283545f3886ec14c881ec0108af12e319e4c
--- /dev/null
+++ b/FCHost.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Free Cities FCHost Launcher - Unix
+
+# run dependencyCheck.sh
+./devTools/scripts/dependencyCheck.sh
+exitCode=$?
+# exit code is now stored in $exitCode
+
+# if exit code is 69, then we don't have all the dependencies we need
+if [[ $exitCode -eq 69 ]]; then
+    echo "Dependencies not met."
+    echo ""
+   exit 0
+# if exit code is not 0, print error message
+elif [[ $exitCode -ne 0 ]]; then
+	echo "dependencyCheck.sh exited with code: $exitCode"
+    echo "Dependency check failed unexpectedly."
+    echo ""
+    exit 0
+# if exit code is 0, run FCHostInstallAndRun.js
+else
+    node devTools/scripts/FCHostInstallAndRun.js
+fi
diff --git a/FCHost/.gitignore b/FCHost/.gitignore
index 0c8b4c1c999e1e2ae5c9a61da951ddc483dab3ee..00e8d2bdbdac408ce9523ae1c3216684553414aa 100644
--- a/FCHost/.gitignore
+++ b/FCHost/.gitignore
@@ -2,6 +2,7 @@ CMakeCache.txt
 CMakeFiles
 Debug
 Release
+Release.file
 x64
 *.sln
 *.vcxproj
@@ -11,4 +12,5 @@ libcef_dll_wrapper
 .vs
 cmake_install.cmake
 *.VC.db
-GPUCache
\ No newline at end of file
+GPUCache
+PreCompiledFCHost.zip
diff --git a/devTools/scripts/FCHostInstallAndRun.js b/devTools/scripts/FCHostInstallAndRun.js
new file mode 100644
index 0000000000000000000000000000000000000000..7184a331c5111e1a66167e6c6ac78659ce7528be
--- /dev/null
+++ b/devTools/scripts/FCHostInstallAndRun.js
@@ -0,0 +1,187 @@
+// cSpell:ignore fchost, megajs
+
+// @ts-ignore
+import jetpack from "fs-jetpack";
+import {execSync} from "child_process";
+import * as path from "path";
+import inquirer from 'inquirer';
+import {File} from 'megajs';
+import decompress from "decompress";
+
+// location to save the zip file to
+const zipLocation = path.join("fchost", "PreCompiledFCHost.zip");
+
+// make sure settings.json exists and has all the required properties
+execSync("node devTools/scripts/setup.js --settings");
+
+// load settings.json
+/** @type {import("./setup.js").Settings} */
+const settings = jetpack.read("settings.json", "json");
+
+// link to pre-compiled fchost
+let windowsLink = "https://mega.nz/file/AFhTxLxR#fQgZFswJHVLpLlY5BzhTPmUKtmISeHdJ065b_MW0700";
+
+let wineExists = false;
+try {
+	if (execSync("command -v wine").toString().trim() !== "") { wineExists = true; }
+} catch (e) {
+	// fail silently
+	// console.log(e);
+}
+
+let megaLink = "";
+
+// if FCHost doesn't exist
+if (
+	jetpack.exists(path.join(settings.FCHostPath, "fchost.exe")) === false &&
+	jetpack.exists(path.join(settings.FCHostPath, "fchost")) === false
+) {
+	if (process.platform === "win32") {
+		megaLink = windowsLink;
+	} else {
+		if (wineExists === false) {
+			// there are no pre-compiled versions of FCHost for this os at this time and wine isn't installed.
+			console.log("There is not a pre-compiled version of FCHost available for your system at this time.");
+			console.log("You can still use FCHost, but you will have to manually build it yourself.");
+			console.log("Instructions for doing so are here: https://gitgud.io/pregmodfan/fc-pregmod/-/blob/pregmod-master/FCHost/Building_FCHost.txt");
+			console.log("Alternatively you can install Wine (https://www.winehq.org/) and rerun this script to attempt to run the Windows version of FCHost.");
+		} else {
+			// use windows FCHost link
+			megaLink = windowsLink;
+			console.log("A native pre-compiled version of FCHost is not available for your os, but Wine is installed.");
+			console.log("Selected the pre-compiled Windows version of FCHost for download.");
+		}
+	}
+
+	// ask user if they want to download FCHost
+	if (
+		megaLink !== ""
+	) {
+		console.log("This script will download, extract, and run FCHost.");
+		// ask the users permission to download FCHost
+		let choice;
+		// @ts-ignore
+		await inquirer
+			.prompt([{
+				type: "rawlist",
+				name: "choice",
+				message: `Do you want to download and extract a pre-compiled version of FCHost from '${megaLink}'?`,
+				choices: ["Yes", "No"],
+				default: "Yes",
+				loop: false
+			}])
+			.then((answers) => {
+				choice = answers.choice;
+			});
+		if (choice === "Yes") {
+			// download FCHost
+			const file = File.fromURL(megaLink);
+	
+			// @ts-ignore
+			await file.loadAttributes();
+			console.log(`Downloading ${file.name} with a size of ${file.size} bytes`);
+	
+			// if zipLocation exists then remove it
+			jetpack.remove(zipLocation);
+	
+			// @ts-ignore
+			const data = await file.downloadBuffer();
+			// check that buffer size is the same as file.size
+			if (data.byteLength !== file.size) {
+				console.log(`File did not download correctly! There is a ${file.size - data.byteLength} byte size difference.}`);
+				console.log("Rerun this script to try again.");
+				process.exit();
+			}
+			jetpack.write(zipLocation, data, {atomic: true});
+	
+			// create settings.FCHostPath directory
+			if (jetpack.exists(settings.FCHostPath) === "file") {
+				// I don't know how we got both a folder and a file with the same name, but that is invalid on Windows
+				// Renaming it to `${settings.FCHostPath}.file` should be okay since anyone manually compiling should be recreating the file anyway
+				jetpack.move(settings.FCHostPath, settings.FCHostPath + ".file");
+			}
+			jetpack.dir(settings.FCHostPath);
+			// extract FCHost
+			// @ts-ignore
+			await decompress(zipLocation, settings.FCHostPath).then(files => {
+				// find the FCHost folder in releases
+				/** @type {string[]|string} */
+				let folder = jetpack.find(settings.FCHostPath, {
+					matching: "FCHost*", files: false, directories: true, recursive: false
+				});
+				if (folder.length === 0) {
+					console.log("Zip file extraction failed!");
+					jetpack.remove(settings.FCHostPath);
+					process.exit();
+				} else {
+					// move contents of folder[0] to settings.FCHostPath
+					jetpack.find(folder[0]).forEach(element => {
+						jetpack.move(element, path.join(settings.FCHostPath, path.relative(folder[0], element)));
+					});
+					// remove folder[0]
+					jetpack.remove(folder[0]);
+					console.log('Zip file extracted successfully!');
+				}
+			});
+			// delete zip file
+			jetpack.remove(zipLocation);
+		} else {
+			console.log("You can run this script at any time if you change your mind.");
+			console.log("You can also manually compile FCHost if you wish.");
+			console.log("Instructions for doing so are here: https://gitgud.io/pregmodfan/fc-pregmod/-/blob/pregmod-master/FCHost/Building_FCHost.txt");
+			process.exit();
+		}
+	}
+}
+
+if (
+	jetpack.exists(path.join(settings.FCHostPath, "fchost.exe")) === false &&
+	jetpack.exists(path.join(settings.FCHostPath, "fchost")) === false
+) {
+	console.log(`FCHost doesn't exist at "${settings.FCHostPath}"`);
+	console.log("You can manually compile FCHost if you wish.");
+	console.log("Instructions for doing so are here: https://gitgud.io/pregmodfan/fc-pregmod/-/blob/pregmod-master/FCHost/Building_FCHost.txt");
+	process.exit();
+}
+
+// if FC_pregmod.html is not in settings.FCHostPath
+if (jetpack.exists(path.join(settings.FCHostPath, "FC_pregmod.html")) !== "file") {
+	console.log(`There doesn't seem to be a FC_pregmod.html file at ${settings.FCHostPath}`);
+	console.log("Running the compiler with it's default settings should fix this problem.");
+	let choice;
+	// @ts-ignore
+	await inquirer
+		.prompt([{
+			type: "rawlist",
+			name: "choice",
+			message: `Do want to run the compiler now?`,
+			choices: ["Yes", "No"],
+			default: "Yes",
+			loop: false
+		}])
+		.then((answers) => {
+			choice = answers.choice;
+		});
+	if (choice === "Yes") {
+		try {
+			execSync("node devTools/scripts/advancedCompiler.js --skip-sanity-checks --no-interaction", {stdio: "inherit"});
+		} catch (e) {
+			console.log(e);
+		}
+	}
+}
+
+// launch FCHost
+// cd into settings.FCHostPath
+process.chdir(settings.FCHostPath);
+console.log("Launching FCHost");
+if (process.platform === "win32") {
+	// run fchost
+	execSync("fchost.exe", {stdio: "inherit"});
+} else if (wineExists === true) {
+	console.log("Using Wine to run the Windows version of FCHost");
+	execSync("wine fchost.exe", {stdio: "inherit"});
+} else {
+	// run fchost
+	execSync("./fchost", {stdio: "inherit"});
+}
diff --git a/devTools/scripts/advancedCompiler.js b/devTools/scripts/advancedCompiler.js
index 0eadef0df4fbbe0027dac382da2f58a8aa7ceeb3..a888e473cb8fdc6ac152ab5d038e71edacb924e6 100644
--- a/devTools/scripts/advancedCompiler.js
+++ b/devTools/scripts/advancedCompiler.js
@@ -23,6 +23,11 @@ const args = yargs(hideBin(process.argv))
 		description: 'The filename to save the compiled HTML file as',
 		default: "FC_pregmod.html"
 	})
+	.option('skip-sanity-checks', {
+		type: 'boolean',
+		description: 'If true sanity checks will be skipped regardless of settings',
+		default: false,
+	})
 	.parse();
 
 const batSh = (process.platform === "win32") ? "bat" : "sh";
@@ -50,7 +55,7 @@ if (settings.compilerMode === "simple") {
 		command += ` --themes`;
 	}
 } else {
-	if (settings.compilerRunSanityChecks === 1) {
+	if (settings.compilerRunSanityChecks === 1 && args.skipSanityChecks === false) {
 		try {
 			execSync(
 				`node devTools/scripts/sanityCheck.js${args.interaction ? "" : " --no-interaction"}`,
@@ -122,7 +127,7 @@ if (settings.compilerCopyToFCHost === true) {
 	}
 }
 
-if (settings.compilerMode === "advanced" && settings.compilerRunSanityChecks === 2) {
+if (settings.compilerMode === "advanced" && settings.compilerRunSanityChecks === 2 && args.skipSanityChecks === false) {
 	try {
 		execSync(
 			`node devTools/scripts/sanityCheck.js${args.interaction ? "" : " --no-interaction"}`,
diff --git a/package.json b/package.json
index 2f38d3d8c84b3d186a282014c581ad30a3dcf1a9..ef97ab154d723e621ee1f3866d40db866ac1ec60 100644
--- a/package.json
+++ b/package.json
@@ -38,12 +38,14 @@
 		"@types/twine-sugarcube": "^2.36.1",
 		"ansi-colors": "^4.1.3",
 		"cspell": "^8.3.2",
+		"decompress": "^4.2.1",
 		"eslint": "^8.0.0",
 		"eslint-plugin-jsdoc": "^46.0.0",
 		"eslint-plugin-sonarjs": "^0.23.0",
 		"http-server": "^14.1.1",
 		"indefinite": "^2.4.3",
 		"inquirer": "^9.2.15",
+		"megajs": "^1.1.8",
 		"node-watch": "^0.7.4",
 		"strip-ansi": "^7.1.0",
 		"ts-essentials": "^9.1.1",