diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
new file mode 100644
index 00000000..857e9390
--- /dev/null
+++ b/.github/workflows/lint.yml
@@ -0,0 +1,16 @@
+on:
+ push:
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+ env:
+ GITHUB_ACTIONS: true
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: latest
+ - run: node scripts/lint.mjs
\ No newline at end of file
diff --git a/.github/workflows/mdbook.yml b/.github/workflows/mdbook.yml
index f56e6748..81ec1e3d 100644
--- a/.github/workflows/mdbook.yml
+++ b/.github/workflows/mdbook.yml
@@ -20,8 +20,14 @@ jobs:
env:
MDBOOK_VERSION: 0.4.37
CARGO_TERM_COLOR: always
+ GITHUB_ACTIONS: true
steps:
- uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: latest
+ - name: Generate summary
+ run: node scripts/generate.mjs
- uses: Swatinem/rust-cache@v2
- name: Install mdBook
run: |
diff --git a/.gitignore b/.gitignore
index bad7316d..72d81851 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
book
.idea
**/.DS_Store
+src/games.json
\ No newline at end of file
diff --git a/README.md b/README.md
index a9a0f1d0..029490cb 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,9 @@ Documentation for Whisky.
cargo install mdbook-template
cargo install mdbook-last-changed
```
-5. You can preview changes to the book with `mdbook serve --open`
+5. Install [Node.js](https://nodejs.org/en/download/).
+ You can also install it through [Homebrew](https://brew.sh/) with `brew install node`.
+6. You can preview changes to the book with `mdbook serve --open`
### Adding Game Pages:
0. Standards to uphold:
@@ -69,19 +71,11 @@ Documentation for Whisky.
```
-3. Add your game to `~/whisky-book/src/SUMMARY.md`. Make sure that you insert it in the proper alphabetical order, not deleting any games. Ensure the proper spacing and indentation is followed. Here is an example with [Diablo IV (Battle.net)](https://docs.getwhisky.app/game-support/diablo-4-battle-net.html)
- ```
- ...
- - [Cyberpunk 2077](./game-support/cyberpunk-2077.md)
- - [Dark Souls III](./game-support/dark-souls-3.md)
- - [Diablo IV (Battle.net)](./game-support/diablo-4-battle-net.md)
- - [Diablo IV (Steam)](./game-support/diablo-4-steam.md)
- - [Dorfromantik](./game-support/dorfromantik.md)
- ...
- ```
-4. Add your game to `~/whisky-book/src/game-support/README.md`. Follow the same standards as above.
-5. Create a pull request detailing the changes you made. Ensure that it's consise, yet readable and coherent.
+3. Run the `generate` script with `./scripts/generate.mjs` to update `SUMMARY.md`.
+ This will also make the game appear in the sidebar of the book.
+4. Create a pull request detailing the changes you made. Ensure that it's consise, yet readable and coherent.
- You will need to create a fork of `whisky-book` and push your changes there before creating a PR. Once you've done that, then you can submit a PR to merge your fork with `main`.
+5. Run `./scripts/lint.mjs` to ensure that your changes are properly formatted.
6. Sit back, wait for PR reviews, and make changes as necessary.
Have any questions about this process or anything Whisky-related? Stop by the [Discord](https://discord.gg/CsqAfs9CnM) and ask us a question! We're more than happy to help.
diff --git a/scripts/.prettierrc.yaml b/scripts/.prettierrc.yaml
new file mode 100644
index 00000000..8f5e8ffe
--- /dev/null
+++ b/scripts/.prettierrc.yaml
@@ -0,0 +1,7 @@
+singleQuote: true
+semi: true
+trailingComma: none
+arrowParens: avoid
+endOfLine: lf
+tabWidth: 4
+printWidth: 80
\ No newline at end of file
diff --git a/scripts/core.mjs b/scripts/core.mjs
new file mode 100644
index 00000000..aa42afa7
--- /dev/null
+++ b/scripts/core.mjs
@@ -0,0 +1,276 @@
+/**
+ * @fileoverview Core shared functions between linting and generation.
+ */
+import { readdir } from 'node:fs/promises';
+import { getDirName, logging } from './utils.mjs';
+import { resolve } from 'node:path';
+import { request } from 'node:https';
+
+/**
+ * Core directory paths.
+ * @property {string} rootDir
+ * @property {string} srcDir
+ * @property {string} gameSupportDir
+ * @property {string} summaryFile
+ * @property {string} gamesJsonFile
+ * @readonly
+ */
+export const CORE_PATHS = {
+ rootDir: resolve(getDirName(), '..'),
+ srcDir: resolve(getDirName(), '..', 'src'),
+ gameSupportDir: resolve(getDirName(), '..', 'src', 'game-support'),
+ summaryFile: resolve(getDirName(), '..', 'src', 'SUMMARY.md'),
+ gamesJsonFile: resolve(getDirName(), '..', 'src', 'games.json')
+};
+
+export const SCRIPT_GENERATE_START = '';
+export const SCRIPT_GENERATE_END = '';
+
+/**
+ * Gets the start and end sections of a file.
+ * @param {string} content
+ * @returns {[[number, number], null] | [null, 'not-found' | 'invalid-position']}
+ */
+export const sectionsGetStartAndEnd = content => {
+ // The start and end sections both need to be present
+ const startMatch = content.indexOf(SCRIPT_GENERATE_START);
+ const endMatch = content.indexOf(SCRIPT_GENERATE_END);
+ if (startMatch === -1 || endMatch === -1) {
+ logging.debug('Failed to find start or end section in file.');
+ return [null, 'not-found'];
+ }
+
+ // The end section must come after the start section
+ if (startMatch > endMatch) {
+ logging.debug('End section comes before start section in file.');
+ return [null, 'invalid-position'];
+ }
+
+ // Get the start and end sections
+ return [[startMatch, endMatch], null];
+};
+
+export const TITLES_REGEX = /^# (.+)/;
+
+/**
+ * Gets the title of a file.
+ * @param {string} content
+ * @returns {[string, null] | [null, 'not-found']}
+ */
+export const getTitle = content => {
+ // Match the title
+ const titleMatch = content.match(TITLES_REGEX);
+ if (!titleMatch || titleMatch.length < 2) {
+ logging.debug('Failed to find title in file.');
+ return [null, 'not-found'];
+ }
+
+ return [titleMatch[1], null];
+};
+
+export const SCRIPT_ALIASES_REGEX = //;
+
+/**
+ * Parse aliases from a file.
+ * @param {string} content
+ * @returns {[string[], null] | [null, 'not-found' | 'bad-json' | 'bad-json-format']}
+ */
+export const parseAliases = content => {
+ // Match the aliases section
+ const aliasesMatch = content.match(SCRIPT_ALIASES_REGEX);
+ if (!aliasesMatch || aliasesMatch.length < 2) {
+ logging.debug('Failed to find aliases section in file.');
+ return [null, 'not-found'];
+ }
+
+ // Parse the aliases
+ let [aliasesParsed, aliasesError] = (() => {
+ try {
+ return [JSON.parse(aliasesMatch[1]), null];
+ } catch (error) {
+ logging.debug('Failed to parse aliases section in file: %o', error);
+ return [null, error];
+ }
+ })();
+ if (aliasesError) {
+ return [null, 'bad-json'];
+ }
+ if (
+ !aliasesParsed ||
+ !Array.isArray(aliasesParsed) ||
+ !aliasesParsed.every(alias => typeof alias === 'string')
+ ) {
+ logging.debug(
+ 'Failed to parse aliases section in file: not an array of strings.'
+ );
+ return [null, 'bad-json-format'];
+ }
+
+ return [aliasesParsed, null];
+};
+
+export const REVIEW_METADATA_REGEX =
+ /{{#template \.\.\/templates\/rating.md status=(Platinum|Gold|Silver|Bronze|Garbage) installs=(Yes|No) opens=(Yes|No)}}/;
+
+/**
+ * @typedef {'Platinum' | 'Gold' | 'Silver' | 'Bronze' | 'Garbage'} RatingStatus
+ */
+
+/**
+ * Parse rating information from a file.
+ * @param {string} content
+ * @returns {[{
+ * status: RatingStatus,
+ * installs: 'Yes' | 'No',
+ * opens: 'Yes' | 'No',
+ * }, null] | [null, 'not-found']
+ */
+export const parseReviewMetadata = content => {
+ // Match the rating section
+ const ratingMatch = content.match(REVIEW_METADATA_REGEX);
+ if (!ratingMatch || ratingMatch.length < 4) {
+ logging.debug('Failed to find rating section in file.');
+ return [null, 'not-found'];
+ }
+
+ const status = ratingMatch[1];
+ const installs = ratingMatch[2];
+ const opens = ratingMatch[3];
+
+ return [
+ {
+ status,
+ installs,
+ opens
+ },
+ null
+ ];
+};
+
+export const GAMES_EMBEDS_METADATA = {
+ steam: /{{#template ..\/templates\/steam.md id=(\d+)}}/
+};
+
+/**
+ * @typedef {{
+ * type: 'steam',
+ * id: number,
+ * }} GameEmbed
+ */
+
+/**
+ * Get game embeds from a file.
+ * @param {string} content
+ * @returns {[[GameEmbed, number] | null, 'not-found' | 'multiple-found']}
+ *
+ */
+export const parseGameEmbeds = content => {
+ // Match the game embeds section
+ /**
+ * @type {{
+ * location: number,
+ * embed: GameEmbed
+ * }[]}
+ */
+ const embeds = [];
+ for (const [type, regex] of Object.entries(GAMES_EMBEDS_METADATA)) {
+ const match = content.match(regex);
+ if (match && match.length > 1) {
+ embeds.push({
+ location: match.index,
+ embed: {
+ type,
+ id: parseInt(match[1])
+ }
+ });
+ }
+ }
+
+ if (embeds.length === 0) {
+ logging.debug('Failed to find game embeds section in file.');
+ return [null, 'not-found'];
+ }
+ if (embeds.length > 1) {
+ logging.debug('Found multiple game embeds section in file.');
+ return [null, 'multiple-found'];
+ }
+
+ return [[embeds[0].embed, embeds[0].location], null];
+};
+
+/**
+ * Use webservers to check that a GameEmbed is valid.
+ * @param {GameEmbed} embed
+ * @returns {Promise<[boolean, null] | [null, 'invalid-embed' | 'web-request-failed']>}
+ */
+export const checkGameEmbed = async embed => {
+ if (embed.type === 'steam') {
+ const steamUrl =
+ 'https://store.steampowered.com/app/' +
+ encodeURIComponent(embed.id);
+ const url = new URL(steamUrl);
+ /**
+ * @type {import('http').IncomingMessage}
+ */
+ const [response, responseError] = await new Promise(resolve => {
+ request(
+ {
+ hostname: url.hostname,
+ port: 443,
+ path: url.pathname,
+ method: 'GET',
+ headers: {
+ 'User-Agent': 'WhiskyBookBot/1.0'
+ }
+ },
+ resolve
+ ).end();
+ })
+ .then(response => [response, null])
+ .catch(error => [null, error]);
+ if (responseError) {
+ logging.debug('Failed to request Steam URL: %o', responseError);
+ return [null, 'web-request-failed'];
+ }
+
+ if (response.statusCode === 200) {
+ return [true, null];
+ }
+ }
+
+ return [false, 'invalid-embed'];
+};
+
+const FILES_SKIP = ['README.md', 'template.md'];
+
+/**
+ * Gets all markdown files in the game-support directory.
+ * @returns {Promise<[string[], null] | [null, 'failed-to-read-dir']>}
+ */
+export const getMarkdownFiles = async () => {
+ const [gameSupportDirFiles, gameSupportDirFilesError] = await readdir(
+ CORE_PATHS.gameSupportDir,
+ { withFileTypes: true }
+ )
+ .then(files => [files, null])
+ .catch(error => [null, error]);
+ if (gameSupportDirFilesError) {
+ logging.error(
+ 'Failed to read game-support directory: %o',
+ gameSupportDirFilesError
+ );
+ return [null, 'failed-to-read-dir'];
+ }
+
+ return [
+ gameSupportDirFiles
+ .filter(
+ file =>
+ file.isFile() &&
+ file.name.endsWith('.md') &&
+ !FILES_SKIP.includes(file.name)
+ )
+ .map(file => resolve(CORE_PATHS.gameSupportDir, file.name)),
+ null
+ ];
+};
diff --git a/scripts/generate.mjs b/scripts/generate.mjs
new file mode 100755
index 00000000..7f32b878
--- /dev/null
+++ b/scripts/generate.mjs
@@ -0,0 +1,295 @@
+#!/usr/bin/env node
+/**
+ * @fileoverview Generates the SUMMARY.md and games.json files.
+ */
+
+import { readFile, writeFile } from 'node:fs/promises';
+import { extname, basename } from 'node:path';
+
+import {
+ markdownEscape,
+ logging,
+ removeDuplicates,
+ getLastUpdated
+} from './utils.mjs';
+import {
+ CORE_PATHS,
+ sectionsGetStartAndEnd,
+ getMarkdownFiles,
+ getTitle,
+ parseAliases,
+ parseReviewMetadata,
+ parseGameEmbeds,
+ SCRIPT_GENERATE_START,
+ SCRIPT_GENERATE_END
+} from './core.mjs';
+
+/**
+ * @typedef {import('./core.mjs').GameEmbed} GameEmbed
+ * @typedef {import('./core.mjs').RatingStatus} RatingStatus
+ */
+
+/**
+ * @typedef {{
+ * title: string,
+ * lastUpdated: Date,
+ * aliases: string[],
+ * rating: {
+ * status: RatingStatus,
+ * installs: boolean,
+ * opens: boolean,
+ * },
+ * embed: GameEmbed | null,
+ * }} GameMetadata
+ */
+
+/**
+ * Generate GameMetadata for every game.
+ * @returns {Promise<[{
+ * path: string,
+ * game: GameMetadata,
+ * }[], null] | [null, 'folder-read-error']>}
+ */
+export const generateGameMetadata = async () => {
+ const [markdownFiles, markdownFilesError] = await getMarkdownFiles();
+ if (markdownFilesError) {
+ logging.error('Failed to get markdown files: %s', markdownFilesError);
+ return [null, 'folder-read-error'];
+ }
+
+ /**
+ * @type {{
+ * path: string,
+ * game: GameMetadata,
+ * }[]}
+ */
+ const links = [];
+ for (const file of markdownFiles) {
+ // Read the file
+ /**
+ * @type {[string, null] | [null, Error]}
+ */
+ const [fileContent, fileContentError] = await readFile(file, 'utf-8')
+ .then(data => [data, null])
+ .catch(error => [null, error]);
+ if (fileContentError) {
+ logging.error(
+ 'Failed to read file %s: %o',
+ filePath,
+ fileContentError
+ );
+ continue;
+ }
+
+ // Get the title
+ const [title, titleError] = getTitle(fileContent);
+ if (titleError) {
+ logging.warning(
+ 'Failed to get title in file %s: %s',
+ filePath,
+ titleError
+ );
+ continue;
+ }
+
+ // Look for aliases
+ const [aliasesParsed, aliasesError] = parseAliases(fileContent);
+ if (aliasesError && aliasesError !== 'not-found') {
+ logging.error(
+ 'Failed to parse aliases in file %s: %s',
+ filePath,
+ aliasesError
+ );
+ continue;
+ }
+
+ const aliases = removeDuplicates(
+ [...(aliasesParsed ?? []), title].map(alias => alias.toLowerCase())
+ );
+
+ // Look for rating
+ const [ratingParsed, ratingError] = parseReviewMetadata(fileContent);
+ if (ratingError) {
+ logging.error(
+ 'Failed to parse rating in file %s: %s',
+ filePath,
+ ratingError
+ );
+ continue;
+ }
+
+ // Look for embed
+ const [embedData, embedError] = parseGameEmbeds(fileContent);
+ if (embedError && embedError !== 'not-found') {
+ logging.error(
+ 'Failed to parse embed in file %s: %s',
+ filePath,
+ embedError
+ );
+ continue;
+ }
+ const embed = embedData && embedData.length > 0 ? embedData[0] : [];
+
+ // Look for last updated
+ const [lastUpdated, lastUpdatedError] = getLastUpdated(file);
+ if (lastUpdatedError) {
+ logging.error(
+ 'Failed to get last updated in file %s: %s',
+ file,
+ lastUpdatedError
+ );
+ continue;
+ }
+
+ links.push({
+ path: file,
+ game: {
+ title,
+ lastUpdated,
+ aliases,
+ rating: {
+ status: ratingParsed.status,
+ installs: ratingParsed.installs === 'Yes',
+ opens: ratingParsed.opens === 'Yes'
+ },
+ embed: embedError ? null : embed
+ }
+ });
+ }
+
+ return [links, null];
+};
+
+/**
+ * Generate the sidebar links.
+ * @param {{
+ * path: string,
+ * game: GameMetadata
+ * }[]} links
+ * @returns {string}
+ */
+export const generateLinks = links => {
+ return (
+ '\n' +
+ links
+ .map(link => {
+ return ` - [${markdownEscape(
+ link.game.title
+ )}](/game-support/${encodeURIComponent(basename(link.path))})`;
+ })
+ .join('\n') +
+ '\n'
+ );
+};
+
+/**
+ * Generate the games.json file.
+ * @param {{
+ * path: string,
+ * game: GameMetadata
+ * }[]} links
+ * @returns {string}
+ */
+export const generateGamesJson = links => {
+ return JSON.stringify(
+ links.map(link => {
+ // Strip the extension
+ const name = basename(link.path);
+ const ext = extname(name);
+ const base = name.slice(0, -ext.length);
+ return {
+ url: `/game-support/${encodeURIComponent(base + '.html')}`,
+ title: link.game.title,
+ aliases: link.game.aliases,
+ lastUpdated: link.game.lastUpdated.toISOString(),
+ rating: {
+ status: link.game.rating.status,
+ installs: link.game.rating.installs,
+ opens: link.game.rating.opens
+ },
+ embed: link.game.embed
+ };
+ }),
+ null,
+ 2
+ );
+};
+
+/**
+ * Main function.
+ * @returns {Promise}
+ */
+const main = async () => {
+ logging.info('Generating SUMMARY.md and games.json...');
+ const [gameData, gameDataError] = await generateGameMetadata();
+ if (gameDataError) {
+ return 1;
+ }
+
+ // Get the SUMMARY.md file
+ /**
+ * @type {[string, null] | [null, Error]}
+ */
+ const [summaryFile, summaryFileError] = await readFile(
+ CORE_PATHS.summaryFile,
+ 'utf-8'
+ )
+ .then(data => [data, null])
+ .catch(error => [null, error]);
+ if (summaryFileError) {
+ logging.error('Failed to read SUMMARY.md: %o', summaryFileError);
+ return 1;
+ }
+
+ // Get the start and end of the SUMMARY.md file
+ const [summarySections, summarySectionsError] =
+ sectionsGetStartAndEnd(summaryFile);
+ if (summarySectionsError) {
+ logging.error('Failed to find start and end sections in SUMMARY.md.');
+ return 1;
+ }
+ const [start, end] = summarySections;
+
+ // Write the new SUMMARY.md file
+ const newSummaryFileContent = [
+ summaryFile.slice(0, start),
+ SCRIPT_GENERATE_START,
+ generateLinks(gameData),
+ SCRIPT_GENERATE_END,
+ summaryFile.slice(end + SCRIPT_GENERATE_END.length)
+ ].join('');
+ /**
+ * @type {[string, null] | [null, Error]}
+ */
+ const [_1, writeError] = await writeFile(
+ CORE_PATHS.summaryFile,
+ newSummaryFileContent
+ )
+ .then(() => [null, null])
+ .catch(error => [null, error]);
+ if (writeError) {
+ logging.error('Failed to write SUMMARY.md: %o', writeError);
+ return 1;
+ }
+
+ logging.info('SUMMARY.md generated successfully.');
+
+ // Write the games.json file
+ const [_3, writeGamesError] = await writeFile(
+ CORE_PATHS.gamesJsonFile,
+ generateGamesJson(gameData)
+ )
+ .then(() => [null, null])
+ .catch(error => [null, error]);
+ if (writeGamesError) {
+ logging.error('Failed to write games.json: %o', writeGamesError);
+ return 1;
+ }
+ logging.info('games.json generated successfully.');
+
+ return 0;
+};
+
+// Check if this is the file that is being run
+if (process.argv[1] === new URL(import.meta.url).pathname)
+ main().then(code => process.exit(code));
diff --git a/scripts/lint.mjs b/scripts/lint.mjs
new file mode 100755
index 00000000..afccba41
--- /dev/null
+++ b/scripts/lint.mjs
@@ -0,0 +1,360 @@
+#!/usr/bin/env node
+
+/**
+ * @fileoverview Provides linting for the project.
+ */
+
+import { readFile } from 'node:fs/promises';
+
+import { logging } from './utils.mjs';
+import {
+ CORE_PATHS,
+ checkGameEmbed,
+ sectionsGetStartAndEnd,
+ getTitle,
+ getMarkdownFiles,
+ parseAliases,
+ parseReviewMetadata,
+ parseGameEmbeds,
+ SCRIPT_ALIASES_REGEX,
+ SCRIPT_GENERATE_START,
+ REVIEW_METADATA_REGEX
+} from './core.mjs';
+import { generateGameMetadata, generateLinks } from './generate.mjs';
+
+const isGithubAnotationsMode = process.env['GITHUB_ACTIONS'] === 'true';
+
+/**
+ * Remove path prefix to the root directory.
+ * @param {string} path The path to remove the root directory from.
+ * @returns {string}
+ */
+const removeRootDir = path => {
+ return path.replace(CORE_PATHS.rootDir + '/', '');
+};
+
+let hasBeenWarned = false;
+
+/**
+ * Logs a lint violation.
+ * @param {'warning' | 'error'} type The type of violation.
+ * @param {string | null} file The file path.
+ * @param {number | null} line The line number.
+ * @param {number | null} column The column number.
+ * @param {string} message The violation message.
+ */
+const logLintViolation = (type = 'error', file, line, column, message) => {
+ hasBeenWarned = true;
+ if (isGithubAnotationsMode) {
+ const args = [];
+ file !== null && args.push(`file=${removeRootDir(file)}`);
+ line !== null && args.push(`line=${line}`);
+ column !== null && args.push(`col=${column}`);
+ console.log('::%s %s::%s', type, args.join(','), message);
+ } else {
+ if (type === 'warning') {
+ logging.warning('[%s%s] %s', file, line ? `:${line}` : '', message);
+ } else {
+ logging.error('[%s%s] %s', file, line ? `:${line}` : '', message);
+ }
+ }
+};
+
+/**
+ * Check game embeds for linting issues.
+ * @param {GameEmbed}
+ */
+
+/**
+ * Checks a markdown file for linting issues.
+ * @param {string} file The file path.
+ */
+const lintMarkdownFile = async file => {
+ // Read the file
+ /**
+ * @type {[string, null] | [null, Error]}
+ */
+ const [content, error] = await readFile(file, 'utf-8')
+ .then(data => [data, null])
+ .catch(error => [null, error]);
+ if (error) {
+ logging.error('Failed to read file: %o', error);
+ return;
+ }
+ if (content.includes('\r\n')) {
+ logLintViolation(
+ 'warning',
+ file,
+ null,
+ null,
+ 'File contains CRLF line endings, should be LF.'
+ );
+ }
+
+ // Create an array of indexes for each line
+ const lineIndexes = [0];
+ for (let i = 0; i < content.length; i++) {
+ if (content[i] === '\n') {
+ lineIndexes.push(i + 1);
+ }
+ }
+
+ // Check the title
+ const [_0, titleError] = getTitle(content);
+ if (titleError) {
+ const error = {
+ 'not-found': 'Failed to find title in file.'
+ };
+ logLintViolation('error', file, 1, 1, error[titleError]);
+ }
+
+ /**
+ * Find the line and column number from the index.
+ * @param {number} index The index to find the line and column number for.
+ * @returns {[number, number]}
+ */
+ const findLineAndColumn = index => {
+ const line = lineIndexes.filter(i => i <= index).length;
+ const column = index - lineIndexes[line - 1];
+ return [line, column + 1];
+ };
+
+ // Check the line of the aliases (should be on second line)
+ let reviewMetadataExpectedLine = 3;
+ const aliasesMatch = SCRIPT_ALIASES_REGEX.exec(content);
+ if (aliasesMatch !== null) {
+ const [line, column] = findLineAndColumn(aliasesMatch.index);
+ if (column !== 1) {
+ logLintViolation(
+ 'warning',
+ file,
+ line,
+ column,
+ 'Aliases should be on the first column.'
+ );
+ }
+ if (line !== 2) {
+ logLintViolation(
+ 'warning',
+ file,
+ line,
+ column,
+ 'Aliases should be on the second line of the file.'
+ );
+ }
+
+ // Update the expected line for the review metadata to be two lines after the aliases
+ const [aliasesLine, _] = findLineAndColumn(
+ aliasesMatch.index + aliasesMatch[0].length
+ );
+
+ reviewMetadataExpectedLine = aliasesLine + 2;
+ }
+
+ // Check the aliases
+ const [_1, aliasesError] = parseAliases(content);
+ if (aliasesError) {
+ const error = {
+ 'not-found': 'Failed to find aliases in file.',
+ 'bad-json': 'Failed to parse aliases JSON in file.',
+ 'bad-json-format':
+ 'Aliases JSON in file is not an array of strings.'
+ };
+ logLintViolation(
+ aliasesError === 'not-found' ? 'warning' : 'error',
+ file,
+ 1,
+ 1,
+ error[aliasesError]
+ );
+ }
+
+ // Check the review metadata
+ const reviewMetadataMatch = REVIEW_METADATA_REGEX.exec(content);
+ if (reviewMetadataMatch.length > 0) {
+ const [line, column] = findLineAndColumn(reviewMetadataMatch.index);
+ if (column !== 1) {
+ logLintViolation(
+ 'warning',
+ file,
+ line,
+ column,
+ 'Review metadata should be on the first column.'
+ );
+ }
+ if (line !== reviewMetadataExpectedLine) {
+ logLintViolation(
+ 'warning',
+ file,
+ line,
+ column,
+ 'Review metadata should be on the line after the aliases (line ' +
+ reviewMetadataExpectedLine +
+ ').'
+ );
+ } else {
+ // Make sure the line before the review metadata is empty
+ const previousLineIndex = lineIndexes[line - 2];
+ if (
+ content
+ .slice(previousLineIndex, lineIndexes[line - 1])
+ .trim() !== ''
+ ) {
+ logLintViolation(
+ 'warning',
+ file,
+ line - 1,
+ 1,
+ 'Line before review metadata should be empty.'
+ );
+ }
+ }
+ }
+
+ // Check the review metadata
+ const [_2, reviewMetadataError] = parseReviewMetadata(content);
+ if (reviewMetadataError) {
+ const error = {
+ 'not-found':
+ 'Failed to find review metadata in file. (Might be because it is the wrong format.)'
+ };
+ logLintViolation('error', file, 1, 1, error[reviewMetadataError]);
+ }
+
+ // Game embeds should be on the last line
+ const [gameEmbedsMatch, gameEmbedsMatchError] = parseGameEmbeds(content);
+ if (gameEmbedsMatchError && gameEmbedsMatchError !== 'not-found') {
+ logLintViolation(
+ 'warning',
+ file,
+ null,
+ null,
+ 'Multiple game embeds found in file.'
+ );
+ } else if (gameEmbedsMatch !== null) {
+ const [embed, position] = gameEmbedsMatch;
+ const [line, column] = findLineAndColumn(position);
+ if (column !== 1) {
+ logLintViolation(
+ 'warning',
+ file,
+ line,
+ column,
+ 'Game embeds should be on the first column.'
+ );
+ }
+ if (line !== lineIndexes.length - 1) {
+ logLintViolation(
+ 'warning',
+ file,
+ line,
+ column,
+ 'Game embeds should be on the second last line of the file. (Line ' +
+ (lineIndexes.length - 1) +
+ ')'
+ );
+ }
+
+ // Check the game embeds is not invalid
+ const [isValid, gameEmbedsError] = await checkGameEmbed(embed);
+ if (!isValid) {
+ const error = {
+ 'invalid-embed': 'Invalid game embed found in file.',
+ 'web-request-failed': 'Failed to fetch game embed data.'
+ };
+ logLintViolation(
+ 'error',
+ file,
+ line,
+ column,
+ error[gameEmbedsError]
+ );
+ }
+ }
+
+ // There should be a trailing newline with no content
+ if (lineIndexes[lineIndexes.length - 1] !== content.length) {
+ logLintViolation(
+ 'warning',
+ file,
+ lineIndexes.length,
+ 1,
+ 'File should end with a newline.'
+ );
+ }
+};
+
+/**
+ * Main function.
+ * @returns {Promise}
+ */
+const main = async () => {
+ logging.info('Linting files...');
+
+ // First lint the SUMMARY.md file
+ /**
+ * @type {[string, null] | [null, Error]}
+ */
+ const [summaryFile, summaryFileError] = await readFile(
+ CORE_PATHS.summaryFile,
+ 'utf-8'
+ )
+ .then(data => [data, null])
+ .catch(error => [null, error]);
+ if (summaryFileError) {
+ logging.error('Failed to read SUMMARY.md: %o', summaryFileError);
+ return 1;
+ }
+
+ // Games metadata
+ const [gameData, gameDataError] = await generateGameMetadata();
+
+ // Check if the SUMMARY.md file contains the correct sections
+ const [summarySections, summarySectionsError] =
+ sectionsGetStartAndEnd(summaryFile);
+ if (summarySectionsError) {
+ const error = {
+ 'not-found': 'Failed to find start and end sections in SUMMARY.md.',
+ 'invalid-position':
+ 'End section comes before start section in SUMMARY.md.'
+ };
+ logLintViolation(
+ 'error',
+ CORE_PATHS.summaryFile,
+ null,
+ null,
+ error[summarySectionsError]
+ );
+ } else if (!gameDataError) {
+ const [start, end] = summarySections;
+ // Slice at these indexes to get the content between the sections
+ const contentBetweenSections = summaryFile.slice(
+ start + SCRIPT_GENERATE_START.length,
+ end
+ );
+ // Check if the content between the sections is up to date
+ const expectedContent = generateLinks(gameData);
+ if (contentBetweenSections !== expectedContent) {
+ logLintViolation(
+ 'error',
+ CORE_PATHS.summaryFile,
+ null,
+ null,
+ 'SUMMARY.md content is out of date.'
+ );
+ }
+ }
+
+ // Lint all markdown files in the game-support directory
+ const [markdownFiles, markdownFilesError] = await getMarkdownFiles();
+ if (markdownFilesError) {
+ return 1;
+ }
+
+ await Promise.all(markdownFiles.map(file => lintMarkdownFile(file)));
+
+ return hasBeenWarned ? 1 : 0;
+};
+
+if (process.argv[1] === new URL(import.meta.url).pathname)
+ main().then(code => process.exit(code));
diff --git a/scripts/utils.mjs b/scripts/utils.mjs
new file mode 100644
index 00000000..a3b1aa86
--- /dev/null
+++ b/scripts/utils.mjs
@@ -0,0 +1,159 @@
+/**
+ * @fileoverview Utility functions.
+ */
+import { format } from 'node:util';
+import { dirname } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { execSync } from 'node:child_process';
+
+/**
+ * Returns the directory of the current module. (utils.mjs)
+ * @returns {string}
+ */
+export const getDirName = () => {
+ return dirname(fileURLToPath(import.meta.url));
+};
+
+/**
+ * Escapes a string for use in Markdown.
+ * @type {Array<[RegExp, string]>}
+ */
+const markdownEscapeItems = [
+ [/\*/g, '\\*'], // Asterisks
+ [/#/g, '\\#'], // Hashes
+ [/\//g, '\\/'], // Slashes
+ [/\(/g, '\\('], // Open parentheses
+ [/\)/g, '\\)'], // Close parentheses
+ [/\[/g, '\\['], // Open square brackets
+ [/\]/g, '\\]'], // Close square brackets
+ [//g, '>'], // Close angle brackets
+ [/_/g, '\\_'], // Underscores
+ [/`/g, '\\`'] // Backticks
+];
+
+/**
+ * Escapes a string for use in Markdown.
+ * @param {string} str
+ */
+export const markdownEscape = str => {
+ for (const [regex, replacement] of markdownEscapeItems) {
+ str = str.replace(regex, replacement);
+ }
+ return str;
+};
+
+/**
+ * Fancy colors for console output.
+ * @type {Object<'debug' | 'info' | 'warning' | 'error | 'bold' | 'reset', string>}
+ */
+const colors = {
+ debug: '\x1b[2m',
+ info: '\x1b[36m',
+ warning: '\x1b[33m',
+ error: '\x1b[31m',
+ bold: '\x1b[1m',
+ reset: '\x1b[0m'
+};
+
+/**
+ * Logs a message to the console with fancy colors.
+ * @param {'debug' | 'info' | 'warning' | 'error'} type
+ * @param {string} message
+ * @param {...any} args
+ */
+export const fancyLog = (type, message, ...args) => {
+ console.log(
+ '%s%s[%s]%s%s %s%s',
+ colors.bold,
+ colors[type],
+ type.toUpperCase(),
+ colors.reset,
+ colors[type],
+ format(message, ...args),
+ colors.reset
+ );
+};
+
+const LOG_LEVELS = ['debug', 'info', 'warning', 'error', 'none'];
+
+/**
+ * Logging levels.
+ */
+const loggingLevel = LOG_LEVELS.includes(process.env['LOG'])
+ ? LOG_LEVELS.indexOf(process.env['LOG'])
+ : 1;
+
+/**
+ * Logging functions.
+ * @property {(message: string, ...args: any[]) => void} debug
+ * @property {(message: string, ...args: any[]) => void} info
+ * @property {(message: string, ...args: any[]) => void} warning
+ * @property {(message: string, ...args: any[]) => void} error
+ */
+export const logging = {
+ /**
+ * Logs an debug message.
+ * @param {string} message
+ * @param {...any} args
+ */
+ debug: (message, ...args) =>
+ loggingLevel <= 0 && fancyLog('debug', message, ...args),
+ /**
+ * Logs an info message.
+ * @param {string} message
+ * @param {...any} args
+ */
+ info: (message, ...args) =>
+ loggingLevel <= 1 && fancyLog('info', message, ...args),
+ /**
+ * Logs a warning message.
+ * @param {string} message
+ * @param {...any} args
+ */
+ warning: (message, ...args) =>
+ loggingLevel <= 2 && fancyLog('warning', message, ...args),
+ /**
+ * Logs an error message.
+ * @param {string} message
+ * @param {...any} args
+ */
+ error: (message, ...args) =>
+ loggingLevel <= 3 && fancyLog('error', message, ...args)
+};
+
+/**
+ * Remove duplicates from an array.
+ * @param {T[]} arr
+ * @returns {T[]}
+ */
+export const removeDuplicates = arr => {
+ return [...new Set(arr)];
+};
+
+/**
+ * Get last updated date from a file.
+ * MUST BE IN GIT SOURCE TREE
+ * @param {string} path
+ * @returns {[Date, null] | [null, 'git-error']}
+ */
+export const getLastUpdated = path => {
+ try {
+ const lastUpdated = new Date(
+ execSync(`git log -1 --format=%cd -- ${path}`).toString().trim()
+ );
+
+ if (isNaN(lastUpdated.getTime())) {
+ throw new Error('Invalid date');
+ }
+
+ return [lastUpdated, null];
+ } catch (error) {
+ logging.warning(
+ 'Failed to get last updated for file %s: %o',
+ path,
+ error
+ );
+ return [null, 'git-error'];
+ }
+};
diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index a5702227..a1ba4c87 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -8,93 +8,95 @@
- [Whisky x Heroic](./whisky-x-heroic.md)
- [Debugging](./debugging.md)
- [Game Support](./game-support/README.md)
- - [Among Us](./game-support/among-us.md)
- - [Armored Core VI: Fires of Rubicon](./game-support/armored-core-6.md)
- - [Assassin's Creed: Director's Cut Edition](./game-support/ac-directors-cut.md)
- - [Battle Brothers](./game-support/battle-brothers.md)
- - [Betrayer](./game-support/betrayer.md)
- - [Blasphemous 2](./game-support/blasphemous-2.md)
- - [Blitzkrieg 2 Anthology](./game-support/blitzkrieg-2-anthology.md)
- - [Buckshot Roulette](./game-support/buckshot-roulette.md)
- - [Call of Cthulhu](./game-support/call-of-cthulhu.md)
- - [Call of Juarez: Gunslinger](./game-support/coj-gunslinger.md)
- - [Cities: Skylines II](./game-support/cities-skylines-2.md)
- - [Content Warning](./game-support/content-warning.md)
- - [Contraband Police](./game-support/contraband-police.md)
- - [Control](./game-support/control.md)
- - [Counter-Strike 2](./game-support/counter-strike-2.md)
- - [Cyberpunk 2077](./game-support/cyberpunk-2077.md)
- - [Dagon: by H. P. Lovecraft](./game-support/dagon.md)
- - [Dark Souls III](./game-support/dark-souls-3.md)
- - [Dark Souls: Remastered](./game-support/dark-souls-remastered.md)
- - [Dead Space (2023)](./game-support/dead-space-2023.md)
- - [Deadlink](./game-support/deadlink.md)
- - [Deep Rock Galactic](./game-support/deep-rock-galactic.md)
- - [Diablo IV (Battle.net)](./game-support/diablo-4-battle-net.md)
- - [Diablo IV (Steam)](./game-support/diablo-4-steam.md)
- - [Dishonored](./game-support/dishonored.md)
- - [Dishonored 2](./game-support/dishonored-2.md)
- - [Dorfromantik](./game-support/dorfromantik.md)
- - [Dying Light 2](./game-support/dying-light-2.md)
- - [Elden Ring](./game-support/elden-ring.md)
- - [Elite Dangerous](./game-support/elite-dangerous.md)
- - [F1 Manager 2023](./game-support/f1m23.md)
- - [Fallout 3: Game of the Year Edition](./game-support/fallout-3-goty.md)
- - [Fallout 4](./game-support/fallout-4.md)
- - [Fear and Hunger](./game-support/fear-and-hunger.md)
- - [FlatOut](./game-support/flatout.md)
- - [Forgive Me Father 2](./game-support/forgive-me-father-2.md)
- - [Fortnite](./game-support/fortnite.md)
- - [Friends vs Friends](./game-support/friends-vs-friends.md)
- - [Geometry Wars 3: Dimensions Evolved](./game-support/gw3-dimensions-evolved.md)
- - [Guild Wars 2](./game-support/gw2.md)
- - [Grand Theft Auto V](./game-support/gta-5.md)
- - [Half-Life 1](./game-support/half-life-1.md)
- - [Half-Life 2](./game-support/half-life-2.md)
- - [Hearts of Iron III](./game-support/hoi-3.md)
- - [Hellblade: Senua's Sacrifice](./game-support/hellblade.md)
- - [Hitman: Contracts](./game-support/hitman-3-c.md)
- - [Horizon Zero Dawn](./game-support/horizon-zero-dawn.md)
- - [JoJo's Bizarre Adventure: All Star Battle R](./game-support/jjba-asbr.md)
- - [Kenshi](./game-support/kenshi.md)
- - [Kingdom Come: Deliverance](./game-support/kcd.md)
- - [Kingsway](./game-support/kingsway.md)
- - [LEGO Star Wars III - The Clone Wars](./game-support/lego-sw-iii-clone-wars.md)
- - [LEGO Star Wars: The Skywalker Saga](./game-support/lego-sw-skywalker-saga.md)
- - [Lethal Company](./game-support/lethal-company.md)
- - [Manor Lords](./game-support/manor-lords.md)
- - [Metal Gear Solid V: The Phantom Pain](./game-support/mgs-5.md)
- - [Metro 2033 Redux](./game-support/metro-2033-rx.md)
- - [Metro: Last Light Redux](./game-support/metro-ll-rx.md)
- - [Monster Hunter World: Iceborne](./game-support/monster-hunter-world-iceborne.md)
- - [Mount & Blade: With Fire & Sword](./game-support/mb-wfas.md)
- - [Neon White](./game-support/neon-white.md)
- - [Overwatch 2](./game-support/overwatch-2.md)
- - [Persona 3 Reload](./game-support/p3r.md)
- - [Persona 4 Golden](./game-support/p4g.md)
- - [Palworld](./game-support/palworld.md)
- - [People Playground](./game-support/people-playground.md)
- - [Phasmophobia](./game-support/phasmophobia.md)
- - [Prey (2017)](./game-support/prey-2017.md)
- - [Ruiner](./game-support/ruiner.md)
- - [Quake II](./game-support/quake2.md)
- - [r2modman](./game-support/r2modman.md)
- - [Rain World](./game-support/rain-world.md)
- - [Risk of Rain 2](./game-support/risk-of-rain-2.md)
- - [Risk of Rain Returns](./game-support/risk-of-rain-returns.md)
- - [Satisfactory](./game-support/satisfactory.md)
- - [Sekiro: Shadows Die Twice](./game-support/sekiro.md)
- - [Skyrim SE](./game-support/skyrim-se.md)
- - [Stardew Valley](./game-support/stardew-valley.md)
- - [Star Wars Jedi: Fallen Order](./game-support/sw-fallen-order.md)
- - [Star Wars: Squadrons](./game-support/sw-squadrons.md)
- - [Stronghold Crusader HD](./game-support/stronghold-crusader-hd.md)
- - [Tom Clancy's Rainbow Six Siege](./game-support/tcr6s.md)
- - [The Stanley Parable: Ultra Deluxe](./game-support/tsp-ud.md)
- - [The Vanishing of Ethan Carter](./game-support/vanishing-of-ethan-carter.md)
- - [The Witcher 3: Wild Hunt](./game-support/witcher3.md)
- - [The Wolf Among Us](./game-support/wolf-among-us.md)
- - [Turbo Overkill](./game-support/turbo-overkill.md)
- - [Ultrakill](./game-support/ultrakill.md)
- - [Undertale](./game-support/undertale.md)
- - [Warframe](./game-support/warframe.md)
+
+ - [Assassin's Creed: Director's Cut Edition](/game-support/ac-directors-cut.md)
+ - [Among Us](/game-support/among-us.md)
+ - [Armored Core VI: Fires of Rubicon](/game-support/armored-core-6.md)
+ - [Battle Brothers](/game-support/battle-brothers.md)
+ - [Betrayer](/game-support/betrayer.md)
+ - [Blasphemous 2](/game-support/blasphemous-2.md)
+ - [Blitzkrieg 2 Anthology](/game-support/blitzkrieg-2-anthology.md)
+ - [Buckshot Roulette](/game-support/buckshot-roulette.md)
+ - [Call of Cthulhu](/game-support/call-of-cthulhu.md)
+ - [Cities: Skylines 2](/game-support/cities-skylines-2.md)
+ - [Call of Juarez: Gunslinger](/game-support/coj-gunslinger.md)
+ - [Content Warning](/game-support/content-warning.md)
+ - [Contraband Police](/game-support/contraband-police.md)
+ - [Control](/game-support/control.md)
+ - [Counter-Strike 2](/game-support/counter-strike-2.md)
+ - [Cyberpunk 2077](/game-support/cyberpunk-2077.md)
+ - [Dagon: by H. P. Lovecraft](/game-support/dagon.md)
+ - [Dark Souls III](/game-support/dark-souls-3.md)
+ - [Dark Souls: Remastered](/game-support/dark-souls-remastered.md)
+ - [Dead Space \(2023\)](/game-support/dead-space-2023.md)
+ - [Deadlink](/game-support/deadlink.md)
+ - [Deep Rock Galactic](/game-support/deep-rock-galactic.md)
+ - [Diablo IV \(Battle.net\)](/game-support/diablo-4-battle-net.md)
+ - [Diablo IV \(Steam\)](/game-support/diablo-4-steam.md)
+ - [Dishonored 2](/game-support/dishonored-2.md)
+ - [Dishonored](/game-support/dishonored.md)
+ - [Dorfromantik](/game-support/dorfromantik.md)
+ - [Dying Light 2](/game-support/dying-light-2.md)
+ - [Elden Ring](/game-support/elden-ring.md)
+ - [Elite Dangerous](/game-support/elite-dangerous.md)
+ - [F1 Manager 2023](/game-support/f1m23.md)
+ - [Fallout 3: Game of the Year Edition](/game-support/fallout-3-goty.md)
+ - [Fallout 4](/game-support/fallout-4.md)
+ - [Fear and Hunger](/game-support/fear-and-hunger.md)
+ - [FlatOut](/game-support/flatout.md)
+ - [Forgive Me Father 2](/game-support/forgive-me-father-2.md)
+ - [Fortnite](/game-support/fortnite.md)
+ - [Friends vs Friends](/game-support/friends-vs-friends.md)
+ - [Grand Theft Auto V](/game-support/gta-5.md)
+ - [Guild Wars 2](/game-support/gw2.md)
+ - [Geometry Wars 3: Dimensions Evolved](/game-support/gw3-dimensions-evolved.md)
+ - [Half-Life 1](/game-support/half-life-1.md)
+ - [Half-Life 2](/game-support/half-life-2.md)
+ - [Hellblade: Senua's Sacrifice](/game-support/hellblade.md)
+ - [Hitman: Contracts](/game-support/hitman-3-c.md)
+ - [Hearts of Iron III](/game-support/hoi-3.md)
+ - [Horizon Zero Dawn](/game-support/horizon-zero-dawn.md)
+ - [JoJo's Bizarre Adventure: All-Star Battle R](/game-support/jjba-asbr.md)
+ - [Kingdom Come: Deliverance](/game-support/kcd.md)
+ - [Kenshi](/game-support/kenshi.md)
+ - [Kingsway](/game-support/kingsway.md)
+ - [LEGO Star Wars III: The Clone Wars](/game-support/lego-sw-iii-clone-wars.md)
+ - [LEGO Star Wars: The Skywalker Saga](/game-support/lego-sw-skywalker-saga.md)
+ - [Lethal Company](/game-support/lethal-company.md)
+ - [Manor Lords](/game-support/manor-lords.md)
+ - [Mount & Blade: With Fire & Sword](/game-support/mb-wfas.md)
+ - [Metro 2033 Redux](/game-support/metro-2033-rx.md)
+ - [Metro: Last Light Redux](/game-support/metro-ll-rx.md)
+ - [Metal Gear Solid V: The Phantom Pain](/game-support/mgs-5.md)
+ - [Monster Hunter World: Iceborne](/game-support/monster-hunter-world-iceborne.md)
+ - [Neon White](/game-support/neon-white.md)
+ - [Overwatch 2](/game-support/overwatch-2.md)
+ - [Persona 3 Reload](/game-support/p3r.md)
+ - [Persona 4 Golden](/game-support/p4g.md)
+ - [Palworld](/game-support/palworld.md)
+ - [People Playground](/game-support/people-playground.md)
+ - [Phasmophobia](/game-support/phasmophobia.md)
+ - [Prey \(2017\)](/game-support/prey-2017.md)
+ - [Quake II](/game-support/quake2.md)
+ - [r2modman](/game-support/r2modman.md)
+ - [Rain World](/game-support/rain-world.md)
+ - [Risk of Rain 2](/game-support/risk-of-rain-2.md)
+ - [Risk of Rain Returns](/game-support/risk-of-rain-returns.md)
+ - [Ruiner](/game-support/ruiner.md)
+ - [Satisfactory](/game-support/satisfactory.md)
+ - [Sekiro: Shadows Die Twice](/game-support/sekiro.md)
+ - [Skyrim SE](/game-support/skyrim-se.md)
+ - [Stardew Valley](/game-support/stardew-valley.md)
+ - [Stronghold Crusader HD](/game-support/stronghold-crusader-hd.md)
+ - [Star Wars Jedi: Fallen Order](/game-support/sw-fallen-order.md)
+ - [Star Wars: Squadrons](/game-support/sw-squadrons.md)
+ - [Tom Clancy's Rainbow Six Siege \(Steam\)](/game-support/tcr6s.md)
+ - [The Stanley Parable: Ultra Deluxe](/game-support/tsp-ud.md)
+ - [Turbo Overkill](/game-support/turbo-overkill.md)
+ - [Ultrakill](/game-support/ultrakill.md)
+ - [Undertale](/game-support/undertale.md)
+ - [The Vanishing of Ethan Carter](/game-support/vanishing-of-ethan-carter.md)
+ - [Warframe](/game-support/warframe.md)
+ - [The Witcher 3: Wild Hunt](/game-support/witcher3.md)
+ - [The Wolf Among Us](/game-support/wolf-among-us.md)
+
\ No newline at end of file
diff --git a/src/game-support/README.md b/src/game-support/README.md
index 319ffbae..26a4591c 100644
--- a/src/game-support/README.md
+++ b/src/game-support/README.md
@@ -10,9 +10,12 @@ be sure to contribute to these docs on GitHub.
Game support status is rated on a scale. The placement of a particular
title is partially left to the article author, but some general guidelines apply.
-| Status | Description |
-| ------- | ---------------------------------------------------------------------------------------------- |
-| Gold | Game works out-of-the-box with no issues and/or requires minimal workarounds. |
-| Silver | Game requires some workarounds, but they are simple and/or there are minor in-game issues |
-| Bronze | Game is very difficult to get working and/or has severe in-game issues that limit playability. |
-| Garbage | Game does not work at all. |
\ No newline at end of file
+| Status | Description |
+| -------- | ---------------------------------------------------------------------------------------------- |
+| Platinum | Game without any defects and runs perfectly. |
+| Gold | Game can be configured to run perfectly and without any defects. |
+| Silver | Game requires some configuration to run and or has minor defects. |
+| Bronze | Game is very difficult to get working and/or has severe in-game issues that limit playability. |
+| Garbage | Game does not work at all. |
+
+
diff --git a/src/game-support/ac-directors-cut.md b/src/game-support/ac-directors-cut.md
index ba2fb1b2..5b0fcd38 100644
--- a/src/game-support/ac-directors-cut.md
+++ b/src/game-support/ac-directors-cut.md
@@ -1,4 +1,7 @@
# Assassin's Creed: Director's Cut Edition
+
{{#template ../templates/rating.md status=Bronze installs=Yes opens=Yes}}
@@ -6,4 +9,4 @@
> The game suffers from a severe heartbeat-like sound stuttering. Also it's performance is quite poor.
> DX10 version does not render part of the player and NPCs. DX9 version renders fine.
-{{#template ../templates/steam.md id=15100}}
\ No newline at end of file
+{{#template ../templates/steam.md id=15100}}
diff --git a/src/game-support/among-us.md b/src/game-support/among-us.md
index 23cbb7bf..f1428694 100644
--- a/src/game-support/among-us.md
+++ b/src/game-support/among-us.md
@@ -1,8 +1,9 @@
# Among Us
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
> [!NOTE]
> This game has an iPad Mac port through the App Store.
-{{#template ../templates/steam.md id=945360}}
\ No newline at end of file
+{{#template ../templates/steam.md id=945360}}
diff --git a/src/game-support/armored-core-6.md b/src/game-support/armored-core-6.md
index 428a25f1..f80c7d9e 100644
--- a/src/game-support/armored-core-6.md
+++ b/src/game-support/armored-core-6.md
@@ -1,8 +1,13 @@
# Armored Core VI: Fires of Rubicon
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
## Setup
- Disable DXVK
-{{#template ../templates/steam.md id=1888160}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1888160}}
diff --git a/src/game-support/battle-brothers.md b/src/game-support/battle-brothers.md
index 6d74a49e..7ff52482 100644
--- a/src/game-support/battle-brothers.md
+++ b/src/game-support/battle-brothers.md
@@ -1,4 +1,5 @@
# Battle Brothers
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=No}}
diff --git a/src/game-support/betrayer.md b/src/game-support/betrayer.md
index 09fbc28f..f584244e 100644
--- a/src/game-support/betrayer.md
+++ b/src/game-support/betrayer.md
@@ -1,4 +1,5 @@
# Betrayer
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -8,4 +9,4 @@
> [!WARNING]
> Audio is glitchy - sounds like a mix of original audio quality with 8-bit version of it.
-{{#template ../templates/steam.md id=243120}}
\ No newline at end of file
+{{#template ../templates/steam.md id=243120}}
diff --git a/src/game-support/blasphemous-2.md b/src/game-support/blasphemous-2.md
index c563b1bc..ae875752 100644
--- a/src/game-support/blasphemous-2.md
+++ b/src/game-support/blasphemous-2.md
@@ -1,5 +1,6 @@
# Blasphemous 2
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=2114740}}
\ No newline at end of file
+{{#template ../templates/steam.md id=2114740}}
diff --git a/src/game-support/blitzkrieg-2-anthology.md b/src/game-support/blitzkrieg-2-anthology.md
index c6a24ef2..15da9056 100644
--- a/src/game-support/blitzkrieg-2-anthology.md
+++ b/src/game-support/blitzkrieg-2-anthology.md
@@ -1,4 +1,5 @@
# Blitzkrieg 2 Anthology
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
@@ -7,4 +8,4 @@
> Audio stutters during intro movies.
> There may be issue with exiting. Sometimes it is helpful to use the Activity Monitor and Force Quit if in-game button won't help.
-{{#template ../templates/steam.md id=313500}}
\ No newline at end of file
+{{#template ../templates/steam.md id=313500}}
diff --git a/src/game-support/buckshot-roulette.md b/src/game-support/buckshot-roulette.md
index b10f7876..b0e0a426 100644
--- a/src/game-support/buckshot-roulette.md
+++ b/src/game-support/buckshot-roulette.md
@@ -1,7 +1,8 @@
# Buckshot Roulette
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
Minor graphical issues with particle effects, but the game is playable.
-{{#template ../templates/steam.md id=2835570}}
\ No newline at end of file
+{{#template ../templates/steam.md id=2835570}}
diff --git a/src/game-support/call-of-cthulhu.md b/src/game-support/call-of-cthulhu.md
index a2daef85..aa7ec913 100644
--- a/src/game-support/call-of-cthulhu.md
+++ b/src/game-support/call-of-cthulhu.md
@@ -1,8 +1,9 @@
# Call of Cthulhu
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
> [!NOTE]
> Runs great. However when moving mouse intensively a native cursor appears on screen all the time and also hovers the in-game one
-{{#template ../templates/steam.md id=399810}}
\ No newline at end of file
+{{#template ../templates/steam.md id=399810}}
diff --git a/src/game-support/cities-skylines-2.md b/src/game-support/cities-skylines-2.md
index 290c7e26..1ef3dd07 100644
--- a/src/game-support/cities-skylines-2.md
+++ b/src/game-support/cities-skylines-2.md
@@ -1,4 +1,7 @@
# Cities: Skylines 2
+
{{#template ../templates/rating.md status=Bronze installs=Yes opens=Yes}}
@@ -20,4 +23,4 @@
> - Tabbing out will cause the game to become unresponsive and require it to be restarted. Do **not** change window focus while playing.
> - Subsequent launches may fail to open the Paradox Launcher. This can be resolved temporarily by deleting the `Paradox Interactive` folder in `Program Files`. Reinstalling the launcher may also be required.
-{{#template ../templates/steam.md id=949230}}
\ No newline at end of file
+{{#template ../templates/steam.md id=949230}}
diff --git a/src/game-support/coj-gunslinger.md b/src/game-support/coj-gunslinger.md
index 72f0bcad..b645be98 100644
--- a/src/game-support/coj-gunslinger.md
+++ b/src/game-support/coj-gunslinger.md
@@ -1,5 +1,6 @@
# Call of Juarez: Gunslinger
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=No}}
-{{#template ../templates/steam.md id=204450}}
\ No newline at end of file
+{{#template ../templates/steam.md id=204450}}
diff --git a/src/game-support/content-warning.md b/src/game-support/content-warning.md
index de09a3d5..2aa6bbc3 100644
--- a/src/game-support/content-warning.md
+++ b/src/game-support/content-warning.md
@@ -1,4 +1,5 @@
# Content Warning
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -8,4 +9,4 @@
> [!WARNING]
> If you press "Paste" in the face editor the game experiences a fatal error and crashes
-{{#template ../templates/steam.md id=2881650}}
\ No newline at end of file
+{{#template ../templates/steam.md id=2881650}}
diff --git a/src/game-support/contraband-police.md b/src/game-support/contraband-police.md
index 1bf6f35a..75290abd 100644
--- a/src/game-support/contraband-police.md
+++ b/src/game-support/contraband-police.md
@@ -1,5 +1,6 @@
# Contraband Police
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=756800}}
\ No newline at end of file
+{{#template ../templates/steam.md id=756800}}
diff --git a/src/game-support/control.md b/src/game-support/control.md
index 007062b3..f6b5b148 100644
--- a/src/game-support/control.md
+++ b/src/game-support/control.md
@@ -1,5 +1,6 @@
# Control
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=870780}}
\ No newline at end of file
+{{#template ../templates/steam.md id=870780}}
diff --git a/src/game-support/counter-strike-2.md b/src/game-support/counter-strike-2.md
index 6705a122..2e7f4c4a 100644
--- a/src/game-support/counter-strike-2.md
+++ b/src/game-support/counter-strike-2.md
@@ -1,4 +1,8 @@
# Counter-Strike 2
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -13,4 +17,4 @@
- Start CS2 from Steam as normal
-{{#template ../templates/steam.md id=730}}
\ No newline at end of file
+{{#template ../templates/steam.md id=730}}
diff --git a/src/game-support/cyberpunk-2077.md b/src/game-support/cyberpunk-2077.md
index 29f00aea..3521a9d3 100644
--- a/src/game-support/cyberpunk-2077.md
+++ b/src/game-support/cyberpunk-2077.md
@@ -1,5 +1,6 @@
# Cyberpunk 2077
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1091500}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1091500}}
diff --git a/src/game-support/dagon.md b/src/game-support/dagon.md
index 3eeb3b02..ddff9a73 100644
--- a/src/game-support/dagon.md
+++ b/src/game-support/dagon.md
@@ -1,5 +1,8 @@
# Dagon: by H. P. Lovecraft
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1481400}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1481400}}
diff --git a/src/game-support/dark-souls-3.md b/src/game-support/dark-souls-3.md
index 832e4d9b..444cc63a 100644
--- a/src/game-support/dark-souls-3.md
+++ b/src/game-support/dark-souls-3.md
@@ -1,5 +1,8 @@
# Dark Souls III
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=374320}}
\ No newline at end of file
+{{#template ../templates/steam.md id=374320}}
diff --git a/src/game-support/dark-souls-remastered.md b/src/game-support/dark-souls-remastered.md
index e518c959..a29d8592 100644
--- a/src/game-support/dark-souls-remastered.md
+++ b/src/game-support/dark-souls-remastered.md
@@ -1,4 +1,7 @@
# Dark Souls: Remastered
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
diff --git a/src/game-support/dead-space-2023.md b/src/game-support/dead-space-2023.md
index 394ae3b1..3796e98d 100644
--- a/src/game-support/dead-space-2023.md
+++ b/src/game-support/dead-space-2023.md
@@ -1,5 +1,9 @@
# Dead Space (2023)
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1693980}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1693980}}
diff --git a/src/game-support/deadlink.md b/src/game-support/deadlink.md
index 15795f1b..fa33de54 100644
--- a/src/game-support/deadlink.md
+++ b/src/game-support/deadlink.md
@@ -1,7 +1,8 @@
# Deadlink
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
Viewing an effect for the first time will cause the game to hang for a second. After a few minutes of gameplay stutters stop and the game runs perfectly.
-{{#template ../templates/steam.md id=1676130}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1676130}}
diff --git a/src/game-support/deep-rock-galactic.md b/src/game-support/deep-rock-galactic.md
index f144caf9..7b91febd 100644
--- a/src/game-support/deep-rock-galactic.md
+++ b/src/game-support/deep-rock-galactic.md
@@ -1,7 +1,8 @@
# Deep Rock Galactic
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
When using a controller, both analog sticks look and move at the same time. The UI takes double clicks to interact. I was not able to find any servers or join any games. Solo missions work perfectly. The game runs well in DX12 mode.
-{{#template ../templates/steam.md id=548430}}
\ No newline at end of file
+{{#template ../templates/steam.md id=548430}}
diff --git a/src/game-support/diablo-4-battle-net.md b/src/game-support/diablo-4-battle-net.md
index 4443bb90..44ec25c9 100644
--- a/src/game-support/diablo-4-battle-net.md
+++ b/src/game-support/diablo-4-battle-net.md
@@ -1,4 +1,8 @@
-# Diablo IV - Battle.net Version
+# Diablo IV (Battle.net)
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=No}}
@@ -15,4 +19,4 @@
- Login and install Diablo IV as normal
-->
-Diablo IV is currently **unplayable** in Whisky.
\ No newline at end of file
+Diablo IV is currently **unplayable** in Whisky.
diff --git a/src/game-support/diablo-4-steam.md b/src/game-support/diablo-4-steam.md
index 2c93a3ad..e0fe10d6 100644
--- a/src/game-support/diablo-4-steam.md
+++ b/src/game-support/diablo-4-steam.md
@@ -1,4 +1,10 @@
-# Diablo IV - Steam Version
+# Diablo IV (Steam)
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=No}}
@@ -15,4 +21,4 @@
Diablo IV is currently **unplayable** in Whisky.
-{{#template ../templates/steam.md id=2344520}}
\ No newline at end of file
+{{#template ../templates/steam.md id=2344520}}
diff --git a/src/game-support/dishonored-2.md b/src/game-support/dishonored-2.md
index 4a8fe73a..92bdb8c1 100644
--- a/src/game-support/dishonored-2.md
+++ b/src/game-support/dishonored-2.md
@@ -1,4 +1,5 @@
# Dishonored 2
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -8,4 +9,4 @@
> [!NOTE]
> Set "world detail" to low for a smoother experience.
-{{#template ../templates/steam.md id=403640}}
\ No newline at end of file
+{{#template ../templates/steam.md id=403640}}
diff --git a/src/game-support/dishonored.md b/src/game-support/dishonored.md
index d1e4a317..d612dd0d 100644
--- a/src/game-support/dishonored.md
+++ b/src/game-support/dishonored.md
@@ -1,7 +1,8 @@
# Dishonored
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
The game runs with constant stutters.
-{{#template ../templates/steam.md id=205100}}
\ No newline at end of file
+{{#template ../templates/steam.md id=205100}}
diff --git a/src/game-support/dorfromantik.md b/src/game-support/dorfromantik.md
index 1a4e5370..e78273f6 100644
--- a/src/game-support/dorfromantik.md
+++ b/src/game-support/dorfromantik.md
@@ -1,5 +1,6 @@
# Dorfromantik
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1455840}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1455840}}
diff --git a/src/game-support/dying-light-2.md b/src/game-support/dying-light-2.md
index 8060ce1f..91c6eb81 100644
--- a/src/game-support/dying-light-2.md
+++ b/src/game-support/dying-light-2.md
@@ -1,4 +1,5 @@
# Dying Light 2
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -24,4 +25,4 @@
> You can use the above solution to change your texture settings to low (which you are unable to do in the in-game settings menu).
> Set `TextureQuality(...)` to `TextureQuality("Low")`.
-{{#template ../templates/steam.md id=534380}}
\ No newline at end of file
+{{#template ../templates/steam.md id=534380}}
diff --git a/src/game-support/elden-ring.md b/src/game-support/elden-ring.md
index c71bf874..27e1ab99 100644
--- a/src/game-support/elden-ring.md
+++ b/src/game-support/elden-ring.md
@@ -1,4 +1,5 @@
# Elden Ring
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -13,4 +14,4 @@
- Start Elden Ring from Steam as normal
-{{#template ../templates/steam.md id=1245620}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1245620}}
diff --git a/src/game-support/elite-dangerous.md b/src/game-support/elite-dangerous.md
index ae6f32c2..c2b2185b 100644
--- a/src/game-support/elite-dangerous.md
+++ b/src/game-support/elite-dangerous.md
@@ -1,4 +1,5 @@
# Elite Dangerous
+
{{#template ../templates/rating.md status=Bronze installs=Yes opens=Yes}}
diff --git a/src/game-support/f1m23.md b/src/game-support/f1m23.md
index b48e8b4d..33b067c1 100644
--- a/src/game-support/f1m23.md
+++ b/src/game-support/f1m23.md
@@ -1,4 +1,5 @@
# F1 Manager 2023
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
diff --git a/src/game-support/fallout-3-goty.md b/src/game-support/fallout-3-goty.md
index 152b7359..a34041b7 100644
--- a/src/game-support/fallout-3-goty.md
+++ b/src/game-support/fallout-3-goty.md
@@ -1,4 +1,7 @@
# Fallout 3: Game of the Year Edition
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=Yes}}
diff --git a/src/game-support/fallout-4.md b/src/game-support/fallout-4.md
index d78cbc21..b16ae141 100644
--- a/src/game-support/fallout-4.md
+++ b/src/game-support/fallout-4.md
@@ -1,4 +1,5 @@
# Fallout 4
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
diff --git a/src/game-support/fear-and-hunger.md b/src/game-support/fear-and-hunger.md
index d994f287..cdc9bd5a 100644
--- a/src/game-support/fear-and-hunger.md
+++ b/src/game-support/fear-and-hunger.md
@@ -1,4 +1,5 @@
# Fear and Hunger
+
{{#template ../templates/rating.md status=Bronze installs=Yes opens=Yes}}
@@ -14,4 +15,4 @@
> The game is terribly optimized and runs very poorly without community-made fixes, which have not yet been compatible with macOS and Whisky.
> You can find those fixes [here](https://www.pcgamingwiki.com/wiki/Fear_%26_Hunger#Essential_Improvements), however at the current time they **do not work** on macOS and will prevent your game from running.
-{{#template ../templates/steam.md id=1002300}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1002300}}
diff --git a/src/game-support/flatout.md b/src/game-support/flatout.md
index eba3757d..7c5416a7 100644
--- a/src/game-support/flatout.md
+++ b/src/game-support/flatout.md
@@ -1,5 +1,6 @@
# FlatOut
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=6220}}
\ No newline at end of file
+{{#template ../templates/steam.md id=6220}}
diff --git a/src/game-support/forgive-me-father-2.md b/src/game-support/forgive-me-father-2.md
index 5e6517b0..cc93c197 100644
--- a/src/game-support/forgive-me-father-2.md
+++ b/src/game-support/forgive-me-father-2.md
@@ -1,7 +1,8 @@
# Forgive Me Father 2
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
The game complains about you not having the right driver; this prompt can be completely ignored.
-{{#template ../templates/steam.md id=2272250}}
\ No newline at end of file
+{{#template ../templates/steam.md id=2272250}}
diff --git a/src/game-support/fortnite.md b/src/game-support/fortnite.md
index 124f2d39..525e8c73 100644
--- a/src/game-support/fortnite.md
+++ b/src/game-support/fortnite.md
@@ -1 +1,6 @@
-# No.
\ No newline at end of file
+# Fortnite
+
+
+{{#template ../templates/rating.md status=Garbage installs=No opens=No}}
+
+No.
diff --git a/src/game-support/friends-vs-friends.md b/src/game-support/friends-vs-friends.md
index be89f190..4be2ce6b 100644
--- a/src/game-support/friends-vs-friends.md
+++ b/src/game-support/friends-vs-friends.md
@@ -1,5 +1,6 @@
# Friends vs Friends
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1785150}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1785150}}
diff --git a/src/game-support/gta-5.md b/src/game-support/gta-5.md
index 4e9043f4..46fb7bbd 100644
--- a/src/game-support/gta-5.md
+++ b/src/game-support/gta-5.md
@@ -1,7 +1,12 @@
# Grand Theft Auto V
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
Works with DXVK.
-{{#template ../templates/steam.md id=271590}}
\ No newline at end of file
+{{#template ../templates/steam.md id=271590}}
diff --git a/src/game-support/gw2.md b/src/game-support/gw2.md
index 68ac11f4..5c8126df 100644
--- a/src/game-support/gw2.md
+++ b/src/game-support/gw2.md
@@ -1,4 +1,5 @@
# Guild Wars 2
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
@@ -13,4 +14,4 @@
- Download in Steam as normal
-{{#template ../templates/steam.md id=1284210}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1284210}}
diff --git a/src/game-support/gw3-dimensions-evolved.md b/src/game-support/gw3-dimensions-evolved.md
index 1681818b..ceadf0bf 100644
--- a/src/game-support/gw3-dimensions-evolved.md
+++ b/src/game-support/gw3-dimensions-evolved.md
@@ -1,5 +1,8 @@
# Geometry Wars 3: Dimensions Evolved
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=310790}}
\ No newline at end of file
+{{#template ../templates/steam.md id=310790}}
diff --git a/src/game-support/half-life-1.md b/src/game-support/half-life-1.md
index 97f97b01..ba5f8ebe 100644
--- a/src/game-support/half-life-1.md
+++ b/src/game-support/half-life-1.md
@@ -1,4 +1,9 @@
# Half-Life 1
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=No}}
diff --git a/src/game-support/half-life-2.md b/src/game-support/half-life-2.md
index 11f79b25..866034e5 100644
--- a/src/game-support/half-life-2.md
+++ b/src/game-support/half-life-2.md
@@ -1,4 +1,7 @@
# Half-Life 2
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
diff --git a/src/game-support/hellblade.md b/src/game-support/hellblade.md
index 26444176..60dd800f 100644
--- a/src/game-support/hellblade.md
+++ b/src/game-support/hellblade.md
@@ -1,5 +1,8 @@
# Hellblade: Senua's Sacrifice
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=414340}}
\ No newline at end of file
+{{#template ../templates/steam.md id=414340}}
diff --git a/src/game-support/hitman-3-c.md b/src/game-support/hitman-3-c.md
index 410fb8b4..4f567ec1 100644
--- a/src/game-support/hitman-3-c.md
+++ b/src/game-support/hitman-3-c.md
@@ -1,8 +1,13 @@
# Hitman: Contracts
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
> [!WARNING]
> Sound is stuttering and it is barely audible. Very quiet samples of the game's audio output are played in a heartbeat rhythm.
-{{#template ../templates/steam.md id=247430}}
\ No newline at end of file
+{{#template ../templates/steam.md id=247430}}
diff --git a/src/game-support/hoi-3.md b/src/game-support/hoi-3.md
index 709b6abc..4fd60392 100644
--- a/src/game-support/hoi-3.md
+++ b/src/game-support/hoi-3.md
@@ -1,4 +1,5 @@
# Hearts of Iron III
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -8,4 +9,4 @@
> [!WARNING]
> Music does not play in the game.
-{{#template ../templates/steam.md id=25890}}
\ No newline at end of file
+{{#template ../templates/steam.md id=25890}}
diff --git a/src/game-support/horizon-zero-dawn.md b/src/game-support/horizon-zero-dawn.md
index d92ab354..1aac1ea5 100644
--- a/src/game-support/horizon-zero-dawn.md
+++ b/src/game-support/horizon-zero-dawn.md
@@ -1,4 +1,5 @@
# Horizon Zero Dawn
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
diff --git a/src/game-support/jjba-asbr.md b/src/game-support/jjba-asbr.md
index a0aa2a9b..4d0000a5 100644
--- a/src/game-support/jjba-asbr.md
+++ b/src/game-support/jjba-asbr.md
@@ -1,5 +1,13 @@
-# JoJo's Bizarre Adventure: All Star Battle R
+# JoJo's Bizarre Adventure: All-Star Battle R
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1372110}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1372110}}
diff --git a/src/game-support/kcd.md b/src/game-support/kcd.md
index 6bbdb06f..8f93b419 100644
--- a/src/game-support/kcd.md
+++ b/src/game-support/kcd.md
@@ -1,4 +1,8 @@
# Kingdom Come: Deliverance
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
diff --git a/src/game-support/kenshi.md b/src/game-support/kenshi.md
index 6f8923d4..cfcb3dea 100644
--- a/src/game-support/kenshi.md
+++ b/src/game-support/kenshi.md
@@ -1,4 +1,5 @@
# Kenshi
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
diff --git a/src/game-support/kingsway.md b/src/game-support/kingsway.md
index 5c29edd1..17c958a1 100644
--- a/src/game-support/kingsway.md
+++ b/src/game-support/kingsway.md
@@ -1,5 +1,6 @@
# Kingsway
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=588950}}
\ No newline at end of file
+{{#template ../templates/steam.md id=588950}}
diff --git a/src/game-support/lego-sw-iii-clone-wars.md b/src/game-support/lego-sw-iii-clone-wars.md
index 58937f43..d35a6b4a 100644
--- a/src/game-support/lego-sw-iii-clone-wars.md
+++ b/src/game-support/lego-sw-iii-clone-wars.md
@@ -1,8 +1,15 @@
-# LEGO Star Wars III - The Clone Wars
+# LEGO Star Wars III: The Clone Wars
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=Yes}}
> [!WARNING]
> Opening scene is flashing a lot with some simply colored rectangles. In the middle of that, the game crashes.
-{{#template ../templates/steam.md id=32510}}
\ No newline at end of file
+{{#template ../templates/steam.md id=32510}}
diff --git a/src/game-support/lego-sw-skywalker-saga.md b/src/game-support/lego-sw-skywalker-saga.md
index 087b79b0..c787f444 100644
--- a/src/game-support/lego-sw-skywalker-saga.md
+++ b/src/game-support/lego-sw-skywalker-saga.md
@@ -1,5 +1,8 @@
# LEGO Star Wars: The Skywalker Saga
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=920210}}
\ No newline at end of file
+{{#template ../templates/steam.md id=920210}}
diff --git a/src/game-support/lethal-company.md b/src/game-support/lethal-company.md
index e69f4c18..32d7803e 100644
--- a/src/game-support/lethal-company.md
+++ b/src/game-support/lethal-company.md
@@ -1,4 +1,5 @@
# Lethal Company
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
diff --git a/src/game-support/manor-lords.md b/src/game-support/manor-lords.md
index 5d1dd143..ebaa6535 100644
--- a/src/game-support/manor-lords.md
+++ b/src/game-support/manor-lords.md
@@ -1,4 +1,5 @@
# Manor Lords
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
diff --git a/src/game-support/mb-wfas.md b/src/game-support/mb-wfas.md
index 41334a6c..cfbeebcf 100644
--- a/src/game-support/mb-wfas.md
+++ b/src/game-support/mb-wfas.md
@@ -1,8 +1,9 @@
# Mount & Blade: With Fire & Sword
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=No}}
> [!WARNING]
> Freezes after showing a Bing logo with a black screen.
-{{#template ../templates/steam.md id=48720}}
\ No newline at end of file
+{{#template ../templates/steam.md id=48720}}
diff --git a/src/game-support/metro-2033-rx.md b/src/game-support/metro-2033-rx.md
index ed5ad4f1..954001cb 100644
--- a/src/game-support/metro-2033-rx.md
+++ b/src/game-support/metro-2033-rx.md
@@ -1,8 +1,9 @@
# Metro 2033 Redux
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
> [!NOTE]
> Enabling tesselation causes objects that use this option like stones flickering. FPS may drop significantly when entering areas full of smoke and light. Also setting gamma doesn't work.
-{{#template ../templates/steam.md id=286690}}
\ No newline at end of file
+{{#template ../templates/steam.md id=286690}}
diff --git a/src/game-support/metro-ll-rx.md b/src/game-support/metro-ll-rx.md
index 3d0859fd..9a794ab6 100644
--- a/src/game-support/metro-ll-rx.md
+++ b/src/game-support/metro-ll-rx.md
@@ -1,8 +1,11 @@
# Metro: Last Light Redux
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
> [!NOTE]
> When tesselation is set to "High" or "The Highest" option, it causes random textures to appear above the ground. FPS may drop significantly when entering areas full of smoke and light. Also setting gamma doesn't work.
-{{#template ../templates/steam.md id=287390}}
\ No newline at end of file
+{{#template ../templates/steam.md id=287390}}
diff --git a/src/game-support/mgs-5.md b/src/game-support/mgs-5.md
index 316e6f86..c2a0e0ed 100644
--- a/src/game-support/mgs-5.md
+++ b/src/game-support/mgs-5.md
@@ -1,5 +1,10 @@
# Metal Gear Solid V: The Phantom Pain
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=287700}}
\ No newline at end of file
+{{#template ../templates/steam.md id=287700}}
diff --git a/src/game-support/monster-hunter-world-iceborne.md b/src/game-support/monster-hunter-world-iceborne.md
index 525bfa3a..5fd73f2f 100644
--- a/src/game-support/monster-hunter-world-iceborne.md
+++ b/src/game-support/monster-hunter-world-iceborne.md
@@ -1,8 +1,11 @@
# Monster Hunter World: Iceborne
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
- Do not enable DirectX 12, it will cause the game to crash.
- A black screen may show instead of the Capcom logo.
-{{#template ../templates/steam.md id=1118010}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1118010}}
diff --git a/src/game-support/neon-white.md b/src/game-support/neon-white.md
index 6abf04db..ccb7475b 100644
--- a/src/game-support/neon-white.md
+++ b/src/game-support/neon-white.md
@@ -1,5 +1,6 @@
# Neon White
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1533420}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1533420}}
diff --git a/src/game-support/overwatch-2.md b/src/game-support/overwatch-2.md
index 91f20528..55e2de02 100644
--- a/src/game-support/overwatch-2.md
+++ b/src/game-support/overwatch-2.md
@@ -1,7 +1,8 @@
# Overwatch 2
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=No}}
Overwatch 2 is currently **unplayable** in Whisky.
-{{#template ../templates/steam.md id=2357570}}
\ No newline at end of file
+{{#template ../templates/steam.md id=2357570}}
diff --git a/src/game-support/p3r.md b/src/game-support/p3r.md
index bb5f5d87..6169bf54 100644
--- a/src/game-support/p3r.md
+++ b/src/game-support/p3r.md
@@ -1,4 +1,7 @@
# Persona 3 Reload
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
diff --git a/src/game-support/p4g.md b/src/game-support/p4g.md
index 5dc4e936..3e2e80ad 100644
--- a/src/game-support/p4g.md
+++ b/src/game-support/p4g.md
@@ -1,4 +1,7 @@
# Persona 4 Golden
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=Yes}}
diff --git a/src/game-support/palworld.md b/src/game-support/palworld.md
index 84e4a08e..e57f0218 100644
--- a/src/game-support/palworld.md
+++ b/src/game-support/palworld.md
@@ -1,4 +1,5 @@
# Palworld
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
diff --git a/src/game-support/people-playground.md b/src/game-support/people-playground.md
index 739b55bb..964c2f89 100644
--- a/src/game-support/people-playground.md
+++ b/src/game-support/people-playground.md
@@ -1,5 +1,6 @@
# People Playground
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1118200}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1118200}}
diff --git a/src/game-support/phasmophobia.md b/src/game-support/phasmophobia.md
index 3563fde3..61935e85 100644
--- a/src/game-support/phasmophobia.md
+++ b/src/game-support/phasmophobia.md
@@ -1,5 +1,6 @@
# Phasmophobia
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=739630}}
\ No newline at end of file
+{{#template ../templates/steam.md id=739630}}
diff --git a/src/game-support/prey-2017.md b/src/game-support/prey-2017.md
index 9156d445..c8c71174 100644
--- a/src/game-support/prey-2017.md
+++ b/src/game-support/prey-2017.md
@@ -1,4 +1,7 @@
# Prey (2017)
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -7,4 +10,4 @@ Main game and Mooncrash DLC running smoothly
> [!NOTE]
> Turning V-Sync off will fix any slowdowns that occur. Unfortunately, you may have some screen-tearing.
-{{#template ../templates/steam.md id=480490}}
\ No newline at end of file
+{{#template ../templates/steam.md id=480490}}
diff --git a/src/game-support/quake2.md b/src/game-support/quake2.md
index 7c59db56..e4bb378a 100644
--- a/src/game-support/quake2.md
+++ b/src/game-support/quake2.md
@@ -1,5 +1,8 @@
# Quake II
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=2320}}
\ No newline at end of file
+{{#template ../templates/steam.md id=2320}}
diff --git a/src/game-support/r2modman.md b/src/game-support/r2modman.md
index 57630eca..ad23ed68 100644
--- a/src/game-support/r2modman.md
+++ b/src/game-support/r2modman.md
@@ -1,4 +1,5 @@
# r2modman
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -17,3 +18,5 @@
> [!NOTE]
> If using the BepInEx framework, install `winhttp` through `Winetricks > DLLs` or override `winhttp` to `Native then Builtin` from `Wine Configuration` (console may not show up)
+
+
diff --git a/src/game-support/rain-world.md b/src/game-support/rain-world.md
index 4a777404..8ad7826c 100644
--- a/src/game-support/rain-world.md
+++ b/src/game-support/rain-world.md
@@ -1,7 +1,8 @@
# Rain World
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
Runs out of the box. A controller is required to play.
-{{#template ../templates/steam.md id=312520}}
\ No newline at end of file
+{{#template ../templates/steam.md id=312520}}
diff --git a/src/game-support/risk-of-rain-2.md b/src/game-support/risk-of-rain-2.md
index a505a420..98648328 100644
--- a/src/game-support/risk-of-rain-2.md
+++ b/src/game-support/risk-of-rain-2.md
@@ -1,8 +1,9 @@
# Risk of Rain 2
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
> [!NOTE]
> The game does not work with the multiplayer menu, as selecting multiplayer in the main menu freezes the game. Multiplayer through Steam invites still works, however.
-{{#template ../templates/steam.md id=632360}}
\ No newline at end of file
+{{#template ../templates/steam.md id=632360}}
diff --git a/src/game-support/risk-of-rain-returns.md b/src/game-support/risk-of-rain-returns.md
index ee4fb529..06aa2267 100644
--- a/src/game-support/risk-of-rain-returns.md
+++ b/src/game-support/risk-of-rain-returns.md
@@ -1,5 +1,6 @@
# Risk of Rain Returns
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1337520}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1337520}}
diff --git a/src/game-support/ruiner.md b/src/game-support/ruiner.md
index 4bf93372..5f56640c 100644
--- a/src/game-support/ruiner.md
+++ b/src/game-support/ruiner.md
@@ -1,5 +1,6 @@
# Ruiner
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=464060}}
\ No newline at end of file
+{{#template ../templates/steam.md id=464060}}
diff --git a/src/game-support/satisfactory.md b/src/game-support/satisfactory.md
index a320d0b4..49e3cff6 100644
--- a/src/game-support/satisfactory.md
+++ b/src/game-support/satisfactory.md
@@ -1,5 +1,6 @@
# Satisfactory
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=526870}}
\ No newline at end of file
+{{#template ../templates/steam.md id=526870}}
diff --git a/src/game-support/sekiro.md b/src/game-support/sekiro.md
index 57436cdf..b526936e 100644
--- a/src/game-support/sekiro.md
+++ b/src/game-support/sekiro.md
@@ -1,5 +1,8 @@
# Sekiro: Shadows Die Twice
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=814380}}
\ No newline at end of file
+{{#template ../templates/steam.md id=814380}}
diff --git a/src/game-support/skyrim-se.md b/src/game-support/skyrim-se.md
index d8077e03..4149c719 100644
--- a/src/game-support/skyrim-se.md
+++ b/src/game-support/skyrim-se.md
@@ -1,4 +1,5 @@
# Skyrim SE
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
diff --git a/src/game-support/stardew-valley.md b/src/game-support/stardew-valley.md
index f12943c8..436db496 100644
--- a/src/game-support/stardew-valley.md
+++ b/src/game-support/stardew-valley.md
@@ -1,8 +1,9 @@
# Stardew Valley
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
> [!NOTE]
> This game has a native Mac port.
-{{#template ../templates/steam.md id=413150}}
\ No newline at end of file
+{{#template ../templates/steam.md id=413150}}
diff --git a/src/game-support/stronghold-crusader-hd.md b/src/game-support/stronghold-crusader-hd.md
index 8570c37b..6334b3b3 100644
--- a/src/game-support/stronghold-crusader-hd.md
+++ b/src/game-support/stronghold-crusader-hd.md
@@ -1,5 +1,8 @@
# Stronghold Crusader HD
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=40970}}
\ No newline at end of file
+{{#template ../templates/steam.md id=40970}}
diff --git a/src/game-support/sw-fallen-order.md b/src/game-support/sw-fallen-order.md
index deb3110f..30719a17 100644
--- a/src/game-support/sw-fallen-order.md
+++ b/src/game-support/sw-fallen-order.md
@@ -1,4 +1,7 @@
# Star Wars Jedi: Fallen Order
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
diff --git a/src/game-support/sw-squadrons.md b/src/game-support/sw-squadrons.md
index 374b02cd..68b7c611 100644
--- a/src/game-support/sw-squadrons.md
+++ b/src/game-support/sw-squadrons.md
@@ -1,5 +1,8 @@
# Star Wars: Squadrons
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1222730}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1222730}}
diff --git a/src/game-support/tcr6s.md b/src/game-support/tcr6s.md
index 2778626e..6cf4b334 100644
--- a/src/game-support/tcr6s.md
+++ b/src/game-support/tcr6s.md
@@ -1,7 +1,11 @@
# Tom Clancy's Rainbow Six Siege (Steam)
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=No}}
Tom Clancy's Rainbow Six Siege is currently **unplayable** in Whisky.
-{{#template ../templates/steam.md id=359550}}
\ No newline at end of file
+{{#template ../templates/steam.md id=359550}}
diff --git a/src/game-support/template.md b/src/game-support/template.md
index f265be02..37313ff2 100644
--- a/src/game-support/template.md
+++ b/src/game-support/template.md
@@ -1,4 +1,5 @@
# Game Name
+
{{#template ../templates/rating.md status=[RATING] installs=[Y/N] opens=[Y/N]}}
@@ -6,4 +7,4 @@
- Lorem ipsum
-{{#template ../templates/steam.md id=APPID}}
\ No newline at end of file
+{{#template ../templates/steam.md id=APPID}}
diff --git a/src/game-support/tsp-ud.md b/src/game-support/tsp-ud.md
index d72c8758..957bf6a8 100644
--- a/src/game-support/tsp-ud.md
+++ b/src/game-support/tsp-ud.md
@@ -1,5 +1,8 @@
# The Stanley Parable: Ultra Deluxe
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1703340}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1703340}}
diff --git a/src/game-support/turbo-overkill.md b/src/game-support/turbo-overkill.md
index 80da66ca..f3d81f0c 100644
--- a/src/game-support/turbo-overkill.md
+++ b/src/game-support/turbo-overkill.md
@@ -1,7 +1,8 @@
# Turbo Overkill
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
The game has longer than normal loading times, and some audio doesn't play during cutscenes. Otherwise, it runs very well.
-{{#template ../templates/steam.md id=1328350}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1328350}}
diff --git a/src/game-support/ultrakill.md b/src/game-support/ultrakill.md
index 5cc8a357..cf547a6b 100644
--- a/src/game-support/ultrakill.md
+++ b/src/game-support/ultrakill.md
@@ -1,5 +1,6 @@
# Ultrakill
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1229490}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1229490}}
diff --git a/src/game-support/undertale.md b/src/game-support/undertale.md
index b885713a..86070cd8 100644
--- a/src/game-support/undertale.md
+++ b/src/game-support/undertale.md
@@ -1,4 +1,5 @@
# Undertale
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -7,4 +8,4 @@
Works, but suffers from severe audio stutters.
-{{#template ../templates/steam.md id=391540}}
\ No newline at end of file
+{{#template ../templates/steam.md id=391540}}
diff --git a/src/game-support/vanishing-of-ethan-carter.md b/src/game-support/vanishing-of-ethan-carter.md
index 27a27ac8..483952fb 100644
--- a/src/game-support/vanishing-of-ethan-carter.md
+++ b/src/game-support/vanishing-of-ethan-carter.md
@@ -1,8 +1,9 @@
# The Vanishing of Ethan Carter
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=No}}
> [!WARNING]
> The game launcher works. Running 32-bit version of the game causes an instant crash, while 64-bit opens with a few-seconds long black screen and then crashes too.
-{{#template ../templates/steam.md id=258520}}
\ No newline at end of file
+{{#template ../templates/steam.md id=258520}}
diff --git a/src/game-support/warframe.md b/src/game-support/warframe.md
index 6254f4d8..8575fd56 100644
--- a/src/game-support/warframe.md
+++ b/src/game-support/warframe.md
@@ -1,4 +1,5 @@
# Warframe
+
{{#template ../templates/rating.md status=Bronze installs=Yes opens=Yes}}
@@ -6,4 +7,4 @@
- Go to Bottle Configuration -> Open Wine Configuration -> Libraries
- Add `dwrite` library and set it to disabled
-{{#template ../templates/steam.md id=230410}}
\ No newline at end of file
+{{#template ../templates/steam.md id=230410}}
diff --git a/src/game-support/witcher3.md b/src/game-support/witcher3.md
index 28128adb..25fd647a 100644
--- a/src/game-support/witcher3.md
+++ b/src/game-support/witcher3.md
@@ -1,4 +1,5 @@
# The Witcher 3: Wild Hunt
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
@@ -7,4 +8,4 @@
> Ocassionaly there are objects pop-ups but overall it doesn't break the gameplay or immersion.
> DX11 is preffered over the DX12 due to the much better performance.
-{{#template ../templates/steam.md id=292030}}
\ No newline at end of file
+{{#template ../templates/steam.md id=292030}}
diff --git a/src/game-support/wolf-among-us.md b/src/game-support/wolf-among-us.md
index 121422a1..582ad91c 100644
--- a/src/game-support/wolf-among-us.md
+++ b/src/game-support/wolf-among-us.md
@@ -1,8 +1,9 @@
# The Wolf Among Us
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
> [!NOTE]
> There are a minor sound and video lags during the fighting scenes. The game sometimes crashes when starting a new Episode for the first time.
-{{#template ../templates/steam.md id=250320}}
\ No newline at end of file
+{{#template ../templates/steam.md id=250320}}