diff --git a/.eslintrc.json b/.eslintrc.json index 067f47e1f..c317f7a67 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,249 +1,187 @@ { - "env": { - "browser": true, - "node": true - }, - "extends": [ - "eslint:recommended", - "plugin:jest/style", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "plugin:import/errors", - "plugin:import/typescript" + "env": { + "browser": true, + "node": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:import/errors", + "plugin:import/typescript", + "plugin:jest/style", + "plugin:jsdoc/recommended" + ], + "ignorePatterns": [ + "target/**/*", + // Typescript plugins typing check cause eslint issues, takes too much time for few files + "cli/build/plugins/**/*" + ], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint", "jest", "import", "sort-keys-fix"], + "rules": { + "@typescript-eslint/no-misused-new": "off", + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/ban-ts-ignore": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-member-accessibility": ["error"], + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-empty-interface": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-unused-vars": "off", + "jsdoc/require-param-type": "off", + "jsdoc/require-returns-type": "off", + "jsdoc/tag-lines": ["error", "any", { "startLines": 1, "endLines": 0 }], + "jsdoc/check-tag-names": "off", + "jsdoc/require-param": "off", + "jsdoc/require-returns": "off", + "jsdoc/require-param-description": "off", + "jsdoc/require-jsdoc": "off", + "array-element-newline": ["error", "consistent"], + "arrow-parens": ["error", "always"], + "arrow-spacing": "error", + "brace-style": "error", + "camelcase": "off", + "sort-vars": "error", + "sort-imports": [ + "error", + { + "ignoreCase": true, + "ignoreDeclarationSort": true, + "ignoreMemberSort": false, + "allowSeparatedGroups": false + } ], - "ignorePatterns": [ - "target/**/*", - // Typescript plugins typing check cause eslint issues, takes too much time for few files - "cli/build/plugins/**/*" + "comma-dangle": [ + "error", + { + "arrays": "always-multiline", + "objects": "always-multiline", + "imports": "always-multiline", + "exports": "never", + "functions": "never" + } ], - "parser": "@typescript-eslint/parser", - "plugins": [ - "@typescript-eslint", - "jest", - "import", - "sort-keys-fix" + "eqeqeq": "error", + "eol-last": ["error", "always"], + "func-call-spacing": ["error", "never"], + "function-paren-newline": ["error", "multiline-arguments"], + "import/default": "off", + "import/no-relative-parent-imports": "error", + "import/no-unresolved": "off", + "import/order": [ + "error", + { + "alphabetize": { + "caseInsensitive": true, + "order": "asc" + }, + "groups": ["builtin", "external", "parent", "sibling", "index"], + "newlines-between": "always", + "pathGroups": [ + { + "group": "external", + "pattern": "#/**", + "position": "after" + }, + { + "group": "external", + "pattern": "@/**", + "position": "after" + } + ], + "pathGroupsExcludedImportTypes": ["builtin"] + } ], - "rules": { - "@typescript-eslint/no-misused-new": "off", - "@typescript-eslint/ban-ts-comment": "off", - "@typescript-eslint/ban-ts-ignore": "off", - "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/explicit-member-accessibility": [ - "error" - ], - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-empty-interface": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-inferrable-types": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-unused-vars": "off", - "array-element-newline": [ - "error", - "consistent" - ], - "arrow-parens": [ - "error", - "always" - ], - "arrow-spacing": "error", - "brace-style": "error", - "camelcase": "off", - "sort-vars": "error", - "sort-imports": ["error", { - "ignoreCase": true, - "ignoreDeclarationSort": true, - "ignoreMemberSort": false, - "allowSeparatedGroups": false - }], - "comma-dangle": [ - "error", - { - "arrays": "always-multiline", - "objects": "always-multiline", - "imports": "always-multiline", - "exports": "never", - "functions": "never" - } - ], - "eqeqeq": "error", - "eol-last": [ - "error", - "always" - ], - "func-call-spacing": [ - "error", - "never" - ], - "function-paren-newline": [ - "error", - "multiline-arguments" - ], - "import/default": "off", - "import/no-relative-parent-imports": "error", - "import/no-unresolved": "off", - "import/order": [ - "error", - { - "alphabetize": { - "caseInsensitive": true, - "order": "asc" - }, - "groups": [ - "builtin", - "external", - "parent", - "sibling", - "index" - ], - "newlines-between": "always", - "pathGroups": [ - { - "group": "external", - "pattern": "#/**", - "position": "after" - }, - { - "group": "external", - "pattern": "@/**", - "position": "after" - } - ], - "pathGroupsExcludedImportTypes": [ - "builtin" - ] - } - ], - "indent": [ - "error", - 2, - { - "SwitchCase": 1 - } - ], - "key-spacing": [ - "error", - { - "afterColon": true, - "beforeColon": false - } - ], - "keyword-spacing": "error", - "max-len": [ - "error", - { - "code": 120, - "ignorePattern": "^import\\W.*" - } - ], - "no-constructor-return": "error", - "no-duplicate-imports": "error", - "no-multi-spaces": "error", - "no-multiple-empty-lines": [ - "error", - { - "max": 1, - "maxBOF": 1 - } - ], - "no-trailing-spaces": "error", - "object-curly-newline": [ - "error", - { - "consistent": true, - "multiline": true - } - ], - "object-curly-spacing": [ - "error", - "always" - ], - "object-property-newline": [ - "error", - { - "allowAllPropertiesOnSameLine": true - } - ], - "padding-line-between-statements": [ - "error", - { - "blankLine": "always", - "next": "return", - "prev": "*" - }, - { - "blankLine": "always", - "next": [ - "const", - "let", - "var" - ], - "prev": "expression" - }, - { - "blankLine": "always", - "next": "*", - "prev": [ - "const", - "let", - "var" - ] - }, - { - "blankLine": "always", - "next": "*", - "prev": [ - "for", - "if", - "while", - "do", - "with" - ] - }, - { - "blankLine": "always", - "next": [ - "function", - "class" - ], - "prev": [ - "function", - "class" - ] - }, - { - "blankLine": "any", - "next": [ - "const", - "let", - "var" - ], - "prev": [ - "const", - "let", - "var" - ] - } - ], - "quotes": [ - "error", - "double" - ], - "semi": "error", - "space-in-parens": [ - "error", - "never" - ], - "spaced-comment": [ - "error", - "always" - ], - "template-tag-spacing": [ - "error", - "never" - ], - "yoda": "error" - }, - "settings": { - } + "indent": [ + "error", + 2, + { + "SwitchCase": 1 + } + ], + "key-spacing": [ + "error", + { + "afterColon": true, + "beforeColon": false + } + ], + "keyword-spacing": "error", + "max-len": [ + "error", + { + "code": 120, + "ignorePattern": "^import\\W.*" + } + ], + "no-constructor-return": "error", + "no-duplicate-imports": "error", + "no-multi-spaces": "error", + "no-multiple-empty-lines": [ + "error", + { + "max": 1, + "maxBOF": 1 + } + ], + "no-trailing-spaces": "error", + "object-curly-newline": [ + "error", + { + "consistent": true, + "multiline": true + } + ], + "object-curly-spacing": ["error", "always"], + "object-property-newline": [ + "error", + { + "allowAllPropertiesOnSameLine": true + } + ], + "padding-line-between-statements": [ + "error", + { + "blankLine": "always", + "next": "return", + "prev": "*" + }, + { + "blankLine": "always", + "next": ["const", "let", "var"], + "prev": "expression" + }, + { + "blankLine": "always", + "next": "*", + "prev": ["const", "let", "var"] + }, + { + "blankLine": "always", + "next": "*", + "prev": ["for", "if", "while", "do", "with"] + }, + { + "blankLine": "always", + "next": ["function", "class"], + "prev": ["function", "class"] + }, + { + "blankLine": "any", + "next": ["const", "let", "var"], + "prev": ["const", "let", "var"] + } + ], + "quotes": ["error", "double"], + "semi": "error", + "space-in-parens": ["error", "never"], + "spaced-comment": ["error", "always"], + "template-tag-spacing": ["error", "never"], + "yoda": "error" + }, + "settings": {} } diff --git a/README.md b/README.md index 42534ab4c..e37d340ca 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,11 @@ Optimizations, quality and logics updates are welcome. - [parse](cli/parse/README.md) - parsing utils to collect documentation or JSON summaries - `help` - print list of commands and information about them +## 💿 Build + +Script engine can be packaged and built into custom game package.
+Detailed description: [link](doc/BUILDING_CUSTOM_GAME_PACKAGE.md) + --- ## 🧰 Docs @@ -104,7 +109,11 @@ Optimizations, quality and logics updates are welcome. ## 🏗️ Assets +Additional assets repository can be cloned manually or with shortcut command:
+`npm run cli clone *name*` (`extended`, `locale-eng`, `locale-ukr`, `locale-rus`) + - Extended assets: [https://gitlab.com/xray-forge/stalker-xrf-resources-extended](https://gitlab.com/xray-forge/stalker-xrf-resources-extended) - EN locale assets: [https://gitlab.com/xray-forge/stalker-xrf-resources-locale-eng](https://gitlab.com/xray-forge/stalker-xrf-resources-locale-eng) - UA locale assets: [https://gitlab.com/xray-forge/stalker-xrf-resources-locale-ukr](https://gitlab.com/xray-forge/stalker-xrf-resources-locale-ukr) - RU locale assets: [https://gitlab.com/xray-forge/stalker-xrf-resources-locale-rus](https://gitlab.com/xray-forge/stalker-xrf-resources-locale-rus) + diff --git a/cli/build/steps/configs_dynamic.ts b/cli/build/steps/configs_dynamic.ts index 7c63f30b1..b4bd617ac 100644 --- a/cli/build/steps/configs_dynamic.ts +++ b/cli/build/steps/configs_dynamic.ts @@ -67,6 +67,9 @@ export async function buildDynamicConfigs(parameters: IBuildCommandParameters): * Get list of LTX transformable descriptors. */ async function getLtxConfigs(filters: Array = []): Promise> { + /** + * todo; + */ function collectLtxConfigs( acc: Array, it: TFolderFiles diff --git a/cli/build/steps/configs_statics.ts b/cli/build/steps/configs_statics.ts index cab6109e7..0114d69bf 100644 --- a/cli/build/steps/configs_statics.ts +++ b/cli/build/steps/configs_statics.ts @@ -53,6 +53,9 @@ export async function buildStaticConfigs(parameters: IBuildCommandParameters): P * Get list of static configs. */ async function getStaticConfigs(filters: Array = []): Promise> { + /** + * todo; + */ function collectConfigs( acc: Array, it: TFolderFiles diff --git a/cli/build/steps/meta.ts b/cli/build/steps/meta.ts index 879a328da..646a83bd3 100644 --- a/cli/build/steps/meta.ts +++ b/cli/build/steps/meta.ts @@ -17,9 +17,6 @@ interface IBuildMetaParams { /** * Step to collect metadata in a single file with timing metrics. - * - * @param meta - build meta information to save - * @param timeTracker - build time tracker with performance metrics */ export async function buildMeta({ meta, timeTracker }: IBuildMetaParams): Promise { log.info(blueBright("Build metadata")); diff --git a/cli/build/steps/translations_dynamic.ts b/cli/build/steps/translations_dynamic.ts index e090ed939..a59713dfe 100644 --- a/cli/build/steps/translations_dynamic.ts +++ b/cli/build/steps/translations_dynamic.ts @@ -35,6 +35,9 @@ export async function buildDynamicTranslations(): Promise { return log.warn("No languages to translate found in config.json file, skip"); } + /** + * todo; + */ function collectTranslations( acc: Array, it: TFolderFiles diff --git a/cli/build/steps/ui_dynamic.ts b/cli/build/steps/ui_dynamic.ts index c0647d76a..ea461d0ad 100644 --- a/cli/build/steps/ui_dynamic.ts +++ b/cli/build/steps/ui_dynamic.ts @@ -63,6 +63,9 @@ export async function buildDynamicUi(parameters: IBuildCommandParameters): Promi * Get list of UI config files in engine source files. */ async function getUiConfigs(filters: Array = []): Promise> { + /** + * todo; + */ function collectXmlConfigs( acc: Array, it: TFolderFiles diff --git a/cli/build/steps/ui_statics.ts b/cli/build/steps/ui_statics.ts index 5d18a06a1..0060b3695 100644 --- a/cli/build/steps/ui_statics.ts +++ b/cli/build/steps/ui_statics.ts @@ -51,6 +51,9 @@ export async function buildStaticUi(parameters: IBuildCommandParameters): Promis * Get UI configuration files list. */ async function getUiConfigs(filters: Array = []): Promise> { + /** + * todo; + */ function collectXmlConfigs( acc: Array, it: Array | string diff --git a/cli/format/format_ltx.ts b/cli/format/format_ltx.ts index 35ca7b22f..33436ccee 100644 --- a/cli/format/format_ltx.ts +++ b/cli/format/format_ltx.ts @@ -49,6 +49,9 @@ async function formatLtxFile(file: string): Promise { * Get list of static configs. */ async function getLtxConfigs(filters: Array = []): Promise> { + /** + * todo; + */ function collectConfigs(acc: Array, it: TFolderFiles): Array { if (Array.isArray(it)) { it.forEach((nested) => collectConfigs(acc, nested)); diff --git a/cli/parse/parse_externals.ts b/cli/parse/parse_externals.ts index 799ec5d93..a3a1c4985 100644 --- a/cli/parse/parse_externals.ts +++ b/cli/parse/parse_externals.ts @@ -47,6 +47,9 @@ export async function parseExternals(): Promise { * Get list of LTX transformable descriptors. */ async function getSourcesList(source: string): Promise> { + /** + * todo; + */ function collectList(acc: Array, it: TFolderFiles): Array { if (Array.isArray(it)) { it.forEach((nested) => collectList(acc, nested)); diff --git a/cli/parse/utils/__test__/declaration.ts b/cli/parse/utils/__test__/declaration.ts index 423659eca..e024a92cb 100644 --- a/cli/parse/utils/__test__/declaration.ts +++ b/cli/parse/utils/__test__/declaration.ts @@ -10,8 +10,14 @@ interface IAbstractInterface { b: string; } +/** + * todo; + */ function extern(name: string, cb: (...args: Array) => void): void {} +/** + * todo; + */ function another(name: string, cb: (...args: Array) => void): void {} extern("module.callback_name_one", (a: number, b: string, c: boolean, d: SomeAlias): boolean => true); diff --git a/cli/preview/preview.ts b/cli/preview/preview.ts index 3072633e3..8267a8a55 100644 --- a/cli/preview/preview.ts +++ b/cli/preview/preview.ts @@ -98,7 +98,13 @@ function createFoldersForConfigs(xmlConfigs: Array }); } +/** + * todo; + */ async function getUiConfigs(filters: Array = []): Promise> { + /** + * todo; + */ function collectXmlConfigs( acc: Array, it: TFolderFiles diff --git a/cli/preview/utils/generate_preview.ts b/cli/preview/utils/generate_preview.ts index fa032a3cf..f103e2136 100644 --- a/cli/preview/utils/generate_preview.ts +++ b/cli/preview/utils/generate_preview.ts @@ -2,6 +2,9 @@ import { default as jsdom } from "jsdom"; const { style, STATIC_ASSET, GRADIENT_BG_, GENERIC } = generateDomClasses(); +/** + * + */ export function generateHTMLPreviewFromXMLString(content: string): string { const dom = new jsdom.JSDOM(content); @@ -58,10 +61,16 @@ export function generateHTMLPreviewFromXMLString(content: string): string { return dom.serialize(); } +/** + * + */ function prepareOther(node: HTMLElement): void { node.style.border = "solid black 1px"; } +/** + * + */ function prepareText(node: HTMLElement): void { node.style.overflow = "hidden"; node.style.width = "100%"; @@ -74,6 +83,9 @@ function prepareText(node: HTMLElement): void { } } +/** + * + */ function prepareTexture(node: HTMLElement): void { node.setAttribute("texture_resource", node.textContent); @@ -84,15 +96,24 @@ function prepareTexture(node: HTMLElement): void { node.style.height = "100%"; } +/** + * + */ function prepareWindow(node: HTMLElement): void { node.style.position = "absolute"; node.style.background = "rgba(50, 50, 50, 0.05)"; } +/** + * + */ function prepareStaticAsset(node: HTMLElement): void { node.className = STATIC_ASSET + " " + GRADIENT_BG_ + Math.floor(Math.random() * 10); } +/** + * + */ function generateDomClasses() { const GENERIC: string = "generic"; const STATIC_ASSET: string = "static-asset"; @@ -144,6 +165,9 @@ function generateDomClasses() { }; } +/** + * todo; + */ function getRandomColor(): string { return "#" + (((1 << 24) * Math.random()) | 0).toString(16).padStart(6, "0"); } diff --git a/cli/utils/fs/get_diffs.ts b/cli/utils/fs/get_diffs.ts index 62aa4bab1..9500a11d4 100644 --- a/cli/utils/fs/get_diffs.ts +++ b/cli/utils/fs/get_diffs.ts @@ -31,10 +31,16 @@ export interface IDiffs { deletions: IDiff; } +/** + * todo; + */ function getTime(dateOrDateStr: Date | string): number { return typeof dateOrDateStr === "string" ? Date.parse(dateOrDateStr) : dateOrDateStr.getTime(); } +/** + * todo; + */ async function ensureDirAccess(directory: string): Promise { try { await fsp.access(directory); @@ -43,6 +49,11 @@ async function ensureDirAccess(directory: string): Promise { } } +/** + * todo; + * + * @yields - files from directory in a recursive way + */ async function* getFiles(directory: string): AsyncGenerator { const dirents = await fsp.readdir(directory, { withFileTypes: true }); @@ -54,6 +65,9 @@ async function* getFiles(directory: string): AsyncGenerator { } } +/** + * todo; + */ async function getFileStats(directory: string, options): Promise { const dir = path.resolve(directory); @@ -85,6 +99,9 @@ async function getFileStats(directory: string, options): Promise { return fileStats; } +/** + * todo; + */ export async function getDiffs(base: FilePathMap, target: FilePathMap, options?: DiffOptions): Promise { const { exclusions = [], compareSizes = true } = options || {}; const statsOptions = { exclusions }; diff --git a/cli/utils/fs/open_folder_in_explorer.ts b/cli/utils/fs/open_folder_in_explorer.ts index 8eb4ab1e9..740e0f8aa 100644 --- a/cli/utils/fs/open_folder_in_explorer.ts +++ b/cli/utils/fs/open_folder_in_explorer.ts @@ -1,6 +1,9 @@ import * as cp from "child_process"; import * as os from "os"; +/** + * todo; + */ export function openFolderInExplorer(path: string): Promise { return new Promise((resolve, reject) => { const osType: string = os.type(); diff --git a/cli/utils/fs/read_dir_content.ts b/cli/utils/fs/read_dir_content.ts index 7736d12a7..1b0d01312 100644 --- a/cli/utils/fs/read_dir_content.ts +++ b/cli/utils/fs/read_dir_content.ts @@ -8,9 +8,7 @@ import { TDirectoryFilesTree } from "#/utils/fs/types"; */ export async function readDirContent(dirPath: string): Promise { return (await Promise.all( - ( - await fs.readdir(dirPath, { withFileTypes: true }) - ).map(async (dirent) => { + (await fs.readdir(dirPath, { withFileTypes: true })).map(async (dirent) => { const it = path.join(dirPath, dirent.name); return dirent.isDirectory() ? await readDirContent(it) : it; diff --git a/cli/utils/fs/read_dir_content_flat.ts b/cli/utils/fs/read_dir_content_flat.ts index f49a63092..0ac7826b4 100644 --- a/cli/utils/fs/read_dir_content_flat.ts +++ b/cli/utils/fs/read_dir_content_flat.ts @@ -6,9 +6,7 @@ import * as path from "path"; */ export async function readDirContentFlat(dirPath: string, container: Array = []): Promise> { await Promise.all( - ( - await fs.readdir(dirPath, { withFileTypes: true }) - ).map(async (dirent) => { + (await fs.readdir(dirPath, { withFileTypes: true })).map(async (dirent) => { const it = path.join(dirPath, dirent.name); if (dirent.isDirectory()) { diff --git a/cli/utils/fs/read_dir_content_flat_gen.ts b/cli/utils/fs/read_dir_content_flat_gen.ts index d59012cca..e6ff145cd 100644 --- a/cli/utils/fs/read_dir_content_flat_gen.ts +++ b/cli/utils/fs/read_dir_content_flat_gen.ts @@ -1,6 +1,12 @@ -import fsp from "fs/promises"; -import path from "path"; +import * as fsp from "fs/promises"; +import * as path from "path"; +/** + * Read folder content with generator. + * + * @param directory - target folder to traverse + * @yields next item in directory + */ export async function* readFolderGen(directory: string) { const dirents = await fsp.readdir(directory, { withFileTypes: true }); diff --git a/cli/utils/fs/read_last_lines_of_file.ts b/cli/utils/fs/read_last_lines_of_file.ts index 8fa6f2c9c..e2a7d7f52 100644 --- a/cli/utils/fs/read_last_lines_of_file.ts +++ b/cli/utils/fs/read_last_lines_of_file.ts @@ -6,6 +6,9 @@ import { Optional } from "#/utils/types"; const NEW_LINE_CHARACTERS: Array = ["\n"]; +/** + * todo; + */ export async function readLastLinesOfFile( filePath: string, maxLineCount: number, diff --git a/doc/BUILDING_CUSTOM_GAME_PACKAGE.md b/doc/BUILDING_CUSTOM_GAME_PACKAGE.md index b9fa375b0..9a7a0816f 100644 --- a/doc/BUILDING_CUSTOM_GAME_PACKAGE.md +++ b/doc/BUILDING_CUSTOM_GAME_PACKAGE.md @@ -10,7 +10,7 @@ and bundled together with custom engine. Comparing to normal gamedata builds the only needed thing is full assets list.
To build package you will need [extended](https://gitlab.com/xray-forge/stalker-xrf-resources-extended) assets -and one of locales packs, for example [en](https://gitlab.com/xray-forge/stalker-xrf-resources-locale-en).
+and one of locales packs, for example [eng](https://gitlab.com/xray-forge/stalker-xrf-resources-locale-eng).
After cloning suggested repositories or providing custom assets, you should list them in 'config.json' if paths are different from already suggested. @@ -19,10 +19,10 @@ After cloning suggested repositories or providing custom assets, you should list If assets are downloaded and configured correctly, the only needed thing is: ``` -npm run cli pack game -- --clean --build --optimize +npm run cli pack game -- --clean --optimize # or -npm run cli pack game -- -c -b -o +npm run cli pack game -- -c -o # or npm run pack:game diff --git a/doc/TODO.md b/doc/TODO.md index ad314d575..53eda9ba9 100644 --- a/doc/TODO.md +++ b/doc/TODO.md @@ -13,6 +13,7 @@ ## 🧰 Requests to open x-ray +- Add callback notifying about game save to get filename - With lua bindings generation include all call overrides when output TXT - Export actor menu and actor menu item classes for overriding with lua - Fix numerous calls to disk with menu, implement caching for character menu and fix lags when opening inventory diff --git a/package-lock.json b/package-lock.json index e4ab870d1..8ab1b7bf2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,11 +21,12 @@ "@typescript-eslint/parser": "^5.59.11", "@typescript-to-lua/language-extensions": "1.0.0", "chalk": "4.1.2", - "commander": "^10.0.1", - "eslint": "^8.43.0", - "eslint-config-standard-with-typescript": "^35.0.0", + "commander": "^11.0.0", + "eslint": "^8.44.0", + "eslint-config-standard-with-typescript": "^36.0.0", "eslint-plugin-import": "^2.27.5", - "eslint-plugin-jest": "^27.2.1", + "eslint-plugin-jest": "^27.2.2", + "eslint-plugin-jsdoc": "^46.4.3", "eslint-plugin-sort-keys-fix": "^1.1.2", "fast-xml-parser": "^4.2.4", "fengari": "0.1.4", @@ -34,13 +35,22 @@ "jsdom": "^22.1.0", "jsx-xml": "^0.2.3", "lua-types": "^2.13.1", - "prettier": "^2.8.8", + "prettier": "^3.0.0", "steam-path": "^1.0.2", "ts-jest": "^29.1.0", "ts-node": "10.9.1", "tsconfig-paths": "^4.2.0", - "typescript": "^5.1.3", - "typescript-to-lua": "^1.16.2" + "typescript": "^5.1.6", + "typescript-to-lua": "^1.16.3" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/@ampproject/remapping": { @@ -693,6 +703,20 @@ "node": ">=12" } }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.39.4", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.39.4.tgz", + "integrity": "sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg==", + "dev": true, + "dependencies": { + "comment-parser": "1.3.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz", @@ -718,14 +742,14 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", + "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -741,9 +765,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", - "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1711,9 +1735,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1838,6 +1862,15 @@ "node": ">= 8" } }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -2094,6 +2127,18 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/builtins": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", @@ -2258,12 +2303,21 @@ } }, "node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", + "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", "dev": true, "engines": { - "node": ">=14" + "node": ">=16" + } + }, + "node_modules/comment-parser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", + "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", + "dev": true, + "engines": { + "node": ">= 12.0.0" } }, "node_modules/concat-map": { @@ -2607,15 +2661,15 @@ } }, "node_modules/eslint": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", - "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", + "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.43.0", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -2627,7 +2681,7 @@ "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.0", "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", + "espree": "^9.6.0", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -2647,7 +2701,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -2689,9 +2743,9 @@ } }, "node_modules/eslint-config-standard-with-typescript": { - "version": "35.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-35.0.0.tgz", - "integrity": "sha512-Xa7DY9GgduZyp0qmXxBF0/dB+Vm4/DgWu1lGpNLJV2d46aCaUxTKDEnkzjUWX/1O9S0a+Dhnw7A4oI0JpYzwtw==", + "version": "36.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-36.0.0.tgz", + "integrity": "sha512-8ZSEskfrDAkUF2lTQLMT0CBzgRNlx1uIM7l2I7L683dKAXUdHuEL2x+GxuGAsdsoWbx7W7Zv0xF67VCEZXIk0Q==", "dev": true, "dependencies": { "@typescript-eslint/parser": "^5.50.0", @@ -2882,9 +2936,9 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "27.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz", - "integrity": "sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==", + "version": "27.2.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.2.tgz", + "integrity": "sha512-euzbp06F934Z7UDl5ZUaRPLAc9MKjh0rMPERrHT7UhlCEwgb25kBj37TvMgWeHZVkR5I9CayswrpoaqZU1RImw==", "dev": true, "dependencies": { "@typescript-eslint/utils": "^5.10.0" @@ -2894,7 +2948,8 @@ }, "peerDependencies": { "@typescript-eslint/eslint-plugin": "^5.0.0", - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0", + "jest": "*" }, "peerDependenciesMeta": { "@typescript-eslint/eslint-plugin": { @@ -2905,6 +2960,29 @@ } } }, + "node_modules/eslint-plugin-jsdoc": { + "version": "46.4.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.4.3.tgz", + "integrity": "sha512-Prc7ol+vCIghPeECpwZq5+P+VZfoi87suywvbYCiCnkI1kTmVSdcOC2M8mioglWxBbd28wbb1OVjg/8OzGzatA==", + "dev": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.39.4", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.3.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.1", + "spdx-expression-parse": "^3.0.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, "node_modules/eslint-plugin-n": { "version": "15.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.6.0.tgz", @@ -3052,12 +3130,12 @@ } }, "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz", + "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" }, @@ -3824,6 +3902,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -4716,6 +4809,15 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/jsdom": { "version": "22.1.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", @@ -5175,17 +5277,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -5424,15 +5526,15 @@ } }, "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", + "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", "dev": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" @@ -5770,9 +5872,9 @@ } }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -5880,6 +5982,28 @@ "node": ">=0.10.0" } }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "dev": true + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -6322,9 +6446,9 @@ } }, "node_modules/typescript": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", - "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", + "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -6335,9 +6459,9 @@ } }, "node_modules/typescript-to-lua": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/typescript-to-lua/-/typescript-to-lua-1.16.2.tgz", - "integrity": "sha512-QtkQCDMNWMVilw/MsgIMLEVKYmSXvTgM21Li77KKKOyDJ+sSxph2oJfQ8XvXI3X6sse9VZhYC7gKLWi7qHKr7w==", + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/typescript-to-lua/-/typescript-to-lua-1.16.3.tgz", + "integrity": "sha512-vWJIfupLO6u22tMYmlczdcb5TtFUv8Mwf79ZKUyxqX4td5xWv3L2wu5WCx0YrOZ4//JwDQohrkfX1y4LbZTugQ==", "dev": true, "dependencies": { "@typescript-to-lua/language-extensions": "1.0.0", @@ -6567,15 +6691,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -6792,6 +6907,21 @@ "url": "https://github.com/sponsors/isaacs" } }, + "src/typedefs/xray16/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "src/typedefs/xray16/node_modules/typedoc": { "version": "0.23.26", "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.26.tgz", @@ -6828,6 +6958,12 @@ } }, "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, "@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -7328,6 +7464,17 @@ "@jridgewell/trace-mapping": "0.3.9" } }, + "@es-joy/jsdoccomment": { + "version": "0.39.4", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.39.4.tgz", + "integrity": "sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg==", + "dev": true, + "requires": { + "comment-parser": "1.3.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + } + }, "@eslint-community/eslint-utils": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz", @@ -7344,14 +7491,14 @@ "dev": true }, "@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", + "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -7361,9 +7508,9 @@ } }, "@eslint/js": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", - "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", "dev": true }, "@humanwhocodes/config-array": { @@ -8124,9 +8271,9 @@ "dev": true }, "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true }, "acorn-jsx": { @@ -8211,6 +8358,12 @@ "picomatch": "^2.0.4" } }, + "are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true + }, "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -8403,6 +8556,12 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true + }, "builtins": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", @@ -8517,9 +8676,15 @@ } }, "commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", + "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "dev": true + }, + "comment-parser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", + "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", "dev": true }, "concat-map": { @@ -8780,15 +8945,15 @@ "dev": true }, "eslint": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", - "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", + "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.43.0", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -8800,7 +8965,7 @@ "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.0", "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", + "espree": "^9.6.0", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -8820,7 +8985,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -8834,9 +8999,9 @@ "requires": {} }, "eslint-config-standard-with-typescript": { - "version": "35.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-35.0.0.tgz", - "integrity": "sha512-Xa7DY9GgduZyp0qmXxBF0/dB+Vm4/DgWu1lGpNLJV2d46aCaUxTKDEnkzjUWX/1O9S0a+Dhnw7A4oI0JpYzwtw==", + "version": "36.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-36.0.0.tgz", + "integrity": "sha512-8ZSEskfrDAkUF2lTQLMT0CBzgRNlx1uIM7l2I7L683dKAXUdHuEL2x+GxuGAsdsoWbx7W7Zv0xF67VCEZXIk0Q==", "dev": true, "requires": { "@typescript-eslint/parser": "^5.50.0", @@ -8986,14 +9151,31 @@ } }, "eslint-plugin-jest": { - "version": "27.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz", - "integrity": "sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==", + "version": "27.2.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.2.tgz", + "integrity": "sha512-euzbp06F934Z7UDl5ZUaRPLAc9MKjh0rMPERrHT7UhlCEwgb25kBj37TvMgWeHZVkR5I9CayswrpoaqZU1RImw==", "dev": true, "requires": { "@typescript-eslint/utils": "^5.10.0" } }, + "eslint-plugin-jsdoc": { + "version": "46.4.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.4.3.tgz", + "integrity": "sha512-Prc7ol+vCIghPeECpwZq5+P+VZfoi87suywvbYCiCnkI1kTmVSdcOC2M8mioglWxBbd28wbb1OVjg/8OzGzatA==", + "dev": true, + "requires": { + "@es-joy/jsdoccomment": "~0.39.4", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.3.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.1", + "spdx-expression-parse": "^3.0.1" + } + }, "eslint-plugin-n": { "version": "15.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.6.0.tgz", @@ -9092,12 +9274,12 @@ "dev": true }, "espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz", + "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==", "dev": true, "requires": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" } @@ -9658,6 +9840,15 @@ "has-tostringtag": "^1.0.0" } }, + "is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "requires": { + "builtin-modules": "^3.3.0" + } + }, "is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -10325,6 +10516,12 @@ "argparse": "^2.0.1" } }, + "jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true + }, "jsdom": { "version": "22.1.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", @@ -10679,17 +10876,17 @@ } }, "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" } }, "os-tmpdir": { @@ -10855,9 +11052,9 @@ "dev": true }, "prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", + "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", "dev": true }, "pretty-format": { @@ -11088,9 +11285,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -11176,6 +11373,28 @@ } } }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "dev": true + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -11487,15 +11706,15 @@ "dev": true }, "typescript": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", - "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", + "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", "dev": true }, "typescript-to-lua": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/typescript-to-lua/-/typescript-to-lua-1.16.2.tgz", - "integrity": "sha512-QtkQCDMNWMVilw/MsgIMLEVKYmSXvTgM21Li77KKKOyDJ+sSxph2oJfQ8XvXI3X6sse9VZhYC7gKLWi7qHKr7w==", + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/typescript-to-lua/-/typescript-to-lua-1.16.3.tgz", + "integrity": "sha512-vWJIfupLO6u22tMYmlczdcb5TtFUv8Mwf79ZKUyxqX4td5xWv3L2wu5WCx0YrOZ4//JwDQohrkfX1y4LbZTugQ==", "dev": true, "requires": { "@typescript-to-lua/language-extensions": "1.0.0", @@ -11669,12 +11888,6 @@ "is-symbol": "^1.0.3" } }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -11771,6 +11984,12 @@ "brace-expansion": "^2.0.1" } }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true + }, "typedoc": { "version": "0.23.26", "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.26.tgz", diff --git a/package.json b/package.json index 6f80de6cf..3509594cc 100644 --- a/package.json +++ b/package.json @@ -29,11 +29,12 @@ "@typescript-eslint/parser": "^5.59.11", "@typescript-to-lua/language-extensions": "1.0.0", "chalk": "4.1.2", - "commander": "^10.0.1", - "eslint": "^8.43.0", - "eslint-config-standard-with-typescript": "^35.0.0", + "commander": "^11.0.0", + "eslint": "^8.44.0", + "eslint-config-standard-with-typescript": "^36.0.0", "eslint-plugin-import": "^2.27.5", - "eslint-plugin-jest": "^27.2.1", + "eslint-plugin-jest": "^27.2.2", + "eslint-plugin-jsdoc": "^46.4.3", "eslint-plugin-sort-keys-fix": "^1.1.2", "fast-xml-parser": "^4.2.4", "fengari": "0.1.4", @@ -42,13 +43,13 @@ "jsdom": "^22.1.0", "jsx-xml": "^0.2.3", "lua-types": "^2.13.1", - "prettier": "^2.8.8", + "prettier": "^3.0.0", "steam-path": "^1.0.2", "ts-jest": "^29.1.0", "ts-node": "10.9.1", "tsconfig-paths": "^4.2.0", - "typescript": "^5.1.3", - "typescript-to-lua": "^1.16.2" + "typescript": "^5.1.6", + "typescript-to-lua": "^1.16.3" }, "bin": { "xrf": "./cli/run.ts" diff --git a/src/engine/core/database/offline.ts b/src/engine/core/database/offline.ts index 16a60006a..f22d884b0 100644 --- a/src/engine/core/database/offline.ts +++ b/src/engine/core/database/offline.ts @@ -30,10 +30,6 @@ export function registerOfflineObject( /** * Hard reset offline object state. * Create new representation entry if it was not initialize before. - * - * @param objectId - game object ID to register offline representation - * @param state - base offline state to register - * @returns stored offline object state representation */ export function hardResetOfflineObject( objectId: TNumberId, @@ -48,10 +44,6 @@ export function hardResetOfflineObject( /** * Soft reset offline object state. * Do not create new representation entry if it was not initialize before. - * - * @param objectId - game object ID to register offline representation - * @param state - base offline state to register - * @returns stored offline object state representation */ export function softResetOfflineObject( objectId: TNumberId, diff --git a/src/engine/core/database/save_markers.ts b/src/engine/core/database/save_markers.ts index ebb6c58d5..8281fc715 100644 --- a/src/engine/core/database/save_markers.ts +++ b/src/engine/core/database/save_markers.ts @@ -14,7 +14,7 @@ const logger: LuaLogger = new LuaLogger($filename); export function openSaveMarker(packet: NetPacket, markerName: TName): void { const packetSize: TCount = packet.w_tell(); - assert(packetSize < 20_480, "You are saving too much in '%s' - '%s'.", markerName, packetSize); + assert(packetSize < 16_384, "You are saving too much in '%s' - '%s'.", markerName, packetSize); registry.saveMarkers.set(markerName, packet.w_tell()); } diff --git a/src/engine/core/managers/base/SaveManager.test.ts b/src/engine/core/managers/base/SaveManager.test.ts index 4fe5e3b22..28b7d3c9f 100644 --- a/src/engine/core/managers/base/SaveManager.test.ts +++ b/src/engine/core/managers/base/SaveManager.test.ts @@ -1,6 +1,7 @@ import { beforeEach, describe, expect, it, jest } from "@jest/globals"; import { disposeManagers, initializeManager, registerActor, registry } from "@/engine/core/database"; +import { EGameEvent, EventsManager } from "@/engine/core/managers"; import { TAbstractCoreManagerConstructor } from "@/engine/core/managers/base/AbstractCoreManager"; import { SaveManager } from "@/engine/core/managers/base/SaveManager"; import { AchievementsManager } from "@/engine/core/managers/interaction/achievements"; @@ -16,8 +17,9 @@ import { SurgeManager } from "@/engine/core/managers/world/SurgeManager"; import { TreasureManager } from "@/engine/core/managers/world/TreasureManager"; import { WeatherManager } from "@/engine/core/managers/world/WeatherManager"; import { AnyObject } from "@/engine/lib/types"; -import { mockClientGameObject } from "@/fixtures/xray"; -import { mockNetPacket } from "@/fixtures/xray/mocks/save"; +import { MockIoFile } from "@/fixtures/lua"; +import { resetFunctionMock } from "@/fixtures/utils"; +import { mockClientGameObject, mockNetPacket } from "@/fixtures/xray"; describe("SaveManager class", () => { const mockLifecycleMethods = () => { @@ -38,9 +40,10 @@ describe("SaveManager class", () => { beforeEach(() => { disposeManagers(); + resetFunctionMock(io.open); }); - it("Should save and load data from managers in a strict order", () => { + it("should save and load data from managers in a strict order", () => { const expectedOrder: Array = [ WeatherManager, ReleaseBodyManager, @@ -62,18 +65,18 @@ describe("SaveManager class", () => { expect(saveOrder).toEqual([]); expect(loadOrder).toEqual([]); - SaveManager.getInstance().save(mockNetPacket()); + SaveManager.getInstance().clientSave(mockNetPacket()); expect(saveOrder).toEqual(expectedOrder); expect(loadOrder).toEqual([]); - SaveManager.getInstance().load(mockNetPacket()); + SaveManager.getInstance().clientLoad(mockNetPacket()); expect(saveOrder).toEqual(expectedOrder); expect(loadOrder).toEqual(expectedOrder); }); - it("Should read and write data from managers in a strict order", () => { + it("should read and write data from managers in a strict order", () => { registerActor(mockClientGameObject()); const expectedOrder: Array = [SimulationBoardManager]; @@ -85,14 +88,85 @@ describe("SaveManager class", () => { expect(saveOrder).toEqual([]); expect(loadOrder).toEqual([]); - SaveManager.getInstance().writeState(mockNetPacket()); + SaveManager.getInstance().serverSave(mockNetPacket()); expect(saveOrder).toEqual(expectedOrder); expect(loadOrder).toEqual([]); - SaveManager.getInstance().readState(mockNetPacket()); + SaveManager.getInstance().serverLoad(mockNetPacket()); expect(saveOrder).toEqual(expectedOrder); expect(loadOrder).toEqual(expectedOrder); }); + + it("should have implementation base for save callbacks", () => { + const saveManager: SaveManager = SaveManager.getInstance(); + + expect(saveManager.onBeforeGameSave).toBeDefined(); + expect(saveManager.onGameSave).toBeDefined(); + expect(saveManager.onBeforeGameLoad).toBeDefined(); + expect(saveManager.onGameLoad).toBeDefined(); + }); + + it("should properly create dynamic saves", () => { + const saveManager: SaveManager = SaveManager.getInstance(); + const file: MockIoFile = new MockIoFile("test", "wb"); + + const onSave = jest.fn((data: AnyObject) => { + data.example = 123; + }); + + EventsManager.getInstance().registerCallback(EGameEvent.GAME_SAVE, onSave); + + jest.spyOn(io, "open").mockImplementationOnce(() => $multi(file.asMock())); + + saveManager.onBeforeGameSave("test.scop"); + + expect(onSave).toHaveBeenCalledTimes(1); + expect(io.open).toHaveBeenCalledWith("$game_saves$test.scopx", "wb"); + expect(file.write).toHaveBeenCalledWith(JSON.stringify({ generic: { example: 123 }, store: {} })); + expect(file.close).toHaveBeenCalledTimes(1); + }); + + it("should properly load dynamic saves", () => { + const saveManager: SaveManager = SaveManager.getInstance(); + const file: MockIoFile = new MockIoFile("test", "wb"); + + file.content = JSON.stringify({ generic: { example: 123 }, store: {} }); + + const onLoad = jest.fn((data: AnyObject) => { + expect(data).toEqual({ example: 123 }); + }); + + EventsManager.getInstance().registerCallback(EGameEvent.GAME_LOAD, onLoad); + + jest.spyOn(io, "open").mockImplementation(() => $multi(file.asMock())); + + const contentBefore: AnyObject = saveManager.dynamicData; + + saveManager.onBeforeGameLoad("F:\\\\parent\\\\test.scop"); + + expect(marshal.decode).toHaveBeenCalledWith(file.content); + expect(onLoad).toHaveBeenCalledTimes(1); + expect(io.open).toHaveBeenCalledWith("F:\\\\parent\\\\test.scopx", "rb"); + expect(file.read).toHaveBeenCalledTimes(1); + expect(file.close).toHaveBeenCalledTimes(1); + expect(contentBefore).not.toBe(saveManager.dynamicData); + + // In case of empty file data should stay same. + const contentAfter: AnyObject = saveManager.dynamicData; + + file.content = ""; + saveManager.onBeforeGameLoad("F:\\\\parent\\\\test.scop"); + expect(contentAfter).toBe(saveManager.dynamicData); + + file.content = null; + saveManager.onBeforeGameLoad("F:\\\\parent\\\\test.scop"); + expect(contentAfter).toBe(saveManager.dynamicData); + + file.content = "{}"; + file.isOpen = false; + saveManager.onBeforeGameLoad("F:\\\\parent\\\\test.scop"); + expect(contentAfter).toBe(saveManager.dynamicData); + }); }); diff --git a/src/engine/core/managers/base/SaveManager.ts b/src/engine/core/managers/base/SaveManager.ts index 1dad527e9..d78dbf908 100644 --- a/src/engine/core/managers/base/SaveManager.ts +++ b/src/engine/core/managers/base/SaveManager.ts @@ -1,3 +1,4 @@ +import { EGameEvent, EventsManager } from "@/engine/core/managers"; import { AbstractCoreManager } from "@/engine/core/managers/base/AbstractCoreManager"; import { AchievementsManager } from "@/engine/core/managers/interaction/achievements"; import { SimulationBoardManager } from "@/engine/core/managers/interaction/SimulationBoardManager"; @@ -11,20 +12,28 @@ import { ReleaseBodyManager } from "@/engine/core/managers/world/ReleaseBodyMana import { SurgeManager } from "@/engine/core/managers/world/SurgeManager"; import { TreasureManager } from "@/engine/core/managers/world/TreasureManager"; import { WeatherManager } from "@/engine/core/managers/world/WeatherManager"; +import { loadDynamicGameSave, saveDynamicGameSave } from "@/engine/core/utils/game"; import { LuaLogger } from "@/engine/core/utils/logging"; -import { NetPacket, NetProcessor } from "@/engine/lib/types"; +import { AnyObject, NetPacket, NetProcessor, Optional, TName } from "@/engine/lib/types"; const logger: LuaLogger = new LuaLogger($filename); +export interface IDynamicSaveData { + generic: AnyObject; + store: AnyObject; +} + /** * Manage game saves for other managers / parts. */ export class SaveManager extends AbstractCoreManager { + public dynamicData: IDynamicSaveData = { generic: {}, store: {} }; + /** * Save core managers data. */ - public override save(packet: NetPacket): void { - logger.info("Saving"); + public clientSave(packet: NetPacket): void { + logger.info("Saving client"); WeatherManager.getInstance().save(packet); ReleaseBodyManager.getInstance().save(packet); @@ -42,8 +51,8 @@ export class SaveManager extends AbstractCoreManager { /** * Load core managers data. */ - public override load(reader: NetProcessor): void { - logger.info("Loading"); + public clientLoad(reader: NetProcessor): void { + logger.info("Loading client"); WeatherManager.getInstance().load(reader); ReleaseBodyManager.getInstance().load(reader); @@ -61,14 +70,64 @@ export class SaveManager extends AbstractCoreManager { /** * Write state for core managers. */ - public writeState(packet: NetPacket): void { + public serverSave(packet: NetPacket): void { + logger.info("Saving server"); + SimulationBoardManager.getInstance().save(packet); } /** * Read state for core managers. */ - public readState(reader: NetProcessor): void { + public serverLoad(reader: NetProcessor): void { + logger.info("Loading server"); + SimulationBoardManager.getInstance().load(reader); } + + /** + * When game save creation starting. + * + * @param saveName - name of save file, just base name with extension like `example.scop` + */ + public onBeforeGameSave(saveName: TName): void { + logger.info("Before game save:", saveName); + + EventsManager.getInstance().emitEvent(EGameEvent.GAME_SAVE, this.dynamicData.generic); + + saveDynamicGameSave(saveName, this.dynamicData); + } + + /** + * When game saved successfully. + * + * @param saveName - name of save file, just base name with extension like `example.scop` + */ + public onGameSave(saveName: TName): void { + logger.info("On game save:", saveName); + } + + /** + * When game save loading starts. + * + * @param saveName - name of save file, full path with disk/system folders structure + */ + public onBeforeGameLoad(saveName: TName): void { + logger.info("Before game load:", saveName); + + const data: Optional = loadDynamicGameSave(saveName); + + this.dynamicData = data ? data : this.dynamicData; + + EventsManager.getInstance().emitEvent(EGameEvent.GAME_LOAD, this.dynamicData.generic); + } + + /** + * When game save loaded successfully. + * + * @param saveName - name of save file, full path with disk/system folders structure + */ + public onGameLoad(saveName: TName): void { + logger.info("On game load:", saveName); + } } diff --git a/src/engine/core/managers/events/EventsManager.test.ts b/src/engine/core/managers/events/EventsManager.test.ts index dc81d4aa9..ccd293144 100644 --- a/src/engine/core/managers/events/EventsManager.test.ts +++ b/src/engine/core/managers/events/EventsManager.test.ts @@ -13,7 +13,7 @@ describe("EventsManager class", () => { it("should correctly initialize", () => { const manager: EventsManager = getManagerInstance(EventsManager); - expect(MockLuaTable.getMockSize(manager.callbacks)).toBe(29); + expect(MockLuaTable.getMockSize(manager.callbacks)).toBe(31); Object.keys(manager.callbacks).forEach((it) => { expect(MockLuaTable.getMockSize(manager.callbacks[it as unknown as EGameEvent])).toBe(0); diff --git a/src/engine/core/managers/events/types.ts b/src/engine/core/managers/events/types.ts index d716dd411..ad63479ff 100644 --- a/src/engine/core/managers/events/types.ts +++ b/src/engine/core/managers/events/types.ts @@ -120,6 +120,14 @@ export enum EGameEvent { * Game started. */ GAME_STARTED, + /** + * Game state save. + */ + GAME_SAVE, + /** + * Game state load. + */ + GAME_LOAD, } /** diff --git a/src/engine/core/managers/interaction/SimulationBoardManager.ts b/src/engine/core/managers/interaction/SimulationBoardManager.ts index 6a0ace681..0ad1ec4f8 100644 --- a/src/engine/core/managers/interaction/SimulationBoardManager.ts +++ b/src/engine/core/managers/interaction/SimulationBoardManager.ts @@ -303,8 +303,10 @@ export class SimulationBoardManager extends AbstractCoreManager { } if (oldSmartTerrainId !== null && this.smartTerrains.has(oldSmartTerrainId)) { + const smartTerrain: SmartTerrain = this.smartTerrains.get(oldSmartTerrainId).smartTerrain; + this.smartTerrains.get(oldSmartTerrainId).assignedSquads.delete(squad.id); - this.smartTerrains.get(oldSmartTerrainId).smartTerrain.updateMapDisplay(); + smartTerrain.mapDisplayManager.updateSmartTerrainMapSpot(smartTerrain); } if (smartTerrainId === null) { @@ -317,7 +319,7 @@ export class SimulationBoardManager extends AbstractCoreManager { squad.assignSmartTerrain(target.smartTerrain); target.assignedSquads.set(squad.id, squad); - target.smartTerrain.updateMapDisplay(); + target.smartTerrain.mapDisplayManager.updateSmartTerrainMapSpot(target.smartTerrain); } /** diff --git a/src/engine/core/managers/interaction/tasks/types.ts b/src/engine/core/managers/interaction/tasks/types.ts index fe04a5c6f..0ec56cdfa 100644 --- a/src/engine/core/managers/interaction/tasks/types.ts +++ b/src/engine/core/managers/interaction/tasks/types.ts @@ -21,8 +21,11 @@ export enum ETaskStatus { /** * Set of possible task states, where key is state and value is true / null. */ -export const POSSIBLE_STATES: Record = Object.values(ETaskState).reduce((acc, it) => { - acc[it] = true; +export const POSSIBLE_STATES: Record = Object.values(ETaskState).reduce( + (acc, it) => { + acc[it] = true; - return acc; -}, {} as Record); + return acc; + }, + {} as Record +); diff --git a/src/engine/core/managers/interface/MapDisplayManager.ts b/src/engine/core/managers/interface/MapDisplayManager.ts index 04431fb28..f1334cfa1 100644 --- a/src/engine/core/managers/interface/MapDisplayManager.ts +++ b/src/engine/core/managers/interface/MapDisplayManager.ts @@ -9,10 +9,18 @@ import { primaryMapSpotObjects, sleepZones, } from "@/engine/core/managers/interface/MapDisplayManagerObjects"; +import { SmartTerrain, Squad } from "@/engine/core/objects"; import { parseConditionsList, pickSectionFromCondList, readIniString, TConditionList } from "@/engine/core/utils/ini"; import { LuaLogger } from "@/engine/core/utils/logging"; -import { anomalyHasArtefact } from "@/engine/core/utils/object/object_anomaly"; +import { isSquadMonsterCommunity } from "@/engine/core/utils/object"; +import { getAnomalyArtefacts } from "@/engine/core/utils/object/object_anomaly"; import { hasAlifeInfo } from "@/engine/core/utils/object/object_info_portion"; +import { + ERelation, + getSquadMembersRelationToActor, + getSquadMembersRelationToActorSafe, +} from "@/engine/core/utils/relation"; +import { gameConfig } from "@/engine/lib/configs/GameConfig"; import { captions } from "@/engine/lib/constants/captions/captions"; import { infoPortions } from "@/engine/lib/constants/info_portions/info_portions"; import { levels } from "@/engine/lib/constants/levels"; @@ -22,12 +30,14 @@ import { AlifeSimulator, ClientObject, EScheme, + LuaArray, Maybe, Optional, ServerObject, TDistance, TDuration, TLabel, + TName, TNumberId, TSection, TTimestamp, @@ -37,11 +47,11 @@ import { const logger: LuaLogger = new LuaLogger($filename); /** - * todo; + * Manager handling display of objects on game map in PDA. */ export class MapDisplayManager extends AbstractCoreManager { public static readonly DISTANCE_TO_SHOW_MAP_MARKS: TDistance = 75; - public static readonly UPDATES_THROTTLE: TDuration = 10_000; + public static readonly UPDATES_THROTTLE: TDuration = 5_000; public isInitialized: boolean = false; public lastUpdateAt: TTimestamp = 0; @@ -59,7 +69,12 @@ export class MapDisplayManager extends AbstractCoreManager { } /** - * todo: Description. + * Update map display for game object. + * + * @param object - target client object + * @param scheme - active logic scheme + * @param state - target object registry state + * @param section - active logic section */ public updateObjectMapSpot( object: ClientObject, @@ -135,7 +150,10 @@ export class MapDisplayManager extends AbstractCoreManager { } /** - * todo: Description. + * Remove object map spot display. + * + * @param object - target client object + * @param state - target object registry state */ public removeObjectMapSpot(object: ClientObject, state: IRegistryObjectState): void { logger.info("Remove object spot:", object.name()); @@ -176,6 +194,183 @@ export class MapDisplayManager extends AbstractCoreManager { } } + /** + * Update map spot for squad. + * + * @param squad - target squad server object + */ + public updateSquadMapSpot(squad: Squad): void { + const squadCommanderId: TNumberId = squad.commander_id(); + + if (squad.isMapDisplayHidden || squadCommanderId === null) { + return this.removeSquadMapSpot(squad); + } + + if (squad.currentMapSpotId !== squadCommanderId) { + this.removeSquadMapSpot(squad); + squad.currentMapSpotId = squadCommanderId; + this.updateSquadMapSpot(squad); + + return; + } + + if ( + level.map_has_object_spot(squadCommanderId, mapMarks.ui_pda2_trader_location) !== 0 || + level.map_has_object_spot(squadCommanderId, mapMarks.ui_pda2_mechanic_location) !== 0 || + level.map_has_object_spot(squadCommanderId, mapMarks.ui_pda2_scout_location) !== 0 || + level.map_has_object_spot(squadCommanderId, mapMarks.ui_pda2_quest_npc_location) !== 0 || + level.map_has_object_spot(squadCommanderId, mapMarks.ui_pda2_medic_location) !== 0 + ) { + squad.isMapDisplayHidden = true; + + return; + } + + let spot: Optional = null; + + /** + * In case of debug use map display like in clear sky. + */ + if (gameConfig.DEBUG.IS_SIMULATION_DEBUG_ENABLED) { + if (isSquadMonsterCommunity(squad.faction)) { + spot = mapMarks.alife_presentation_squad_monster_debug; + } else { + const relation: ERelation = getSquadMembersRelationToActorSafe(squad); + + switch (relation) { + case ERelation.FRIEND: + spot = mapMarks.alife_presentation_squad_friend_debug; + break; + case ERelation.NEUTRAL: + spot = mapMarks.alife_presentation_squad_neutral_debug; + break; + case ERelation.ENEMY: + spot = mapMarks.alife_presentation_squad_enemy_debug; + break; + } + } + /** + * Display only minimap marks. + * Do not display for offline objects. + */ + } else if (!isSquadMonsterCommunity(squad.faction)) { + const relation: Optional = getSquadMembersRelationToActor(squad); + + switch (relation) { + case ERelation.FRIEND: + spot = mapMarks.alife_presentation_squad_friend; + break; + + case ERelation.NEUTRAL: + spot = mapMarks.alife_presentation_squad_neutral; + break; + } + } + + if (spot) { + const hint: TLabel = squad.getMapDisplayHint(); + const hasMapSpot: boolean = level.map_has_object_spot(squad.currentMapSpotId, spot) === 1; + + if (spot === squad.currentMapSpotSection && hasMapSpot) { + return level.map_change_spot_hint(squad.currentMapSpotId, spot, hint); + } + + if (squad.currentMapSpotSection === null || !hasMapSpot) { + level.map_add_object_spot(squad.currentMapSpotId, spot, hint); + } else { + level.map_remove_object_spot(squad.currentMapSpotId, squad.currentMapSpotSection); + level.map_add_object_spot(squad.currentMapSpotId, spot, hint); + } + + squad.currentMapSpotSection = spot; + } else if (squad.currentMapSpotSection) { + level.map_remove_object_spot(squad.currentMapSpotId, squad.currentMapSpotSection); + squad.currentMapSpotSection = null; + } + } + + /** + * Remove map spot for squad. + * + * @param squad - target squad server object + */ + public removeSquadMapSpot(squad: Squad): void { + if (squad.currentMapSpotId === null || squad.currentMapSpotSection === null) { + return; + } + + level.map_remove_object_spot(squad.currentMapSpotId, squad.currentMapSpotSection); + + squad.currentMapSpotId = null; + squad.currentMapSpotSection = null; + } + + /** + * todo: Description. + */ + public updateSmartTerrainMapSpot(smartTerrain: SmartTerrain): void { + /** + * If debug enabled, render map spots. + */ + if (gameConfig.DEBUG.IS_SIMULATION_DEBUG_ENABLED) { + let spot: ERelation = ERelation.NEUTRAL; + + if ( + smartTerrain.isSimulationAvailableConditionList === null || + pickSectionFromCondList(registry.actor, smartTerrain, smartTerrain.isSimulationAvailableConditionList) === TRUE + ) { + spot = ERelation.FRIEND; + } else { + spot = ERelation.ENEMY; + } + + const previousSelector: TName = string.format( + "alife_presentation_smart_%s_%s", + smartTerrain.simulationRole, + smartTerrain.smartTerrainDisplayedMapSpot + ); + + if (smartTerrain.smartTerrainDisplayedMapSpot === spot) { + level.map_change_spot_hint(smartTerrain.id, previousSelector, smartTerrain.getMapDisplayHint()); + + return; + } + + // If previous mark is defined. + if (smartTerrain.smartTerrainDisplayedMapSpot !== null) { + level.map_remove_object_spot(smartTerrain.id, previousSelector); + } + + // If next mark is defined. + if (spot !== null) { + const nextSelector: TName = string.format("alife_presentation_smart_%s_%s", smartTerrain.simulationRole, spot); + + level.map_add_object_spot(smartTerrain.id, nextSelector, smartTerrain.getMapDisplayHint()); + } + + smartTerrain.smartTerrainDisplayedMapSpot = spot; + + return; + } + + /** + * If not enabled rendering, just remove map spot if needed. + */ + if ( + smartTerrain.smartTerrainDisplayedMapSpot !== null && + level.map_has_object_spot( + smartTerrain.id, + "alife_presentation_smart_" + smartTerrain.simulationRole + "_" + smartTerrain.smartTerrainDisplayedMapSpot + ) + ) { + level.map_remove_object_spot( + smartTerrain.id, + "alife_presentation_smart_" + smartTerrain.simulationRole + "_" + smartTerrain.smartTerrainDisplayedMapSpot + ); + smartTerrain.smartTerrainDisplayedMapSpot = null; + } + } + /** * todo: Description. */ @@ -192,6 +387,20 @@ export class MapDisplayManager extends AbstractCoreManager { this.updateSleepZonesDisplay(); } + /** + * todo: Description. + */ + public removeSmartTerrainMapSpot(smartTerrain: SmartTerrain): void { + if (smartTerrain.smartTerrainDisplayedMapSpot === null) { + return; + } + + level.map_remove_object_spot( + smartTerrain.id, + "alife_presentation_smart_" + smartTerrain.simulationRole + "_" + smartTerrain.smartTerrainDisplayedMapSpot + ); + } + /** * todo: Description. */ @@ -234,11 +443,9 @@ export class MapDisplayManager extends AbstractCoreManager { const objectId: Optional = getObjectIdByStoryId(scanner.target); let hint: TLabel = game.translate_string(scanner.hint) + "\\n" + " \\n"; - const actor: ClientObject = registry.actor; + const artefactTable: LuaArray = getAnomalyArtefacts(scanner.zone); - const [hasArtefact, artefactTable] = anomalyHasArtefact(actor, null, scanner.zone, null); - - if (hasArtefact) { + if (artefactTable.length() > 0) { hint = hint + game.translate_string(captions.st_jup_b32_has_af); for (const [k, v] of artefactTable!) { hint = hint + "\\n" + game.translate_string("st_" + v + "_name"); @@ -260,7 +467,7 @@ export class MapDisplayManager extends AbstractCoreManager { } /** - * todo: Description. + * Handle update tick for map display. */ public override update(): void { const now: TTimestamp = time_global(); diff --git a/src/engine/core/managers/world/DropManager.ts b/src/engine/core/managers/world/DropManager.ts index 476dea526..d56aa86cf 100644 --- a/src/engine/core/managers/world/DropManager.ts +++ b/src/engine/core/managers/world/DropManager.ts @@ -171,6 +171,7 @@ export class DropManager extends AbstractCoreManager { /** * todo; + * * @param object - target object to create release items. */ public createCorpseReleaseItems(object: ClientObject): void { diff --git a/src/engine/core/managers/world/WeatherManager.ts b/src/engine/core/managers/world/WeatherManager.ts index 28f9ace14..984a97e83 100644 --- a/src/engine/core/managers/world/WeatherManager.ts +++ b/src/engine/core/managers/world/WeatherManager.ts @@ -244,6 +244,7 @@ export class WeatherManager extends AbstractCoreManager { /** * Transform current state into string. + * * @returns string containing level states, example: `dynamic_default=clear,cloudy;another=cloudy,rainy` */ public getStateAsString(): string { diff --git a/src/engine/core/objects/binders/creature/ActorBinder.ts b/src/engine/core/objects/binders/creature/ActorBinder.ts index 441891f4f..7eed2465d 100644 --- a/src/engine/core/objects/binders/creature/ActorBinder.ts +++ b/src/engine/core/objects/binders/creature/ActorBinder.ts @@ -5,12 +5,14 @@ import { closeSaveMarker, destroyPortableStore, initializePortableStore, + loadPortableStore, + openLoadMarker, openSaveMarker, + registerActor, registry, + savePortableStore, + unregisterActor, } from "@/engine/core/database"; -import { registerActor, unregisterActor } from "@/engine/core/database/actor"; -import { loadPortableStore, savePortableStore } from "@/engine/core/database/portable_store"; -import { openLoadMarker } from "@/engine/core/database/save_markers"; import { updateSimulationObjectAvailability } from "@/engine/core/database/simulation"; import { SaveManager } from "@/engine/core/managers/base/SaveManager"; import { EventsManager } from "@/engine/core/managers/events/EventsManager"; @@ -144,16 +146,14 @@ export class ActorBinder extends object_binder { } public override save(packet: NetPacket): void { - logger.info("Save"); - openSaveMarker(packet, ActorBinder.__name); super.save(packet); savePortableStore(this.object, packet); - SaveManager.getInstance().save(packet); + SaveManager.getInstance().clientSave(packet); - // todo: Move out deimos logic. + // todo: Move out deimos logic. Probably store in pstore? let isDeimosExisting: boolean = false; for (const [id, zone] of registry.zones) { @@ -175,8 +175,6 @@ export class ActorBinder extends object_binder { } public override load(reader: Reader): void { - logger.info("Load"); - this.isFirstUpdatePerformed = false; openLoadMarker(reader, ActorBinder.__name); @@ -184,7 +182,7 @@ export class ActorBinder extends object_binder { super.load(reader); loadPortableStore(this.object, reader); - SaveManager.getInstance().load(reader); + SaveManager.getInstance().clientLoad(reader); // todo: Move out deimos logic. const hasDeimos: boolean = reader.r_bool(); diff --git a/src/engine/core/objects/binders/creature/CrowBinder.ts b/src/engine/core/objects/binders/creature/CrowBinder.ts index 299e83560..509f2fe92 100644 --- a/src/engine/core/objects/binders/creature/CrowBinder.ts +++ b/src/engine/core/objects/binders/creature/CrowBinder.ts @@ -3,14 +3,15 @@ import { alife, callback, LuabindClass, object_binder, time_global } from "xray1 import { closeLoadMarker, closeSaveMarker, + loadObjectLogic, + openLoadMarker, openSaveMarker, registerObject, registry, resetObject, + saveObjectLogic, unregisterObject, } from "@/engine/core/database"; -import { loadObjectLogic, saveObjectLogic } from "@/engine/core/database/logic"; -import { openLoadMarker } from "@/engine/core/database/save_markers"; import { LuaLogger } from "@/engine/core/utils/logging"; import { logicsConfig } from "@/engine/lib/configs/LogicsConfig"; import { diff --git a/src/engine/core/objects/binders/zones/AnomalyZoneBinder.ts b/src/engine/core/objects/binders/zones/AnomalyZoneBinder.ts index a530ee020..74b4087d3 100644 --- a/src/engine/core/objects/binders/zones/AnomalyZoneBinder.ts +++ b/src/engine/core/objects/binders/zones/AnomalyZoneBinder.ts @@ -457,7 +457,7 @@ export class AnomalyZoneBinder extends object_binder { this.artefactWaysByArtefactId.set(artefactObject.id, randomPathName); this.artefactPointsByArtefactId.set(artefactObject.id, randomPathPoint); - this.spawnedArtefactsCount = this.spawnedArtefactsCount + 1; + this.spawnedArtefactsCount += 1; logger.info("Spawned random artefact:", randomArtefact, artefactObject.id); } diff --git a/src/engine/core/objects/server/creature/Actor.ts b/src/engine/core/objects/server/creature/Actor.ts index bea066c30..0cce4a7d0 100644 --- a/src/engine/core/objects/server/creature/Actor.ts +++ b/src/engine/core/objects/server/creature/Actor.ts @@ -32,6 +32,7 @@ import { Optional, ServerCreatureObject, TNumberId, + TSize, Vector, } from "@/engine/lib/types"; @@ -70,15 +71,15 @@ export class Actor extends cse_alife_creature_actor implements ISimulationTarget super.STATE_Write(packet); openSaveMarker(packet, Actor.__name); - SaveManager.getInstance().writeState(packet); + SaveManager.getInstance().serverSave(packet); closeSaveMarker(packet, Actor.__name); } - public override STATE_Read(packet: NetPacket, size: number): void { + public override STATE_Read(packet: NetPacket, size: TSize): void { super.STATE_Read(packet, size); openLoadMarker(packet, Actor.__name); - SaveManager.getInstance().readState(packet); + SaveManager.getInstance().serverLoad(packet); closeLoadMarker(packet, Actor.__name); } diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_anim_pri_a22.ts b/src/engine/core/objects/server/smart_cover/smart_covers_anim_pri_a22.ts index 41cd6a164..ea5aa4413 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_anim_pri_a22.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_anim_pri_a22.ts @@ -4,6 +4,9 @@ import { ISmartCoverDescriptor } from "@/engine/core/objects/server/smart_cover/ import { getAnimPriA22Loophole } from "@/engine/core/objects/server/smart_cover/smart_covers_loophole_anim_pri_a22"; import { createEmptyVector, createVector } from "@/engine/core/utils/vector"; +/** + * todo; + */ export function getSmartCoverAnimPriA22(): ISmartCoverDescriptor { return { need_weapon: false, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_pri_a15.ts b/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_pri_a15.ts index 98fd10769..ab7d0c299 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_pri_a15.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_pri_a15.ts @@ -4,6 +4,9 @@ import { ISmartCoverDescriptor } from "@/engine/core/objects/server/smart_cover/ import { getAnimpointPriA15Loophole } from "@/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_pri_a15"; import { createVector } from "@/engine/core/utils/vector"; +/** + * todo; + */ export function getSmartCoverAnimpointPriA15(): ISmartCoverDescriptor { return { need_weapon: false, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_sit_high.ts b/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_sit_high.ts index 2a40dc492..3d24dc830 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_sit_high.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_sit_high.ts @@ -4,6 +4,9 @@ import { ISmartCoverDescriptor } from "@/engine/core/objects/server/smart_cover/ import { getAnimpointSitHighLoophole } from "@/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_high"; import { createVector } from "@/engine/core/utils/vector"; +/** + * todo; + */ export function getSmartCoverAnimpointSitHigh(): ISmartCoverDescriptor { return { need_weapon: false, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_sit_low.ts b/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_sit_low.ts index 5e6dd6cb3..8cd1550b8 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_sit_low.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_sit_low.ts @@ -4,6 +4,9 @@ import { ISmartCoverDescriptor } from "@/engine/core/objects/server/smart_cover/ import { getAnimpointSitLowLoophole } from "@/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_low"; import { createVector } from "@/engine/core/utils/vector"; +/** + * todo; + */ export function getSmartCoverAnimpointSitLow(): ISmartCoverDescriptor { return { need_weapon: false, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_sit_normal.ts b/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_sit_normal.ts index 49c5694fb..0c3428c96 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_sit_normal.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_sit_normal.ts @@ -5,6 +5,9 @@ import { ISmartCoverDescriptor } from "@/engine/core/objects/server/smart_cover/ import { getAnimpointSitNormalLoophole } from "@/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_normal"; import { createVector } from "@/engine/core/utils/vector"; +/** + * todo; + */ export function getSmartCoverAnimpointSitNormal(): ISmartCoverDescriptor { return { need_weapon: false, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_stay_table.ts b/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_stay_table.ts index ff43a07b9..44cd2b656 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_stay_table.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_stay_table.ts @@ -5,6 +5,9 @@ import { ISmartCoverDescriptor } from "@/engine/core/objects/server/smart_cover/ import { getAnimpointStayTableLoophole } from "@/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_stay_table"; import { createVector } from "@/engine/core/utils/vector"; +/** + * todo; + */ export function getSmartCoverAnimpointStayTable(): ISmartCoverDescriptor { return { need_weapon: false, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_stay_wall.ts b/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_stay_wall.ts index 4088c5a56..4f5db4ceb 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_stay_wall.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_animpoint_stay_wall.ts @@ -4,6 +4,9 @@ import { ISmartCoverDescriptor } from "@/engine/core/objects/server/smart_cover/ import { getAnimpointStayWallLoophole } from "@/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_stay_wall"; import { createVector } from "@/engine/core/utils/vector"; +/** + * todo; + */ export function getSmartCoverAnimpointStayWall(): ISmartCoverDescriptor { return { need_weapon: false, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_combat.ts b/src/engine/core/objects/server/smart_cover/smart_covers_combat.ts index 64c754363..99e59889b 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_combat.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_combat.ts @@ -13,6 +13,9 @@ import { getStandLeftLoophole } from "@/engine/core/objects/server/smart_cover/s import { getStandRightLoophole } from "@/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_right"; import { createVector } from "@/engine/core/utils/vector"; +/** + * todo; + */ function getSmartCoverCombat(): ISmartCoverDescriptor { return { need_weapon: true, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_combat_front.ts b/src/engine/core/objects/server/smart_cover/smart_covers_combat_front.ts index 6dfe341b5..48a60e3b7 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_combat_front.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_combat_front.ts @@ -8,6 +8,9 @@ import { getStandFrontLeftLoophole } from "@/engine/core/objects/server/smart_co import { getStandFrontRightLoophole } from "@/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_front_right"; import { createVector } from "@/engine/core/utils/vector"; +/** + * + */ export function getSmartCoverCombatFront(): ISmartCoverDescriptor { return { need_weapon: true, @@ -500,7 +503,7 @@ export function getSmartCoverCombatFront(): ISmartCoverDescriptor { vertex1: "", weight: 1.1, actions: [ - /** ### { + /* ### { precondition_functor: "xr_conditions.always", precondition_params: "", @@ -531,7 +534,8 @@ export function getSmartCoverCombatFront(): ISmartCoverDescriptor { vertex1: "", weight: 1.1, actions: [ - /** ### { + /** + ### { precondition_functor: "xr_conditions.always", precondition_params: "", actions = { @@ -541,7 +545,8 @@ export function getSmartCoverCombatFront(): ISmartCoverDescriptor { body_state: move.crouch, movement_type: move.run, }, }, - },*/ + }, + */ { precondition_functor: "xr_conditions.always", precondition_params: "", @@ -561,7 +566,8 @@ export function getSmartCoverCombatFront(): ISmartCoverDescriptor { vertex1: "", weight: 1.1, actions: [ - /** ### { + /* + ### { precondition_functor: "xr_conditions.always", precondition_params: "", actions = { @@ -571,7 +577,8 @@ export function getSmartCoverCombatFront(): ISmartCoverDescriptor { body_state: move.crouch, movement_type: move.run, }, }, - },*/ + }, + */ { precondition_functor: "xr_conditions.always", precondition_params: "", diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_combat_prone.ts b/src/engine/core/objects/server/smart_cover/smart_covers_combat_prone.ts index 5823e31eb..cc2aeaafe 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_combat_prone.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_combat_prone.ts @@ -5,6 +5,9 @@ import { createVector } from "@/engine/core/utils/vector"; import { getProneLoophole } from "./smart_covers_loophole_prone"; +/** + * todo; + */ export function getSmartCoverCombatProne(): ISmartCoverDescriptor { return { loopholes: [getProneLoophole("prone", createVector(-1, 0, 0))] as any, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_anim_pri_a22.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_anim_pri_a22.ts index 8d3fa1b69..ad12472fc 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_anim_pri_a22.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_anim_pri_a22.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getAnimPriA22Loophole( id: TStringId, position: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_pri_a15.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_pri_a15.ts index 3c87b2377..60dae4535 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_pri_a15.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_pri_a15.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getAnimpointPriA15Loophole( id: string, position: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_high.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_high.ts index 87ba63333..16ba396b4 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_high.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_high.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getAnimpointSitHighLoophole( id: string, position: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_low.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_low.ts index e17fa8b4f..c874bddb1 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_low.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_low.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getAnimpointSitLowLoophole( id: TStringId, position: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_normal.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_normal.ts index 5d180b1f0..9f318eb1a 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_normal.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_sit_normal.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getAnimpointSitNormalLoophole( id: TStringId, position: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_stay_table.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_stay_table.ts index 7480fbc2c..3152df35f 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_stay_table.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_stay_table.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getAnimpointStayTableLoophole( id: TStringId, position: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_stay_wall.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_stay_wall.ts index 5bfc57021..e25391023 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_stay_wall.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_animpoint_stay_wall.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getAnimpointStayWallLoophole( id: TStringId, position: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_back.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_back.ts index a6ff48284..604439d3f 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_back.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_back.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createEmptyVector, createVector } from "@/engine/core/utils/vector"; import { Optional, TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getCrouchBackLoophole( id: TStringId, fovDirection: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_front.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_front.ts index 7767b62ab..cb2ce17c0 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_front.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_front.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { Optional, TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getCrouchFrontLoophole( id: TStringId, fovDirection: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_front_left.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_front_left.ts index f4588d86e..f263306a2 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_front_left.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_front_left.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { Optional, TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getCrouchFrontLeftLoophole( id: TStringId, fovDirection: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_front_right.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_front_right.ts index aca09d0f1..11859e54f 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_front_right.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_front_right.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { Optional, TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getCrouchFrontRightLoophole( id: TStringId, fovDirection: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_left.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_left.ts index 37dda8a85..8fe800b6b 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_left.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_left.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createEmptyVector, createVector } from "@/engine/core/utils/vector"; import { Optional, TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getCrouchLeftLoophole( id: TStringId, fovDirection: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_right.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_right.ts index 46ec2b62c..c19a31db9 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_right.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_crouch_right.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createEmptyVector, createVector } from "@/engine/core/utils/vector"; import { TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getCrouchRightLoophole( id: TStringId, fovDirection: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_prone.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_prone.ts index e57dee14e..d6f946c19 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_prone.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_prone.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { Optional, TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getProneLoophole( id: TStringId, fovDirection: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_back.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_back.ts index 60d41952c..41f3f2146 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_back.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_back.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { Optional, TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getStandBackLoophole( id: TStringId, fovDirection: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_front_left.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_front_left.ts index aa902c3d1..a46fca60e 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_front_left.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_front_left.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { Optional, TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getStandFrontLeftLoophole( id: TStringId, fovDirection: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_front_right.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_front_right.ts index 110c9dbfc..4a1e86a61 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_front_right.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_front_right.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { Optional, TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getStandFrontRightLoophole( id: TStringId, fovDirection: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_left.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_left.ts index dbbe968bf..6f658702c 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_left.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_left.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { Optional, TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getStandLeftLoophole( id: TStringId, fovDirection: Vector, diff --git a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_right.ts b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_right.ts index f654c8e31..2c58004c8 100644 --- a/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_right.ts +++ b/src/engine/core/objects/server/smart_cover/smart_covers_loophole_stand_right.ts @@ -2,6 +2,9 @@ import { ISmartCoverLoopholeDescriptor } from "@/engine/core/objects/server/smar import { createVector } from "@/engine/core/utils/vector"; import { Optional, TStringId, Vector } from "@/engine/lib/types"; +/** + * todo; + */ export function getStandRightLoophole( id: TStringId, fovDirection: Vector, diff --git a/src/engine/core/objects/server/smart_terrain/SmartTerrain.ts b/src/engine/core/objects/server/smart_terrain/SmartTerrain.ts index 54770b0e8..b15890fbf 100644 --- a/src/engine/core/objects/server/smart_terrain/SmartTerrain.ts +++ b/src/engine/core/objects/server/smart_terrain/SmartTerrain.ts @@ -32,6 +32,7 @@ import { updateSimulationObjectAvailability, } from "@/engine/core/database/simulation"; import { SimulationBoardManager } from "@/engine/core/managers/interaction/SimulationBoardManager"; +import { MapDisplayManager } from "@/engine/core/managers/interface"; import { areOnlyMonstersOnJobs, jobIterator, @@ -115,17 +116,17 @@ import { const logger: LuaLogger = new LuaLogger($filename); -export const path_fields: LuaArray = $fromArray(["path_walk", "path_main", "path_home", "center_point"]); +export const PATH_FIELDS: LuaArray = $fromArray(["path_walk", "path_main", "path_home", "center_point"]); /** * todo; */ -export const valid_territory: LuaTable = { +export const VALID_SMART_TERRAINS_SIMULATION_ROLES: LuaTable = $fromObject({ default: true, base: true, resource: true, territory: true, -} as any; +}); /** * todo; @@ -201,7 +202,8 @@ export class SmartTerrain extends cse_alife_smart_zone implements ISimulationTar public jobDeadTimeById: LuaTable = new LuaTable(); // job id -> time public simulationProperties!: AnyObject; - public simulationBoardManager!: SimulationBoardManager; + public simulationBoardManager: SimulationBoardManager = SimulationBoardManager.getInstance(); + public mapDisplayManager: MapDisplayManager = MapDisplayManager.getInstance(); public respawnConfiguration!: LuaTable; num: TConditionList }>; public alreadySpawned!: LuaTable; @@ -209,7 +211,6 @@ export class SmartTerrain extends cse_alife_smart_zone implements ISimulationTar public override on_before_register(): void { super.on_before_register(); - this.simulationBoardManager = SimulationBoardManager.getInstance(); this.simulationBoardManager.registerSmartTerrain(this); this.level = alife().level_name(game_graph().vertex(this.m_game_vertex_id).level_id()); } @@ -221,7 +222,7 @@ export class SmartTerrain extends cse_alife_smart_zone implements ISimulationTar registerSimulationObject(this); if (gameConfig.DEBUG.IS_SIMULATION_DEBUG_ENABLED) { - this.updateMapDisplay(); + this.mapDisplayManager.updateSmartTerrainMapSpot(this); } this.smartTerrainAlifeTask = new CALifeSmartTerrainTask(this.m_game_vertex_id, this.m_level_vertex_id); @@ -492,8 +493,8 @@ export class SmartTerrain extends cse_alife_smart_zone implements ISimulationTar public override update(): void { super.update(); - if (gameConfig.DEBUG.IS_SIMULATION_DEBUG_ENABLED || this.smartTerrainDisplayedMapSpot !== null) { - this.updateMapDisplay(); + if (this.smartTerrainDisplayedMapSpot !== null || gameConfig.DEBUG.IS_SIMULATION_DEBUG_ENABLED) { + this.mapDisplayManager.updateSmartTerrainMapSpot(this); } const now: TTimestamp = time_global(); @@ -586,7 +587,7 @@ export class SmartTerrain extends cse_alife_smart_zone implements ISimulationTar ESimulationTerrainRole.DEFAULT ) as ESimulationTerrainRole; - if (valid_territory.get(this.simulationRole) === null) { + if (VALID_SMART_TERRAINS_SIMULATION_ROLES.get(this.simulationRole) === null) { abort("Wrong sim_type value [%s] in smart [%s]", this.simulationRole, this.name()); } @@ -792,7 +793,7 @@ export class SmartTerrain extends cse_alife_smart_zone implements ISimulationTar if (job.job_type === "path_job") { let path_field: string = ""; - for (const [i, vv] of path_fields) { + for (const [i, vv] of PATH_FIELDS) { if (ltx.line_exist(active_section, vv)) { path_field = vv; break; @@ -1130,90 +1131,6 @@ export class SmartTerrain extends cse_alife_smart_zone implements ISimulationTar } } - /** - * todo: Description. - */ - public updateMapDisplay(): void { - /** - * If debug enabled, render map spots. - */ - if (gameConfig.DEBUG.IS_SIMULATION_DEBUG_ENABLED) { - let spot: ERelation = ERelation.NEUTRAL; - - if ( - this.isSimulationAvailableConditionList === null || - pickSectionFromCondList(registry.actor, this, this.isSimulationAvailableConditionList) === TRUE - ) { - spot = ERelation.FRIEND; - } else { - spot = ERelation.ENEMY; - } - - const previousSelector: TName = string.format( - "alife_presentation_smart_%s_%s", - tostring(this.simulationRole), - tostring(this.smartTerrainDisplayedMapSpot) - ); - - if (this.smartTerrainDisplayedMapSpot === spot) { - level.map_change_spot_hint(this.id, previousSelector, this.getMapDisplayHint()); - - return; - } - - // If previous mark is defined. - if (this.smartTerrainDisplayedMapSpot !== null) { - level.map_remove_object_spot(this.id, previousSelector); - } - - // If next mark is defined. - if (spot !== null) { - const nextSelector: TName = string.format( - "alife_presentation_smart_%s_%s", - tostring(this.simulationRole), - tostring(spot) - ); - - level.map_add_object_spot(this.id, nextSelector, this.getMapDisplayHint()); - } - - this.smartTerrainDisplayedMapSpot = spot; - - return; - } - - /** - * If not enabled rendering, just remove map spot if needed. - */ - if ( - this.smartTerrainDisplayedMapSpot !== null && - level.map_has_object_spot( - this.id, - "alife_presentation_smart_" + this.simulationRole + "_" + this.smartTerrainDisplayedMapSpot - ) - ) { - level.map_remove_object_spot( - this.id, - "alife_presentation_smart_" + this.simulationRole + "_" + this.smartTerrainDisplayedMapSpot - ); - this.smartTerrainDisplayedMapSpot = null; - } - } - - /** - * todo: Description. - */ - public hide(): void { - if (this.smartTerrainDisplayedMapSpot === null) { - return; - } - - level.map_remove_object_spot( - this.id, - "alife_presentation_smart_" + this.simulationRole + "_" + this.smartTerrainDisplayedMapSpot - ); - } - /** * Trigger smart terrain alarm. */ diff --git a/src/engine/core/objects/server/squad/Squad.ts b/src/engine/core/objects/server/squad/Squad.ts index c1936029f..507f70947 100644 --- a/src/engine/core/objects/server/squad/Squad.ts +++ b/src/engine/core/objects/server/squad/Squad.ts @@ -29,6 +29,7 @@ import { } from "@/engine/core/database/simulation"; import { unregisterStoryLinkByObjectId } from "@/engine/core/database/story_objects"; import { SimulationBoardManager } from "@/engine/core/managers/interaction/SimulationBoardManager"; +import { MapDisplayManager } from "@/engine/core/managers/interface/MapDisplayManager"; import type { SmartTerrain } from "@/engine/core/objects/server/smart_terrain/SmartTerrain"; import { ESmartTerrainStatus } from "@/engine/core/objects/server/smart_terrain/types"; import { SquadReachTargetAction, SquadStayOnTargetAction } from "@/engine/core/objects/server/squad/action"; @@ -53,25 +54,17 @@ import { TConditionList, } from "@/engine/core/utils/ini"; import { LuaLogger } from "@/engine/core/utils/logging"; -import { areObjectsOnSameLevel, hasAlifeInfo, isSquadMonsterCommunity } from "@/engine/core/utils/object"; -import { - areCommunitiesEnemies, - ERelation, - getSquadMembersRelationToActor, - getSquadMembersRelationToActorSafe, - setObjectSympathy, -} from "@/engine/core/utils/relation"; +import { areObjectsOnSameLevel, hasAlifeInfo } from "@/engine/core/utils/object"; +import { areCommunitiesEnemies, ERelation, setObjectSympathy } from "@/engine/core/utils/relation"; import { isEmpty } from "@/engine/core/utils/table"; import { gameConfig } from "@/engine/lib/configs/GameConfig"; import { squadCommunityByBehaviour } from "@/engine/lib/constants/behaviours"; import { communities, TCommunity } from "@/engine/lib/constants/communities"; import { infoPortions } from "@/engine/lib/constants/info_portions"; -import { mapMarks } from "@/engine/lib/constants/map_marks"; import { MAX_U16 } from "@/engine/lib/constants/memory"; import { SMART_TERRAIN_SECTION } from "@/engine/lib/constants/sections"; import { FALSE, NIL, TRUE } from "@/engine/lib/constants/words"; import { - AlifeSimulator, ALifeSmartTerrainTask, AnyObject, ClientObject, @@ -93,7 +86,7 @@ import { TSection } from "@/engine/lib/types/scheme"; const logger: LuaLogger = new LuaLogger($filename); /** - * todo; + * Server object implementation for squad groups. */ @LuabindClass() export class Squad extends cse_alife_online_offline_group implements ISimulationTarget { @@ -110,6 +103,7 @@ export class Squad extends cse_alife_online_offline_group implements ISimulation public assignedSmartTerrainId: Optional = null; public enteredSmartTerrainId: Optional = null; + public mapDisplayManager: MapDisplayManager = MapDisplayManager.getInstance(); public simulationBoardManager: SimulationBoardManager = SimulationBoardManager.getInstance(); public simulationProperties!: AnyObject; @@ -150,7 +144,7 @@ export class Squad extends cse_alife_online_offline_group implements ISimulation public override update(): void { super.update(); - this.refreshMapDisplay(); + this.mapDisplayManager.updateSquadMapSpot(this); updateSimulationObjectAvailability(this); @@ -545,7 +539,7 @@ export class Squad extends cse_alife_online_offline_group implements ISimulation } } - this.hideMapDisplay(); + this.mapDisplayManager.removeSquadMapSpot(this); } /** @@ -574,7 +568,7 @@ export class Squad extends cse_alife_online_offline_group implements ISimulation return; } - this.refreshMapDisplay(); + this.mapDisplayManager.updateSquadMapSpot(this); } /** @@ -803,7 +797,7 @@ export class Squad extends cse_alife_online_offline_group implements ISimulation } this.assignedSmartTerrainId = spawnSmartTerrain.id; - this.refreshMapDisplay(); + this.mapDisplayManager.updateSquadMapSpot(this); } /** @@ -874,124 +868,6 @@ export class Squad extends cse_alife_online_offline_group implements ISimulation return squadCommunity; } - /** - * todo: Description. - */ - public refreshMapDisplay(): void { - if (this.commander_id() === null) { - return this.hideMapDisplay(); - } - - this.updateMapDisplay(); - } - - /** - * todo: Description. - */ - public hideMapDisplay(): void { - if (this.currentMapSpotId === null || this.currentMapSpotSection === null) { - return; - } - - level.map_remove_object_spot(this.currentMapSpotId, this.currentMapSpotSection); - - this.currentMapSpotId = null; - this.currentMapSpotSection = null; - } - - /** - * todo: Description. - */ - public updateMapDisplay(): void { - if (this.isMapDisplayHidden) { - return this.hideMapDisplay(); - } - - const squadCommanderId: TNumberId = this.commander_id(); - - if (this.currentMapSpotId !== squadCommanderId) { - this.hideMapDisplay(); - this.currentMapSpotId = squadCommanderId; - this.updateMapDisplay(); - - return; - } - - if ( - level.map_has_object_spot(squadCommanderId, mapMarks.ui_pda2_trader_location) !== 0 || - level.map_has_object_spot(squadCommanderId, mapMarks.ui_pda2_mechanic_location) !== 0 || - level.map_has_object_spot(squadCommanderId, mapMarks.ui_pda2_scout_location) !== 0 || - level.map_has_object_spot(squadCommanderId, mapMarks.ui_pda2_quest_npc_location) !== 0 || - level.map_has_object_spot(squadCommanderId, mapMarks.ui_pda2_medic_location) !== 0 - ) { - this.isMapDisplayHidden = true; - - return; - } - - let spot: Optional = null; - - /** - * In case of debug use map display like in clear sky. - */ - if (gameConfig.DEBUG.IS_SIMULATION_DEBUG_ENABLED) { - if (isSquadMonsterCommunity(this.faction)) { - spot = mapMarks.alife_presentation_squad_monster_debug; - } else { - const relation: ERelation = getSquadMembersRelationToActorSafe(this); - - switch (relation) { - case ERelation.FRIEND: - spot = mapMarks.alife_presentation_squad_friend_debug; - break; - case ERelation.NEUTRAL: - spot = mapMarks.alife_presentation_squad_neutral_debug; - break; - case ERelation.ENEMY: - spot = mapMarks.alife_presentation_squad_enemy_debug; - break; - } - } - /** - * Display only minimap marks. - * Do not display for offline objects. - */ - } else if (!isSquadMonsterCommunity(this.faction)) { - const relation: Optional = getSquadMembersRelationToActor(this); - - switch (relation) { - case ERelation.FRIEND: - spot = mapMarks.alife_presentation_squad_friend; - break; - - case ERelation.NEUTRAL: - spot = mapMarks.alife_presentation_squad_neutral; - break; - } - } - - if (spot) { - const hint: TLabel = this.getMapDisplayHint(); - const hasMapSpot: boolean = level.map_has_object_spot(this.currentMapSpotId, spot) === 1; - - if (spot === this.currentMapSpotSection && hasMapSpot) { - return level.map_change_spot_hint(this.currentMapSpotId, spot, hint); - } - - if (this.currentMapSpotSection === null || !hasMapSpot) { - level.map_add_object_spot(this.currentMapSpotId, spot, hint); - } else { - level.map_remove_object_spot(this.currentMapSpotId, this.currentMapSpotSection); - level.map_add_object_spot(this.currentMapSpotId, spot, hint); - } - - this.currentMapSpotSection = spot; - } else if (this.currentMapSpotSection) { - level.map_remove_object_spot(this.currentMapSpotId, this.currentMapSpotSection); - this.currentMapSpotSection = null; - } - } - /** * Get map display hint for debugging and display in game UI map. */ diff --git a/src/engine/core/objects/state/add_state_manager.ts b/src/engine/core/objects/state/add_state_manager.ts index 01541740b..c3acfd056 100644 --- a/src/engine/core/objects/state/add_state_manager.ts +++ b/src/engine/core/objects/state/add_state_manager.ts @@ -27,6 +27,7 @@ const logger: LuaLogger = new LuaLogger($filename); /** * Add state manager instance to Stalker object. + * * @param object */ export function addStateManager(object: ClientObject): StalkerStateManager { diff --git a/src/engine/core/objects/state_lib/state_manager_scenario.ts b/src/engine/core/objects/state_lib/state_manager_scenario.ts index 5f4ee236d..f9d7aedbd 100644 --- a/src/engine/core/objects/state_lib/state_manager_scenario.ts +++ b/src/engine/core/objects/state_lib/state_manager_scenario.ts @@ -798,6 +798,9 @@ export function getStateLibScenarios(): LuaTable { } as any; } +/** + * todo; + */ export function getAnimationListScenario(): LuaTable { return { zat_b14_give_artefact_idle: { diff --git a/src/engine/core/objects/state_lib/state_mgr_animation_list_animpoint.ts b/src/engine/core/objects/state_lib/state_mgr_animation_list_animpoint.ts index afbb3ddda..6b04e210b 100644 --- a/src/engine/core/objects/state_lib/state_mgr_animation_list_animpoint.ts +++ b/src/engine/core/objects/state_lib/state_mgr_animation_list_animpoint.ts @@ -1,6 +1,9 @@ import { IAnimationDescriptor } from "@/engine/core/objects/state/types"; import { ClientObject } from "@/engine/lib/types"; +/** + * todo; + */ export function getAnimpointAnimationList(): LuaTable { return { animpoint_stay_wall: { diff --git a/src/engine/core/objects/state_lib/state_mgr_animstate_list_animpoint.ts b/src/engine/core/objects/state_lib/state_mgr_animstate_list_animpoint.ts index c42962644..d85345011 100644 --- a/src/engine/core/objects/state_lib/state_mgr_animstate_list_animpoint.ts +++ b/src/engine/core/objects/state_lib/state_mgr_animstate_list_animpoint.ts @@ -2,6 +2,9 @@ import { IAnimationStateDescriptor } from "@/engine/core/objects/state/types"; import { getExtern } from "@/engine/core/utils/binding"; import { AnyArgs, AnyCallablesModule } from "@/engine/lib/types"; +/** + * todo; + */ export function addAnimstateAnimationList(): LuaTable { return { animpoint_stay_wall: { diff --git a/src/engine/core/objects/state_lib/state_mgr_pri_a15.ts b/src/engine/core/objects/state_lib/state_mgr_pri_a15.ts index bc8c2ee38..0387b52eb 100644 --- a/src/engine/core/objects/state_lib/state_mgr_pri_a15.ts +++ b/src/engine/core/objects/state_lib/state_mgr_pri_a15.ts @@ -23,6 +23,9 @@ const WEAP_TABLE_UNSTRAPPED: LuaArray = [ "pri_a15_wpn_ak74_unstrapped", ] as any; +/** + * todo; + */ function unstrapWeapon(object: ClientObject): void { let item: Optional = null; let index: TIndex = 0; @@ -42,6 +45,9 @@ function unstrapWeapon(object: ClientObject): void { item.attachable_item_load_attach(WEAP_TABLE_UNSTRAPPED.get(index as number)); } +/** + * todo; + */ function strapWeapon(object: ClientObject): void { let item: Optional = null; let index: TIndex = 0; @@ -61,18 +67,30 @@ function strapWeapon(object: ClientObject): void { item.attachable_item_load_attach(WEAP_TABLE.get(index)); } +/** + * todo; + */ function breakFence(): void { registry.doors.get(storyNames.pri_a15_door).forwardAnimation(); } +/** + * todo; + */ function lightsOff(): void { registry.actor.give_info_portion(infoPortions.pri_a15_lights_off); } +/** + * todo; + */ function lightsOn(): void { registry.actor.disable_info_portion(infoPortions.pri_a15_lights_off); } +/** + * todo; + */ function endScene(): void { registry.actor.give_info_portion(infoPortions.pri_a15_cutscene_end); } @@ -616,6 +634,9 @@ const cutscene: Record< }, }; +/** + * + */ function check_availability(precondition: LuaArray, existing_npc: string): boolean { const check_names = parseStringsList(existing_npc); @@ -703,6 +724,9 @@ function get_sequence_for_npc(objectName: TName, existing_npc: string): TNpcSequ return result; } +/** + * + */ export function addStateLibPriA15(): LuaTable { return { pri_a15_idle_none: { @@ -1850,6 +1874,9 @@ export function addStateLibPriA15(): LuaTable { } as any; } +/** + * todo; + */ export function addAnimationListPriA15(): LuaTable> { return { pri_a15_idle_none: { diff --git a/src/engine/core/schemes/combat_idle/evaluators/EvaluatorPostCombatIdleEnemy.ts b/src/engine/core/schemes/combat_idle/evaluators/EvaluatorPostCombatIdleEnemy.ts index f3532e201..a17685d4d 100644 --- a/src/engine/core/schemes/combat_idle/evaluators/EvaluatorPostCombatIdleEnemy.ts +++ b/src/engine/core/schemes/combat_idle/evaluators/EvaluatorPostCombatIdleEnemy.ts @@ -4,7 +4,7 @@ import { registry } from "@/engine/core/database"; import { ISchemePostCombatIdleState } from "@/engine/core/schemes/combat_idle/ISchemePostCombatIdleState"; import { ISchemeCombatIgnoreState } from "@/engine/core/schemes/combat_ignore"; import { LuaLogger } from "@/engine/core/utils/logging"; -import { isObjectEnemy } from "@/engine/core/utils/object"; +import { canObjectSelectAsEnemy } from "@/engine/core/utils/object"; import { logicsConfig } from "@/engine/lib/configs/LogicsConfig"; import { ClientObject, EScheme, Optional, TDistance, TTimestamp } from "@/engine/lib/types"; @@ -31,7 +31,7 @@ export class EvaluatorPostCombatIdleEnemy extends property_evaluator { if ( bestEnemy !== null && - !isObjectEnemy( + !canObjectSelectAsEnemy( this.object, bestEnemy, registry.objects.get(this.object.id())[EScheme.COMBAT_IGNORE] as ISchemeCombatIgnoreState diff --git a/src/engine/core/schemes/combat_ignore/CombatProcessEnemyManager.ts b/src/engine/core/schemes/combat_ignore/CombatProcessEnemyManager.ts index 7c2f1c871..cc4f98a7f 100644 --- a/src/engine/core/schemes/combat_ignore/CombatProcessEnemyManager.ts +++ b/src/engine/core/schemes/combat_ignore/CombatProcessEnemyManager.ts @@ -5,7 +5,7 @@ import { SmartTerrain } from "@/engine/core/objects/server/smart_terrain/SmartTe import { AbstractSchemeManager } from "@/engine/core/schemes"; import { ISchemeCombatIgnoreState } from "@/engine/core/schemes/combat_ignore/index"; import { LuaLogger } from "@/engine/core/utils/logging"; -import { isObjectEnemy } from "@/engine/core/utils/object"; +import { canObjectSelectAsEnemy } from "@/engine/core/utils/object"; import { logicsConfig } from "@/engine/lib/configs/LogicsConfig"; import { ACTOR_ID } from "@/engine/lib/constants/ids"; import { MAX_U16 } from "@/engine/lib/constants/memory"; @@ -25,7 +25,7 @@ export class CombatProcessEnemyManager extends AbstractSchemeManager = alife().object(object.id()); diff --git a/src/engine/core/schemes/heli_move/HeliCombat.ts b/src/engine/core/schemes/heli_move/HeliCombat.ts index 528a4aa29..c4d79a1b8 100644 --- a/src/engine/core/schemes/heli_move/HeliCombat.ts +++ b/src/engine/core/schemes/heli_move/HeliCombat.ts @@ -769,6 +769,9 @@ export class HeliCombat { } } +/** + * todo; + */ export function crossRayCircle(p: Vector, v: Vector, o: Vector, r: number): Vector { const po: Vector = copyVector(o).sub(p); const vperp: Vector = createVector(-v.z, 0, v.x); diff --git a/src/engine/core/schemes/heli_move/HeliFire.ts b/src/engine/core/schemes/heli_move/HeliFire.ts index 9424d4288..e2bbfd18e 100644 --- a/src/engine/core/schemes/heli_move/HeliFire.ts +++ b/src/engine/core/schemes/heli_move/HeliFire.ts @@ -241,6 +241,9 @@ export class HeliFire { } } +/** + * todo; + */ export function getHeliFirer(object: ClientObject): HeliFire { if (heliFirer.get(object.id()) === null) { heliFirer.set(object.id(), new HeliFire(object)); diff --git a/src/engine/core/schemes/heli_move/HeliFly.ts b/src/engine/core/schemes/heli_move/HeliFly.ts index 86b1de329..46c04ddfb 100644 --- a/src/engine/core/schemes/heli_move/HeliFly.ts +++ b/src/engine/core/schemes/heli_move/HeliFly.ts @@ -190,7 +190,9 @@ export class HeliFly { this.pointByLook = lPoint; } } - +/** + * todo; + */ export function getHeliFlyer(object: ClientObject): HeliFly { if (heliFlyer.get(object.id()) === null) { heliFlyer.set(object.id(), new HeliFly(object)); diff --git a/src/engine/core/schemes/heli_move/HeliLook.ts b/src/engine/core/schemes/heli_move/HeliLook.ts index cebf54937..03020fc37 100644 --- a/src/engine/core/schemes/heli_move/HeliLook.ts +++ b/src/engine/core/schemes/heli_move/HeliLook.ts @@ -55,6 +55,9 @@ export class HeliLook { } } +/** + * todo; + */ export function getHeliLooker(object: ClientObject): HeliLook { if (heliLooker.get(object.id()) === null) { heliLooker.set(object.id(), new HeliLook(object)); diff --git a/src/engine/core/schemes/remark/actions/ActionRemarkActivity.ts b/src/engine/core/schemes/remark/actions/ActionRemarkActivity.ts index bd6e8313b..aebb01f33 100644 --- a/src/engine/core/schemes/remark/actions/ActionRemarkActivity.ts +++ b/src/engine/core/schemes/remark/actions/ActionRemarkActivity.ts @@ -189,6 +189,10 @@ export function initTarget( targetString: string ): LuaMultiReturn<[Optional, Optional, Optional]> { // todo: Simplify. + + /** + * todo; + */ function parseTarget(targetStr: string): LuaMultiReturn<[Optional, Optional]> { const [pos] = string.find(targetStr, ","); @@ -200,6 +204,10 @@ export function initTarget( } // todo: Simplify. + + /** + * todo; + */ function parseType(targetStr: string): LuaMultiReturn<[string, string]> { const [pos] = string.find(targetStr, "|"); diff --git a/src/engine/core/ui/game/FreeplayDialog.ts b/src/engine/core/ui/game/FreeplayDialog.ts index 6a5cabc05..034e899a7 100644 --- a/src/engine/core/ui/game/FreeplayDialog.ts +++ b/src/engine/core/ui/game/FreeplayDialog.ts @@ -47,6 +47,9 @@ export class FreeplayDialog extends CUIScriptWnd { let freeplayControl: Optional = null; +/** + * todo; + */ export function showFreeplayDialog(selector: string, text: string): void { if (freeplayControl === null) { freeplayControl = new FreeplayDialog(); diff --git a/src/engine/core/ui/menu/options/OptionsVideoAdvanced.ts b/src/engine/core/ui/menu/options/OptionsVideoAdvanced.ts index fe8541604..6a200b84f 100644 --- a/src/engine/core/ui/menu/options/OptionsVideoAdvanced.ts +++ b/src/engine/core/ui/menu/options/OptionsVideoAdvanced.ts @@ -86,8 +86,7 @@ export class OptionsVideoAdvanced extends CUIWindow { owner.preconditions.set(particlesDistanceTrackBar, only2aAndMoreMode); - /** - * + /* * _st = xml:InitStatic("video_adv:templ_item", nil) * xml:InitStatic("video_adv:cap_r2_smap_size", _st) * ctl = xml:InitComboBox("video_adv:list_r2_smap_size", _st) @@ -200,7 +199,7 @@ export class OptionsVideoAdvanced extends CUIWindow { owner.preconditions.set(wetSurfacesCheck, only3andMoreMode); - /** + /* * * _st = xml:InitStatic("video_adv:templ_item", nil) * xml:InitStatic("video_adv:cap_r3_dynamic_wet_surfaces_opt", _st) @@ -224,14 +223,14 @@ export class OptionsVideoAdvanced extends CUIWindow { owner.preconditions.set(volumetricSmokeCheck, only3andMoreMode); - /** + /* * _st = xml:InitStatic("video_adv:templ_item", nil) * xml:InitStatic("video_adv:cap_r3_msaa_opt", _st) * ctl = xml:InitCheck("video_adv:check_r3_msaa_opt", _st) * table.insert(handler.m_preconditions, {func=mode_ge_3, control=_st}) */ - /** + /* * -- r4_enable_tessellation only r4 * _st = xml:InitStatic("video_adv:templ_item", nil) * xml:InitStatic("video_adv:cap_r4_tessellation", _st) @@ -250,7 +249,7 @@ export class OptionsVideoAdvanced extends CUIWindow { xml.InitStatic("video_adv:cap_60hz", only60HZSetting); xml.InitCheck("video_adv:check_60hz", only60HZSetting); - /** + /* * _st = xml:InitStatic("video_adv:templ_item", nil) * xml:InitStatic("video_adv:cap_always_active", _st) * xml:InitCheck("video_adv:check_always_active", _st) @@ -261,30 +260,48 @@ export class OptionsVideoAdvanced extends CUIWindow { } } +/** + * todo; + */ function only1mode(control: CUIWindow, id: EGameRenderer): void { control.Enable(id === EGameRenderer.R1); } // -- >=R2a +/** + * todo; + */ function only2aAndMoreMode(control: CUIWindow, id: EGameRenderer): void { control.Enable(id >= EGameRenderer.R2A); } // -- >=R2 +/** + * todo; + */ function only2andMoreMode(control: CUIWindow, id: EGameRenderer): void { control.Enable(id >= EGameRenderer.R2); } // -- >=R2.5 +/** + * todo; + */ function only25andMoreMode(control: CUIWindow, id: EGameRenderer): void { control.Enable(id >= EGameRenderer.R25); } // -- >=R3 +/** + * todo; + */ function only3andMoreMode(control: CUIWindow, id: EGameRenderer): void { control.Enable(id >= EGameRenderer.R3); } +/** + * todo; + */ function only3andMoreModeVisible(control: CUIWindow, id: EGameRenderer): void { const isEnabled: boolean = id >= EGameRenderer.R3; @@ -292,6 +309,9 @@ function only3andMoreModeVisible(control: CUIWindow, id: EGameRenderer): void { control.Show(isEnabled); } +/** + * todo; + */ function only3andMoreModeInvisible(control: CUIWindow, id: EGameRenderer): void { const isEnabled: boolean = id < EGameRenderer.R3; @@ -299,10 +319,16 @@ function only3andMoreModeInvisible(control: CUIWindow, id: EGameRenderer): void control.Show(isEnabled); } +/** + * todo; + */ function only4(control: CUIWindow, id: EGameRenderer) { return id === EGameRenderer.R4; } +/** + * todo; + */ function only4andMore(control: CUIWindow, id: EGameRenderer) { return id >= EGameRenderer.R4; } diff --git a/src/engine/core/utils/game/game_console.test.ts b/src/engine/core/utils/game/game_console.test.ts index e81db0dc5..7f2564971 100644 --- a/src/engine/core/utils/game/game_console.test.ts +++ b/src/engine/core/utils/game/game_console.test.ts @@ -26,9 +26,12 @@ describe("'console' utils", () => { }); it("'getConsoleFloatCommand' should correctly generate commands", () => { - gameConsole.get_float = jest.fn((cmd: string) => (cmd === "snd_volume_eff" ? 50.4 : -1)); + gameConsole.get_float = jest.fn((cmd: string) => (cmd.startsWith("snd_volume_eff") ? 50.4 : -1)); expect(getConsoleFloatCommand(consoleCommands.snd_volume_eff)).toBe(50.4); expect(gameConsole.get_float).toHaveBeenCalledWith("snd_volume_eff"); + + expect(getConsoleFloatCommand(consoleCommands.snd_volume_eff, 1, 2)).toBe(50.4); + expect(gameConsole.get_float).toHaveBeenNthCalledWith(2, "snd_volume_eff 1 2"); }); }); diff --git a/src/engine/core/utils/game/game_save.test.ts b/src/engine/core/utils/game/game_save.test.ts index ff54325ed..3655e9c96 100644 --- a/src/engine/core/utils/game/game_save.test.ts +++ b/src/engine/core/utils/game/game_save.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it } from "@jest/globals"; +import { beforeEach, describe, expect, it, jest } from "@jest/globals"; import { createAutoSave, @@ -6,7 +6,10 @@ import { deleteGameSave, getFileDataForGameSave, isGameSaveFileExist, + loadDynamicGameSave, + saveDynamicGameSave, } from "@/engine/core/utils/game/game_save"; +import { MockIoFile } from "@/fixtures/lua"; import { resetFunctionMock } from "@/fixtures/utils"; import { gameConsole, MockFileSystem, MockFileSystemList, mocksConfig } from "@/fixtures/xray"; @@ -14,6 +17,7 @@ describe("'game_save' utils", () => { beforeEach(() => { resetFunctionMock(gameConsole.execute); resetFunctionMock(gameConsole.get_float); + resetFunctionMock(io.open); }); it("'getFileDataForGameSave' should correctly get save data", () => { @@ -48,7 +52,8 @@ describe("'game_save' utils", () => { MockFileSystem.getInstance().file_list_open_ex.mockImplementation(() => new MockFileSystemList(["a"])); deleteGameSave("another"); expect(fileSystem.file_delete).toHaveBeenNthCalledWith(1, "$game_saves$", "another.scop"); - expect(fileSystem.file_delete).toHaveBeenNthCalledWith(2, "$game_saves$", "another.dds"); + expect(fileSystem.file_delete).toHaveBeenNthCalledWith(2, "$game_saves$", "another.scopx"); + expect(fileSystem.file_delete).toHaveBeenNthCalledWith(3, "$game_saves$", "another.dds"); }); it("'createSave' should correctly generate commands", () => { @@ -92,4 +97,51 @@ describe("'game_save' utils", () => { expect(() => createSave(null)).toThrow(); }); + + it("'saveDynamicGameSave' should correctly create dynamic file saves", () => { + const file: MockIoFile = new MockIoFile("test", "wb"); + + jest.spyOn(io, "open").mockImplementation(() => $multi(file.asMock())); + + saveDynamicGameSave("example.scop", { a: 1, b: 2, c: 3 }); + + expect(lfs.mkdir).toHaveBeenCalledTimes(1); + expect(io.open).toHaveBeenCalledWith("$game_saves$example.scopx", "wb"); + expect(file.write).toHaveBeenCalledWith(JSON.stringify({ a: 1, b: 2, c: 3 })); + expect(file.close).toHaveBeenCalledTimes(1); + + expect(file.content).toBe(JSON.stringify({ a: 1, b: 2, c: 3 })); + + file.isOpen = false; + saveDynamicGameSave("example.scop", { a: 1000 }); + + expect(file.write).toHaveBeenCalledTimes(1); + expect(file.content).toBe(JSON.stringify({ a: 1, b: 2, c: 3 })); + expect(file.close).toHaveBeenCalledTimes(1); + }); + + it("'loadDynamicGameSave' should correctly load dynamic file saves", () => { + const file: MockIoFile = new MockIoFile("test", "wb"); + + file.content = JSON.stringify({ a: 1, b: 33 }); + + jest.spyOn(io, "open").mockImplementation(() => $multi(file.asMock())); + + expect(loadDynamicGameSave("F:\\\\parent\\\\example.scop")).toEqual({ a: 1, b: 33 }); + + expect(marshal.decode).toHaveBeenCalledWith(file.content); + expect(io.open).toHaveBeenCalledWith("F:\\\\parent\\\\example.scopx", "rb"); + expect(file.read).toHaveBeenCalledTimes(1); + expect(file.close).toHaveBeenCalledTimes(1); + + file.content = ""; + expect(loadDynamicGameSave("F:\\\\parent\\\\example.scop")).toBeNull(); + + file.content = null; + expect(loadDynamicGameSave("F:\\\\parent\\\\example.scop")).toBeNull(); + + file.content = "{}"; + file.isOpen = false; + expect(loadDynamicGameSave("F:\\\\parent\\\\example.scop")).toBeNull(); + }); }); diff --git a/src/engine/core/utils/game/game_save.ts b/src/engine/core/utils/game/game_save.ts index 5c0a2642c..2a54c6f65 100644 --- a/src/engine/core/utils/game/game_save.ts +++ b/src/engine/core/utils/game/game_save.ts @@ -8,7 +8,7 @@ import { gameConfig } from "@/engine/lib/configs/GameConfig"; import { captions } from "@/engine/lib/constants/captions"; import { consoleCommands } from "@/engine/lib/constants/console_commands"; import { roots } from "@/engine/lib/constants/roots"; -import { FSFileListEX, Optional, SavedGameWrapper, TCount, TLabel, TName } from "@/engine/lib/types"; +import { AnyObject, FSFileListEX, Optional, SavedGameWrapper, TCount, TLabel, TName, TPath } from "@/engine/lib/types"; const logger: LuaLogger = new LuaLogger($filename); @@ -34,15 +34,76 @@ export function isGameSaveFileExist(filename: TName): boolean { * @param filename - target name to delete from saves folder */ export function deleteGameSave(filename: TName): void { - const saveFileName: TName = filename + gameConfig.GAME_SAVE_EXTENSION; - const ddsFile: TName = filename + gameConfig.GAME_SAVE_PREVIEW_EXTENSION; + const saveBaseFile: TName = filename + gameConfig.GAME_SAVE_EXTENSION; + const saveDynamicFile: TName = filename + gameConfig.GAME_SAVE_DYNAMIC_EXTENSION; + const savePreviewFile: TName = filename + gameConfig.GAME_SAVE_PREVIEW_EXTENSION; const fs: FS = getFS(); - fs.file_delete(roots.gameSaves, saveFileName); + logger.info("Delete game save:", filename); - if (isGameSaveFileExist(ddsFile)) { - fs.file_delete(roots.gameSaves, ddsFile); + fs.file_delete(roots.gameSaves, saveBaseFile); + + // Delete dynamic base. + if (isGameSaveFileExist(saveDynamicFile)) { + fs.file_delete(roots.gameSaves, saveDynamicFile); + } + + // Delete preview. + if (isGameSaveFileExist(savePreviewFile)) { + fs.file_delete(roots.gameSaves, savePreviewFile); + } +} + +/** + * Create dynamic game save based on stringified binary data. + * + * @param filename - target save filename base to create or overwrite it + * @param data - data to save + */ +export function saveDynamicGameSave(filename: TName, data: AnyObject): void { + const savesFolder: TPath = getFS().update_path(roots.gameSaves, ""); + const saveFile: TPath = + savesFolder + string.lower(string.sub(filename, 0, -6)) + gameConfig.GAME_SAVE_DYNAMIC_EXTENSION; + + // Make sure saves directory exists. + lfs.mkdir(savesFolder); + + const [existingSave] = io.open(saveFile, "wb"); + + if (!existingSave || io.type(existingSave) !== "file") { + return logger.error("Cannot write to save path:", saveFile); + } + + existingSave.write(marshal.encode(data)); + existingSave.close(); +} + +/** + * Read dynamic game save with stringified binary data. + * + * @param filename - target save filename full path + * @returns stringified binary data or null + */ +export function loadDynamicGameSave(filename: TName): Optional { + const saveFile: TPath = string.sub(filename, 0, -6) + gameConfig.GAME_SAVE_DYNAMIC_EXTENSION; + + const [existingSave] = io.open(saveFile, "rb"); + + if (!existingSave || io.type(existingSave) !== "file") { + return null; + } + + const data: Optional = existingSave.read("*all" as unknown as "*a") as Optional; + + existingSave.close(); + + if (data && data !== "") { + return marshal.decode(data); + } else { + logger.warn("Was not able to read dynamic game save:", filename); + + return null; } } diff --git a/src/engine/core/utils/ini/ini_config.ts b/src/engine/core/utils/ini/ini_config.ts index a32e66840..00a82ad4c 100644 --- a/src/engine/core/utils/ini/ini_config.ts +++ b/src/engine/core/utils/ini/ini_config.ts @@ -285,6 +285,9 @@ export function getConfigSwitchConditions(ini: IniFile, section: TSection): Opti const linesCount: TCount = ini.line_count(section); let index: TIndex = 1; + /** + * todo; + */ function addConditions( func: (ini: IniFile, section: TSection, id: TStringId) => Optional, cond: ESchemeCondition diff --git a/src/engine/core/utils/object/object_anomaly.test.ts b/src/engine/core/utils/object/object_anomaly.test.ts new file mode 100644 index 000000000..0966ad833 --- /dev/null +++ b/src/engine/core/utils/object/object_anomaly.test.ts @@ -0,0 +1,58 @@ +import { describe, expect, it } from "@jest/globals"; + +import { registry } from "@/engine/core/database"; +import { AnomalyZoneBinder } from "@/engine/core/objects"; +import { anomalyHasArtefact, getAnomalyArtefacts } from "@/engine/core/utils/object/object_anomaly"; +import { mockClientGameObject, mockServerAlifeObject } from "@/fixtures/xray"; + +describe("'object_anomaly' utils", () => { + it("'anomalyHasArtefact' should correctly check if anomaly has artefact", () => { + expect(anomalyHasArtefact("another", "")).toBe(false); + expect(anomalyHasArtefact("test-anomaly", "")).toBe(false); + expect(anomalyHasArtefact("test-anomaly", "sect_1")).toBe(false); + + const anomalyZoneBinder: AnomalyZoneBinder = new AnomalyZoneBinder(mockClientGameObject()); + + registry.anomalyZones.set("test-anomaly", anomalyZoneBinder); + expect(anomalyHasArtefact("test-anomaly", "sect_1")).toBe(false); + + anomalyZoneBinder.spawnedArtefactsCount = 3; + expect(anomalyHasArtefact("test-anomaly", "sect_1")).toBe(false); + + anomalyZoneBinder.artefactWaysByArtefactId.set(511, "sect_1"); + anomalyZoneBinder.artefactWaysByArtefactId.set(512, "sect_2"); + anomalyZoneBinder.artefactWaysByArtefactId.set(513, "sect_3"); + expect(anomalyHasArtefact("test-anomaly", "sect_1")).toBe(false); + + mockServerAlifeObject({ id: 511, section_name: () => "sect_1" as T }); + mockServerAlifeObject({ id: 512, section_name: () => "sect_2" as T }); + + expect(anomalyHasArtefact("test-anomaly", "sect_1")).toBe(true); + expect(anomalyHasArtefact("test-anomaly", "sect_2")).toBe(true); + expect(anomalyHasArtefact("test-anomaly", "sect_3")).toBe(false); + }); + + it("'getAnomalyArtefacts' should correctly get anomaly artefacts list", () => { + expect(getAnomalyArtefacts("another")).toEqualLuaArrays([]); + expect(getAnomalyArtefacts("another-anomaly")).toEqualLuaArrays([]); + expect(getAnomalyArtefacts("another-anomaly")).toEqualLuaArrays([]); + + const anomalyZoneBinder: AnomalyZoneBinder = new AnomalyZoneBinder(mockClientGameObject()); + + registry.anomalyZones.set("another-anomaly", anomalyZoneBinder); + expect(getAnomalyArtefacts("another-anomaly")).toEqualLuaArrays([]); + + anomalyZoneBinder.spawnedArtefactsCount = 3; + expect(getAnomalyArtefacts("another-anomaly")).toEqualLuaArrays([]); + + anomalyZoneBinder.artefactWaysByArtefactId.set(521, "sect_1"); + anomalyZoneBinder.artefactWaysByArtefactId.set(522, "sect_2"); + anomalyZoneBinder.artefactWaysByArtefactId.set(523, "sect_3"); + expect(getAnomalyArtefacts("another-anomaly")).toEqualLuaArrays([]); + + mockServerAlifeObject({ id: 521, section_name: () => "sect_1" as T }); + mockServerAlifeObject({ id: 523, section_name: () => "sect_3" as T }); + + expect(getAnomalyArtefacts("another-anomaly")).toEqualLuaArrays(["sect_1", "sect_3"]); + }); +}); diff --git a/src/engine/core/utils/object/object_anomaly.ts b/src/engine/core/utils/object/object_anomaly.ts index dd1b75b77..45f6bb6c9 100644 --- a/src/engine/core/utils/object/object_anomaly.ts +++ b/src/engine/core/utils/object/object_anomaly.ts @@ -2,49 +2,50 @@ import { alife } from "xray16"; import { registry } from "@/engine/core/database"; import { AnomalyZoneBinder } from "@/engine/core/objects"; -import { ClientObject, LuaArray, Optional, ServerObject, TName } from "@/engine/lib/types"; +import { LuaArray, Optional, ServerObject, TName, TSection } from "@/engine/lib/types"; /** - * todo; + * @param anomalyZoneName - name of anomaly zone to check + * @param artefactSection - name of artefact to search in the anomaly + * @returns whether anomaly has artefact */ -export function anomalyHasArtefact( - actor: ClientObject, - object: Optional, - anomalyZoneName: TName, - artefactName: Optional -): LuaMultiReturn<[boolean, Optional>]> { - const anomalyZone: AnomalyZoneBinder = registry.anomalyZones.get(anomalyZoneName); - - if (anomalyZone === null) { - return $multi(false, null); - } +export function anomalyHasArtefact(anomalyZoneName: TName, artefactSection: TSection): boolean { + const anomalyZone: Optional = registry.anomalyZones.get(anomalyZoneName); - if (anomalyZone.spawnedArtefactsCount < 1) { - return $multi(false, null); + if (!anomalyZone || anomalyZone.spawnedArtefactsCount < 1) { + return false; } - if (artefactName === null) { - const artefactsList: LuaArray = new LuaTable(); - - for (const [k, v] of registry.artefacts.ways) { - const artefactObject: Optional = alife().object(tonumber(k)!); + for (const [artefactId] of anomalyZone.artefactWaysByArtefactId) { + const object: Optional = alife().object(artefactId); - if (artefactObject) { - table.insert(artefactsList, artefactObject.section_name()); - } + if (object && object.section_name() === artefactSection) { + return true; } + } + + return false; +} - return $multi(true, artefactsList); +/** + * @param anomalyZoneName - name of anomaly zone to check + * @returns list of artefacts in the anomaly + */ +export function getAnomalyArtefacts(anomalyZoneName: TName): LuaArray { + const anomalyZone: Optional = registry.anomalyZones.get(anomalyZoneName); + const artefactsList: LuaArray = new LuaTable(); + + if (!anomalyZone || anomalyZone.spawnedArtefactsCount < 1) { + return artefactsList; } - for (const [artefactId] of registry.artefacts.ways) { - if ( - alife().object(tonumber(artefactId)!) && - artefactName === alife().object(tonumber(artefactId)!)!.section_name() - ) { - return $multi(true, null); + for (const [artefactId] of anomalyZone.artefactWaysByArtefactId) { + const artefactObject: Optional = alife().object(artefactId); + + if (artefactObject) { + table.insert(artefactsList, artefactObject.section_name()); } } - return $multi(false, null); + return artefactsList; } diff --git a/src/engine/core/utils/object/object_danger.test.ts b/src/engine/core/utils/object/object_danger.test.ts new file mode 100644 index 000000000..21e69d287 --- /dev/null +++ b/src/engine/core/utils/object/object_danger.test.ts @@ -0,0 +1,212 @@ +import { describe, expect, it, jest } from "@jest/globals"; +import { danger_object } from "xray16"; + +import { IRegistryObjectState, registerObject, registry } from "@/engine/core/database"; +import { SimulationBoardManager } from "@/engine/core/managers/interaction/SimulationBoardManager"; +import { SmartTerrain, SmartTerrainControl } from "@/engine/core/objects"; +import { ESmartTerrainStatus } from "@/engine/core/objects/server/smart_terrain/types"; +import { ISchemeCombatIgnoreState } from "@/engine/core/schemes/combat_ignore"; +import { ISchemeWoundedState } from "@/engine/core/schemes/wounded"; +import { WoundManager } from "@/engine/core/schemes/wounded/WoundManager"; +import { parseConditionsList } from "@/engine/core/utils/ini"; +import { canObjectSelectAsEnemy, isObjectFacingDanger } from "@/engine/core/utils/object/object_danger"; +import { classIds } from "@/engine/lib/constants/class_ids"; +import { FALSE, TRUE } from "@/engine/lib/constants/words"; +import { ClientObject, EClientObjectRelation, EScheme, ServerSmartZoneObject, TClassId } from "@/engine/lib/types"; +import { mockSchemeState } from "@/fixtures/engine"; +import { replaceFunctionMock } from "@/fixtures/utils"; +import { + mockClientGameObject, + MockDangerObject, + mockServerAlifeHumanStalker, + mockServerAlifeObject, + mockServerAlifeSmartZone, +} from "@/fixtures/xray"; + +describe("'object_danger' utils", () => { + it("'isObjectFacingDanger' should correctly check generic danger", () => { + expect(isObjectFacingDanger(mockClientGameObject())).toBe(false); + + const object: ClientObject = mockClientGameObject(); + const bestDanger: MockDangerObject = new MockDangerObject(); + const state: IRegistryObjectState = registerObject(object); + + state[EScheme.COMBAT_IGNORE] = mockSchemeState(object, EScheme.COMBAT_IGNORE); + replaceFunctionMock(object.best_danger, () => bestDanger); + + expect(isObjectFacingDanger(object)).toBe(false); + + bestDanger.dangerDependentObject = mockClientGameObject(); + expect(isObjectFacingDanger(object)).toBe(false); + + replaceFunctionMock(object.relation, () => EClientObjectRelation.ENEMY); + expect(isObjectFacingDanger(object)).toBe(false); + + bestDanger.dangerType = danger_object.hit; + jest.spyOn(bestDanger.dangerPosition, "distance_to_sqr").mockImplementation(() => 150 * 150); + expect(isObjectFacingDanger(object)).toBe(true); + }); + + it("'isObjectFacingDanger' should correctly check generic danger", () => { + expect(isObjectFacingDanger(mockClientGameObject())).toBe(false); + + const object: ClientObject = mockClientGameObject(); + const bestDanger: MockDangerObject = new MockDangerObject(); + const state: IRegistryObjectState = registerObject(object); + + state[EScheme.COMBAT_IGNORE] = mockSchemeState(object, EScheme.COMBAT_IGNORE); + replaceFunctionMock(object.best_danger, () => bestDanger); + + bestDanger.dangerDependentObject = mockClientGameObject(); + replaceFunctionMock(object.relation, () => EClientObjectRelation.ENEMY); + bestDanger.dangerType = danger_object.hit; + jest.spyOn(bestDanger.dangerPosition, "distance_to_sqr").mockImplementation(() => 150 * 150); + + jest.spyOn(object, "alive").mockImplementation(() => false); + expect(isObjectFacingDanger(object)).toBe(false); + + jest.spyOn(object, "alive").mockImplementation(() => true); + expect(isObjectFacingDanger(object)).toBe(true); + }); + + it("'isObjectFacingDanger' should correctly ignore corpses", () => { + const object: ClientObject = mockClientGameObject(); + const bestDanger: MockDangerObject = new MockDangerObject(); + const state: IRegistryObjectState = registerObject(object); + + state[EScheme.COMBAT_IGNORE] = mockSchemeState(object, EScheme.COMBAT_IGNORE); + replaceFunctionMock(object.best_danger, () => bestDanger); + + bestDanger.dangerType = danger_object.entity_corpse; + expect(isObjectFacingDanger(object)).toBe(false); + }); + + it("'isObjectFacingDanger' should correctly check ignore distance", () => { + const object: ClientObject = mockClientGameObject(); + const bestDanger: MockDangerObject = new MockDangerObject(); + const state: IRegistryObjectState = registerObject(object); + + state[EScheme.COMBAT_IGNORE] = mockSchemeState(object, EScheme.COMBAT_IGNORE); + replaceFunctionMock(object.best_danger, () => bestDanger); + + bestDanger.dangerType = danger_object.entity_death; + jest.spyOn(bestDanger.dangerPosition, "distance_to_sqr").mockImplementation(() => 100); + expect(isObjectFacingDanger(object)).toBe(true); + + bestDanger.dangerType = danger_object.entity_death; + jest.spyOn(bestDanger.dangerPosition, "distance_to_sqr").mockImplementation(() => 101); + expect(isObjectFacingDanger(object)).toBe(false); + }); + + it("'isObjectFacingDanger' should correctly check grenades", () => { + const object: ClientObject = mockClientGameObject({ clsid: () => classIds.script_stalker as TClassId }); + const bestDanger: MockDangerObject = new MockDangerObject(); + const state: IRegistryObjectState = registerObject(object); + + state[EScheme.COMBAT_IGNORE] = mockSchemeState(object, EScheme.COMBAT_IGNORE); + bestDanger.dangerType = danger_object.grenade; + replaceFunctionMock(object.best_danger, () => bestDanger); + + // Out of range. + jest.spyOn(bestDanger.dangerPosition, "distance_to_sqr").mockImplementation(() => 226); + expect(isObjectFacingDanger(object)).toBe(false); + + // In range. + jest.spyOn(bestDanger.dangerPosition, "distance_to_sqr").mockImplementation(() => 225); + expect(isObjectFacingDanger(object)).toBe(true); + + // When zombied. + jest.spyOn(object, "character_community").mockImplementation(() => "zombied"); + expect(isObjectFacingDanger(object)).toBe(false); + + // When stalker. + jest.spyOn(object, "character_community").mockImplementation(() => "stalker"); + expect(isObjectFacingDanger(object)).toBe(true); + + // When injured. + state[EScheme.WOUNDED] = mockSchemeState(object, EScheme.WOUNDED, { + woundManager: { woundState: "true" } as WoundManager, + }); + expect(isObjectFacingDanger(object)).toBe(false); + }); + + it("'canObjectSelectAsEnemy' should correctly check enemies selection possibility", () => { + const object: ClientObject = mockClientGameObject({ clsid: () => classIds.script_stalker as TClassId }); + const enemy: ClientObject = mockClientGameObject(); + const state: IRegistryObjectState = registerObject(object); + const combatIgnoreState: ISchemeCombatIgnoreState = mockSchemeState(object, EScheme.COMBAT_IGNORE); + + state[EScheme.COMBAT_IGNORE] = combatIgnoreState; + expect(canObjectSelectAsEnemy(object, enemy, combatIgnoreState)).toBe(true); + expect(state.enemy_id).toBe(enemy.id()); + + state.enemy_id = null; + jest.spyOn(object, "alive").mockImplementationOnce(() => false); + expect(canObjectSelectAsEnemy(object, enemy, combatIgnoreState)).toBe(false); + expect(state.enemy_id).toBeNull(); + + expect(canObjectSelectAsEnemy(mockClientGameObject(), enemy, null as unknown as ISchemeCombatIgnoreState)).toBe( + true + ); + + state.enemy_id = null; + combatIgnoreState.overrides = { + combat_ignore: { + condlist: parseConditionsList(TRUE), + }, + }; + expect(canObjectSelectAsEnemy(object, enemy, combatIgnoreState)).toBe(false); + expect(state.enemy_id).toBe(enemy.id()); + + state.enemy_id = null; + combatIgnoreState.overrides = { + combat_ignore: { + condlist: parseConditionsList(FALSE), + }, + }; + expect(canObjectSelectAsEnemy(object, enemy, combatIgnoreState)).toBe(true); + expect(state.enemy_id).toBe(enemy.id()); + }); + + it("'canObjectSelectAsEnemy' should correctly check enemies in no-combat zones", () => { + const object: ClientObject = mockClientGameObject({ clsid: () => classIds.script_stalker as TClassId }); + const enemy: ClientObject = mockClientGameObject(); + const state: IRegistryObjectState = registerObject(object); + const combatIgnoreState: ISchemeCombatIgnoreState = mockSchemeState(object, EScheme.COMBAT_IGNORE); + + const noCombatZone: ClientObject = mockClientGameObject(); + const noCombatSmart: ServerSmartZoneObject = mockServerAlifeSmartZone({ + name: () => "zat_stalker_base_smart" as T, + }); + + state[EScheme.COMBAT_IGNORE] = combatIgnoreState; + + registry.zones.set("zat_a2_sr_no_assault", noCombatZone); + jest.spyOn(noCombatZone, "inside").mockImplementation(() => true); + SimulationBoardManager.getInstance().registerSmartTerrain(noCombatSmart as SmartTerrain); + + (noCombatSmart as SmartTerrain).smartTerrainActorControl = { + status: ESmartTerrainStatus.NORMAL, + } as SmartTerrainControl; + + expect(canObjectSelectAsEnemy(object, enemy, combatIgnoreState)).toBe(false); + expect(state.enemy_id).toBe(enemy.id()); + }); + + it("'canObjectSelectAsEnemy' should correctly ignore enemies in no-combat smarts", () => { + const object: ClientObject = mockClientGameObject({ clsid: () => classIds.script_stalker as TClassId }); + const enemy: ClientObject = mockClientGameObject(); + const state: IRegistryObjectState = registerObject(object); + const combatIgnoreState: ISchemeCombatIgnoreState = mockSchemeState(object, EScheme.COMBAT_IGNORE); + + const noCombatSmart: ServerSmartZoneObject = mockServerAlifeSmartZone({ + name: () => "zat_stalker_base_smart" as T, + }); + + mockServerAlifeHumanStalker({ id: enemy.id(), m_smart_terrain_id: noCombatSmart.id }); + + state[EScheme.COMBAT_IGNORE] = combatIgnoreState; + expect(canObjectSelectAsEnemy(object, enemy, combatIgnoreState)).toBe(false); + expect(state.enemy_id).toBe(enemy.id()); + }); +}); diff --git a/src/engine/core/utils/object/object_danger.ts b/src/engine/core/utils/object/object_danger.ts index ded65502c..6f4a427b1 100644 --- a/src/engine/core/utils/object/object_danger.ts +++ b/src/engine/core/utils/object/object_danger.ts @@ -28,11 +28,15 @@ import { } from "@/engine/lib/types"; /** + * Check whether object is facing any danger. + * + * @param object - target client object to check * @returns whether object is facing any danger right now */ export function isObjectFacingDanger(object: ClientObject): boolean { const bestDanger: Optional = object.best_danger(); + // No danger at all. if (bestDanger === null) { return false; } @@ -43,28 +47,16 @@ export function isObjectFacingDanger(object: ClientObject): boolean { ? bestDanger.dependent_object() : bestDanger.object(); + // No danger source object. if (bestDangerObject === null) { return false; } - if ( - bestDangerType !== danger_object.entity_corpse && - bestDangerType !== danger_object.grenade && - object.relation(bestDangerObject) !== EClientObjectRelation.ENEMY - ) { - return false; - } - - if (bestDangerType === danger_object.grenade) { - // Zombied ignore grenades. - if (getObjectCommunity(object) === communities.zombied) { - return false; - } - } - - // todo: Implement? + // Ignore corpses. if (bestDangerType === danger_object.entity_corpse) { return false; + // todo: Implement? + /** * --const corpse_object = best_danger:object() * --if time_global() - corpse_object:death_time() >= DANGER_INERTION_TIME then @@ -73,8 +65,23 @@ export function isObjectFacingDanger(object: ClientObject): boolean { */ } + // Zombied ignore grenades. + if (bestDangerType === danger_object.grenade && getObjectCommunity(object) === communities.zombied) { + return false; + } + + // Verify relation of enemy object. Handle friendly grenades and death. + if ( + bestDangerType !== danger_object.grenade && + bestDangerType !== danger_object.entity_death && + object.relation(bestDangerObject) !== EClientObjectRelation.ENEMY + ) { + return false; + } + + // Verify if object is not enemy at all. if ( - !isObjectEnemy( + !canObjectSelectAsEnemy( object, bestDangerObject, registry.objects.get(object.id())[EScheme.COMBAT_IGNORE] as ISchemeCombatIgnoreState @@ -85,18 +92,17 @@ export function isObjectFacingDanger(object: ClientObject): boolean { const dangerDistanceSqrt: TDistance = bestDanger.position().distance_to_sqr(object.position()); const ignoreDistanceByType: Optional = logicsConfig.DANGER_IGNORE_DISTANCE_BY_TYPE[bestDangerType]; + const ignoreDistance: TDistance = + ignoreDistanceByType === null + ? logicsConfig.DANGER_IGNORE_DISTANCE_GENERAL * logicsConfig.DANGER_IGNORE_DISTANCE_GENERAL + : ignoreDistanceByType * ignoreDistanceByType; - if (ignoreDistanceByType !== null) { - if (dangerDistanceSqrt >= ignoreDistanceByType * ignoreDistanceByType) { - return false; - } - } else if ( - dangerDistanceSqrt >= - logicsConfig.DANGER_IGNORE_DISTANCE_GENERAL * logicsConfig.DANGER_IGNORE_DISTANCE_GENERAL - ) { + // Verify danger distance. + if (dangerDistanceSqrt > ignoreDistance) { return false; } + // Verify if object is wounded and cannot react to danger. if (isObjectWounded(object.id())) { return false; } @@ -112,43 +118,56 @@ export function isObjectFacingDanger(object: ClientObject): boolean { } /** - * todo; + * Check whether object is valid enemy of another object. + * + * @param object - target object to check + * @param enemy - possible enemy to check + * @param combatIgnoreState - state of combat ignore state scheme * @returns whether object os enemy of provided client entity */ -export function isObjectEnemy(object: ClientObject, enemy: ClientObject, state: ISchemeCombatIgnoreState): boolean { +export function canObjectSelectAsEnemy( + object: ClientObject, + enemy: ClientObject, + combatIgnoreState: ISchemeCombatIgnoreState +): boolean { + // Dead, cannot select enemies. if (!object.alive()) { return false; } - if (object.critically_wounded()) { - return true; - } + const objectState: Optional = registry.objects.get(object.id()); - if (state.enabled === false) { + if (objectState === null) { return true; } - const overrides: Optional = state.overrides; - const objectId: TNumberId = object.id(); - const objectState: IRegistryObjectState = registry.objects.get(objectId); + // todo: Probably also clean it up? And set only when 'true' + objectState.enemy_id = enemy.id(); - if (objectState === null) { + // When object is critically wounded, it should fight back. + if (object.critically_wounded()) { return true; } - objectState.enemy_id = enemy.id(); + // Combat ignoring is explicitly disabled. + if (combatIgnoreState.enabled === false) { + return true; + } if (enemy.id() !== ACTOR_ID) { - for (const [k, v] of registry.noCombatZones) { - const zone = registry.zones.get(k); + // If enemy of object is in no-combat zone. + for (const [name, storyId] of registry.noCombatZones) { + const zone: Optional = registry.zones.get(name); if (zone && (isObjectInZone(object, zone) || isObjectInZone(enemy, zone))) { - const smart: Optional = SimulationBoardManager.getInstance().getSmartTerrainByName(v); + const smartTerrain: Optional = + SimulationBoardManager.getInstance().getSmartTerrainByName(storyId); + // Still allow combat if zone is set to alarm. if ( - smart && - smart.smartTerrainActorControl !== null && - smart.smartTerrainActorControl.status !== ESmartTerrainStatus.ALARM + smartTerrain && + smartTerrain.smartTerrainActorControl !== null && + smartTerrain.smartTerrainActorControl.status !== ESmartTerrainStatus.ALARM ) { return false; } @@ -158,6 +177,7 @@ export function isObjectEnemy(object: ClientObject, enemy: ClientObject, state: const serverObject: Optional = alife().object(enemy.id()); + // Check if server object is in no-combat zone. if ( serverObject !== null && serverObject.m_smart_terrain_id !== null && @@ -172,8 +192,11 @@ export function isObjectEnemy(object: ClientObject, enemy: ClientObject, state: } } - if (overrides && overrides.combat_ignore) { - return pickSectionFromCondList(enemy, object, overrides.combat_ignore.condlist) !== TRUE; + // Check if object have any state overrides that cause object to explicitly ignore combat. + const stateOverrides: Optional = combatIgnoreState.overrides; + + if (stateOverrides && stateOverrides.combat_ignore) { + return pickSectionFromCondList(enemy, object, stateOverrides.combat_ignore.condlist) !== TRUE; } return true; diff --git a/src/engine/core/utils/object/object_find.ts b/src/engine/core/utils/object/object_find.ts index 7cee019ef..815c2fac6 100644 --- a/src/engine/core/utils/object/object_find.ts +++ b/src/engine/core/utils/object/object_find.ts @@ -3,6 +3,7 @@ import { alife, level } from "xray16"; import { registry } from "@/engine/core/database"; import { LuaLogger } from "@/engine/core/utils/logging"; import { areObjectsOnSameLevel } from "@/engine/core/utils/object/object_location"; +import { ACTOR_ID } from "@/engine/lib/constants/ids"; import { AlifeSimulator, AnyCallable, @@ -141,7 +142,7 @@ export function getNearestClientObject( let nearest: Optional = null; level.iterate_online_objects((object: ClientObject): void => { - if (object.parent() !== registry.actor) { + if (object.id() !== ACTOR_ID && object.parent()?.id() !== ACTOR_ID) { let isMatch: boolean = false; // Filter objects if pattern is provided. @@ -187,17 +188,17 @@ export function getClientObjects( ): LuaArray { const list: LuaArray = new LuaTable(); - level.iterate_online_objects((clientObject: ClientObject) => { - if (clientObject.parent() !== registry.actor) { + level.iterate_online_objects((object: ClientObject) => { + if (object.id() !== ACTOR_ID && object.parent()?.id() !== ACTOR_ID) { let isMatch: boolean = false; // Filter objects if pattern is provided. if (pattern !== null) { - if (type(pattern) === "string" && string.find(clientObject.name(), pattern as string)[0]) { + if (type(pattern) === "string" && string.find(object.name(), pattern as string)[0]) { isMatch = true; - } else if (type(pattern) === "number" && pattern === clientObject.clsid()) { + } else if (type(pattern) === "number" && pattern === object.clsid()) { isMatch = true; - } else if (type(pattern) === "function" && (pattern as AnyCallable)(clientObject)) { + } else if (type(pattern) === "function" && (pattern as AnyCallable)(object)) { isMatch = true; } } else { @@ -206,7 +207,7 @@ export function getClientObjects( // Validate match and online-offline check. if (isMatch) { - table.insert(list, clientObject); + table.insert(list, object); } } }); diff --git a/src/engine/core/utils/scheme/scheme_initialization.test.ts b/src/engine/core/utils/scheme/scheme_initialization.test.ts index 4af38b40c..3e4f7de2d 100644 --- a/src/engine/core/utils/scheme/scheme_initialization.test.ts +++ b/src/engine/core/utils/scheme/scheme_initialization.test.ts @@ -138,7 +138,7 @@ describe("'scheme initialization' utils", () => { jest.spyOn(it, "reset").mockImplementation(() => {}); }); - jest.spyOn(smartTerrain, "getJob").mockImplementation(() => ({ ini_path: "job_test.ltx" } as ISmartTerrainJob)); + jest.spyOn(smartTerrain, "getJob").mockImplementation(() => ({ ini_path: "job_test.ltx" }) as ISmartTerrainJob); resetFunctionMock(alife().create); diff --git a/src/engine/core/utils/scheme/scheme_logic.test.ts b/src/engine/core/utils/scheme/scheme_logic.test.ts index 644dc480e..3903b29d6 100644 --- a/src/engine/core/utils/scheme/scheme_logic.test.ts +++ b/src/engine/core/utils/scheme/scheme_logic.test.ts @@ -50,6 +50,9 @@ import { MockAlifeSimulator, mockClientGameObject, mockIniFile, mockServerAlifeH import { MockCTime } from "@/fixtures/xray/mocks/CTime.mock"; describe("'scheme logic' utils", () => { + /** + * todo; + */ function loadGenericSchemes(): Array { const schemes: Array = [ SchemeMeet, @@ -212,7 +215,7 @@ describe("'scheme logic' utils", () => { () => ({ section: "patrol@test", - } as ISmartTerrainJob) + }) as ISmartTerrainJob ); const ini: IniFile = mockIniFile("test.ltx", { diff --git a/src/engine/core/utils/transform/decamelize.ts b/src/engine/core/utils/transform/decamelize.ts index 3daacdb2c..debfb43e7 100644 --- a/src/engine/core/utils/transform/decamelize.ts +++ b/src/engine/core/utils/transform/decamelize.ts @@ -16,10 +16,6 @@ function handlePreserveConsecutiveUppercase(decamelized: string, separator: stri /** * Fork of NPM 'decamelize' package utility. * Decamelize provided string. - * - * @param text - string value to decamelize - * @param config - decamelize process parameters - * @returns decamelized string */ export function decamelize(text: string, { separator = "_", preserveConsecutiveUppercase = false } = {}) { if (text.length < 2) { diff --git a/src/engine/core/utils/transform/json.test.ts b/src/engine/core/utils/transform/json.test.ts index 7ae39ec1f..9ba58d797 100644 --- a/src/engine/core/utils/transform/json.test.ts +++ b/src/engine/core/utils/transform/json.test.ts @@ -1,11 +1,11 @@ -import { describe, expect, it } from "@jest/globals"; +import { describe, expect, it, jest } from "@jest/globals"; import { quoted } from "#/utils"; -import { toJSON } from "@/engine/core/utils/transform/json"; +import { stringifyKey, toJSON } from "@/engine/core/utils/transform/json"; describe("'json' util", () => { - it("should correctly stringify simple types", () => { + it("'toJSON' should correctly stringify simple types", () => { expect(toJSON("abc")).toBe(quoted("abc")); expect(toJSON("bca")).toBe(quoted("bca")); expect(toJSON(123)).toBe("123"); @@ -16,7 +16,7 @@ describe("'json' util", () => { expect(toJSON(undefined)).toBe(""); }); - it("should correctly stringify tables", () => { + it("'toJSON' should correctly stringify tables", () => { expect(toJSON({})).toBe("{}"); expect(toJSON({ a: 10 })).toBe(`{${quoted("a")}: 10}`); expect(toJSON({ b: "ab", c: 5, d: false, e: null })).toBe( @@ -25,7 +25,7 @@ describe("'json' util", () => { expect(toJSON({ a: 10, b: { c: 1234 } })).toBe(`{${quoted("a")}: 10, "b": {"c": 1234}}`); }); - it("should correctly stringify circular references", () => { + it("'toJSON' should correctly stringify circular references", () => { const base = { nested: { circular: {} } }; base.nested.circular = base; @@ -33,7 +33,7 @@ describe("'json' util", () => { expect(toJSON(base)).toBe(`{${quoted("nested")}: {"circular": }}`); }); - it("should correctly limit depth", () => { + it("'toJSON' should correctly limit depth", () => { const base = { nested: { nested: { nested: { nested: {} } } } }; expect(toJSON(base, " ", 0, 3)).toBe(`{${quoted("nested")}: {"nested": {"nested": {"nested": }}}}`); @@ -41,4 +41,27 @@ describe("'json' util", () => { expect(toJSON(base, " ", 0, 1)).toBe(`{${quoted("nested")}: {"nested": }}`); expect(toJSON(base, " ", 0, 0)).toBe(`{${quoted("nested")}: }`); }); + + it("'toJSON' should correctly transform unusual non-table values", () => { + expect(toJSON(() => {})).toBe(""); + + jest.spyOn(global, "type").mockReturnValueOnce("userdata"); + expect(toJSON({})).toBe(""); + + jest.spyOn(global, "type").mockReturnValueOnce("thread"); + expect(toJSON({})).toBe(""); + }); + + it("'stringifyKey' should correctly stringify json keys", () => { + expect(stringifyKey(123)).toBe("123"); + expect(stringifyKey("abc")).toBe("abc"); + expect(stringifyKey(true)).toBe(""); + expect(stringifyKey(() => {})).toBe(""); + + jest.spyOn(global, "type").mockReturnValueOnce("userdata"); + expect(stringifyKey({})).toBe(""); + + jest.spyOn(global, "type").mockReturnValueOnce("thread"); + expect(stringifyKey({})).toBe(""); + }); }); diff --git a/src/engine/core/utils/vector.ts b/src/engine/core/utils/vector.ts index 0a03254ad..f545e3717 100644 --- a/src/engine/core/utils/vector.ts +++ b/src/engine/core/utils/vector.ts @@ -51,6 +51,8 @@ export function subVectors(first: Vector, second: Vector): Vector { } /** + * Cross-multiply vectors. + * * @param first - vector to cross * @param second - vector to cross * @returns vectors cross multiplication result @@ -74,6 +76,8 @@ export function copyVector(source: Vector): Vector { } /** + * Get vectors yaw. + * * @param first - vector to compute * @param second - vector to compute * @returns vectors yaw @@ -86,6 +90,8 @@ export function yaw(first: Vector, second: Vector): TRate { } /** + * Get vectors yaw degree. + * * @param first - vector to compute * @param second - vector to compute * @returns vectors yaw degree @@ -100,6 +106,8 @@ export function yawDegree(first: Vector, second: Vector): TRate { } /** + * Get vectors yaw degree in 3 dimensions. + * * @param first - vector to compute * @param second - vector to compute * @returns vectors yaw degree in 3 dimensions @@ -115,6 +123,8 @@ export function yawDegree3d(first: Vector, second: Vector): TRate { } /** + * Rotate vector by Y axis. + * * @param target - vector to rotate * @param angleBase - angle to rotate vector * @returns new rotated vector @@ -159,6 +169,8 @@ export function angleDiff(first: Vector, second: Vector): number { } /** + * Transform angle vector to direction vector. + * * @param angle - angle vector * @returns direction vector based on angle vector */ diff --git a/src/engine/forms/actor_menu.tsx b/src/engine/forms/actor_menu.tsx index 12d6ce8ec..6e7d73f88 100644 --- a/src/engine/forms/actor_menu.tsx +++ b/src/engine/forms/actor_menu.tsx @@ -2,6 +2,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { captions } from "@/engine/lib/constants/captions"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/actor_menu_16.tsx b/src/engine/forms/actor_menu_16.tsx index 7dd119967..291e1f3ca 100644 --- a/src/engine/forms/actor_menu_16.tsx +++ b/src/engine/forms/actor_menu_16.tsx @@ -2,6 +2,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { captions } from "@/engine/lib/constants/captions"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/actor_menu_item.tsx b/src/engine/forms/actor_menu_item.tsx index 96d3a6a70..ce69c460f 100644 --- a/src/engine/forms/actor_menu_item.tsx +++ b/src/engine/forms/actor_menu_item.tsx @@ -3,6 +3,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { ArtefactParams } from "@/engine/forms/af_params"; import { BoosterParams } from "@/engine/forms/booster_params"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/actor_menu_item_16.tsx b/src/engine/forms/actor_menu_item_16.tsx index f08e768d0..b8cd9283d 100644 --- a/src/engine/forms/actor_menu_item_16.tsx +++ b/src/engine/forms/actor_menu_item_16.tsx @@ -3,6 +3,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { ArtefactParams } from "@/engine/forms/af_params_16"; import { BoosterParams } from "@/engine/forms/booster_params_16"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/af_params.tsx b/src/engine/forms/af_params.tsx index 294cdee13..f0a5454f6 100644 --- a/src/engine/forms/af_params.tsx +++ b/src/engine/forms/af_params.tsx @@ -1,9 +1,15 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ; } +/** + * todo; + */ export function ArtefactParams(): JSXNode { return ( diff --git a/src/engine/forms/af_params_16.tsx b/src/engine/forms/af_params_16.tsx index 30e74882b..9d113ca62 100644 --- a/src/engine/forms/af_params_16.tsx +++ b/src/engine/forms/af_params_16.tsx @@ -1,9 +1,15 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ; } +/** + * todo; + */ export function ArtefactParams(): JSXNode { return ( diff --git a/src/engine/forms/booster_params.tsx b/src/engine/forms/booster_params.tsx index c1db4655f..73a834c03 100644 --- a/src/engine/forms/booster_params.tsx +++ b/src/engine/forms/booster_params.tsx @@ -4,10 +4,16 @@ import { XrComponent, XrText } from "@/engine/forms/components/base"; import { XrTexture } from "@/engine/forms/components/base/XrTexture.component"; import { fonts } from "@/engine/lib/constants/fonts"; +/** + * todo; + */ export function create(): JSXNode { return ; } +/** + * todo; + */ export function BoosterParams(): JSXNode { return ( @@ -41,6 +47,9 @@ export function BoosterParams(): JSXNode { ); } +/** + * todo; + */ function BoosterParam({ name, texture, diff --git a/src/engine/forms/booster_params_16.tsx b/src/engine/forms/booster_params_16.tsx index e33279cce..8073edea7 100644 --- a/src/engine/forms/booster_params_16.tsx +++ b/src/engine/forms/booster_params_16.tsx @@ -4,10 +4,16 @@ import { XrComponent, XrText } from "@/engine/forms/components/base"; import { XrTexture } from "@/engine/forms/components/base/XrTexture.component"; import { fonts } from "@/engine/lib/constants/fonts"; +/** + * todo; + */ export function create(): JSXNode { return ; } +/** + * todo; + */ export function BoosterParams(): JSXNode { return ( @@ -41,6 +47,9 @@ export function BoosterParams(): JSXNode { ); } +/** + * + */ function BoosterParam({ name, texture, diff --git a/src/engine/forms/buy_menu_item.tsx b/src/engine/forms/buy_menu_item.tsx index bfe2ed691..9af08e21a 100644 --- a/src/engine/forms/buy_menu_item.tsx +++ b/src/engine/forms/buy_menu_item.tsx @@ -3,6 +3,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { ArtefactParams } from "@/engine/forms/af_params"; import { BoosterParams } from "@/engine/forms/booster_params"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/buy_menu_item_16.tsx b/src/engine/forms/buy_menu_item_16.tsx index f1c89c659..3fa2f507e 100644 --- a/src/engine/forms/buy_menu_item_16.tsx +++ b/src/engine/forms/buy_menu_item_16.tsx @@ -3,6 +3,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { ArtefactParams } from "@/engine/forms/af_params_16"; import { BoosterParams } from "@/engine/forms/booster_params_16"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/chat_mp.tsx b/src/engine/forms/chat_mp.tsx index c6874b04b..4c921a394 100644 --- a/src/engine/forms/chat_mp.tsx +++ b/src/engine/forms/chat_mp.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/color_defs.tsx b/src/engine/forms/color_defs.tsx index f61907f39..92da34557 100644 --- a/src/engine/forms/color_defs.tsx +++ b/src/engine/forms/color_defs.tsx @@ -1,6 +1,10 @@ import { JSXNode, JSXXML } from "jsx-xml"; // todo: Use enum with defined colors. + +/** + * todo; + */ export function create(): JSXNode { // // diff --git a/src/engine/forms/components/base/XrBackground.component.tsx b/src/engine/forms/components/base/XrBackground.component.tsx index afd9efc68..6ee21194d 100644 --- a/src/engine/forms/components/base/XrBackground.component.tsx +++ b/src/engine/forms/components/base/XrBackground.component.tsx @@ -8,6 +8,9 @@ export interface IXrBackgroundProps extends IBaseXmlNode { stretch?: boolean; } +/** + * todo; + */ export function XrBackground(props: IXrBackgroundProps): JSXNode { const { x, y, width, height, stretch } = normalizeBaseNodeProps(props); diff --git a/src/engine/forms/components/base/XrCheckBox.component.tsx b/src/engine/forms/components/base/XrCheckBox.component.tsx index 26d34d36d..138f5cbc3 100644 --- a/src/engine/forms/components/base/XrCheckBox.component.tsx +++ b/src/engine/forms/components/base/XrCheckBox.component.tsx @@ -16,6 +16,9 @@ export interface IXrCheckBoxProps extends IBaseXmlNode { group?: string; } +/** + * todo; + */ export function XrCheckBox(props: IXrCheckBoxProps): JSXNode { const { tag = "check", diff --git a/src/engine/forms/components/base/XrComponent.component.tsx b/src/engine/forms/components/base/XrComponent.component.tsx index 168e0ba8f..a06a9ec33 100644 --- a/src/engine/forms/components/base/XrComponent.component.tsx +++ b/src/engine/forms/components/base/XrComponent.component.tsx @@ -6,6 +6,9 @@ import { IBaseXmlNode } from "@/engine/lib/types"; export interface IXrContainerProps extends IBaseXmlNode {} +/** + * todo; + */ export function XrComponent(props: IXrContainerProps): JSXNode { const { x, y, width, height, stretch } = normalizeBaseNodeProps(props); diff --git a/src/engine/forms/components/base/XrEditBox.component.tsx b/src/engine/forms/components/base/XrEditBox.component.tsx index d58c03a2a..7f8845bbc 100644 --- a/src/engine/forms/components/base/XrEditBox.component.tsx +++ b/src/engine/forms/components/base/XrEditBox.component.tsx @@ -17,6 +17,9 @@ export interface IXrEditBoxProps extends IBaseXmlNode { maxSymbolsCount?: number; } +/** + * todo; + */ export function XrEditBox(props: IXrEditBoxProps): JSXNode { const { tag = "edit_box", diff --git a/src/engine/forms/components/base/XrList.component.tsx b/src/engine/forms/components/base/XrList.component.tsx index 80e75f494..e6a68fdb2 100644 --- a/src/engine/forms/components/base/XrList.component.tsx +++ b/src/engine/forms/components/base/XrList.component.tsx @@ -10,7 +10,9 @@ export interface IXrListComponentProps extends IBaseXmlNode { itemHeight: number; canSelect?: boolean; } - +/** + * todo; + */ export function XrList(props: IXrListComponentProps): JSXNode { const { tag = "list", diff --git a/src/engine/forms/components/base/XrListRenderer.component.tsx b/src/engine/forms/components/base/XrListRenderer.component.tsx index 479164304..29e01fb28 100644 --- a/src/engine/forms/components/base/XrListRenderer.component.tsx +++ b/src/engine/forms/components/base/XrListRenderer.component.tsx @@ -7,6 +7,9 @@ import { IBaseXmlNode } from "@/engine/lib/types"; export interface IXrComboBoxProps extends IBaseXmlNode {} +/** + * todo; + */ export function XrComboBox(props: IXrComboBoxProps): JSXNode { const { tag = "list_renderer", x, y, width, height, children = null } = normalizeBaseNodeProps(props); diff --git a/src/engine/forms/components/base/XrRoot.component.tsx b/src/engine/forms/components/base/XrRoot.component.tsx index e6bb1dcd8..b612d1983 100644 --- a/src/engine/forms/components/base/XrRoot.component.tsx +++ b/src/engine/forms/components/base/XrRoot.component.tsx @@ -6,6 +6,9 @@ import { IBaseXmlNode } from "@/engine/lib/types"; export interface IXrRootProps extends IBaseXmlNode {} +/** + * todo; + */ export function XrRoot(props: IXrRootProps): JSXNode { const { width, height, x, y } = normalizeBaseNodeProps(props); diff --git a/src/engine/forms/components/base/XrScrollView.component.tsx b/src/engine/forms/components/base/XrScrollView.component.tsx index f337b1994..5a759a528 100644 --- a/src/engine/forms/components/base/XrScrollView.component.tsx +++ b/src/engine/forms/components/base/XrScrollView.component.tsx @@ -17,6 +17,9 @@ export interface IXrScrollViewProps extends IBaseXmlNode { scrollProfile?: string; } +/** + * todo; + */ export function XrScrollView(props: IXrScrollViewProps): JSXNode { const { tag = "scroll_view", diff --git a/src/engine/forms/components/base/XrTabButton.component.tsx b/src/engine/forms/components/base/XrTabButton.component.tsx index 6d897ce43..01073a529 100644 --- a/src/engine/forms/components/base/XrTabButton.component.tsx +++ b/src/engine/forms/components/base/XrTabButton.component.tsx @@ -12,6 +12,9 @@ export interface IXrTabButtonProps extends IBaseXmlNode { stretch?: boolean; } +/** + * todo; + */ export function XrTabButton(props: IXrTabButtonProps): JSXNode { const { x, y, width, height, children, texture, id, stretch } = normalizeBaseNodeProps(props); diff --git a/src/engine/forms/demo_play_control.tsx b/src/engine/forms/demo_play_control.tsx index 4e0bfc3ab..d9f74dd9c 100644 --- a/src/engine/forms/demo_play_control.tsx +++ b/src/engine/forms/demo_play_control.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/game/GameUi.component.16.tsx b/src/engine/forms/game/GameUi.component.16.tsx index f562f25f0..be1501da2 100644 --- a/src/engine/forms/game/GameUi.component.16.tsx +++ b/src/engine/forms/game/GameUi.component.16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function GameUi(): JSXNode { return ( diff --git a/src/engine/forms/game/GameUi.component.tsx b/src/engine/forms/game/GameUi.component.tsx index 9498c77ed..b0229bc92 100644 --- a/src/engine/forms/game/GameUi.component.tsx +++ b/src/engine/forms/game/GameUi.component.tsx @@ -2,6 +2,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { captions } from "@/engine/lib/constants/captions"; +/** + * todo; + */ export function GameUi(): JSXNode { return ( diff --git a/src/engine/forms/game/heli/heli_progress.tsx b/src/engine/forms/game/heli/heli_progress.tsx index 50edeba03..a2aa9cdc4 100644 --- a/src/engine/forms/game/heli/heli_progress.tsx +++ b/src/engine/forms/game/heli/heli_progress.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/game/map/MapDescription.component.16.tsx b/src/engine/forms/game/map/MapDescription.component.16.tsx index e8b883294..f4c3696bf 100644 --- a/src/engine/forms/game/map/MapDescription.component.16.tsx +++ b/src/engine/forms/game/map/MapDescription.component.16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function MapDescription(): JSXNode { return ( diff --git a/src/engine/forms/game/map/MapDescription.component.tsx b/src/engine/forms/game/map/MapDescription.component.tsx index 662a141f9..ca94c1b48 100644 --- a/src/engine/forms/game/map/MapDescription.component.tsx +++ b/src/engine/forms/game/map/MapDescription.component.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function MapDescription(): JSXNode { return ( diff --git a/src/engine/forms/game/map/MapSpots.component.16.tsx b/src/engine/forms/game/map/MapSpots.component.16.tsx index 9d5f7bc10..1aac8948a 100644 --- a/src/engine/forms/game/map/MapSpots.component.16.tsx +++ b/src/engine/forms/game/map/MapSpots.component.16.tsx @@ -6,6 +6,9 @@ import { SmartTerrainSpots } from "@/engine/forms/game/map/spots/SmartTerrainSpo import { SquadSpots } from "@/engine/forms/game/map/spots/SquadSpots"; import { TaskSpots } from "@/engine/forms/game/map/spots/TaskSpots"; +/** + * todo; + */ export function MapSpots(): JSXNode { return ( @@ -349,8 +352,10 @@ export function MapSpots(): JSXNode { - {/** */} + {/** + + */} ui_inGame2_PDA_icon_secret @@ -848,7 +853,7 @@ export function MapSpots(): JSXNode { > ui_inGame2_PDA_icon_location - {/** */} + {/** + + */} ui_inGame2_PDA_icon_secret @@ -848,11 +853,13 @@ export function MapSpots(): JSXNode { > ui_inGame2_PDA_icon_location - {/** */} + --> + */} diff --git a/src/engine/forms/game/map/Pda.component.16.tsx b/src/engine/forms/game/map/Pda.component.16.tsx index 94642994c..fdb0c86dd 100644 --- a/src/engine/forms/game/map/Pda.component.16.tsx +++ b/src/engine/forms/game/map/Pda.component.16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function Pda(): JSXNode { return ( diff --git a/src/engine/forms/game/map/Pda.component.tsx b/src/engine/forms/game/map/Pda.component.tsx index 4854e2ae4..aac3908a4 100644 --- a/src/engine/forms/game/map/Pda.component.tsx +++ b/src/engine/forms/game/map/Pda.component.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function Pda(): JSXNode { return ( diff --git a/src/engine/forms/game/map/spots/MapMultiplayerSpots.tsx b/src/engine/forms/game/map/spots/MapMultiplayerSpots.tsx index 34fc0ee85..e3782bc6b 100644 --- a/src/engine/forms/game/map/spots/MapMultiplayerSpots.tsx +++ b/src/engine/forms/game/map/spots/MapMultiplayerSpots.tsx @@ -1,5 +1,8 @@ import { Fragment, JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function MapMultiplayerSpots(): JSXNode { return ( diff --git a/src/engine/forms/game/map/spots/MapRelationSpots.tsx b/src/engine/forms/game/map/spots/MapRelationSpots.tsx index d3df11a44..f5340a024 100644 --- a/src/engine/forms/game/map/spots/MapRelationSpots.tsx +++ b/src/engine/forms/game/map/spots/MapRelationSpots.tsx @@ -1,5 +1,8 @@ import { Fragment, JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function MapRelationSpots(): JSXNode { return ( diff --git a/src/engine/forms/game/map/spots/SmartTerrainSpots.tsx b/src/engine/forms/game/map/spots/SmartTerrainSpots.tsx index 0b5127da3..e8c1b4b25 100644 --- a/src/engine/forms/game/map/spots/SmartTerrainSpots.tsx +++ b/src/engine/forms/game/map/spots/SmartTerrainSpots.tsx @@ -1,5 +1,8 @@ import { Fragment, JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function SmartTerrainSpots(): JSXNode { return ( diff --git a/src/engine/forms/game/map/spots/SquadSpots.tsx b/src/engine/forms/game/map/spots/SquadSpots.tsx index 162361537..81bc346ea 100644 --- a/src/engine/forms/game/map/spots/SquadSpots.tsx +++ b/src/engine/forms/game/map/spots/SquadSpots.tsx @@ -1,5 +1,8 @@ import { Fragment, JSXNode, JSXXML } from "jsx-xml"; +/** + * + */ export function SquadSpots(): JSXNode { return ( @@ -171,7 +174,7 @@ export function SquadSpots(): JSXNode { - {/** - */} + */} @@ -461,13 +464,16 @@ export function TaskSpots(): JSXNode { - {/** */} + --> + */} - {/** */} + --> + */} @@ -708,7 +715,8 @@ export function TaskSpots(): JSXNode { - {/** */} + --> + */} ); } diff --git a/src/engine/forms/game_tutorials.tsx b/src/engine/forms/game_tutorials.tsx index 19814930f..e11791d05 100644 --- a/src/engine/forms/game_tutorials.tsx +++ b/src/engine/forms/game_tutorials.tsx @@ -10,6 +10,9 @@ import { GameVendorsIntro, } from "@/engine/forms/tutorials"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/grenade.tsx b/src/engine/forms/grenade.tsx index b516f8a38..1967b3eb5 100644 --- a/src/engine/forms/grenade.tsx +++ b/src/engine/forms/grenade.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/hint_item.tsx b/src/engine/forms/hint_item.tsx index 1f156afa6..971518466 100644 --- a/src/engine/forms/hint_item.tsx +++ b/src/engine/forms/hint_item.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ingame_msglog_mp.tsx b/src/engine/forms/ingame_msglog_mp.tsx index f04b4d560..0bca27e43 100644 --- a/src/engine/forms/ingame_msglog_mp.tsx +++ b/src/engine/forms/ingame_msglog_mp.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ingame_msglog_sp.tsx b/src/engine/forms/ingame_msglog_sp.tsx index d13c33bc7..207ea1c0a 100644 --- a/src/engine/forms/ingame_msglog_sp.tsx +++ b/src/engine/forms/ingame_msglog_sp.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/interaction/SleepDialog.component.16.tsx b/src/engine/forms/interaction/SleepDialog.component.16.tsx index 4a47a8beb..996357bee 100644 --- a/src/engine/forms/interaction/SleepDialog.component.16.tsx +++ b/src/engine/forms/interaction/SleepDialog.component.16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/interaction/SleepDialog.component.tsx b/src/engine/forms/interaction/SleepDialog.component.tsx index 204f463ff..dc319b9ec 100644 --- a/src/engine/forms/interaction/SleepDialog.component.tsx +++ b/src/engine/forms/interaction/SleepDialog.component.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/inventory_new.tsx b/src/engine/forms/inventory_new.tsx index fa8426401..e76ed1bb1 100644 --- a/src/engine/forms/inventory_new.tsx +++ b/src/engine/forms/inventory_new.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ; } diff --git a/src/engine/forms/inventory_new_16.tsx b/src/engine/forms/inventory_new_16.tsx index fa8426401..e76ed1bb1 100644 --- a/src/engine/forms/inventory_new_16.tsx +++ b/src/engine/forms/inventory_new_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ; } diff --git a/src/engine/forms/inventory_upgrade.tsx b/src/engine/forms/inventory_upgrade.tsx index 31a998650..464b1e7b6 100644 --- a/src/engine/forms/inventory_upgrade.tsx +++ b/src/engine/forms/inventory_upgrade.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/inventory_upgrade_16.tsx b/src/engine/forms/inventory_upgrade_16.tsx index 89cad9704..d9d92fdd6 100644 --- a/src/engine/forms/inventory_upgrade_16.tsx +++ b/src/engine/forms/inventory_upgrade_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/inventory_upgrade_info.tsx b/src/engine/forms/inventory_upgrade_info.tsx index fa8426401..e76ed1bb1 100644 --- a/src/engine/forms/inventory_upgrade_info.tsx +++ b/src/engine/forms/inventory_upgrade_info.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ; } diff --git a/src/engine/forms/inventory_upgrade_info_16.tsx b/src/engine/forms/inventory_upgrade_info_16.tsx index fa8426401..e76ed1bb1 100644 --- a/src/engine/forms/inventory_upgrade_info_16.tsx +++ b/src/engine/forms/inventory_upgrade_info_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ; } diff --git a/src/engine/forms/maingame.tsx b/src/engine/forms/maingame.tsx index 2a6b727e2..ca10bc1ff 100644 --- a/src/engine/forms/maingame.tsx +++ b/src/engine/forms/maingame.tsx @@ -2,6 +2,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { GameUi } from "@/engine/forms/game/GameUi.component"; +/** + * todo; + */ export function create(): JSXNode { return ; } diff --git a/src/engine/forms/maingame_16.tsx b/src/engine/forms/maingame_16.tsx index 62b01d4a5..84e24276c 100644 --- a/src/engine/forms/maingame_16.tsx +++ b/src/engine/forms/maingame_16.tsx @@ -2,6 +2,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { GameUi } from "@/engine/forms/game/GameUi.component.16"; +/** + * todo; + */ export function create(): JSXNode { return ; } diff --git a/src/engine/forms/maingame_pda_msg.tsx b/src/engine/forms/maingame_pda_msg.tsx index eb67157ea..fe94f2402 100644 --- a/src/engine/forms/maingame_pda_msg.tsx +++ b/src/engine/forms/maingame_pda_msg.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/maingame_pda_msg_16.tsx b/src/engine/forms/maingame_pda_msg_16.tsx index 2c65b90a7..a4be57051 100644 --- a/src/engine/forms/maingame_pda_msg_16.tsx +++ b/src/engine/forms/maingame_pda_msg_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/map_desc.tsx b/src/engine/forms/map_desc.tsx index 6f9b3f526..d686585a0 100644 --- a/src/engine/forms/map_desc.tsx +++ b/src/engine/forms/map_desc.tsx @@ -2,6 +2,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { MapDescription } from "@/engine/forms/game/map/MapDescription.component"; +/** + * todo; + */ export function create(): JSXNode { return ; } diff --git a/src/engine/forms/map_desc_16.tsx b/src/engine/forms/map_desc_16.tsx index da3e20d81..680acbc85 100644 --- a/src/engine/forms/map_desc_16.tsx +++ b/src/engine/forms/map_desc_16.tsx @@ -2,6 +2,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { MapDescription } from "@/engine/forms/game/map/MapDescription.component.16"; +/** + * todo; + */ export function create(): JSXNode { return ; } diff --git a/src/engine/forms/map_spots.tsx b/src/engine/forms/map_spots.tsx index 3662d3bd5..95a25d82e 100644 --- a/src/engine/forms/map_spots.tsx +++ b/src/engine/forms/map_spots.tsx @@ -2,6 +2,9 @@ import { MapSpots } from "@/engine/forms/game/map/MapSpots.component"; +/** + * todo; + */ export function create(): JSXNode { return ; } diff --git a/src/engine/forms/map_spots_16.tsx b/src/engine/forms/map_spots_16.tsx index 113a1558b..49a8b7f42 100644 --- a/src/engine/forms/map_spots_16.tsx +++ b/src/engine/forms/map_spots_16.tsx @@ -2,6 +2,9 @@ import { MapSpots } from "@/engine/forms/game/map/MapSpots.component.16"; +/** + * todo; + */ export function create(): JSXNode { return ; } diff --git a/src/engine/forms/menu/LoadDialog.component.tsx b/src/engine/forms/menu/LoadDialog.component.tsx index 902ce424b..8b8d6edb8 100644 --- a/src/engine/forms/menu/LoadDialog.component.tsx +++ b/src/engine/forms/menu/LoadDialog.component.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/MainMenu.component.tsx b/src/engine/forms/menu/MainMenu.component.tsx index 235d63a1c..544ee08b7 100644 --- a/src/engine/forms/menu/MainMenu.component.tsx +++ b/src/engine/forms/menu/MainMenu.component.tsx @@ -4,6 +4,9 @@ import { captions } from "@/engine/lib/constants/captions/captions"; import { fonts } from "@/engine/lib/constants/fonts"; import { textures } from "@/engine/lib/constants/textures"; +/** + * todo; + */ export function create(): JSXNode { return ( @@ -105,6 +108,9 @@ export function create(): JSXNode { ); } +/** + * todo; + */ function MainMenuBackground(): JSXNode { return ( diff --git a/src/engine/forms/menu/MenuCredits.tsx b/src/engine/forms/menu/MenuCredits.tsx index c2d1cf0e2..5d4f615db 100644 --- a/src/engine/forms/menu/MenuCredits.tsx +++ b/src/engine/forms/menu/MenuCredits.tsx @@ -1,5 +1,8 @@ import { Fragment, JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function MenuCredits(): JSXNode { return ( diff --git a/src/engine/forms/menu/OptionsDialog.component.tsx b/src/engine/forms/menu/OptionsDialog.component.tsx index cdcda72d3..497dcd76d 100644 --- a/src/engine/forms/menu/OptionsDialog.component.tsx +++ b/src/engine/forms/menu/OptionsDialog.component.tsx @@ -6,6 +6,9 @@ import { OptionsSounds } from "@/engine/forms/menu/options/OptionsSounds.part"; import { OptionsVideo } from "@/engine/forms/menu/options/OptionsVideo.part"; import { OptionsVideoAdvanced } from "@/engine/forms/menu/options/OptionsVideoAdvanced.part"; +/** + * todo; + */ export function create(): JSXNode { return ( @@ -30,6 +33,9 @@ export function create(): JSXNode { ); } +/** + * todo; + */ function OptionsBody(): JSXNode { return ( @@ -105,6 +111,9 @@ function OptionsBody(): JSXNode { ); } +/** + * todo; + */ function OptionsBackground(): JSXNode { return ( @@ -126,6 +135,9 @@ function OptionsBackground(): JSXNode { ); } +/** + * + */ function OptionsPatchDownload(): JSXNode { return ( diff --git a/src/engine/forms/menu/SaveDialog.component.tsx b/src/engine/forms/menu/SaveDialog.component.tsx index e7af637f4..9fceff10f 100644 --- a/src/engine/forms/menu/SaveDialog.component.tsx +++ b/src/engine/forms/menu/SaveDialog.component.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/debug/DebugCommandsSection.component.tsx b/src/engine/forms/menu/debug/DebugCommandsSection.component.tsx index 4642aa8b4..24f0b3816 100644 --- a/src/engine/forms/menu/debug/DebugCommandsSection.component.tsx +++ b/src/engine/forms/menu/debug/DebugCommandsSection.component.tsx @@ -4,6 +4,9 @@ import { XrCheckBox, XrComponent, XrRoot, XrText } from "@/engine/forms/componen import { XrScrollView } from "@/engine/forms/components/base/XrScrollView.component"; import { SECTION_HEIGHT, SECTION_WIDTH } from "@/engine/forms/menu/debug/DebugDialog.component"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/debug/DebugDialog.component.tsx b/src/engine/forms/menu/debug/DebugDialog.component.tsx index 65cea106b..bbf628d47 100644 --- a/src/engine/forms/menu/debug/DebugDialog.component.tsx +++ b/src/engine/forms/menu/debug/DebugDialog.component.tsx @@ -19,6 +19,9 @@ export const SECTION_HEIGHT: number = BASE_HEIGHT - 16; const TEXT_COLOR_DARKER: IRgbColor = { r: 170, g: 170, b: 170 }; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/debug/DebugGeneralSection.component.tsx b/src/engine/forms/menu/debug/DebugGeneralSection.component.tsx index 680a6a5d8..61fe5d38f 100644 --- a/src/engine/forms/menu/debug/DebugGeneralSection.component.tsx +++ b/src/engine/forms/menu/debug/DebugGeneralSection.component.tsx @@ -9,6 +9,9 @@ import { textures } from "@/engine/lib/constants/textures"; const BASE_WIDTH: number = SECTION_WIDTH; const BASE_HEIGHT: number = SECTION_HEIGHT; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/debug/DebugItemsSection.component.tsx b/src/engine/forms/menu/debug/DebugItemsSection.component.tsx index c8facd963..29d518b3d 100644 --- a/src/engine/forms/menu/debug/DebugItemsSection.component.tsx +++ b/src/engine/forms/menu/debug/DebugItemsSection.component.tsx @@ -7,6 +7,9 @@ import { SECTION_HEIGHT, SECTION_WIDTH } from "@/engine/forms/menu/debug/DebugDi import { WHITE } from "@/engine/lib/constants/colors"; import { textures } from "@/engine/lib/constants/textures"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/debug/DebugObjectSection.component.tsx b/src/engine/forms/menu/debug/DebugObjectSection.component.tsx index 06ffc3541..27c4a5177 100644 --- a/src/engine/forms/menu/debug/DebugObjectSection.component.tsx +++ b/src/engine/forms/menu/debug/DebugObjectSection.component.tsx @@ -4,6 +4,9 @@ import { Xr3tButton, XrCheckBox, XrRoot, XrStatic, XrText } from "@/engine/forms import { WHITE } from "@/engine/lib/constants/colors"; import { fonts } from "@/engine/lib/constants/fonts"; +/** + * todo; + */ export function create(): JSXNode { return ( @@ -24,6 +27,9 @@ export function create(): JSXNode { ); } +/** + * todo; + */ function renderLoggingButtons(): JSXNode { return ( @@ -85,6 +91,9 @@ function renderLoggingButtons(): JSXNode { ); } +/** + * todo; + */ function renderRelationButtons(): JSXNode { return ( diff --git a/src/engine/forms/menu/debug/DebugPlayerSection.component.tsx b/src/engine/forms/menu/debug/DebugPlayerSection.component.tsx index 9ff7810b3..c93426ce5 100644 --- a/src/engine/forms/menu/debug/DebugPlayerSection.component.tsx +++ b/src/engine/forms/menu/debug/DebugPlayerSection.component.tsx @@ -6,6 +6,9 @@ import { textures } from "@/engine/lib/constants/textures"; const BASE_WIDTH: number = SECTION_WIDTH; const BASE_HEIGHT: number = SECTION_HEIGHT; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/debug/DebugPositionSection.component.tsx b/src/engine/forms/menu/debug/DebugPositionSection.component.tsx index 9ff7810b3..c93426ce5 100644 --- a/src/engine/forms/menu/debug/DebugPositionSection.component.tsx +++ b/src/engine/forms/menu/debug/DebugPositionSection.component.tsx @@ -6,6 +6,9 @@ import { textures } from "@/engine/lib/constants/textures"; const BASE_WIDTH: number = SECTION_WIDTH; const BASE_HEIGHT: number = SECTION_HEIGHT; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/debug/DebugRegistrySection.component.tsx b/src/engine/forms/menu/debug/DebugRegistrySection.component.tsx index 7e679b62c..e66ebe164 100644 --- a/src/engine/forms/menu/debug/DebugRegistrySection.component.tsx +++ b/src/engine/forms/menu/debug/DebugRegistrySection.component.tsx @@ -4,6 +4,9 @@ import { Xr3tButton } from "@/engine/forms/components/base"; import { WHITE } from "@/engine/lib/constants/colors"; import { fonts } from "@/engine/lib/constants/fonts"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/debug/DebugSoundSection.component.tsx b/src/engine/forms/menu/debug/DebugSoundSection.component.tsx index 9ff7810b3..c93426ce5 100644 --- a/src/engine/forms/menu/debug/DebugSoundSection.component.tsx +++ b/src/engine/forms/menu/debug/DebugSoundSection.component.tsx @@ -6,6 +6,9 @@ import { textures } from "@/engine/lib/constants/textures"; const BASE_WIDTH: number = SECTION_WIDTH; const BASE_HEIGHT: number = SECTION_HEIGHT; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/debug/DebugSpawnSection.component.tsx b/src/engine/forms/menu/debug/DebugSpawnSection.component.tsx index b99c4f026..74b2209c6 100644 --- a/src/engine/forms/menu/debug/DebugSpawnSection.component.tsx +++ b/src/engine/forms/menu/debug/DebugSpawnSection.component.tsx @@ -7,6 +7,9 @@ import { SECTION_HEIGHT, SECTION_WIDTH } from "@/engine/forms/menu/debug/DebugDi import { WHITE } from "@/engine/lib/constants/colors"; import { textures } from "@/engine/lib/constants/textures"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/debug/DebugTeleportSection.component.tsx b/src/engine/forms/menu/debug/DebugTeleportSection.component.tsx index f8076555a..a482666dd 100644 --- a/src/engine/forms/menu/debug/DebugTeleportSection.component.tsx +++ b/src/engine/forms/menu/debug/DebugTeleportSection.component.tsx @@ -7,6 +7,9 @@ import { SECTION_HEIGHT, SECTION_WIDTH } from "@/engine/forms/menu/debug/DebugDi import { WHITE } from "@/engine/lib/constants/colors"; import { textures } from "@/engine/lib/constants/textures"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/debug/DebugUiSection.component.tsx b/src/engine/forms/menu/debug/DebugUiSection.component.tsx index 6ae0050ea..1b873f1a9 100644 --- a/src/engine/forms/menu/debug/DebugUiSection.component.tsx +++ b/src/engine/forms/menu/debug/DebugUiSection.component.tsx @@ -10,6 +10,9 @@ import { IRgbColor } from "@/engine/lib/types"; const BASE_WIDTH: number = SECTION_WIDTH; const BASE_HEIGHT: number = SECTION_HEIGHT; +/** + * todo; + */ export function create(): JSXNode { const DEFAULT_SPACING: number = 12; diff --git a/src/engine/forms/menu/debug/DebugWeatherSection.component.tsx b/src/engine/forms/menu/debug/DebugWeatherSection.component.tsx index 06a0f4299..f21fd47fe 100644 --- a/src/engine/forms/menu/debug/DebugWeatherSection.component.tsx +++ b/src/engine/forms/menu/debug/DebugWeatherSection.component.tsx @@ -7,6 +7,9 @@ import { WHITE } from "@/engine/lib/constants/colors"; import { fonts } from "@/engine/lib/constants/fonts"; import { textures } from "@/engine/lib/constants/textures"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/multiplayer/MultiplayerAwards.component.tsx b/src/engine/forms/menu/multiplayer/MultiplayerAwards.component.tsx index 0e24c9395..115202390 100644 --- a/src/engine/forms/menu/multiplayer/MultiplayerAwards.component.tsx +++ b/src/engine/forms/menu/multiplayer/MultiplayerAwards.component.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/multiplayer/MultiplayerBuyButtons.16.tsx b/src/engine/forms/menu/multiplayer/MultiplayerBuyButtons.16.tsx index 6333317a4..eec9795e4 100644 --- a/src/engine/forms/menu/multiplayer/MultiplayerBuyButtons.16.tsx +++ b/src/engine/forms/menu/multiplayer/MultiplayerBuyButtons.16.tsx @@ -1,5 +1,8 @@ import { Fragment, JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function MultiplayerBuyButtons16(): JSXNode { return ( diff --git a/src/engine/forms/menu/multiplayer/MultiplayerBuyButtons.tsx b/src/engine/forms/menu/multiplayer/MultiplayerBuyButtons.tsx index d2cd88c02..988980d79 100644 --- a/src/engine/forms/menu/multiplayer/MultiplayerBuyButtons.tsx +++ b/src/engine/forms/menu/multiplayer/MultiplayerBuyButtons.tsx @@ -1,5 +1,8 @@ import { Fragment, JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function MultiplayerBuyButtons(): JSXNode { return ( diff --git a/src/engine/forms/menu/multiplayer/MultiplayerGamespy.component.tsx b/src/engine/forms/menu/multiplayer/MultiplayerGamespy.component.tsx index 8592ae636..32bb92618 100644 --- a/src/engine/forms/menu/multiplayer/MultiplayerGamespy.component.tsx +++ b/src/engine/forms/menu/multiplayer/MultiplayerGamespy.component.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/multiplayer/MultiplayerLocalnet.component.tsx b/src/engine/forms/menu/multiplayer/MultiplayerLocalnet.component.tsx index 9943d433a..fc77914a4 100644 --- a/src/engine/forms/menu/multiplayer/MultiplayerLocalnet.component.tsx +++ b/src/engine/forms/menu/multiplayer/MultiplayerLocalnet.component.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/menu/multiplayer/MultiplayerOffline.component.tsx b/src/engine/forms/menu/multiplayer/MultiplayerOffline.component.tsx index f4a5cc661..5193fbef0 100644 --- a/src/engine/forms/menu/multiplayer/MultiplayerOffline.component.tsx +++ b/src/engine/forms/menu/multiplayer/MultiplayerOffline.component.tsx @@ -5,6 +5,9 @@ import { MultiplayerTabDemo } from "@/engine/forms/menu/multiplayer/tabs/Multipl import { MultiplayerTabOptions } from "@/engine/forms/menu/multiplayer/tabs/MultiplayerTabOptions.part"; import { MultiplayerTabServer } from "@/engine/forms/menu/multiplayer/tabs/MultiplayerTabServer.part"; +/** + * + */ export function create(): JSXNode { return ( @@ -138,7 +141,7 @@ export function create(): JSXNode { - {/** + {/* * --> + +/** + * todo; + */ export function create(): JSXNode { - /** + /* * * <_rank_caption x="23" y="150" width="153" height="15"> * diff --git a/src/engine/forms/tutorials/GameVendorsIntro.component.tsx b/src/engine/forms/tutorials/GameVendorsIntro.component.tsx index 91e32e3cc..3731493c1 100644 --- a/src/engine/forms/tutorials/GameVendorsIntro.component.tsx +++ b/src/engine/forms/tutorials/GameVendorsIntro.component.tsx @@ -2,6 +2,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { gameConfig } from "@/engine/lib/configs/GameConfig"; +/** + * todo; + */ export function GameVendorsIntro(): JSXNode { if (gameConfig.UI.ARE_INTRO_VIDEOS_ENABLED) { return ( diff --git a/src/engine/forms/ui_credits.tsx b/src/engine/forms/ui_credits.tsx index 155bcfd3f..d69206b40 100644 --- a/src/engine/forms/ui_credits.tsx +++ b/src/engine/forms/ui_credits.tsx @@ -2,6 +2,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { MenuCredits } from "@/engine/forms/menu/MenuCredits"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_credits_16.tsx b/src/engine/forms/ui_credits_16.tsx index 80e342487..c2c7e446c 100644 --- a/src/engine/forms/ui_credits_16.tsx +++ b/src/engine/forms/ui_credits_16.tsx @@ -2,6 +2,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { MenuCredits } from "@/engine/forms/menu/MenuCredits"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_custom_msgs.tsx b/src/engine/forms/ui_custom_msgs.tsx index 605877602..24fa53c24 100644 --- a/src/engine/forms/ui_custom_msgs.tsx +++ b/src/engine/forms/ui_custom_msgs.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return (
diff --git a/src/engine/forms/ui_detector_artefact.tsx b/src/engine/forms/ui_detector_artefact.tsx index 2a79096f6..2f6267c28 100644 --- a/src/engine/forms/ui_detector_artefact.tsx +++ b/src/engine/forms/ui_detector_artefact.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_game_ahunt.tsx b/src/engine/forms/ui_game_ahunt.tsx index a6b1eeac4..5bb0f4575 100644 --- a/src/engine/forms/ui_game_ahunt.tsx +++ b/src/engine/forms/ui_game_ahunt.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_game_ahunt_16.tsx b/src/engine/forms/ui_game_ahunt_16.tsx index f8b3cc7ef..707204da2 100644 --- a/src/engine/forms/ui_game_ahunt_16.tsx +++ b/src/engine/forms/ui_game_ahunt_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_game_cta.tsx b/src/engine/forms/ui_game_cta.tsx index a6b1eeac4..5bb0f4575 100644 --- a/src/engine/forms/ui_game_cta.tsx +++ b/src/engine/forms/ui_game_cta.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_game_cta_16.tsx b/src/engine/forms/ui_game_cta_16.tsx index f8b3cc7ef..707204da2 100644 --- a/src/engine/forms/ui_game_cta_16.tsx +++ b/src/engine/forms/ui_game_cta_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_game_dm.tsx b/src/engine/forms/ui_game_dm.tsx index 6390599ca..399ba3b40 100644 --- a/src/engine/forms/ui_game_dm.tsx +++ b/src/engine/forms/ui_game_dm.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_game_dm_16.tsx b/src/engine/forms/ui_game_dm_16.tsx index ddc3d1369..311678268 100644 --- a/src/engine/forms/ui_game_dm_16.tsx +++ b/src/engine/forms/ui_game_dm_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_game_over.tsx b/src/engine/forms/ui_game_over.tsx index 667102e62..193426d3c 100644 --- a/src/engine/forms/ui_game_over.tsx +++ b/src/engine/forms/ui_game_over.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_game_tdm.tsx b/src/engine/forms/ui_game_tdm.tsx index 996539c60..b87b201d9 100644 --- a/src/engine/forms/ui_game_tdm.tsx +++ b/src/engine/forms/ui_game_tdm.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_game_tdm_16.tsx b/src/engine/forms/ui_game_tdm_16.tsx index a89c78571..8f61b38ee 100644 --- a/src/engine/forms/ui_game_tdm_16.tsx +++ b/src/engine/forms/ui_game_tdm_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_keybinding.tsx b/src/engine/forms/ui_keybinding.tsx index b2e067533..f2efab169 100644 --- a/src/engine/forms/ui_keybinding.tsx +++ b/src/engine/forms/ui_keybinding.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_keybinding_gamepad.tsx b/src/engine/forms/ui_keybinding_gamepad.tsx index 88f35c3b2..31bade789 100644 --- a/src/engine/forms/ui_keybinding_gamepad.tsx +++ b/src/engine/forms/ui_keybinding_gamepad.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_mapinfo.tsx b/src/engine/forms/ui_mapinfo.tsx index f84be6925..a82bb610d 100644 --- a/src/engine/forms/ui_mapinfo.tsx +++ b/src/engine/forms/ui_mapinfo.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_mm_loading_screen.tsx b/src/engine/forms/ui_mm_loading_screen.tsx index f3b60f210..60da6f98f 100644 --- a/src/engine/forms/ui_mm_loading_screen.tsx +++ b/src/engine/forms/ui_mm_loading_screen.tsx @@ -2,6 +2,9 @@ import { JSXNode, JSXXML } from "jsx-xml"; import { textures } from "@/engine/lib/constants/textures"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_mm_loading_screen_16.tsx b/src/engine/forms/ui_mm_loading_screen_16.tsx index 5f11f14ec..015a093d2 100644 --- a/src/engine/forms/ui_mm_loading_screen_16.tsx +++ b/src/engine/forms/ui_mm_loading_screen_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_mm_versions_dlg.tsx b/src/engine/forms/ui_mm_versions_dlg.tsx index d36da1559..82563c99d 100644 --- a/src/engine/forms/ui_mm_versions_dlg.tsx +++ b/src/engine/forms/ui_mm_versions_dlg.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_mm_versions_dlg_16.tsx b/src/engine/forms/ui_mm_versions_dlg_16.tsx index c09ff5be0..4d2759bad 100644 --- a/src/engine/forms/ui_mm_versions_dlg_16.tsx +++ b/src/engine/forms/ui_mm_versions_dlg_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_numpad_wnd.tsx b/src/engine/forms/ui_numpad_wnd.tsx index cf20316c9..46e3f9802 100644 --- a/src/engine/forms/ui_numpad_wnd.tsx +++ b/src/engine/forms/ui_numpad_wnd.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_spawn_dlg.tsx b/src/engine/forms/ui_spawn_dlg.tsx index 55aba6787..90bbd9106 100644 --- a/src/engine/forms/ui_spawn_dlg.tsx +++ b/src/engine/forms/ui_spawn_dlg.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_team_panels_ahunt.tsx b/src/engine/forms/ui_team_panels_ahunt.tsx index 1152ac263..f55dab304 100644 --- a/src/engine/forms/ui_team_panels_ahunt.tsx +++ b/src/engine/forms/ui_team_panels_ahunt.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_team_panels_ahunt_16.tsx b/src/engine/forms/ui_team_panels_ahunt_16.tsx index 26119790e..a292046a1 100644 --- a/src/engine/forms/ui_team_panels_ahunt_16.tsx +++ b/src/engine/forms/ui_team_panels_ahunt_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_team_panels_cta.tsx b/src/engine/forms/ui_team_panels_cta.tsx index 1152ac263..f55dab304 100644 --- a/src/engine/forms/ui_team_panels_cta.tsx +++ b/src/engine/forms/ui_team_panels_cta.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_team_panels_cta_16.tsx b/src/engine/forms/ui_team_panels_cta_16.tsx index 26119790e..a292046a1 100644 --- a/src/engine/forms/ui_team_panels_cta_16.tsx +++ b/src/engine/forms/ui_team_panels_cta_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_team_panels_dm.tsx b/src/engine/forms/ui_team_panels_dm.tsx index 0e559aef2..315c8d025 100644 --- a/src/engine/forms/ui_team_panels_dm.tsx +++ b/src/engine/forms/ui_team_panels_dm.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_team_panels_dm_16.tsx b/src/engine/forms/ui_team_panels_dm_16.tsx index 012d9aa50..a40799c82 100644 --- a/src/engine/forms/ui_team_panels_dm_16.tsx +++ b/src/engine/forms/ui_team_panels_dm_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_team_panels_tdm.tsx b/src/engine/forms/ui_team_panels_tdm.tsx index b9876a8fb..aab688635 100644 --- a/src/engine/forms/ui_team_panels_tdm.tsx +++ b/src/engine/forms/ui_team_panels_tdm.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/ui_team_panels_tdm_16.tsx b/src/engine/forms/ui_team_panels_tdm_16.tsx index d48b664c5..3303fd170 100644 --- a/src/engine/forms/ui_team_panels_tdm_16.tsx +++ b/src/engine/forms/ui_team_panels_tdm_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/video_templ.tsx b/src/engine/forms/video_templ.tsx index a2212118d..475d34312 100644 --- a/src/engine/forms/video_templ.tsx +++ b/src/engine/forms/video_templ.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/voting_category.tsx b/src/engine/forms/voting_category.tsx index aae3b3d80..36f32df60 100644 --- a/src/engine/forms/voting_category.tsx +++ b/src/engine/forms/voting_category.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/voting_category_16.tsx b/src/engine/forms/voting_category_16.tsx index 14069d454..63d06ff62 100644 --- a/src/engine/forms/voting_category_16.tsx +++ b/src/engine/forms/voting_category_16.tsx @@ -1,5 +1,8 @@ import { JSXNode, JSXXML } from "jsx-xml"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/zone_map.tsx b/src/engine/forms/zone_map.tsx index 61e7bc21d..b96d004e1 100644 --- a/src/engine/forms/zone_map.tsx +++ b/src/engine/forms/zone_map.tsx @@ -4,6 +4,9 @@ import { XrText } from "@/engine/forms/components/base"; import { XrTexture } from "@/engine/forms/components/base/XrTexture.component"; import { fonts } from "@/engine/lib/constants/fonts"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/forms/zone_map_16.tsx b/src/engine/forms/zone_map_16.tsx index 6eac346eb..24b0af190 100644 --- a/src/engine/forms/zone_map_16.tsx +++ b/src/engine/forms/zone_map_16.tsx @@ -4,6 +4,9 @@ import { XrText } from "@/engine/forms/components/base"; import { XrTexture } from "@/engine/forms/components/base/XrTexture.component"; import { fonts } from "@/engine/lib/constants/fonts"; +/** + * todo; + */ export function create(): JSXNode { return ( diff --git a/src/engine/lib/configs/GameConfig.ts b/src/engine/lib/configs/GameConfig.ts index 743b6d169..529410b9c 100644 --- a/src/engine/lib/configs/GameConfig.ts +++ b/src/engine/lib/configs/GameConfig.ts @@ -46,6 +46,10 @@ export const gameConfig = { * Game save file extension by default. */ GAME_SAVE_EXTENSION: ".scop", + /** + * Game save file extension for dynamic data. + */ + GAME_SAVE_DYNAMIC_EXTENSION: ".scopx", /** * Game save preview file extension by default. */ diff --git a/src/engine/scripts/declarations/callbacks/game.ts b/src/engine/scripts/declarations/callbacks/game.ts index 848664ccb..86e3cb6e9 100644 --- a/src/engine/scripts/declarations/callbacks/game.ts +++ b/src/engine/scripts/declarations/callbacks/game.ts @@ -1,12 +1,13 @@ /** * Outro conditions for game ending based on alife information. */ +import { SaveManager } from "@/engine/core/managers/base/SaveManager"; import { TradeManager } from "@/engine/core/managers/interaction/TradeManager"; import { smartCoversList } from "@/engine/core/objects/server/smart_cover/smart_covers_list"; import { GameOutroManager } from "@/engine/core/ui/game/GameOutroManager"; import { extern } from "@/engine/core/utils/binding"; import { LuaLogger } from "@/engine/core/utils/logging"; -import { TNumberId } from "@/engine/lib/types"; +import { TName, TNumberId } from "@/engine/lib/types"; const logger: LuaLogger = new LuaLogger($filename); @@ -35,3 +36,23 @@ extern("trade_manager", { get_sell_discount: (objectId: TNumberId) => TradeManager.getInstance().getSellDiscountForObject(objectId), get_buy_discount: (objectId: TNumberId) => TradeManager.getInstance().getBuyDiscountForObject(objectId), }); + +/** + * Called from game engine just before creating game save. + */ +extern("on_before_game_save", (saveName: TName) => SaveManager.getInstance().onBeforeGameSave(saveName)); + +/** + * Called from game engine when game save is created. + */ +extern("on_game_save", (saveName: TName) => SaveManager.getInstance().onGameSave(saveName)); + +/** + * Called from game engine just before loading game save. + */ +extern("on_before_game_load", (saveName: TName) => SaveManager.getInstance().onBeforeGameLoad(saveName)); + +/** + * Called from game engine after loading game save. + */ +extern("on_game_load", (saveName: TName) => SaveManager.getInstance().onGameLoad(saveName)); diff --git a/src/engine/scripts/declarations/conditions/world.ts b/src/engine/scripts/declarations/conditions/world.ts index 42043fdb8..4108bcdf6 100644 --- a/src/engine/scripts/declarations/conditions/world.ts +++ b/src/engine/scripts/declarations/conditions/world.ts @@ -8,68 +8,70 @@ import { ESmartTerrainStatus } from "@/engine/core/objects/server/smart_terrain/ import { abort } from "@/engine/core/utils/assertion"; import { extern } from "@/engine/core/utils/binding"; import { anomalyHasArtefact } from "@/engine/core/utils/object/object_anomaly"; -import { ClientObject, LuaArray, Optional, TName } from "@/engine/lib/types"; +import { ClientObject, Optional, TName, TSection, TTimestamp } from "@/engine/lib/types"; /** - * todo; + * @returns whether it is rainy in the game right now */ extern("xr_conditions.is_rain", (): boolean => { return registry.actor !== null && level.rain_factor() > 0; }); /** - * todo; + * @returns whether it is heavy rain weather in the game right now */ extern("xr_conditions.is_heavy_rain", (): boolean => { return registry.actor !== null && level.rain_factor() >= 0.5; }); /** - * todo; + * @returns whether it is dark daytime in the game */ extern("xr_conditions.is_day", (): boolean => { - return registry.actor !== null && level.get_time_hours() >= 6 && level.get_time_hours() < 21; + const timeHours: TTimestamp = level.get_time_hours(); + + return registry.actor !== null && timeHours >= 6 && timeHours < 21; }); /** - * todo; + * @returns whether it is dark nighttime in the game */ extern("xr_conditions.is_dark_night", (): boolean => { - return registry.actor !== null && (level.get_time_hours() < 3 || level.get_time_hours() > 22); + const timeHours: TTimestamp = level.get_time_hours(); + + return registry.actor !== null && (timeHours < 3 || timeHours > 22); }); /** - * todo; + * Check whether anomaly with name has artefact. + * + * @param anomalyName - name of the anomaly to check + * @param artefactSection - section of the artefact to check + * @returns whether anomaly has artefact */ extern( "xr_conditions.anomaly_has_artefact", - ( - actor: ClientObject, - object: ClientObject, - [anomalyName, artefactName]: [TName, TName] - ): LuaMultiReturn<[boolean, Optional>]> => { - const [hasArtefact, details] = anomalyHasArtefact(actor, object, anomalyName, artefactName); - - return $multi(hasArtefact, details); + (actor: ClientObject, object: ClientObject, [anomalyName, artefactSection]: [TName, TSection]): boolean => { + return anomalyHasArtefact(anomalyName, artefactSection); } ); /** - * todo; + * @returns whether surge is completed */ extern("xr_conditions.surge_complete", (): boolean => { return SurgeManager.getInstance().isFinished; }); /** - * todo; + * @returns whether surge is started */ extern("xr_conditions.surge_started", (): boolean => { return SurgeManager.getInstance().isStarted; }); /** - * todo; + * @returns whether surge is killing all not hided objects */ extern("xr_conditions.surge_kill_all", (): boolean => { return SurgeManager.getInstance().isKillingAll(); @@ -119,19 +121,22 @@ const ALARM_STATUSES = { */ extern( "xr_conditions.check_smart_alarm_status", - (actor: ClientObject, npc: ClientObject, params: [TName, string]): boolean => { - const smartName: TName = params[0]; - const status: ESmartTerrainStatus = ALARM_STATUSES[params[1] as keyof typeof ALARM_STATUSES]; + ( + actor: ClientObject, + object: ClientObject, + [smartName, smartStatus]: [TName, keyof typeof ALARM_STATUSES] + ): boolean => { + const status: Optional = ALARM_STATUSES[smartStatus]; - if (status === null) { - abort("Wrong status[%s] in 'check_smart_alarm_status'", tostring(params[1])); + if (!status) { + abort("Wrong status[%s] in 'check_smart_alarm_status'", status); } const smart: SmartTerrain = SimulationBoardManager.getInstance().getSmartTerrainByName(smartName)!; const smartControl: Optional = smart.smartTerrainActorControl; if (smartControl === null) { - abort("Cannot calculate 'check_smart_alarm_status' for smart %s", tostring(smartName)); + abort("Cannot calculate 'check_smart_alarm_status' for smart '%s'.", tostring(smartName)); } return smartControl.getSmartTerrainStatus() === status; diff --git a/src/fixtures/engine/mockEngineGlobals.ts b/src/fixtures/engine/mockEngineGlobals.ts index e28f22887..3d020f407 100644 --- a/src/fixtures/engine/mockEngineGlobals.ts +++ b/src/fixtures/engine/mockEngineGlobals.ts @@ -1,7 +1,9 @@ import { jest } from "@jest/globals"; +import { mockLfs } from "@/fixtures/engine/mocks/lfs.mock"; import { MockLuaLogger } from "@/fixtures/engine/mocks/LuaLogger.mock"; -import { mockTableUtils } from "@/fixtures/engine/mocks/table.mocks"; +import { mockMarshal } from "@/fixtures/engine/mocks/marshal.mock"; +import { mockTableUtils } from "@/fixtures/engine/mocks/table.mock"; /** * todo; @@ -12,4 +14,10 @@ export function mockEngineGlobals(): void { })); jest.mock("@/engine/core/utils/table", () => mockTableUtils); + + // @ts-ignore + global.marshal = mockMarshal; + + // @ts-ignore + global.lfs = mockLfs; } diff --git a/src/fixtures/engine/mocks/index.ts b/src/fixtures/engine/mocks/index.ts index 46e9c208d..74a0ac2ba 100644 --- a/src/fixtures/engine/mocks/index.ts +++ b/src/fixtures/engine/mocks/index.ts @@ -1,4 +1,3 @@ -export * from "@/fixtures/engine/mocks/registry.mocks"; -export * from "@/fixtures/engine/mocks/scheme.mocks"; -export * from "@/fixtures/engine/mocks/scheme.mocks"; -export * from "@/fixtures/engine/mocks/squads.mocks"; +export * from "@/fixtures/engine/mocks/registry.mock"; +export * from "@/fixtures/engine/mocks/scheme.mock"; +export * from "@/fixtures/engine/mocks/squads.mock"; diff --git a/src/fixtures/engine/mocks/lfs.mock.ts b/src/fixtures/engine/mocks/lfs.mock.ts new file mode 100644 index 000000000..bf08f2bfc --- /dev/null +++ b/src/fixtures/engine/mocks/lfs.mock.ts @@ -0,0 +1,5 @@ +import { jest } from "@jest/globals"; + +export const mockLfs = { + mkdir: jest.fn(), +}; diff --git a/src/fixtures/engine/mocks/marshal.mock.ts b/src/fixtures/engine/mocks/marshal.mock.ts new file mode 100644 index 000000000..b55c8835e --- /dev/null +++ b/src/fixtures/engine/mocks/marshal.mock.ts @@ -0,0 +1,6 @@ +import { jest } from "@jest/globals"; + +export const mockMarshal = { + encode: jest.fn((data) => JSON.stringify(data)), + decode: jest.fn((data: string) => JSON.parse(data)), +}; diff --git a/src/fixtures/engine/mocks/registry.mocks.ts b/src/fixtures/engine/mocks/registry.mock.ts similarity index 100% rename from src/fixtures/engine/mocks/registry.mocks.ts rename to src/fixtures/engine/mocks/registry.mock.ts diff --git a/src/fixtures/engine/mocks/scheme.mocks.ts b/src/fixtures/engine/mocks/scheme.mock.ts similarity index 100% rename from src/fixtures/engine/mocks/scheme.mocks.ts rename to src/fixtures/engine/mocks/scheme.mock.ts diff --git a/src/fixtures/engine/mocks/squads.mocks.ts b/src/fixtures/engine/mocks/squads.mock.ts similarity index 100% rename from src/fixtures/engine/mocks/squads.mocks.ts rename to src/fixtures/engine/mocks/squads.mock.ts diff --git a/src/fixtures/engine/mocks/table.mocks.ts b/src/fixtures/engine/mocks/table.mock.ts similarity index 100% rename from src/fixtures/engine/mocks/table.mocks.ts rename to src/fixtures/engine/mocks/table.mock.ts diff --git a/src/fixtures/lua/mocks/index.ts b/src/fixtures/lua/mocks/index.ts index 55ea3c0ba..293cb83e9 100644 --- a/src/fixtures/lua/mocks/index.ts +++ b/src/fixtures/lua/mocks/index.ts @@ -1 +1,2 @@ export * from "@/fixtures/lua/mocks/lua_utils"; +export * from "@/fixtures/lua/mocks/lua_io.mock"; diff --git a/src/fixtures/lua/mocks/lua_globals.mocks.ts b/src/fixtures/lua/mocks/lua_globals.mocks.ts index 360b2370f..e0f915a86 100644 --- a/src/fixtures/lua/mocks/lua_globals.mocks.ts +++ b/src/fixtures/lua/mocks/lua_globals.mocks.ts @@ -2,6 +2,7 @@ import { ILuaState, lauxlib, lua, lualib, to_jsstring, to_luastring } from "feng import { AnyArgs } from "@/engine/lib/types"; import { mockDebug } from "@/fixtures/lua/mocks/lua_debug.mock"; +import { mockIo } from "@/fixtures/lua/mocks/lua_io.mock"; import { mockMath } from "@/fixtures/lua/mocks/lua_math.mocks"; import { mockPairs } from "@/fixtures/lua/mocks/lua_pairs.mock"; import { mockString } from "@/fixtures/lua/mocks/lua_string.mock"; @@ -10,6 +11,9 @@ import { mockToString } from "@/fixtures/lua/mocks/lua_tostring.mock"; import { mockType } from "@/fixtures/lua/mocks/lua_type.mock"; import { MockLuaTable } from "@/fixtures/lua/mocks/LuaTable.mock"; +/** + * Mock lua globals in node testing environment. + */ export function mockLuaGlobals(): void { // @ts-ignore global._G = global; @@ -24,6 +28,8 @@ export function mockLuaGlobals(): void { global.math = mockMath; // @ts-ignore global.debug = mockDebug; + // @ts-ignore + global.io = mockIo; // @ts-ignore global.$range = (start: number, end: number) => { diff --git a/src/fixtures/lua/mocks/lua_io.mock.ts b/src/fixtures/lua/mocks/lua_io.mock.ts new file mode 100644 index 000000000..0c716d1cc --- /dev/null +++ b/src/fixtures/lua/mocks/lua_io.mock.ts @@ -0,0 +1,54 @@ +import { jest } from "@jest/globals"; + +import { Optional } from "@/engine/lib/types"; + +/** + * Mock generic io file. + */ +export class MockIoFile { + public static mock(path: string, mode: string, isOpen: boolean = true): LuaFile { + return new MockIoFile(path, mode, isOpen) as unknown as LuaFile; + } + + public path: string; + public mode: string; + public isOpen: boolean; + public content: Optional = ""; + + public constructor(path: string, mode: string, isOpen: boolean = true) { + this.path = path; + this.mode = mode; + this.isOpen = isOpen; + } + + public write = jest.fn((data: string): void => { + if (!this.isOpen) { + throw new Error("Cannot write in closed file."); + } + + this.content = data; + }); + + public close = jest.fn((): void => { + this.isOpen = false; + }); + + public read = jest.fn((): Optional => { + return this.content; + }); + + public asMock = jest.fn((): LuaFile => { + return this as unknown as LuaFile; + }); +} + +export const mockIo = { + open: jest.fn((path: string, mode: string) => [new MockIoFile(path, mode)]), + type: jest.fn((target) => { + if (target instanceof MockIoFile) { + return target.isOpen ? "file" : "closed file"; + } else { + return null; + } + }), +}; diff --git a/src/fixtures/lua/mocks/lua_string.mock.ts b/src/fixtures/lua/mocks/lua_string.mock.ts index 98008017b..cc108da8a 100644 --- a/src/fixtures/lua/mocks/lua_string.mock.ts +++ b/src/fixtures/lua/mocks/lua_string.mock.ts @@ -174,4 +174,5 @@ export const mockString = { return Number.parseInt(to_jsstring(lauxlib.luaL_tolstring(L, -1))); }, + lower: (target: string) => target.toLowerCase(), }; diff --git a/src/fixtures/xray/mocks/actions/action_base.mock.ts b/src/fixtures/xray/mocks/actions/action_base.mock.ts index eb66a53fb..f237e2e68 100644 --- a/src/fixtures/xray/mocks/actions/action_base.mock.ts +++ b/src/fixtures/xray/mocks/actions/action_base.mock.ts @@ -44,6 +44,9 @@ export class MockActionBase extends MockLuabindClass { } } +/** + * Mock action base method. + */ export function mockActionBase(object: Optional = null, name: string = "generic"): ActionBase { return new MockActionBase(object, name) as unknown as ActionBase; } diff --git a/src/fixtures/xray/mocks/fs/FileSystem.mock.ts b/src/fixtures/xray/mocks/fs/FileSystem.mock.ts index 17218a9c5..8e7011d9e 100644 --- a/src/fixtures/xray/mocks/fs/FileSystem.mock.ts +++ b/src/fixtures/xray/mocks/fs/FileSystem.mock.ts @@ -1,6 +1,8 @@ +import * as path from "path"; + import { jest } from "@jest/globals"; -import { AnyObject, Optional } from "@/engine/lib/types"; +import { AnyObject, Optional, TPath } from "@/engine/lib/types"; import { MockFileSystemList } from "@/fixtures/xray/mocks/fs/FileSystemList.mock"; import { FS_MOCKS } from "@/fixtures/xray/mocks/fs/fs.mock"; @@ -47,6 +49,8 @@ export class MockFileSystem { public file_delete = jest.fn(() => {}); + public update_path = jest.fn((base: TPath, part: TPath) => path.join(base, part)); + public exist = jest.fn((root: string, path: string) => { return Boolean(this.mocks[root] && this.mocks[root][path]); }); diff --git a/src/fixtures/xray/mocks/objects/client/danger_object.mock.ts b/src/fixtures/xray/mocks/objects/client/danger_object.mock.ts index 6c87b554e..aeb3b9a9d 100644 --- a/src/fixtures/xray/mocks/objects/client/danger_object.mock.ts +++ b/src/fixtures/xray/mocks/objects/client/danger_object.mock.ts @@ -1,3 +1,7 @@ +import { ClientObject, Optional, TDangerType } from "@/engine/lib/types"; +import { mockClientGameObject } from "@/fixtures/xray"; +import { MockVector } from "@/fixtures/xray/mocks/vector.mock"; + /** * todo; */ @@ -13,4 +17,25 @@ export class MockDangerObject { public static hit: number = 2; public static sound: number = 1; public static visual: number = 0; + + public dangerType: TDangerType = 6; + public dangerObject: ClientObject = mockClientGameObject(); + public dangerDependentObject: Optional = null; + public dangerPosition: MockVector = MockVector.create(1.5, -0.5, 1); + + public position(): MockVector { + return this.dangerPosition; + } + + public object(): ClientObject { + return this.dangerObject; + } + + public dependent_object(): Optional { + return this.dangerDependentObject; + } + + public type(): TDangerType { + return this.dangerType; + } } diff --git a/src/fixtures/xray/mocks/objects/client/game_object.mock.ts b/src/fixtures/xray/mocks/objects/client/game_object.mock.ts index 60fcd137d..5e6d72fe3 100644 --- a/src/fixtures/xray/mocks/objects/client/game_object.mock.ts +++ b/src/fixtures/xray/mocks/objects/client/game_object.mock.ts @@ -110,6 +110,7 @@ export function mockClientGameObject({ .filter(Boolean) .forEach((it) => inRestrictions.push(it)); }), + best_danger: rest.best_danger || jest.fn(() => null), bleeding, can_select_weapon: rest.can_select_weapon || jest.fn(), change_team: rest.change_team || jest.fn(), @@ -118,6 +119,7 @@ export function mockClientGameObject({ clsid, clear_animations: rest.clear_animations || jest.fn(), command: rest.command || jest.fn(), + critically_wounded: rest.critically_wounded || jest.fn(() => false), direction: rest.direction || jest.fn(() => objectDirection), disable_hit_marks: rest.disable_hit_marks || jest.fn(), disable_info_portion: diff --git a/src/fixtures/xray/mocks/objects/server/cse_alife_human_stalker.mock.ts b/src/fixtures/xray/mocks/objects/server/cse_alife_human_stalker.mock.ts index a31a7b3f7..4029fadd2 100644 --- a/src/fixtures/xray/mocks/objects/server/cse_alife_human_stalker.mock.ts +++ b/src/fixtures/xray/mocks/objects/server/cse_alife_human_stalker.mock.ts @@ -20,6 +20,6 @@ export function mockServerAlifeHumanStalker(base: Partial = { ...base, community: base.community || jest.fn(() => "stalker"), force_set_goodwill: base.force_set_goodwill || jest.fn(), - o_torso: base.o_torso || jest.fn(() => ({} as unknown as rotation)), + o_torso: base.o_torso || jest.fn(() => ({}) as unknown as rotation), } as unknown as ServerHumanObject) as unknown as ServerHumanObject; } diff --git a/src/typedefs/xray16 b/src/typedefs/xray16 index 47d6923c4..7a8856eb0 160000 --- a/src/typedefs/xray16 +++ b/src/typedefs/xray16 @@ -1 +1 @@ -Subproject commit 47d6923c42953d64ed6699f4921dcc43cd8d591c +Subproject commit 7a8856eb0db35854464009ac2640a7318e9f3173