0
0
mirror of https://github.com/sp-tarkov/server.git synced 2025-02-13 02:10:44 -05:00

Merge branch '3.8.2-DEV' into 3.9.0-DEV

# Conflicts:
#	project/src/callbacks/ItemEventCallbacks.ts
#	project/src/models/eft/common/IGlobals.ts
#	project/src/models/eft/common/ILocation.ts
#	project/src/models/eft/common/ILocationBase.ts
#	project/src/models/eft/common/tables/ILootBase.ts
#	project/src/models/eft/common/tables/ITemplateItem.ts
#	project/src/models/eft/weather/IWeatherData.ts
#	project/src/models/spt/bots/BotGenerationDetails.ts
#	project/src/models/spt/config/IPmcConfig.ts
#	project/src/models/spt/config/IWeatherConfig.ts
#	project/src/models/spt/server/IDatabaseTables.ts
#	project/src/models/spt/server/ILocations.ts
#	project/src/servers/http/IHttpListener.ts
This commit is contained in:
Refringe 2024-05-08 00:21:12 -04:00
commit ba1ac09b0b
Signed by: Refringe
GPG Key ID: 7715B85B4A6306ED
586 changed files with 6732 additions and 7165 deletions

61
.gitattributes vendored
View File

@ -1,62 +1,7 @@
############################################################################### # Normalize Line Endings
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto eol=lf * text=auto eol=lf
###############################################################################
# Set default behavior for command prompt diff. # LFS File Listing
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
project/assets/database/locations/interchange/looseLoot.json filter=lfs diff=lfs merge=lfs -text project/assets/database/locations/interchange/looseLoot.json filter=lfs diff=lfs merge=lfs -text
project/assets/database/locations/interchange/staticLoot.json filter=lfs diff=lfs merge=lfs -text project/assets/database/locations/interchange/staticLoot.json filter=lfs diff=lfs merge=lfs -text
project/assets/database/locations/interchange/staticContainers.json filter=lfs diff=lfs merge=lfs -text project/assets/database/locations/interchange/staticContainers.json filter=lfs diff=lfs merge=lfs -text

View File

@ -53,6 +53,7 @@ jobs:
- name: Fix Instructions - name: Fix Instructions
if: failure() && steps.run-tests.outcome == 'failure' if: failure() && steps.run-tests.outcome == 'failure'
run: | run: |
echo -e "Code linting has failed. The linter has been configured to look for coding errors, defects, and questionable patterns. Please look into resolving these errors. The linter may be able to resolve some of these issues automatically. You can launch the automatic fixer by running the following command from within the 'project' directory. Anything not resolved by running this command must be resolved manually.\n\nnpm run lint:fix\n" echo -e "Code linting has failed. The linter has been configured to look for coding errors, defects, questionable patterns, and code formatting issues. Please look into resolving these errors. The linter may be able to resolve some of these issues automatically. You can launch the automatic fixer by running the following command from within the 'project' directory. Anything not resolved by running this command must be resolved manually.\n\nnpm run lint:fix\n"
echo -e "To automatically format code on-save in your IDE, please install the recommended VSCode plugins listed within the 'project/Server.code-workspace' file.\n"
echo -e "Consistency is professionalism.™" echo -e "Consistency is professionalism.™"
shell: bash shell: bash

View File

@ -1,59 +0,0 @@
name: Check Code Style
on:
push:
branches: '*'
pull_request:
branches: '*'
jobs:
dprint:
runs-on: ubuntu-latest
container:
image: refringe/spt-build-node:1.0.7
steps:
- name: Clone
run: |
rm -rf /workspace/SPT-AKI/Build/server
git clone https://dev.sp-tarkov.com/${GITHUB_REPOSITORY}.git --branch master /workspace/SPT-AKI/Build/server
cd /workspace/SPT-AKI/Build/server
git checkout ${GITHUB_SHA}
shell: bash
- name: Pull LFS Files
run: |
cd /workspace/SPT-AKI/Build/server
git lfs pull
git lfs ls-files
shell: bash
- name: Cache NPM Dependencies
id: cache-npm-dependencies
uses: actions/cache@v4
with:
path: /workspace/SPT-AKI/Build/server/project/node_modules
key: npm-dependencies-${{ hashFiles('/workspace/SPT-AKI/Build/server/project/package.json') }}
- name: Install NPM Dependencies
if: steps.cache-npm-dependencies.outputs.cache-hit != 'true'
run: |
cd /workspace/SPT-AKI/Build/server/project
rm -rf node_modules
npm install
shell: bash
- name: Check Code Style
id: check-code-style
run: |
cd /workspace/SPT-AKI/Build/server/project
npm run style
shell: bash
- name: Fix Instructions
if: failure() && steps.check-code-style.outcome == 'failure'
run: |
echo -e "The code style check has failed. To fix this, please ensure your code adheres to the project's style guidelines. You can automatically format the project code by running the following command from within the 'project' directory.\n\nnpm run style:fix\n"
echo -e "To automatically format code on-save in your IDE, please install the recommended VSCode plugins listed within the 'project/Server.code-workspace' file.\n"
echo -e "Thank you for keeping our house clean. ♥"
shell: bash

View File

@ -31,9 +31,7 @@ This project has been built in [Visual Studio Code](https://code.visualstudio.co
There are a number of VSC extensions that we recommended for this project. VSC will prompt you to install these when you open the workspace file. If you do not see the prompt, you can install them manually: There are a number of VSC extensions that we recommended for this project. VSC will prompt you to install these when you open the workspace file. If you do not see the prompt, you can install them manually:
- [EditorConfig](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) - Editor Settings Synchronization - [EditorConfig](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) - Editor Settings Synchronization
- [Dprint Code Formatter](https://marketplace.visualstudio.com/items?itemName=dprint.dprint) - Formatting on Save
- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - Linting for Coding Issues & Naming Conventions - [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - Linting for Coding Issues & Naming Conventions
- [Biome](https://marketplace.visualstudio.com/items?itemName=biomejs.biome) - Linting for Coding Standards
- [Vitest](https://marketplace.visualstudio.com/items?itemName=vitest.explorer) - Debugging Tests - [Vitest](https://marketplace.visualstudio.com/items?itemName=vitest.explorer) - Debugging Tests
- [SPT ID Highlighter](https://marketplace.visualstudio.com/items?itemName=refringe.spt-id-highlighter) - Converts IDs to Names - [SPT ID Highlighter](https://marketplace.visualstudio.com/items?itemName=refringe.spt-id-highlighter) - Converts IDs to Names
@ -54,26 +52,24 @@ To prepare the project for development you will need to:
The following commands are available after the initial setup. Run them with `npm run <command>`. The following commands are available after the initial setup. Run them with `npm run <command>`.
| Command | Description | | Command | Description |
|--------------------------|----------------------------------------------------------------------| |--------------------------|-----------------------------------------------------------------------|
| `check:circular` | Check for circular dependencies in the project. | | `check:circular` | Check for circular dependencies in the project. |
| `lint` | Lint the project for coding standards. | | `lint` | Check the project for coding standards and style/formatting issues. |
| `lint:fix` | Attempt to automatically fix coding standard issues. | | `lint:fix` | Automatically fix coding standard issues and style/formatting issues. |
| `style` | Check the project for style/formatting issues. | | `test` | Run all tests. |
| `style:fix` | Attempt to automatically fix style/formatting issues. | | `test:watch` | Run tests in watch mode. Tests will re-run when files are changed. |
| `test` | Run all tests. | | `test:coverage` | Run tests and generate a coverage report. |
| `test:watch` | Run tests in watch mode. Tests will re-run when files are changed. | | `test:ui` | Run tests in UI mode. This will open a browser window to view tests. |
| `test:coverage` | Run tests and generate a coverage report. | | `build:release` | Build the project for release. |
| `test:ui` | Run tests in UI mode. This will open a browser window to view tests. | | `build:debug` | Build the project for debugging. |
| `build:release` | Build the project for release. | | `build:bleeding` | Build the project on the bleeding edge. |
| `build:debug` | Build the project for debugging. | | `build:bleedingmods` | Build the project on the bleeding edge with mods. |
| `build:bleeding` | Build the project on the bleeding edge. | | `run:build` | Run the project in build mode. |
| `build:bleedingmods` | Build the project on the bleeding edge with mods. | | `run:debug` | Run the project in debug mode. |
| `run:build` | Run the project in build mode. | | `run:profiler` | Run the project in profiler mode. |
| `run:debug` | Run the project in debug mode. | | `gen:types` | Generate types for the project. |
| `run:profiler` | Run the project in profiler mode. | | `gen:docs` | Generate documentation for the project. |
| `gen:types` | Generate types for the project. |
| `gen:docs` | Generate documentation for the project. |
### Debugging ### Debugging
@ -111,7 +107,7 @@ We're really excited that you're interested in contributing! Before submitting y
### Style Guide ### Style Guide
We use Dprint to enforce a consistent code style. Please run `npm run style` and/or `npm run style:fix` before submitting your changes. This is made easier by using the recommended VSC extensions to automatically format your code whenever you save a file. We use ESLint Stylistic to enforce a consistent code style. Please run `npm run lint` and/or `npm run lint:fix` before submitting your changes. This is made easier by using the recommended VSC extensions to automatically format your code whenever you save a file.
### Tests ### Tests

View File

@ -7,3 +7,6 @@ charset = utf-8
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
max_line_length = 120 max_line_length = 120
[*.md]
trim_trailing_whitespace = false

View File

@ -1,5 +1,5 @@
# Exclude these folders from linting # Exclude these folders from linting
node_modules node_modules/
out/ out/
obj/ obj/
build/ build/

View File

@ -1,23 +1,34 @@
{ {
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"env": {
"node": true
},
"extends": [ "extends": [
"plugin:@typescript-eslint/eslint-recommended" "plugin:@typescript-eslint/recommended",
"plugin:@stylistic/recommended-extends",
"plugin:import/recommended",
"plugin:import/typescript"
], ],
"plugins": [
"@typescript-eslint",
"@stylistic",
"import"
],
"settings": {
"import/resolver": {
"typescript": {
"project": "tsconfig.json"
},
"node": {
"extensions": [".ts", ".mjs"]
}
}
},
"rules": { "rules": {
"brace-style": ["error", "allman"], "@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-namespace": "off", "@typescript-eslint/no-dynamic-delete": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-empty-interface": "off", "@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off", // We use a bunch of these.
"@typescript-eslint/no-unused-vars": "off", // Typescript compiler already checks--Will grey out variable.
"@typescript-eslint/no-var-requires": "error", "@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/explicit-module-boundary-types": ["error", { "allowArgumentsExplicitlyTypedAsAny": true }], "@typescript-eslint/explicit-module-boundary-types": ["error", {
"allowArgumentsExplicitlyTypedAsAny": true
}],
"@typescript-eslint/naming-convention": ["error", { "@typescript-eslint/naming-convention": ["error", {
"selector": "default", "selector": "default",
"format": ["camelCase"], "format": ["camelCase"],
@ -40,24 +51,63 @@
"selector": "property", "selector": "property",
"modifiers": ["readonly", "static"], "modifiers": ["readonly", "static"],
"format": ["UPPER_CASE"] "format": ["UPPER_CASE"]
}],
"@stylistic/indent": ["error", 4, { "MemberExpression": 1, "SwitchCase": 1 }],
"@stylistic/brace-style": ["error", "allman", { "allowSingleLine": false }],
"@stylistic/semi": ["error", "always"],
"@stylistic/quotes": ["error", "double", { "avoidEscape": true }],
"@stylistic/linebreak-style": ["error", "unix"],
"@stylistic/max-len": ["error", {
"code": 120,
"tabWidth": 4,
"ignoreComments": true,
"ignoreTrailingComments": true,
"ignoreUrls": true,
"ignoreStrings": true,
"ignoreTemplateLiterals": true,
"ignoreRegExpLiterals": true
}],
"@stylistic/multiline-ternary": ["error", "always-multiline"],
"@stylistic/no-extra-parens": ["error", "all"],
"@stylistic/new-parens": "error",
"@stylistic/newline-per-chained-call": ["error", { "ignoreChainWithDepth": 3 }],
"@stylistic/no-extra-semi": "error",
"@stylistic/no-floating-decimal": "error",
"@stylistic/no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1 }],
"@stylistic/switch-colon-spacing": "error",
"@stylistic/type-annotation-spacing": "error",
"@stylistic/type-generic-spacing": ["error"],
"@stylistic/type-named-tuple-spacing": ["error"],
"@stylistic/wrap-regex": "error",
"@stylistic/yield-star-spacing": ["error", "both"],
"import/order": ["error", {
"groups": ["builtin", "external", "internal", "parent", "sibling", "index"],
"pathGroups": [
{
"pattern": "tsyringe",
"group": "builtin",
"position": "before"
}
],
"newlines-between": "never",
"alphabetize": {
"order": "asc",
"caseInsensitive": true
}
}] }]
}, },
"overrides": [{ "overrides": [
"files": [ {
"src/loaders/**/*.ts" "files": ["src/di/**/*.ts"],
], "rules": {
"rules": { "@typescript-eslint/no-extraneous-class": "off"
"@typescript-eslint/no-var-requires": "off" }
},
{
"files": ["src/loaders/**/*.ts"],
"rules": {
"@typescript-eslint/no-var-requires": "off"
}
} }
}, { ]
"files": [
"**/vitest.config.ts"
],
"rules": {
"@typescript-eslint/naming-convention": ["error", {
"selector": "objectLiteralProperty",
"format": null
}]
}
}]
} }

View File

@ -1,10 +1,8 @@
{ {
"recommendations": [ "recommendations": [
"EditorConfig.EditorConfig", "EditorConfig.EditorConfig",
"dprint.dprint",
"dbaeumer.vscode-eslint",
"biomejs.biome",
"vitest.explorer", "vitest.explorer",
"refringe.spt-id-highlighter" "refringe.spt-id-highlighter",
"dbaeumer.vscode-eslint"
] ]
} }

View File

@ -7,9 +7,11 @@
"settings": { "settings": {
"window.title": "SPT-AKI Server", "window.title": "SPT-AKI Server",
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.defaultFormatter": "dprint.dprint", "editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.codeActionsOnSave": [ "editor.codeActionsOnSave": {
"source.organizeImports.biome" "source.fixAll.eslint": "explicit"
] },
"eslint.debug": true,
"eslint.experimental.useFlatConfig": false
} }
} }

View File

@ -2495,7 +2495,8 @@
"Gizzy", "Gizzy",
"LuckyCharmT", "LuckyCharmT",
"Rena-chan", "Rena-chan",
"HB" "HB",
"John Pork"
], ],
"generation": { "generation": {
"items": { "items": {

View File

@ -2492,7 +2492,8 @@
"Gizzy", "Gizzy",
"LuckyCharmT", "LuckyCharmT",
"Rena-chan", "Rena-chan",
"HB" "HB",
"John Pork"
], ],
"generation": { "generation": {
"items": { "items": {

View File

@ -1,69 +0,0 @@
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"javascript": {
"parser": {
"unsafeParameterDecoratorsEnabled": true
}
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"style": {
"useImportType": "off",
"noImplicitBoolean": "off",
"noParameterAssign": "warn",
"useTemplate": "warn",
"useSingleVarDeclarator": "warn"
},
"a11y": {
"useKeyWithClickEvents": "off",
"useValidAnchor": "warn"
},
"suspicious": {
"noExplicitAny": "off",
"noDoubleEquals": "warn",
"noShadowRestrictedNames": "warn",
"noEmptyInterface": "off"
},
"performance": {
"noDelete": "off"
},
"correctness": {
"noUnnecessaryContinue": "warn"
},
"complexity": {
"noStaticOnlyClass": "off",
"useSimplifiedLogicExpression": "warn",
"useOptionalChain": "warn"
}
}
},
"formatter": {
"enabled": false
},
"files": {
"ignore": [
"**/*.js",
"**/*.json",
"**/*.d.ts",
"**/Dockerfile.*",
"**/.git/**/*",
"**/.vscode/**/*",
"**/node_modules/**/*",
"**/build/**/*",
"**/obj/**/*",
"**/dist/**/*",
"**/user/**/*",
"**/logs/**/*",
"**/assets/**/*",
"**/Aki_Data/**/*",
"**/types/**/*",
"**/tests/__cache__/**/*",
"**/tests/__coverage__/**/*"
]
}
}

View File

@ -1,90 +0,0 @@
{
"incremental": false,
"lineWidth": 120,
"indentWidth": 4,
"newLineKind": "lf",
"useTabs": false,
"typescript": {
"semiColons": "always",
"quoteStyle": "alwaysDouble",
"quoteProps": "asNeeded",
"useBraces": "always",
"bracePosition": "nextLine",
"singleBodyPosition": "maintain",
"nextControlFlowPosition": "nextLine",
"trailingCommas": "onlyMultiLine",
"operatorPosition": "nextLine",
"preferHanging": false,
"preferSingleLine": true,
"arrowFunction.useParentheses": "force",
"binaryExpression.linePerExpression": false,
"memberExpression.linePerExpression": false,
"typeLiteral.separatorKind": "semiColon",
"enumDeclaration.memberSpacing": "newLine",
"spaceAround": false,
"spaceSurroundingProperties": true,
"objectExpression.spaceSurroundingProperties": true,
"objectPattern.spaceSurroundingProperties": true,
"typeLiteral.spaceSurroundingProperties": true,
"binaryExpression.spaceSurroundingBitwiseAndArithmeticOperator": true,
"commentLine.forceSpaceAfterSlashes": true,
"constructor.spaceBeforeParentheses": false,
"constructorType.spaceAfterNewKeyword": false,
"constructSignature.spaceAfterNewKeyword": false,
"doWhileStatement.spaceAfterWhileKeyword": true,
"module.sortImportDeclarations": "maintain",
"module.sortExportDeclarations": "maintain",
"exportDeclaration.sortNamedExports": "maintain",
"importDeclaration.sortNamedImports": "maintain",
"exportDeclaration.spaceSurroundingNamedExports": false,
"forInStatement.spaceAfterForKeyword": true,
"forOfStatement.spaceAfterForKeyword": true,
"forStatement.spaceAfterForKeyword": true,
"forStatement.spaceAfterSemiColons": true,
"functionDeclaration.spaceBeforeParentheses": false,
"functionExpression.spaceBeforeParentheses": false,
"functionExpression.spaceAfterFunctionKeyword": false,
"getAccessor.spaceBeforeParentheses": false,
"ifStatement.spaceAfterIfKeyword": true,
"importDeclaration.spaceSurroundingNamedImports": true,
"method.spaceBeforeParentheses": false,
"setAccessor.spaceBeforeParentheses": false,
"taggedTemplate.spaceBeforeLiteral": false,
"typeAnnotation.spaceBeforeColon": false,
"typeAssertion.spaceBeforeExpression": false,
"whileStatement.spaceAfterWhileKeyword": true
},
"json": {
"trailingCommas": "never",
"preferSingleLine": false
},
"markdown": {
"textWrap": "always",
"emphasisKind": "underscores",
"strongKind": "asterisks"
},
"dockerfile": {},
"excludes": [
"**/*.js",
"**/*.d.ts",
"**/*-lock.json",
"**/.git/**/*",
"**/node_modules/**/*",
"**/build/**/*",
"**/obj/**/*",
"**/dist/**/*",
"**/user/**/*",
"**/logs/**/*",
"**/assets/**/*",
"**/Aki_Data/**/*",
"**/types/**/*",
"**/tests/__cache__/**/*",
"**/tests/__coverage__/**/*"
],
"plugins": [
"https://plugins.dprint.dev/typescript-0.88.3.wasm",
"https://plugins.dprint.dev/json-0.19.0.wasm",
"https://plugins.dprint.dev/markdown-0.16.2.wasm",
"https://plugins.dprint.dev/dockerfile-0.3.0.wasm"
]
}

View File

@ -12,10 +12,8 @@
}, },
"scripts": { "scripts": {
"check:circular": "madge --circular --ts-config tsconfig.json --extensions ts ./src/", "check:circular": "madge --circular --ts-config tsconfig.json --extensions ts ./src/",
"lint": "biome ci src --formatter-enabled=false --max-diagnostics=200", "lint": "eslint src",
"lint:fix": "biome check --apply-unsafe --max-diagnostics=200 . && dprint fmt --incremental=false", "lint:fix": "eslint src --fix",
"style": "dprint check --incremental=false",
"style:fix": "dprint fmt --incremental=false",
"test": "vitest run", "test": "vitest run",
"test:watch": "vitest", "test:watch": "vitest",
"test:coverage": "vitest run --coverage", "test:coverage": "vitest run --coverage",
@ -32,7 +30,7 @@
}, },
"dependencies": { "dependencies": {
"atomically": "~1.7", "atomically": "~1.7",
"buffer-crc32": "^1.0.0", "buffer-crc32": "~1.0",
"date-fns": "~2.30", "date-fns": "~2.30",
"date-fns-tz": "~2.0", "date-fns-tz": "~2.0",
"i18n": "~0.15", "i18n": "~0.15",
@ -51,8 +49,9 @@
"ws": "~8.16" "ws": "~8.16"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "~1.6", "@eslint/js": "~9.2",
"@pnpm/exe": "8.15.4", "@pnpm/exe": "8.15.4",
"@stylistic/eslint-plugin": "~1.8",
"@swc/cli": "~0.3", "@swc/cli": "~0.3",
"@swc/core": "~1.4", "@swc/core": "~1.4",
"@types/i18n": "~0.13", "@types/i18n": "~0.13",
@ -60,15 +59,16 @@
"@types/proper-lockfile": "~4.1", "@types/proper-lockfile": "~4.1",
"@types/semver": "~7.5", "@types/semver": "~7.5",
"@types/ws": "~8.5", "@types/ws": "~8.5",
"@typescript-eslint/eslint-plugin": "~7.2", "@typescript-eslint/eslint-plugin": "~7.8",
"@typescript-eslint/parser": "~7.2", "@typescript-eslint/parser": "~7.8",
"@vitest/coverage-istanbul": "~1.3", "@vitest/coverage-istanbul": "~1.3",
"@vitest/ui": "~1.3", "@vitest/ui": "~1.3",
"@yao-pkg/pkg": "5.11.5", "@yao-pkg/pkg": "5.11.5",
"@yao-pkg/pkg-fetch": "3.5.9", "@yao-pkg/pkg-fetch": "3.5.9",
"cross-env": "~7.0", "cross-env": "~7.0",
"dprint": "~0.45",
"eslint": "~8.57", "eslint": "~8.57",
"eslint-import-resolver-typescript": "~3.6",
"eslint-plugin-import": "~2.29",
"fs-extra": "~11.2", "fs-extra": "~11.2",
"gulp": "~4.0", "gulp": "~4.0",
"gulp-decompress": "~3.0", "gulp-decompress": "~3.0",
@ -82,6 +82,7 @@
"tsconfig-paths": "~4.2", "tsconfig-paths": "~4.2",
"typedoc": "~0.25", "typedoc": "~0.25",
"typemoq": "~2.1", "typemoq": "~2.1",
"typescript-eslint": "~7.8",
"vitest": "~1.3" "vitest": "~1.3"
}, },
"targets": { "targets": {

View File

@ -1,5 +1,4 @@
import readline from "node:readline"; import readline from "node:readline";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import { AsyncQueue } from "@spt-aki/utils/AsyncQueue"; import { AsyncQueue } from "@spt-aki/utils/AsyncQueue";
import { WinstonMainLogger } from "@spt-aki/utils/logging/WinstonMainLogger"; import { WinstonMainLogger } from "@spt-aki/utils/logging/WinstonMainLogger";
@ -24,7 +23,7 @@ export class ErrorHandler
this.logger.error(`\nStacktrace:\n${err.stack}`); this.logger.error(`\nStacktrace:\n${err.stack}`);
} }
this.readLine.question("Press Enter to close the window", (_ans) => this.readLine.close()); this.readLine.question("Press Enter to close the window", _ans => this.readLine.close());
this.readLine.on("close", () => process.exit(1)); this.readLine.on("close", () => process.exit(1));
} }
} }

View File

@ -1,7 +1,6 @@
import { container } from "tsyringe"; import { container } from "tsyringe";
import { ErrorHandler } from "@spt-aki/ErrorHandler";
import { Container } from "@spt-aki/di/Container"; import { Container } from "@spt-aki/di/Container";
import { ErrorHandler } from "@spt-aki/ErrorHandler";
import type { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader"; import type { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader";
import { App } from "@spt-aki/utils/App"; import { App } from "@spt-aki/utils/App";
import { Watermark } from "@spt-aki/utils/Watermark"; import { Watermark } from "@spt-aki/utils/Watermark";

View File

@ -1,3 +1,4 @@
import { inject, injectable } from "tsyringe";
import { AchievementController } from "@spt-aki/controllers/AchievementController"; import { AchievementController } from "@spt-aki/controllers/AchievementController";
import { ProfileController } from "@spt-aki/controllers/ProfileController"; import { ProfileController } from "@spt-aki/controllers/ProfileController";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
@ -6,7 +7,6 @@ import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyR
import { ICompletedAchievementsResponse } from "@spt-aki/models/eft/profile/ICompletedAchievementsResponse"; import { ICompletedAchievementsResponse } from "@spt-aki/models/eft/profile/ICompletedAchievementsResponse";
import { IGetAchievementsResponse } from "@spt-aki/models/eft/profile/IGetAchievementsResponse"; import { IGetAchievementsResponse } from "@spt-aki/models/eft/profile/IGetAchievementsResponse";
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil"; import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
import { inject, injectable } from "tsyringe";
@injectable() @injectable()
export class AchievementCallbacks export class AchievementCallbacks

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { BotController } from "@spt-aki/controllers/BotController"; import { BotController } from "@spt-aki/controllers/BotController";
import { IGenerateBotsRequestData } from "@spt-aki/models/eft/bot/IGenerateBotsRequestData"; import { IGenerateBotsRequestData } from "@spt-aki/models/eft/bot/IGenerateBotsRequestData";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";

View File

@ -1,3 +1,4 @@
import { inject, injectable } from "tsyringe";
import { BuildController } from "@spt-aki/controllers/BuildController"; import { BuildController } from "@spt-aki/controllers/BuildController";
import { ISetMagazineRequest } from "@spt-aki/models/eft/builds/ISetMagazineRequest"; import { ISetMagazineRequest } from "@spt-aki/models/eft/builds/ISetMagazineRequest";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
@ -7,7 +8,6 @@ import { IPresetBuildActionRequestData } from "@spt-aki/models/eft/presetBuild/I
import { IRemoveBuildRequestData } from "@spt-aki/models/eft/presetBuild/IRemoveBuildRequestData"; import { IRemoveBuildRequestData } from "@spt-aki/models/eft/presetBuild/IRemoveBuildRequestData";
import { IUserBuilds } from "@spt-aki/models/eft/profile/IAkiProfile"; import { IUserBuilds } from "@spt-aki/models/eft/profile/IAkiProfile";
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil"; import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
import { inject, injectable } from "tsyringe";
@injectable() @injectable()
export class BuildsCallbacks export class BuildsCallbacks

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { BundleLoader } from "@spt-aki/loaders/BundleLoader"; import { BundleLoader } from "@spt-aki/loaders/BundleLoader";
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
import { IHttpConfig } from "@spt-aki/models/spt/config/IHttpConfig"; import { IHttpConfig } from "@spt-aki/models/spt/config/IHttpConfig";

View File

@ -1,3 +1,4 @@
import { inject, injectable } from "tsyringe";
import { ClientLogController } from "@spt-aki/controllers/ClientLogController"; import { ClientLogController } from "@spt-aki/controllers/ClientLogController";
import { ModLoadOrder } from "@spt-aki/loaders/ModLoadOrder"; import { ModLoadOrder } from "@spt-aki/loaders/ModLoadOrder";
import { INullResponseData } from "@spt-aki/models/eft/httpResponse/INullResponseData"; import { INullResponseData } from "@spt-aki/models/eft/httpResponse/INullResponseData";
@ -7,7 +8,6 @@ import { IClientLogRequest } from "@spt-aki/models/spt/logging/IClientLogRequest
import { ConfigServer } from "@spt-aki/servers/ConfigServer"; import { ConfigServer } from "@spt-aki/servers/ConfigServer";
import { LocalisationService } from "@spt-aki/services/LocalisationService"; import { LocalisationService } from "@spt-aki/services/LocalisationService";
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil"; import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
import { inject, injectable } from "tsyringe";
/** Handle client logging related events */ /** Handle client logging related events */
@injectable() @injectable()

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { CustomizationController } from "@spt-aki/controllers/CustomizationController"; import { CustomizationController } from "@spt-aki/controllers/CustomizationController";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { HideoutController } from "@spt-aki/controllers/HideoutController"; import { HideoutController } from "@spt-aki/controllers/HideoutController";
import { RagfairController } from "@spt-aki/controllers/RagfairController"; import { RagfairController } from "@spt-aki/controllers/RagfairController";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";

View File

@ -1,8 +1,8 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { DialogueController } from "@spt-aki/controllers/DialogueController"; import { DialogueController } from "@spt-aki/controllers/DialogueController";
import { OnUpdate } from "@spt-aki/di/OnUpdate"; import { OnUpdate } from "@spt-aki/di/OnUpdate";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
import { IUIDRequestData } from "@spt-aki/models/eft/common/request/IUIDRequestData";
import { import {
IAcceptFriendRequestData, IAcceptFriendRequestData,
ICancelFriendRequestData, ICancelFriendRequestData,
@ -247,14 +247,14 @@ export class DialogueCallbacks implements OnUpdate
/** Handle client/friend/ignore/set */ /** Handle client/friend/ignore/set */
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
public ignoreFriend(url: string, request: { uid: string; }, sessionID: string): INullResponseData public ignoreFriend(url: string, request: IUIDRequestData, sessionID: string): INullResponseData
{ {
return this.httpResponse.nullResponse(); return this.httpResponse.nullResponse();
} }
/** Handle client/friend/ignore/remove */ /** Handle client/friend/ignore/remove */
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
public unIgnoreFriend(url: string, request: { uid: string; }, sessionID: string): INullResponseData public unIgnoreFriend(url: string, request: IUIDRequestData, sessionID: string): INullResponseData
{ {
return this.httpResponse.nullResponse(); return this.httpResponse.nullResponse();
} }

View File

@ -1,8 +1,8 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { GameController } from "@spt-aki/controllers/GameController"; import { GameController } from "@spt-aki/controllers/GameController";
import { OnLoad } from "@spt-aki/di/OnLoad"; import { OnLoad } from "@spt-aki/di/OnLoad";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
import { IUIDRequestData } from "@spt-aki/models/eft/common/request/IUIDRequestData";
import { ICheckVersionResponse } from "@spt-aki/models/eft/game/ICheckVersionResponse"; import { ICheckVersionResponse } from "@spt-aki/models/eft/game/ICheckVersionResponse";
import { ICurrentGroupResponse } from "@spt-aki/models/eft/game/ICurrentGroupResponse"; import { ICurrentGroupResponse } from "@spt-aki/models/eft/game/ICurrentGroupResponse";
import { IGameConfigResponse } from "@spt-aki/models/eft/game/IGameConfigResponse"; import { IGameConfigResponse } from "@spt-aki/models/eft/game/IGameConfigResponse";
@ -14,7 +14,6 @@ import { IGameModeResponse } from "@spt-aki/models/eft/game/IGameModeResponse";
import { IGameStartResponse } from "@spt-aki/models/eft/game/IGameStartResponse"; import { IGameStartResponse } from "@spt-aki/models/eft/game/IGameStartResponse";
import { IGetRaidTimeRequest } from "@spt-aki/models/eft/game/IGetRaidTimeRequest"; import { IGetRaidTimeRequest } from "@spt-aki/models/eft/game/IGetRaidTimeRequest";
import { IGetRaidTimeResponse } from "@spt-aki/models/eft/game/IGetRaidTimeResponse"; import { IGetRaidTimeResponse } from "@spt-aki/models/eft/game/IGetRaidTimeResponse";
import { IReportNicknameRequestData } from "@spt-aki/models/eft/game/IReportNicknameRequestData";
import { IServerDetails } from "@spt-aki/models/eft/game/IServerDetails"; import { IServerDetails } from "@spt-aki/models/eft/game/IServerDetails";
import { IVersionValidateRequestData } from "@spt-aki/models/eft/game/IVersionValidateRequestData"; import { IVersionValidateRequestData } from "@spt-aki/models/eft/game/IVersionValidateRequestData";
import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData"; import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData";
@ -160,7 +159,7 @@ export class GameCallbacks implements OnLoad
return this.httpResponse.noBody({ Version: this.watermark.getInGameVersionLabel() }); return this.httpResponse.noBody({ Version: this.watermark.getInGameVersionLabel() });
} }
public reportNickname(url: string, info: IReportNicknameRequestData, sessionID: string): INullResponseData public reportNickname(url: string, info: IUIDRequestData, sessionID: string): INullResponseData
{ {
return this.httpResponse.nullResponse(); return this.httpResponse.nullResponse();
} }

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { HandbookController } from "@spt-aki/controllers/HandbookController"; import { HandbookController } from "@spt-aki/controllers/HandbookController";
import { OnLoad } from "@spt-aki/di/OnLoad"; import { OnLoad } from "@spt-aki/di/OnLoad";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { HealthController } from "@spt-aki/controllers/HealthController"; import { HealthController } from "@spt-aki/controllers/HealthController";
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper"; import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { HideoutController } from "@spt-aki/controllers/HideoutController"; import { HideoutController } from "@spt-aki/controllers/HideoutController";
import { OnUpdate } from "@spt-aki/di/OnUpdate"; import { OnUpdate } from "@spt-aki/di/OnUpdate";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { OnLoad } from "@spt-aki/di/OnLoad"; import { OnLoad } from "@spt-aki/di/OnLoad";
import { HttpServer } from "@spt-aki/servers/HttpServer"; import { HttpServer } from "@spt-aki/servers/HttpServer";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { InraidController } from "@spt-aki/controllers/InraidController"; import { InraidController } from "@spt-aki/controllers/InraidController";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
import { INullResponseData } from "@spt-aki/models/eft/httpResponse/INullResponseData"; import { INullResponseData } from "@spt-aki/models/eft/httpResponse/INullResponseData";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { InsuranceController } from "@spt-aki/controllers/InsuranceController"; import { InsuranceController } from "@spt-aki/controllers/InsuranceController";
import { OnUpdate } from "@spt-aki/di/OnUpdate"; import { OnUpdate } from "@spt-aki/di/OnUpdate";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { InventoryController } from "@spt-aki/controllers/InventoryController"; import { InventoryController } from "@spt-aki/controllers/InventoryController";
import { QuestController } from "@spt-aki/controllers/QuestController"; import { QuestController } from "@spt-aki/controllers/QuestController";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData"; import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData";
import { Warning } from "@spt-aki/models/eft/itemEvent/IItemEventRouterBase"; import { Warning } from "@spt-aki/models/eft/itemEvent/IItemEventRouterBase";
import { IItemEventRouterRequest } from "@spt-aki/models/eft/itemEvent/IItemEventRouterRequest"; import { IItemEventRouterRequest } from "@spt-aki/models/eft/itemEvent/IItemEventRouterRequest";
@ -24,7 +23,7 @@ export class ItemEventCallbacks
): Promise<IGetBodyResponseData<IItemEventRouterResponse>> ): Promise<IGetBodyResponseData<IItemEventRouterResponse>>
{ {
const eventResponse = await this.itemEventRouter.handleEvents(info, sessionID); const eventResponse = await this.itemEventRouter.handleEvents(info, sessionID);
const result = (this.isCriticalError(eventResponse.warnings)) const result = this.isCriticalError(eventResponse.warnings)
? this.httpResponse.getBody( ? this.httpResponse.getBody(
eventResponse, eventResponse,
this.getErrorCode(eventResponse.warnings), this.getErrorCode(eventResponse.warnings),

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { LauncherController } from "@spt-aki/controllers/LauncherController"; import { LauncherController } from "@spt-aki/controllers/LauncherController";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
import { IChangeRequestData } from "@spt-aki/models/eft/launcher/IChangeRequestData"; import { IChangeRequestData } from "@spt-aki/models/eft/launcher/IChangeRequestData";
@ -29,13 +28,13 @@ export class LauncherCallbacks
public login(url: string, info: ILoginRequestData, sessionID: string): string public login(url: string, info: ILoginRequestData, sessionID: string): string
{ {
const output = this.launcherController.login(info); const output = this.launcherController.login(info);
return (!output) ? "FAILED" : output; return !output ? "FAILED" : output;
} }
public register(url: string, info: IRegisterData, sessionID: string): "FAILED" | "OK" public register(url: string, info: IRegisterData, sessionID: string): "FAILED" | "OK"
{ {
const output = this.launcherController.register(info); const output = this.launcherController.register(info);
return (!output) ? "FAILED" : "OK"; return !output ? "FAILED" : "OK";
} }
public get(url: string, info: ILoginRequestData, sessionID: string): string public get(url: string, info: ILoginRequestData, sessionID: string): string
@ -47,19 +46,19 @@ export class LauncherCallbacks
public changeUsername(url: string, info: IChangeRequestData, sessionID: string): "FAILED" | "OK" public changeUsername(url: string, info: IChangeRequestData, sessionID: string): "FAILED" | "OK"
{ {
const output = this.launcherController.changeUsername(info); const output = this.launcherController.changeUsername(info);
return (!output) ? "FAILED" : "OK"; return !output ? "FAILED" : "OK";
} }
public changePassword(url: string, info: IChangeRequestData, sessionID: string): "FAILED" | "OK" public changePassword(url: string, info: IChangeRequestData, sessionID: string): "FAILED" | "OK"
{ {
const output = this.launcherController.changePassword(info); const output = this.launcherController.changePassword(info);
return (!output) ? "FAILED" : "OK"; return !output ? "FAILED" : "OK";
} }
public wipe(url: string, info: IRegisterData, sessionID: string): "FAILED" | "OK" public wipe(url: string, info: IRegisterData, sessionID: string): "FAILED" | "OK"
{ {
const output = this.launcherController.wipe(info); const output = this.launcherController.wipe(info);
return (!output) ? "FAILED" : "OK"; return !output ? "FAILED" : "OK";
} }
public getServerVersion(): string public getServerVersion(): string

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { LocationController } from "@spt-aki/controllers/LocationController"; import { LocationController } from "@spt-aki/controllers/LocationController";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
import { ILocationBase } from "@spt-aki/models/eft/common/ILocationBase"; import { ILocationBase } from "@spt-aki/models/eft/common/ILocationBase";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { MatchController } from "@spt-aki/controllers/MatchController"; import { MatchController } from "@spt-aki/controllers/MatchController";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
@ -112,6 +111,7 @@ export class MatchCallbacks
{ {
return this.httpResponse.getBody(true); return this.httpResponse.getBody(true);
} }
/** Handle client/match/group/transfer */ /** Handle client/match/group/transfer */
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
public transferGroup(url: string, info: ITransferGroupRequest, sessionID: string): IGetBodyResponseData<boolean> public transferGroup(url: string, info: ITransferGroupRequest, sessionID: string): IGetBodyResponseData<boolean>

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { OnLoad } from "@spt-aki/di/OnLoad"; import { OnLoad } from "@spt-aki/di/OnLoad";
import { PostAkiModLoader } from "@spt-aki/loaders/PostAkiModLoader"; import { PostAkiModLoader } from "@spt-aki/loaders/PostAkiModLoader";
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { NoteController } from "@spt-aki/controllers/NoteController"; import { NoteController } from "@spt-aki/controllers/NoteController";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse"; import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";

View File

@ -1,11 +1,10 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { NotifierController } from "@spt-aki/controllers/NotifierController"; import { NotifierController } from "@spt-aki/controllers/NotifierController";
import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper"; import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
import { IUIDRequestData } from "@spt-aki/models/eft/common/request/IUIDRequestData";
import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData"; import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData";
import { INotifierChannel } from "@spt-aki/models/eft/notifier/INotifier"; import { INotifierChannel } from "@spt-aki/models/eft/notifier/INotifier";
import { ISelectProfileRequestData } from "@spt-aki/models/eft/notifier/ISelectProfileRequestData";
import { ISelectProfileResponse } from "@spt-aki/models/eft/notifier/ISelectProfileResponse"; import { ISelectProfileResponse } from "@spt-aki/models/eft/notifier/ISelectProfileResponse";
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil"; import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
import { JsonUtil } from "@spt-aki/utils/JsonUtil"; import { JsonUtil } from "@spt-aki/utils/JsonUtil";
@ -38,8 +37,8 @@ export class NotifierCallbacks
* be sent to client as NEWLINE separated strings... yup. * be sent to client as NEWLINE separated strings... yup.
*/ */
this.notifierController.notifyAsync(tmpSessionID).then((messages: any) => this.notifierController.notifyAsync(tmpSessionID).then((messages: any) =>
messages.map((message: any) => this.jsonUtil.serialize(message)).join("\n") messages.map((message: any) => this.jsonUtil.serialize(message)).join("\n"),
).then((text) => this.httpServerHelper.sendTextJson(resp, text)); ).then(text => this.httpServerHelper.sendTextJson(resp, text));
} }
/** Handle push/notifier/get */ /** Handle push/notifier/get */
@ -68,7 +67,7 @@ export class NotifierCallbacks
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
public selectProfile( public selectProfile(
url: string, url: string,
info: ISelectProfileRequestData, info: IUIDRequestData,
sessionID: string, sessionID: string,
): IGetBodyResponseData<ISelectProfileResponse> ): IGetBodyResponseData<ISelectProfileResponse>
{ {

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { PresetController } from "@spt-aki/controllers/PresetController"; import { PresetController } from "@spt-aki/controllers/PresetController";
import { OnLoad } from "@spt-aki/di/OnLoad"; import { OnLoad } from "@spt-aki/di/OnLoad";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ProfileController } from "@spt-aki/controllers/ProfileController"; import { ProfileController } from "@spt-aki/controllers/ProfileController";
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper"; import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { QuestController } from "@spt-aki/controllers/QuestController"; import { QuestController } from "@spt-aki/controllers/QuestController";
import { RepeatableQuestController } from "@spt-aki/controllers/RepeatableQuestController"; import { RepeatableQuestController } from "@spt-aki/controllers/RepeatableQuestController";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { RagfairController } from "@spt-aki/controllers/RagfairController"; import { RagfairController } from "@spt-aki/controllers/RagfairController";
import { OnLoad } from "@spt-aki/di/OnLoad"; import { OnLoad } from "@spt-aki/di/OnLoad";
import { OnUpdate } from "@spt-aki/di/OnUpdate"; import { OnUpdate } from "@spt-aki/di/OnUpdate";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { RepairController } from "@spt-aki/controllers/RepairController"; import { RepairController } from "@spt-aki/controllers/RepairController";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse"; import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { OnLoad } from "@spt-aki/di/OnLoad"; import { OnLoad } from "@spt-aki/di/OnLoad";
import { OnUpdate } from "@spt-aki/di/OnUpdate"; import { OnUpdate } from "@spt-aki/di/OnUpdate";
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { TradeController } from "@spt-aki/controllers/TradeController"; import { TradeController } from "@spt-aki/controllers/TradeController";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse"; import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { TraderController } from "@spt-aki/controllers/TraderController"; import { TraderController } from "@spt-aki/controllers/TraderController";
import { OnLoad } from "@spt-aki/di/OnLoad"; import { OnLoad } from "@spt-aki/di/OnLoad";
import { OnUpdate } from "@spt-aki/di/OnUpdate"; import { OnUpdate } from "@spt-aki/di/OnUpdate";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { WeatherController } from "@spt-aki/controllers/WeatherController"; import { WeatherController } from "@spt-aki/controllers/WeatherController";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData"; import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { WishlistController } from "@spt-aki/controllers/WishlistController"; import { WishlistController } from "@spt-aki/controllers/WishlistController";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse"; import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";

View File

@ -1,5 +1,4 @@
import { injectable } from "tsyringe"; import { injectable } from "tsyringe";
import { ContextVariable } from "@spt-aki/context/ContextVariable"; import { ContextVariable } from "@spt-aki/context/ContextVariable";
import { ContextVariableType } from "@spt-aki/context/ContextVariableType"; import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
import { LinkedList } from "@spt-aki/utils/collections/lists/LinkedList"; import { LinkedList } from "@spt-aki/utils/collections/lists/LinkedList";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ICompletedAchievementsResponse } from "@spt-aki/models/eft/profile/ICompletedAchievementsResponse"; import { ICompletedAchievementsResponse } from "@spt-aki/models/eft/profile/ICompletedAchievementsResponse";
import { IGetAchievementsResponse } from "@spt-aki/models/eft/profile/IGetAchievementsResponse"; import { IGetAchievementsResponse } from "@spt-aki/models/eft/profile/IGetAchievementsResponse";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ApplicationContext } from "@spt-aki/context/ApplicationContext"; import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
import { ContextVariableType } from "@spt-aki/context/ContextVariableType"; import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
import { BotGenerator } from "@spt-aki/generators/BotGenerator"; import { BotGenerator } from "@spt-aki/generators/BotGenerator";
@ -62,7 +61,7 @@ export class BotController
*/ */
public getBotPresetGenerationLimit(type: string): number public getBotPresetGenerationLimit(type: string): number
{ {
const value = this.botConfig.presetBatch[(type === "assaultGroup") ? "assault" : type]; const value = this.botConfig.presetBatch[type === "assaultGroup" ? "assault" : type];
if (!value) if (!value)
{ {
@ -148,7 +147,7 @@ export class BotController
const result = {}; const result = {};
const botDb = this.databaseServer.getTables().bots.types; const botDb = this.databaseServer.getTables().bots.types;
const botTypes = Object.keys(WildSpawnTypeNumber).filter((v) => Number.isNaN(Number(v))); const botTypes = Object.keys(WildSpawnTypeNumber).filter(v => Number.isNaN(Number(v)));
for (let botType of botTypes) for (let botType of botTypes)
{ {
const enumType = botType.toLowerCase(); const enumType = botType.toLowerCase();
@ -212,8 +211,8 @@ export class BotController
const raidSettings = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION)?.getValue< const raidSettings = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION)?.getValue<
IGetRaidConfigurationRequestData IGetRaidConfigurationRequestData
>(); >();
const pmcLevelRangeForMap = const pmcLevelRangeForMap
this.pmcConfig.locationSpecificPmcLevelOverride[raidSettings?.location.toLowerCase()]; = this.pmcConfig.locationSpecificPmcLevelOverride[raidSettings?.location.toLowerCase()];
const allPmcsHaveSameNameAsPlayer = this.randomUtil.getChance100( const allPmcsHaveSameNameAsPlayer = this.randomUtil.getChance100(
this.pmcConfig.allPMCsHavePlayerNameWithRandomPrefixChance, this.pmcConfig.allPMCsHavePlayerNameWithRandomPrefixChance,
@ -239,7 +238,7 @@ export class BotController
conditionPromises.push(this.generateWithBotDetails(condition, botGenerationDetails, sessionId)); conditionPromises.push(this.generateWithBotDetails(condition, botGenerationDetails, sessionId));
} }
await Promise.all(conditionPromises).then((p) => Promise.all(p)); await Promise.all(conditionPromises).then(p => Promise.all(p));
return []; return [];
} }
@ -326,8 +325,8 @@ export class BotController
const raidSettings = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION)?.getValue< const raidSettings = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION)?.getValue<
IGetRaidConfigurationRequestData IGetRaidConfigurationRequestData
>(); >();
const pmcLevelRangeForMap = const pmcLevelRangeForMap
this.pmcConfig.locationSpecificPmcLevelOverride[raidSettings.location.toLowerCase()]; = this.pmcConfig.locationSpecificPmcLevelOverride[raidSettings.location.toLowerCase()];
// Create gen request for when cache is empty // Create gen request for when cache is empty
const botGenerationDetails: BotGenerationDetails = { const botGenerationDetails: BotGenerationDetails = {

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper"; import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
import { ISetMagazineRequest } from "@spt-aki/models/eft/builds/ISetMagazineRequest"; import { ISetMagazineRequest } from "@spt-aki/models/eft/builds/ISetMagazineRequest";
@ -43,11 +42,11 @@ export class BuildController
const defaultEquipmentPresetsClone = this.jsonUtil.clone( const defaultEquipmentPresetsClone = this.jsonUtil.clone(
this.databaseServer.getTables().templates.defaultEquipmentPresets, this.databaseServer.getTables().templates.defaultEquipmentPresets,
); );
const playerSecureContainer = profile.characters.pmc.Inventory.items?.find((x) => const playerSecureContainer = profile.characters.pmc.Inventory.items?.find(x =>
x.slotId === secureContainerSlotId x.slotId === secureContainerSlotId,
); );
const firstDefaultItemsSecureContainer = defaultEquipmentPresetsClone[0]?.Items?.find((x) => const firstDefaultItemsSecureContainer = defaultEquipmentPresetsClone[0]?.Items?.find(x =>
x.slotId === secureContainerSlotId x.slotId === secureContainerSlotId,
); );
if (playerSecureContainer && playerSecureContainer?._tpl !== firstDefaultItemsSecureContainer?._tpl) if (playerSecureContainer && playerSecureContainer?._tpl !== firstDefaultItemsSecureContainer?._tpl)
{ {
@ -55,7 +54,7 @@ export class BuildController
for (const defaultPreset of defaultEquipmentPresetsClone) for (const defaultPreset of defaultEquipmentPresetsClone)
{ {
// Find presets secure container // Find presets secure container
const secureContainer = defaultPreset.Items.find((item) => item.slotId === secureContainerSlotId); const secureContainer = defaultPreset.Items.find(item => item.slotId === secureContainerSlotId);
if (secureContainer) if (secureContainer)
{ {
secureContainer._tpl = playerSecureContainer._tpl; secureContainer._tpl = playerSecureContainer._tpl;
@ -84,7 +83,7 @@ export class BuildController
const newBuild: IWeaponBuild = { Id: body.Id, Name: body.Name, Root: body.Root, Items: body.Items }; const newBuild: IWeaponBuild = { Id: body.Id, Name: body.Name, Root: body.Root, Items: body.Items };
const savedWeaponBuilds = this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds; const savedWeaponBuilds = this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds;
const existingBuild = savedWeaponBuilds.find((x) => x.Id === body.Id); const existingBuild = savedWeaponBuilds.find(x => x.Id === body.Id);
if (existingBuild) if (existingBuild)
{ {
// exists, replace // exists, replace
@ -107,8 +106,8 @@ export class BuildController
const buildType = "equipmentBuilds"; const buildType = "equipmentBuilds";
const pmcData = this.profileHelper.getPmcProfile(sessionID); const pmcData = this.profileHelper.getPmcProfile(sessionID);
const existingSavedEquipmentBuilds: IEquipmentBuild[] = const existingSavedEquipmentBuilds: IEquipmentBuild[] = this.saveServer.getProfile(sessionID)
this.saveServer.getProfile(sessionID).userbuilds[buildType]; .userbuilds[buildType];
// Replace duplicate ID's. The first item is the base item. // Replace duplicate ID's. The first item is the base item.
// Root ID and the base item ID need to match. // Root ID and the base item ID need to match.
@ -122,8 +121,8 @@ export class BuildController
Items: request.Items, Items: request.Items,
}; };
const existingBuild = existingSavedEquipmentBuilds.find((build) => const existingBuild = existingSavedEquipmentBuilds.find(build =>
build.Name === request.Name || build.Id === request.Id build.Name === request.Name || build.Id === request.Id,
); );
if (existingBuild) if (existingBuild)
{ {
@ -141,7 +140,7 @@ export class BuildController
} }
} }
/** Handle client/builds/delete*/ /** Handle client/builds/delete */
public removeBuild(sessionID: string, request: IRemoveBuildRequestData): void public removeBuild(sessionID: string, request: IRemoveBuildRequestData): void
{ {
this.removePlayerBuild(request.id, sessionID); this.removePlayerBuild(request.id, sessionID);
@ -155,7 +154,7 @@ export class BuildController
const magazineBuilds = profile.userbuilds.magazineBuilds; const magazineBuilds = profile.userbuilds.magazineBuilds;
// Check for id in weapon array first // Check for id in weapon array first
const matchingWeaponBuild = weaponBuilds.find((weaponBuild) => weaponBuild.Id === idToRemove); const matchingWeaponBuild = weaponBuilds.find(weaponBuild => weaponBuild.Id === idToRemove);
if (matchingWeaponBuild) if (matchingWeaponBuild)
{ {
weaponBuilds.splice(weaponBuilds.indexOf(matchingWeaponBuild), 1); weaponBuilds.splice(weaponBuilds.indexOf(matchingWeaponBuild), 1);
@ -164,7 +163,7 @@ export class BuildController
} }
// Id not found in weapons, try equipment // Id not found in weapons, try equipment
const matchingEquipmentBuild = equipmentBuilds.find((equipmentBuild) => equipmentBuild.Id === idToRemove); const matchingEquipmentBuild = equipmentBuilds.find(equipmentBuild => equipmentBuild.Id === idToRemove);
if (matchingEquipmentBuild) if (matchingEquipmentBuild)
{ {
equipmentBuilds.splice(equipmentBuilds.indexOf(matchingEquipmentBuild), 1); equipmentBuilds.splice(equipmentBuilds.indexOf(matchingEquipmentBuild), 1);
@ -173,7 +172,7 @@ export class BuildController
} }
// Id not found in weapons/equipment, try mags // Id not found in weapons/equipment, try mags
const matchingMagazineBuild = magazineBuilds.find((magBuild) => magBuild.Id === idToRemove); const matchingMagazineBuild = magazineBuilds.find(magBuild => magBuild.Id === idToRemove);
if (matchingMagazineBuild) if (matchingMagazineBuild)
{ {
magazineBuilds.splice(magazineBuilds.indexOf(matchingMagazineBuild), 1); magazineBuilds.splice(magazineBuilds.indexOf(matchingMagazineBuild), 1);
@ -208,7 +207,7 @@ export class BuildController
profile.userbuilds.magazineBuilds = []; profile.userbuilds.magazineBuilds = [];
} }
const existingArrayId = profile.userbuilds.magazineBuilds.findIndex((item) => item.Name === request.Name); const existingArrayId = profile.userbuilds.magazineBuilds.findIndex(item => item.Name === request.Name);
if (existingArrayId === -1) if (existingArrayId === -1)
{ {

View File

@ -1,9 +1,9 @@
import { inject, injectable } from "tsyringe";
import { IClientLogRequest } from "@spt-aki/models/spt/logging/IClientLogRequest"; import { IClientLogRequest } from "@spt-aki/models/spt/logging/IClientLogRequest";
import { LogBackgroundColor } from "@spt-aki/models/spt/logging/LogBackgroundColor"; import { LogBackgroundColor } from "@spt-aki/models/spt/logging/LogBackgroundColor";
import { LogLevel } from "@spt-aki/models/spt/logging/LogLevel"; import { LogLevel } from "@spt-aki/models/spt/logging/LogLevel";
import { LogTextColor } from "@spt-aki/models/spt/logging/LogTextColor"; import { LogTextColor } from "@spt-aki/models/spt/logging/LogTextColor";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import { inject, injectable } from "tsyringe";
@injectable() @injectable()
export class ClientLogController export class ClientLogController

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper"; import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { ISuit } from "@spt-aki/models/eft/common/tables/ITrader"; import { ISuit } from "@spt-aki/models/eft/common/tables/ITrader";
@ -43,10 +42,10 @@ export class CustomizationController
const suits = this.databaseServer.getTables().traders[traderID].suits; const suits = this.databaseServer.getTables().traders[traderID].suits;
// Get an inner join of clothing from templates.customization and Ragman's suits array // Get an inner join of clothing from templates.customization and Ragman's suits array
const matchingSuits = suits.filter((x) => x.suiteId in templates); const matchingSuits = suits.filter(x => x.suiteId in templates);
// Return all suits that have a side array containing the players side (usec/bear) // Return all suits that have a side array containing the players side (usec/bear)
return matchingSuits.filter((x) => templates[x.suiteId]._props.Side.includes(pmcData.Info.Side)); return matchingSuits.filter(x => templates[x.suiteId]._props.Side.includes(pmcData.Info.Side));
} }
/** /**
@ -133,7 +132,7 @@ export class CustomizationController
protected getTraderClothingOffer(sessionId: string, offerId: string): ISuit protected getTraderClothingOffer(sessionId: string, offerId: string): ISuit
{ {
return this.getAllTraderSuits(sessionId).find((x) => x._id === offerId); return this.getAllTraderSuits(sessionId).find(x => x._id === offerId);
} }
/** /**
@ -181,7 +180,7 @@ export class CustomizationController
output: IItemEventRouterResponse, output: IItemEventRouterResponse,
): void ): void
{ {
const relatedItem = pmcData.Inventory.items.find((x) => x._id === clothingItem.id); const relatedItem = pmcData.Inventory.items.find(x => x._id === clothingItem.id);
if (!relatedItem) if (!relatedItem)
{ {
this.logger.error( this.logger.error(

View File

@ -1,5 +1,4 @@
import { inject, injectAll, injectable } from "tsyringe"; import { inject, injectAll, injectable } from "tsyringe";
import { IDialogueChatBot } from "@spt-aki/helpers/Dialogue/IDialogueChatBot"; import { IDialogueChatBot } from "@spt-aki/helpers/Dialogue/IDialogueChatBot";
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper"; import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
import { IGetAllAttachmentsResponse } from "@spt-aki/models/eft/dialog/IGetAllAttachmentsResponse"; import { IGetAllAttachmentsResponse } from "@spt-aki/models/eft/dialog/IGetAllAttachmentsResponse";
@ -34,21 +33,21 @@ export class DialogueController
// if give command is disabled or commando commands are disabled // if give command is disabled or commando commands are disabled
if (!coreConfigs.features?.chatbotFeatures?.commandoEnabled) if (!coreConfigs.features?.chatbotFeatures?.commandoEnabled)
{ {
const sptCommando = this.dialogueChatBots.find((c) => const sptCommando = this.dialogueChatBots.find(c =>
c.getChatBot()._id.toLocaleLowerCase() === "sptcommando" c.getChatBot()._id.toLocaleLowerCase() === "sptcommando",
); );
this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptCommando), 1); this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptCommando), 1);
} }
if (!coreConfigs.features?.chatbotFeatures?.sptFriendEnabled) if (!coreConfigs.features?.chatbotFeatures?.sptFriendEnabled)
{ {
const sptFriend = this.dialogueChatBots.find((c) => c.getChatBot()._id.toLocaleLowerCase() === "sptFriend"); const sptFriend = this.dialogueChatBots.find(c => c.getChatBot()._id.toLocaleLowerCase() === "sptFriend");
this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptFriend), 1); this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptFriend), 1);
} }
} }
public registerChatBot(chatBot: IDialogueChatBot): void public registerChatBot(chatBot: IDialogueChatBot): void
{ {
if (this.dialogueChatBots.some((cb) => cb.getChatBot()._id === chatBot.getChatBot()._id)) if (this.dialogueChatBots.some(cb => cb.getChatBot()._id === chatBot.getChatBot()._id))
{ {
throw new Error(`The chat bot ${chatBot.getChatBot()._id} being registered already exists!`); throw new Error(`The chat bot ${chatBot.getChatBot()._id} being registered already exists!`);
} }
@ -73,7 +72,7 @@ export class DialogueController
public getFriendList(sessionID: string): IGetFriendListDataResponse public getFriendList(sessionID: string): IGetFriendListDataResponse
{ {
// Force a fake friend called SPT into friend list // Force a fake friend called SPT into friend list
return { Friends: this.dialogueChatBots.map((v) => v.getChatBot()), Ignore: [], InIgnoreList: [] }; return { Friends: this.dialogueChatBots.map(v => v.getChatBot()), Ignore: [], InIgnoreList: [] };
} }
/** /**
@ -117,6 +116,7 @@ export class DialogueController
return result; return result;
} }
/** /**
* Get the users involved in a dialog (player + other party) * Get the users involved in a dialog (player + other party)
* @param dialog The dialog to check for users * @param dialog The dialog to check for users
@ -131,7 +131,7 @@ export class DialogueController
// User to user messages are special in that they need the player to exist in them, add if they don't // User to user messages are special in that they need the player to exist in them, add if they don't
if ( if (
messageType === MessageType.USER_MESSAGE messageType === MessageType.USER_MESSAGE
&& !dialog.Users?.find((userDialog) => userDialog._id === profile.characters.pmc.sessionId) && !dialog.Users?.find(userDialog => userDialog._id === profile.characters.pmc.sessionId)
) )
{ {
if (!dialog.Users) if (!dialog.Users)
@ -207,7 +207,7 @@ export class DialogueController
if (request.type === MessageType.USER_MESSAGE) if (request.type === MessageType.USER_MESSAGE)
{ {
profile.dialogues[request.dialogId].Users = []; profile.dialogues[request.dialogId].Users = [];
const chatBot = this.dialogueChatBots.find((cb) => cb.getChatBot()._id === request.dialogId); const chatBot = this.dialogueChatBots.find(cb => cb.getChatBot()._id === request.dialogId);
if (chatBot) if (chatBot)
{ {
profile.dialogues[request.dialogId].Users.push(chatBot.getChatBot()); profile.dialogues[request.dialogId].Users.push(chatBot.getChatBot());
@ -217,6 +217,7 @@ export class DialogueController
return profile.dialogues[request.dialogId]; return profile.dialogues[request.dialogId];
} }
/** /**
* Get the users involved in a mail between two entities * Get the users involved in a mail between two entities
* @param fullProfile Player profile * @param fullProfile Player profile
@ -230,7 +231,7 @@ export class DialogueController
{ {
result.push(...dialogUsers); result.push(...dialogUsers);
if (!result.find((userDialog) => userDialog._id === fullProfile.info.id)) if (!result.find(userDialog => userDialog._id === fullProfile.info.id))
{ {
// Player doesnt exist, add them in before returning // Player doesnt exist, add them in before returning
const pmcProfile = fullProfile.characters.pmc; const pmcProfile = fullProfile.characters.pmc;
@ -278,7 +279,7 @@ export class DialogueController
*/ */
protected messagesHaveUncollectedRewards(messages: Message[]): boolean protected messagesHaveUncollectedRewards(messages: Message[]): boolean
{ {
return messages.some((message) => message.items?.data?.length > 0); return messages.some(message => message.items?.data?.length > 0);
} }
/** /**
@ -375,7 +376,7 @@ export class DialogueController
{ {
this.mailSendService.sendPlayerMessageToNpc(sessionId, request.dialogId, request.text); this.mailSendService.sendPlayerMessageToNpc(sessionId, request.dialogId, request.text);
return this.dialogueChatBots.find((cb) => cb.getChatBot()._id === request.dialogId)?.handleMessage( return this.dialogueChatBots.find(cb => cb.getChatBot()._id === request.dialogId)?.handleMessage(
sessionId, sessionId,
request, request,
) ?? request.dialogId; ) ?? request.dialogId;
@ -391,7 +392,7 @@ export class DialogueController
{ {
const timeNow = this.timeUtil.getTimestamp(); const timeNow = this.timeUtil.getTimestamp();
const dialogs = this.dialogueHelper.getDialogsForProfile(sessionId); const dialogs = this.dialogueHelper.getDialogsForProfile(sessionId);
return dialogs[dialogueId].messages.filter((message) => timeNow < (message.dt + message.maxStorageTime)); return dialogs[dialogueId].messages.filter(message => timeNow < message.dt + message.maxStorageTime);
} }
/** /**
@ -401,7 +402,7 @@ export class DialogueController
*/ */
protected getMessagesWithAttachments(messages: Message[]): Message[] protected getMessagesWithAttachments(messages: Message[]): Message[]
{ {
return messages.filter((message) => message.items?.data?.length > 0); return messages.filter(message => message.items?.data?.length > 0);
} }
/** /**
@ -446,6 +447,6 @@ export class DialogueController
*/ */
protected messageHasExpired(message: Message): boolean protected messageHasExpired(message: Message): boolean
{ {
return (this.timeUtil.getTimestamp()) > (message.dt + message.maxStorageTime); return this.timeUtil.getTimestamp() > message.dt + message.maxStorageTime;
} }
} }

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ApplicationContext } from "@spt-aki/context/ApplicationContext"; import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
import { ContextVariableType } from "@spt-aki/context/ContextVariableType"; import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
import { HideoutHelper } from "@spt-aki/helpers/HideoutHelper"; import { HideoutHelper } from "@spt-aki/helpers/HideoutHelper";
@ -360,8 +359,8 @@ export class GameController
for (const positionToAdd of positionsToAdd) for (const positionToAdd of positionsToAdd)
{ {
// Exists already, add new items to existing positions pool // Exists already, add new items to existing positions pool
const existingLootPosition = mapLooseLoot.spawnpoints.find((x) => const existingLootPosition = mapLooseLoot.spawnpoints.find(x =>
x.template.Id === positionToAdd.template.Id x.template.Id === positionToAdd.template.Id,
); );
if (existingLootPosition) if (existingLootPosition)
{ {
@ -391,7 +390,7 @@ export class GameController
const mapLootAdjustmentsDict = adjustments[mapId]; const mapLootAdjustmentsDict = adjustments[mapId];
for (const lootKey in mapLootAdjustmentsDict) for (const lootKey in mapLootAdjustmentsDict)
{ {
const lootPostionToAdjust = mapLooseLootData.spawnpoints.find((x) => x.template.Id === lootKey); const lootPostionToAdjust = mapLooseLootData.spawnpoints.find(x => x.template.Id === lootKey);
if (!lootPostionToAdjust) if (!lootPostionToAdjust)
{ {
this.logger.warning(`Unable to adjust loot position: ${lootKey} on map: ${mapId}`); this.logger.warning(`Unable to adjust loot position: ${lootKey} on map: ${mapId}`);
@ -424,7 +423,7 @@ export class GameController
for (const botToLimit of this.locationConfig.botTypeLimits[mapId]) for (const botToLimit of this.locationConfig.botTypeLimits[mapId])
{ {
const index = map.base.MinMaxBots.findIndex((x) => x.WildSpawnType === botToLimit.type); const index = map.base.MinMaxBots.findIndex(x => x.WildSpawnType === botToLimit.type);
if (index !== -1) if (index !== -1)
{ {
// Existing bot type found in MinMaxBots array, edit // Existing bot type found in MinMaxBots array, edit
@ -452,9 +451,9 @@ export class GameController
public getGameConfig(sessionID: string): IGameConfigResponse public getGameConfig(sessionID: string): IGameConfigResponse
{ {
const profile = this.profileHelper.getPmcProfile(sessionID); const profile = this.profileHelper.getPmcProfile(sessionID);
const gameTime = const gameTime
profile.Stats?.Eft.OverallCounters.Items?.find((counter) => = profile.Stats?.Eft.OverallCounters.Items?.find(counter =>
counter.Key.includes("LifeTime") && counter.Key.includes("Pmc") counter.Key.includes("LifeTime") && counter.Key.includes("Pmc"),
)?.Value ?? 0; )?.Value ?? 0;
const config: IGameConfigResponse = { const config: IGameConfigResponse = {
@ -599,12 +598,12 @@ export class GameController
let hpRegenPerHour = 456.6; let hpRegenPerHour = 456.6;
// Set new values, whatever is smallest // Set new values, whatever is smallest
energyRegenPerHour += pmcProfile.Bonuses.filter((bonus) => bonus.type === BonusType.ENERGY_REGENERATION) energyRegenPerHour += pmcProfile.Bonuses.filter(bonus => bonus.type === BonusType.ENERGY_REGENERATION)
.reduce((sum, curr) => sum + curr.value, 0); .reduce((sum, curr) => sum + curr.value, 0);
hydrationRegenPerHour += pmcProfile.Bonuses.filter((bonus) => hydrationRegenPerHour += pmcProfile.Bonuses.filter(bonus =>
bonus.type === BonusType.HYDRATION_REGENERATION bonus.type === BonusType.HYDRATION_REGENERATION,
).reduce((sum, curr) => sum + curr.value, 0); ).reduce((sum, curr) => sum + curr.value, 0);
hpRegenPerHour += pmcProfile.Bonuses.filter((bonus) => bonus.type === BonusType.HEALTH_REGENERATION).reduce( hpRegenPerHour += pmcProfile.Bonuses.filter(bonus => bonus.type === BonusType.HEALTH_REGENERATION).reduce(
(sum, curr) => sum + curr.value, (sum, curr) => sum + curr.value,
0, 0,
); );
@ -701,7 +700,7 @@ export class GameController
for (const wave of location.base.waves ?? []) for (const wave of location.base.waves ?? [])
{ {
if ((wave.slots_max - wave.slots_min === 0)) if (wave.slots_max - wave.slots_min === 0)
{ {
this.logger.debug( this.logger.debug(
`Fixed ${wave.WildSpawnType} Spawn: ${locationKey} wave: ${wave.number} of type: ${wave.WildSpawnType} in zone: ${wave.SpawnPoints} with Max Slots of ${wave.slots_max}`, `Fixed ${wave.WildSpawnType} Spawn: ${locationKey} wave: ${wave.number} of type: ${wave.WildSpawnType} in zone: ${wave.SpawnPoints} with Max Slots of ${wave.slots_max}`,
@ -739,13 +738,13 @@ export class GameController
const currentTimeStamp = this.timeUtil.getTimestamp(); const currentTimeStamp = this.timeUtil.getTimestamp();
// One day post-profile creation // One day post-profile creation
if (currentTimeStamp > (timeStampProfileCreated + oneDaySeconds)) if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds)
{ {
this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 1); this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 1);
} }
// Two day post-profile creation // Two day post-profile creation
if (currentTimeStamp > (timeStampProfileCreated + (oneDaySeconds * 2))) if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds * 2)
{ {
this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 2); this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 2);
} }
@ -771,7 +770,7 @@ export class GameController
// Wave has size that makes it candidate for splitting // Wave has size that makes it candidate for splitting
if ( if (
wave.slots_max - wave.slots_min wave.slots_max - wave.slots_min
>= this.locationConfig.splitWaveIntoSingleSpawnsSettings.waveSizeThreshold >= this.locationConfig.splitWaveIntoSingleSpawnsSettings.waveSizeThreshold
) )
{ {
// Get count of bots to be spawned in wave // Get count of bots to be spawned in wave
@ -842,8 +841,8 @@ export class GameController
{ {
const modDetails = activeMods[modKey]; const modDetails = activeMods[modKey];
if ( if (
fullProfile.aki.mods.some((x) => fullProfile.aki.mods.some(x =>
x.author === modDetails.author && x.name === modDetails.name && x.version === modDetails.version x.author === modDetails.author && x.name === modDetails.name && x.version === modDetails.version,
) )
) )
{ {
@ -958,8 +957,8 @@ export class GameController
protected adjustLabsRaiderSpawnRate(): void protected adjustLabsRaiderSpawnRate(): void
{ {
const labsBase = this.databaseServer.getTables().locations.laboratory.base; const labsBase = this.databaseServer.getTables().locations.laboratory.base;
const nonTriggerLabsBossSpawns = labsBase.BossLocationSpawn.filter((x) => const nonTriggerLabsBossSpawns = labsBase.BossLocationSpawn.filter(x =>
x.TriggerId === "" && x.TriggerName === "" x.TriggerId === "" && x.TriggerName === "",
); );
if (nonTriggerLabsBossSpawns) if (nonTriggerLabsBossSpawns)
{ {

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper"; import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer"; import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { HealthHelper } from "@spt-aki/helpers/HealthHelper"; import { HealthHelper } from "@spt-aki/helpers/HealthHelper";
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper"; import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
@ -66,7 +65,7 @@ export class HealthController
const output = this.eventOutputHolder.getOutput(sessionID); const output = this.eventOutputHolder.getOutput(sessionID);
// Update medkit used (hpresource) // Update medkit used (hpresource)
const healingItemToUse = pmcData.Inventory.items.find((item) => item._id === request.item); const healingItemToUse = pmcData.Inventory.items.find(item => item._id === request.item);
if (!healingItemToUse) if (!healingItemToUse)
{ {
const errorMessage = this.localisationService.getText( const errorMessage = this.localisationService.getText(
@ -114,7 +113,7 @@ export class HealthController
const output = this.eventOutputHolder.getOutput(sessionID); const output = this.eventOutputHolder.getOutput(sessionID);
let resourceLeft = 0; let resourceLeft = 0;
const itemToConsume = pmcData.Inventory.items.find((x) => x._id === request.item); const itemToConsume = pmcData.Inventory.items.find(x => x._id === request.item);
if (!itemToConsume) if (!itemToConsume)
{ {
// Item not found, very bad // Item not found, very bad

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ScavCaseRewardGenerator } from "@spt-aki/generators/ScavCaseRewardGenerator"; import { ScavCaseRewardGenerator } from "@spt-aki/generators/ScavCaseRewardGenerator";
import { HideoutHelper } from "@spt-aki/helpers/HideoutHelper"; import { HideoutHelper } from "@spt-aki/helpers/HideoutHelper";
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper"; import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
@ -106,7 +105,7 @@ export class HideoutController
{ {
const items = request.items.map((reqItem) => const items = request.items.map((reqItem) =>
{ {
const item = pmcData.Inventory.items.find((invItem) => invItem._id === reqItem.id); const item = pmcData.Inventory.items.find(invItem => invItem._id === reqItem.id);
return { inventoryItem: item, requestedItem: reqItem }; return { inventoryItem: item, requestedItem: reqItem };
}); });
@ -139,7 +138,7 @@ export class HideoutController
} }
// Construction time management // Construction time management
const profileHideoutArea = pmcData.Hideout.Areas.find((area) => area.type === request.areaType); const profileHideoutArea = pmcData.Hideout.Areas.find(area => area.type === request.areaType);
if (!profileHideoutArea) if (!profileHideoutArea)
{ {
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType)); this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
@ -148,8 +147,8 @@ export class HideoutController
return; return;
} }
const hideoutDataDb = this.databaseServer.getTables().hideout.areas.find((area) => const hideoutDataDb = this.databaseServer.getTables().hideout.areas.find(area =>
area.type === request.areaType area.type === request.areaType,
); );
if (!hideoutDataDb) if (!hideoutDataDb)
{ {
@ -192,7 +191,7 @@ export class HideoutController
{ {
const db = this.databaseServer.getTables(); const db = this.databaseServer.getTables();
const profileHideoutArea = pmcData.Hideout.Areas.find((area) => area.type === request.areaType); const profileHideoutArea = pmcData.Hideout.Areas.find(area => area.type === request.areaType);
if (!profileHideoutArea) if (!profileHideoutArea)
{ {
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType)); this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
@ -206,7 +205,7 @@ export class HideoutController
profileHideoutArea.completeTime = 0; profileHideoutArea.completeTime = 0;
profileHideoutArea.constructing = false; profileHideoutArea.constructing = false;
const hideoutData = db.hideout.areas.find((area) => area.type === profileHideoutArea.type); const hideoutData = db.hideout.areas.find(area => area.type === profileHideoutArea.type);
if (!hideoutData) if (!hideoutData)
{ {
this.logger.error( this.logger.error(
@ -264,11 +263,11 @@ export class HideoutController
*/ */
protected checkAndUpgradeWall(pmcData: IPmcData): void protected checkAndUpgradeWall(pmcData: IPmcData): void
{ {
const medStation = pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.MEDSTATION); const medStation = pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.MEDSTATION);
const waterCollector = pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.WATER_COLLECTOR); const waterCollector = pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.WATER_COLLECTOR);
if (medStation?.level >= 1 && waterCollector?.level >= 1) if (medStation?.level >= 1 && waterCollector?.level >= 1)
{ {
const wall = pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.EMERGENCY_WALL); const wall = pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.EMERGENCY_WALL);
if (wall?.level === 0) if (wall?.level === 0)
{ {
wall.level = 3; wall.level = 3;
@ -310,8 +309,8 @@ export class HideoutController
} }
// Some areas like gun stand have a child area linked to it, it needs to do the same as above // Some areas like gun stand have a child area linked to it, it needs to do the same as above
const childDbArea = this.databaseServer.getTables().hideout.areas.find((x) => const childDbArea = this.databaseServer.getTables().hideout.areas.find(x =>
x.parentArea === dbHideoutArea._id x.parentArea === dbHideoutArea._id,
); );
if (childDbArea) if (childDbArea)
{ {
@ -322,8 +321,8 @@ export class HideoutController
} }
// Set child area level to same as parent area // Set child area level to same as parent area
pmcData.Hideout.Areas.find((x) => x.type === childDbArea.type).level = pmcData.Hideout.Areas.find((x) => pmcData.Hideout.Areas.find(x => x.type === childDbArea.type).level = pmcData.Hideout.Areas.find(x =>
x.type === profileParentHideoutArea.type x.type === profileParentHideoutArea.type,
).level; ).level;
// Add/upgrade stash item in player inventory // Add/upgrade stash item in player inventory
@ -343,7 +342,7 @@ export class HideoutController
*/ */
protected addUpdateInventoryItemToProfile(pmcData: IPmcData, dbHideoutData: IHideoutArea, hideoutStage: Stage): void protected addUpdateInventoryItemToProfile(pmcData: IPmcData, dbHideoutData: IHideoutArea, hideoutStage: Stage): void
{ {
const existingInventoryItem = pmcData.Inventory.items.find((x) => x._id === dbHideoutData._id); const existingInventoryItem = pmcData.Inventory.items.find(x => x._id === dbHideoutData._id);
if (existingInventoryItem) if (existingInventoryItem)
{ {
// Update existing items container tpl to point to new id (tpl) // Update existing items container tpl to point to new id (tpl)
@ -400,11 +399,11 @@ export class HideoutController
const itemsToAdd = Object.entries(addItemToHideoutRequest.items).map((kvp) => const itemsToAdd = Object.entries(addItemToHideoutRequest.items).map((kvp) =>
{ {
const item = pmcData.Inventory.items.find((invItem) => invItem._id === kvp[1].id); const item = pmcData.Inventory.items.find(invItem => invItem._id === kvp[1].id);
return { inventoryItem: item, requestedItem: kvp[1], slot: kvp[0] }; return { inventoryItem: item, requestedItem: kvp[1], slot: kvp[0] };
}); });
const hideoutArea = pmcData.Hideout.Areas.find((area) => area.type === addItemToHideoutRequest.areaType); const hideoutArea = pmcData.Hideout.Areas.find(area => area.type === addItemToHideoutRequest.areaType);
if (!hideoutArea) if (!hideoutArea)
{ {
this.logger.error( this.logger.error(
@ -431,7 +430,7 @@ export class HideoutController
// Add item to area.slots // Add item to area.slots
const destinationLocationIndex = Number(item.slot); const destinationLocationIndex = Number(item.slot);
const hideoutSlotIndex = hideoutArea.slots.findIndex((x) => x.locationIndex === destinationLocationIndex); const hideoutSlotIndex = hideoutArea.slots.findIndex(x => x.locationIndex === destinationLocationIndex);
hideoutArea.slots[hideoutSlotIndex].item = [{ hideoutArea.slots[hideoutSlotIndex].item = [{
_id: item.inventoryItem._id, _id: item.inventoryItem._id,
_tpl: item.inventoryItem._tpl, _tpl: item.inventoryItem._tpl,
@ -463,7 +462,7 @@ export class HideoutController
{ {
const output = this.eventOutputHolder.getOutput(sessionID); const output = this.eventOutputHolder.getOutput(sessionID);
const hideoutArea = pmcData.Hideout.Areas.find((area) => area.type === request.areaType); const hideoutArea = pmcData.Hideout.Areas.find(area => area.type === request.areaType);
if (!hideoutArea) if (!hideoutArea)
{ {
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType)); this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
@ -520,7 +519,7 @@ export class HideoutController
const slotIndexToRemove = removeResourceRequest.slots[0]; const slotIndexToRemove = removeResourceRequest.slots[0];
// Assume only one item in slot // Assume only one item in slot
const itemToReturn = hideoutArea.slots.find((slot) => slot.locationIndex === slotIndexToRemove).item[0]; const itemToReturn = hideoutArea.slots.find(slot => slot.locationIndex === slotIndexToRemove).item[0];
const request: IAddItemDirectRequest = { const request: IAddItemDirectRequest = {
itemWithModsToAdd: [itemToReturn], itemWithModsToAdd: [itemToReturn],
@ -537,7 +536,7 @@ export class HideoutController
} }
// Remove items from slot, locationIndex remains // Remove items from slot, locationIndex remains
const hideoutSlotIndex = hideoutArea.slots.findIndex((slot) => slot.locationIndex === slotIndexToRemove); const hideoutSlotIndex = hideoutArea.slots.findIndex(slot => slot.locationIndex === slotIndexToRemove);
hideoutArea.slots[hideoutSlotIndex].item = undefined; hideoutArea.slots[hideoutSlotIndex].item = undefined;
return output; return output;
@ -562,7 +561,7 @@ export class HideoutController
// Force a production update (occur before area is toggled as it could be generator and doing it after generator enabled would cause incorrect calculaton of production progress) // Force a production update (occur before area is toggled as it could be generator and doing it after generator enabled would cause incorrect calculaton of production progress)
this.hideoutHelper.updatePlayerHideout(sessionID); this.hideoutHelper.updatePlayerHideout(sessionID);
const hideoutArea = pmcData.Hideout.Areas.find((area) => area.type === request.areaType); const hideoutArea = pmcData.Hideout.Areas.find(area => area.type === request.areaType);
if (!hideoutArea) if (!hideoutArea)
{ {
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType)); this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
@ -592,20 +591,20 @@ export class HideoutController
this.hideoutHelper.registerProduction(pmcData, body, sessionID); this.hideoutHelper.registerProduction(pmcData, body, sessionID);
// Find the recipe of the production // Find the recipe of the production
const recipe = this.databaseServer.getTables().hideout.production.find((p) => p._id === body.recipeId); const recipe = this.databaseServer.getTables().hideout.production.find(p => p._id === body.recipeId);
// Find the actual amount of items we need to remove because body can send weird data // Find the actual amount of items we need to remove because body can send weird data
const recipeRequirementsClone = this.jsonUtil.clone( const recipeRequirementsClone = this.jsonUtil.clone(
recipe.requirements.filter((i) => i.type === "Item" || i.type === "Tool"), recipe.requirements.filter(i => i.type === "Item" || i.type === "Tool"),
); );
const output = this.eventOutputHolder.getOutput(sessionID); const output = this.eventOutputHolder.getOutput(sessionID);
const itemsToDelete = body.items.concat(body.tools); const itemsToDelete = body.items.concat(body.tools);
for (const itemToDelete of itemsToDelete) for (const itemToDelete of itemsToDelete)
{ {
const itemToCheck = pmcData.Inventory.items.find((i) => i._id === itemToDelete.id); const itemToCheck = pmcData.Inventory.items.find(i => i._id === itemToDelete.id);
const requirement = recipeRequirementsClone.find((requirement) => const requirement = recipeRequirementsClone.find(requirement =>
requirement.templateId === itemToCheck._tpl requirement.templateId === itemToCheck._tpl,
); );
// Handle tools not having a `count`, but always only requiring 1 // Handle tools not having a `count`, but always only requiring 1
@ -645,7 +644,7 @@ export class HideoutController
for (const requestedItem of body.items) for (const requestedItem of body.items)
{ {
const inventoryItem = pmcData.Inventory.items.find((item) => item._id === requestedItem.id); const inventoryItem = pmcData.Inventory.items.find(item => item._id === requestedItem.id);
if (!inventoryItem) if (!inventoryItem)
{ {
this.logger.error( this.logger.error(
@ -667,7 +666,7 @@ export class HideoutController
} }
} }
const recipe = this.databaseServer.getTables().hideout.scavcase.find((r) => r._id === body.recipeId); const recipe = this.databaseServer.getTables().hideout.scavcase.find(r => r._id === body.recipeId);
if (!recipe) if (!recipe)
{ {
this.logger.error( this.logger.error(
@ -679,13 +678,12 @@ export class HideoutController
// @Important: Here we need to be very exact: // @Important: Here we need to be very exact:
// - normal recipe: Production time value is stored in attribute "productionTime" with small "p" // - normal recipe: Production time value is stored in attribute "productionTime" with small "p"
// - scav case recipe: Production time value is stored in attribute "ProductionTime" with capital "P" // - scav case recipe: Production time value is stored in attribute "ProductionTime" with capital "P"
const adjustedCraftTime = recipe.ProductionTime const adjustedCraftTime = recipe.ProductionTime - this.hideoutHelper.getSkillProductionTimeReduction(
- this.hideoutHelper.getSkillProductionTimeReduction( pmcData,
pmcData, recipe.ProductionTime,
recipe.ProductionTime, SkillTypes.CRAFTING,
SkillTypes.CRAFTING, this.databaseServer.getTables().globals.config.SkillsSettings.Crafting.CraftTimeReductionPerLevel,
this.databaseServer.getTables().globals.config.SkillsSettings.Crafting.CraftTimeReductionPerLevel, );
);
const modifiedScavCaseTime = this.getScavCaseTime(pmcData, adjustedCraftTime); const modifiedScavCaseTime = this.getScavCaseTime(pmcData, adjustedCraftTime);
@ -772,7 +770,7 @@ export class HideoutController
return output; return output;
} }
const recipe = hideoutDb.production.find((r) => r._id === request.recipeId); const recipe = hideoutDb.production.find(r => r._id === request.recipeId);
if (recipe) if (recipe)
{ {
this.handleRecipe(sessionID, recipe, pmcData, request, output); this.handleRecipe(sessionID, recipe, pmcData, request, output);
@ -780,7 +778,7 @@ export class HideoutController
return output; return output;
} }
const scavCase = hideoutDb.scavcase.find((r) => r._id === request.recipeId); const scavCase = hideoutDb.scavcase.find(r => r._id === request.recipeId);
if (scavCase) if (scavCase)
{ {
this.handleScavCase(sessionID, pmcData, request, output); this.handleScavCase(sessionID, pmcData, request, output);
@ -938,7 +936,7 @@ export class HideoutController
} }
// Check if the recipe is the same as the last one - get bonus when crafting same thing multiple times // Check if the recipe is the same as the last one - get bonus when crafting same thing multiple times
const area = pmcData.Hideout.Areas.find((area) => area.type === recipe.areaType); const area = pmcData.Hideout.Areas.find(area => area.type === recipe.areaType);
if (area && request.recipeId !== area.lastRecipe) if (area && request.recipeId !== area.lastRecipe)
{ {
// 1 point per craft upon the end of production for alternating between 2 different crafting recipes in the same module // 1 point per craft upon the end of production for alternating between 2 different crafting recipes in the same module
@ -948,7 +946,7 @@ export class HideoutController
// Update variable with time spent crafting item(s) // Update variable with time spent crafting item(s)
// 1 point per 8 hours of crafting // 1 point per 8 hours of crafting
hoursCrafting += recipe.productionTime; hoursCrafting += recipe.productionTime;
if ((hoursCrafting / this.hideoutConfig.hoursForSkillCrafting) >= 1) if (hoursCrafting / this.hideoutConfig.hoursForSkillCrafting >= 1)
{ {
// Spent enough time crafting to get a bonus xp multipler // Spent enough time crafting to get a bonus xp multipler
const multiplierCrafting = Math.floor(hoursCrafting / this.hideoutConfig.hoursForSkillCrafting); const multiplierCrafting = Math.floor(hoursCrafting / this.hideoutConfig.hoursForSkillCrafting);
@ -1016,7 +1014,7 @@ export class HideoutController
{ {
this.profileHelper.addSkillPointsToPlayer(pmcData, SkillTypes.CRAFTING, craftingExpAmount); this.profileHelper.addSkillPointsToPlayer(pmcData, SkillTypes.CRAFTING, craftingExpAmount);
const intellectAmountToGive = 0.5 * (Math.round(craftingExpAmount / 15)); const intellectAmountToGive = 0.5 * Math.round(craftingExpAmount / 15);
if (intellectAmountToGive > 0) if (intellectAmountToGive > 0)
{ {
this.profileHelper.addSkillPointsToPlayer(pmcData, SkillTypes.INTELLECT, intellectAmountToGive); this.profileHelper.addSkillPointsToPlayer(pmcData, SkillTypes.INTELLECT, intellectAmountToGive);
@ -1189,14 +1187,14 @@ export class HideoutController
public recordShootingRangePoints(sessionId: string, pmcData: IPmcData, request: IRecordShootingRangePoints): void public recordShootingRangePoints(sessionId: string, pmcData: IPmcData, request: IRecordShootingRangePoints): void
{ {
// Check if counter exists, add placeholder if it doesnt // Check if counter exists, add placeholder if it doesnt
if (!pmcData.Stats.Eft.OverallCounters.Items.find((x) => x.Key.includes("ShootingRangePoints"))) if (!pmcData.Stats.Eft.OverallCounters.Items.find(x => x.Key.includes("ShootingRangePoints")))
{ {
pmcData.Stats.Eft.OverallCounters.Items.push({ Key: ["ShootingRangePoints"], Value: 0 }); pmcData.Stats.Eft.OverallCounters.Items.push({ Key: ["ShootingRangePoints"], Value: 0 });
} }
// Find counter by key and update value // Find counter by key and update value
const shootingRangeHighScore = pmcData.Stats.Eft.OverallCounters.Items.find((x) => const shootingRangeHighScore = pmcData.Stats.Eft.OverallCounters.Items.find(x =>
x.Key.includes("ShootingRangePoints") x.Key.includes("ShootingRangePoints"),
); );
shootingRangeHighScore.Value = request.points; shootingRangeHighScore.Value = request.points;
} }
@ -1218,7 +1216,7 @@ export class HideoutController
// Create mapping of required item with corrisponding item from player inventory // Create mapping of required item with corrisponding item from player inventory
const items = request.items.map((reqItem) => const items = request.items.map((reqItem) =>
{ {
const item = pmcData.Inventory.items.find((invItem) => invItem._id === reqItem.id); const item = pmcData.Inventory.items.find(invItem => invItem._id === reqItem.id);
return { inventoryItem: item, requestedItem: reqItem }; return { inventoryItem: item, requestedItem: reqItem };
}); });
@ -1248,14 +1246,14 @@ export class HideoutController
} }
} }
const profileHideoutArea = pmcData.Hideout.Areas.find((x) => x.type === request.areaType); const profileHideoutArea = pmcData.Hideout.Areas.find(x => x.type === request.areaType);
if (!profileHideoutArea) if (!profileHideoutArea)
{ {
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType)); this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
return this.httpResponse.appendErrorToOutput(output); return this.httpResponse.appendErrorToOutput(output);
} }
const hideoutDbData = this.databaseServer.getTables().hideout.areas.find((x) => x.type === request.areaType); const hideoutDbData = this.databaseServer.getTables().hideout.areas.find(x => x.type === request.areaType);
if (!hideoutDbData) if (!hideoutDbData)
{ {
this.logger.error( this.logger.error(

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ApplicationContext } from "@spt-aki/context/ApplicationContext"; import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
import { ContextVariableType } from "@spt-aki/context/ContextVariableType"; import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
import { PlayerScavGenerator } from "@spt-aki/generators/PlayerScavGenerator"; import { PlayerScavGenerator } from "@spt-aki/generators/PlayerScavGenerator";
@ -204,8 +203,8 @@ export class InraidController
if (locationName === "lighthouse" && postRaidRequest.profile.Info.Side.toLowerCase() === "usec") if (locationName === "lighthouse" && postRaidRequest.profile.Info.Side.toLowerCase() === "usec")
{ {
// Decrement counter if it exists, don't go below 0 // Decrement counter if it exists, don't go below 0
const remainingCounter = serverPmcProfile?.Stats.Eft.OverallCounters.Items.find((x) => const remainingCounter = serverPmcProfile?.Stats.Eft.OverallCounters.Items.find(x =>
x.Key.includes("UsecRaidRemainKills") x.Key.includes("UsecRaidRemainKills"),
); );
if (remainingCounter?.Value > 0) if (remainingCounter?.Value > 0)
{ {
@ -229,9 +228,9 @@ export class InraidController
// Not dead // Not dead
// Check for cultist amulets in special slot (only slot it can fit) // Check for cultist amulets in special slot (only slot it can fit)
const amuletOnPlayer = serverPmcProfile.Inventory.items.filter((item) => const amuletOnPlayer = serverPmcProfile.Inventory.items.filter(item =>
item.slotId?.startsWith("SpecialSlot") item.slotId?.startsWith("SpecialSlot"),
).find((item) => item._tpl === "64d0b40fbe2eed70e254e2d4"); ).find(item => item._tpl === "64d0b40fbe2eed70e254e2d4");
if (amuletOnPlayer) if (amuletOnPlayer)
{ {
// No charges left, delete it // No charges left, delete it
@ -250,8 +249,8 @@ export class InraidController
} }
} }
const victims = postRaidRequest.profile.Stats.Eft.Victims.filter((x) => const victims = postRaidRequest.profile.Stats.Eft.Victims.filter(x =>
["sptbear", "sptusec"].includes(x.Role.toLowerCase()) ["sptbear", "sptusec"].includes(x.Role.toLowerCase()),
); );
if (victims?.length > 0) if (victims?.length > 0)
{ {
@ -283,9 +282,13 @@ export class InraidController
// Find and remove the completed condition from profile if player died, otherwise quest is stuck in limbo // Find and remove the completed condition from profile if player died, otherwise quest is stuck in limbo
// and quest items cannot be picked up again // and quest items cannot be picked up again
const allQuests = this.questHelper.getQuestsFromDb(); const allQuests = this.questHelper.getQuestsFromDb();
const activeQuestIdsInProfile = pmcData.Quests.filter((profileQuest) => const activeQuestIdsInProfile = pmcData.Quests.filter(
![QuestStatus.AvailableForStart, QuestStatus.Success, QuestStatus.Expired].includes(profileQuest.status) profileQuest => ![
).map((x) => x.qid); QuestStatus.AvailableForStart,
QuestStatus.Success,
QuestStatus.Expired,
].includes(profileQuest.status),
).map(x => x.qid);
for (const questItem of postRaidSaveRequest.profile.Stats.Eft.CarriedQuestItems) for (const questItem of postRaidSaveRequest.profile.Stats.Eft.CarriedQuestItems)
{ {
// Get quest/find condition for carried quest item // Get quest/find condition for carried quest item
@ -399,7 +402,7 @@ export class InraidController
*/ */
protected mergePmcAndScavEncyclopedias(primary: IPmcData, secondary: IPmcData): void protected mergePmcAndScavEncyclopedias(primary: IPmcData, secondary: IPmcData): void
{ {
function extend(target: { [key: string]: boolean; }, source: Record<string, boolean>) function extend(target: { [key: string]: boolean }, source: Record<string, boolean>)
{ {
for (const key in source) for (const key in source)
{ {
@ -469,7 +472,7 @@ export class InraidController
for (const quest of scavProfile.Quests) for (const quest of scavProfile.Quests)
{ {
const pmcQuest = pmcProfile.Quests.find((x) => x.qid === quest.qid); const pmcQuest = pmcProfile.Quests.find(x => x.qid === quest.qid);
if (!pmcQuest) if (!pmcQuest)
{ {
this.logger.warning(`No PMC quest found for ID: ${quest.qid}`); this.logger.warning(`No PMC quest found for ID: ${quest.qid}`);
@ -504,7 +507,7 @@ export class InraidController
for (const scavCounter of Object.values(scavProfile.TaskConditionCounters)) for (const scavCounter of Object.values(scavProfile.TaskConditionCounters))
{ {
// If this is an achievement that isn't for the scav, don't process it // If this is an achievement that isn't for the scav, don't process it
const achievement = achievements.find((achievement) => achievement.id === scavCounter.sourceId); const achievement = achievements.find(achievement => achievement.id === scavCounter.sourceId);
if (achievement && achievement.side !== "Savage") if (achievement && achievement.side !== "Savage")
{ {
continue; continue;
@ -541,7 +544,7 @@ export class InraidController
*/ */
protected isPlayerDead(statusOnExit: PlayerRaidEndState): boolean protected isPlayerDead(statusOnExit: PlayerRaidEndState): boolean
{ {
return (statusOnExit !== PlayerRaidEndState.SURVIVED && statusOnExit !== PlayerRaidEndState.RUNNER); return statusOnExit !== PlayerRaidEndState.SURVIVED && statusOnExit !== PlayerRaidEndState.RUNNER;
} }
/** /**
@ -686,8 +689,8 @@ export class InraidController
// Remove any items that were returned by the item delivery, but also insured, from the player's insurance list // Remove any items that were returned by the item delivery, but also insured, from the player's insurance list
// This is to stop items being duplicated by being returned from both the item delivery, and insurance // This is to stop items being duplicated by being returned from both the item delivery, and insurance
const deliveredItemIds = items.map((x) => x._id); const deliveredItemIds = items.map(x => x._id);
pmcData.InsuredItems = pmcData.InsuredItems.filter((x) => !deliveredItemIds.includes(x.itemId)); pmcData.InsuredItems = pmcData.InsuredItems.filter(x => !deliveredItemIds.includes(x.itemId));
// Send the items to the player // Send the items to the player
this.mailSendService.sendLocalisedNpcMessageToPlayer( this.mailSendService.sendLocalisedNpcMessageToPlayer(

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper"; import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper"; import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
@ -113,7 +112,7 @@ export class InsuranceController
this.logger.debug(`Found ${profileInsuranceDetails.length} insurance packages in profile ${sessionID}`); this.logger.debug(`Found ${profileInsuranceDetails.length} insurance packages in profile ${sessionID}`);
} }
return profileInsuranceDetails.filter((insured) => insuranceTime >= insured.scheduledTime); return profileInsuranceDetails.filter(insured => insuranceTime >= insured.scheduledTime);
} }
/** /**
@ -161,7 +160,7 @@ export class InsuranceController
*/ */
protected countAllInsuranceItems(insurance: Insurance[]): number protected countAllInsuranceItems(insurance: Insurance[]): number
{ {
return this.mathUtil.arraySum(insurance.map((ins) => ins.items.length)); return this.mathUtil.arraySum(insurance.map(ins => ins.items.length));
} }
/** /**
@ -174,11 +173,11 @@ export class InsuranceController
protected removeInsurancePackageFromProfile(sessionID: string, insPackage: Insurance): void protected removeInsurancePackageFromProfile(sessionID: string, insPackage: Insurance): void
{ {
const profile = this.saveServer.getProfile(sessionID); const profile = this.saveServer.getProfile(sessionID);
profile.insurance = profile.insurance.filter((insurance) => profile.insurance = profile.insurance.filter(insurance =>
insurance.traderId !== insPackage.traderId insurance.traderId !== insPackage.traderId
|| insurance.systemData.date !== insPackage.systemData.date || insurance.systemData.date !== insPackage.systemData.date
|| insurance.systemData.time !== insPackage.systemData.time || insurance.systemData.time !== insPackage.systemData.time
|| insurance.systemData.location !== insPackage.systemData.location || insurance.systemData.location !== insPackage.systemData.location,
); );
this.logger.debug(`Removed processed insurance package. Remaining packages: ${profile.insurance.length}`); this.logger.debug(`Removed processed insurance package. Remaining packages: ${profile.insurance.length}`);
@ -201,8 +200,8 @@ export class InsuranceController
let parentAttachmentsMap = this.populateParentAttachmentsMap(rootItemParentID, insured, itemsMap); let parentAttachmentsMap = this.populateParentAttachmentsMap(rootItemParentID, insured, itemsMap);
// Check to see if any regular items are present. // Check to see if any regular items are present.
const hasRegularItems = Array.from(itemsMap.values()).some((item) => const hasRegularItems = Array.from(itemsMap.values()).some(item =>
!this.itemHelper.isAttachmentAttached(item) !this.itemHelper.isAttachmentAttached(item),
); );
// Process all items that are not attached, attachments; those are handled separately, by value. // Process all items that are not attached, attachments; those are handled separately, by value.
@ -250,7 +249,7 @@ export class InsuranceController
for (const insuredItem of insured.items) for (const insuredItem of insured.items)
{ {
// Use the parent ID from the item to get the parent item. // Use the parent ID from the item to get the parent item.
const parentItem = insured.items.find((item) => item._id === insuredItem.parentId); const parentItem = insured.items.find(item => item._id === insuredItem.parentId);
// The parent (not the hideout) could not be found. Skip and warn. // The parent (not the hideout) could not be found. Skip and warn.
if (!parentItem && insuredItem.parentId !== rootItemParentID) if (!parentItem && insuredItem.parentId !== rootItemParentID)
@ -490,7 +489,7 @@ export class InsuranceController
{ {
this.logger.debug( this.logger.debug(
`Attachment ${index} Id: ${attachmentId} Tpl: ${ `Attachment ${index} Id: ${attachmentId} Tpl: ${
attachments.find((x) => x._id === attachmentId)?._tpl attachments.find(x => x._id === attachmentId)?._tpl
} - Price: ${attachmentPrices[attachmentId]}`, } - Price: ${attachmentPrices[attachmentId]}`,
); );
index++; index++;
@ -557,7 +556,7 @@ export class InsuranceController
*/ */
protected removeItemsFromInsurance(insured: Insurance, toDelete: Set<string>): void protected removeItemsFromInsurance(insured: Insurance, toDelete: Set<string>): void
{ {
insured.items = insured.items.filter((item) => !toDelete.has(item._id)); insured.items = insured.items.filter(item => !toDelete.has(item._id));
} }
/** /**
@ -746,6 +745,6 @@ export class InsuranceController
// Represents an insurance item that has had it's common locale-name and value added to it. // Represents an insurance item that has had it's common locale-name and value added to it.
interface EnrichedItem extends Item interface EnrichedItem extends Item
{ {
name: string; name: string
dynamicPrice: number; dynamicPrice: number
} }

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { LootGenerator } from "@spt-aki/generators/LootGenerator"; import { LootGenerator } from "@spt-aki/generators/LootGenerator";
import { HideoutHelper } from "@spt-aki/helpers/HideoutHelper"; import { HideoutHelper } from "@spt-aki/helpers/HideoutHelper";
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper"; import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
@ -107,7 +106,7 @@ export class InventoryController
} }
// Check for item in inventory before allowing internal transfer // Check for item in inventory before allowing internal transfer
const originalItemLocation = ownerInventoryItems.from.find((item) => item._id === moveRequest.item); const originalItemLocation = ownerInventoryItems.from.find(item => item._id === moveRequest.item);
if (!originalItemLocation) if (!originalItemLocation)
{ {
// Internal item move but item never existed, possible dupe glitch // Internal item move but item never existed, possible dupe glitch
@ -169,7 +168,7 @@ export class InventoryController
return; return;
} }
const profileToRemoveItemFrom = (!request.fromOwner || request.fromOwner.id === pmcData._id) const profileToRemoveItemFrom = !request.fromOwner || request.fromOwner.id === pmcData._id
? pmcData ? pmcData
: this.profileHelper.getFullProfile(sessionID).characters.scav; : this.profileHelper.getFullProfile(sessionID).characters.scav;
@ -198,12 +197,12 @@ export class InventoryController
// Handle cartridge edge-case // Handle cartridge edge-case
if (!request.container.location && request.container.container === "cartridges") if (!request.container.location && request.container.container === "cartridges")
{ {
const matchingItems = inventoryItems.to.filter((x) => x.parentId === request.container.id); const matchingItems = inventoryItems.to.filter(x => x.parentId === request.container.id);
request.container.location = matchingItems.length; // Wrong location for first cartridge request.container.location = matchingItems.length; // Wrong location for first cartridge
} }
// The item being merged has three possible sources: pmc, scav or mail, getOwnerInventoryItems() handles getting correct one // The item being merged has three possible sources: pmc, scav or mail, getOwnerInventoryItems() handles getting correct one
const itemToSplit = inventoryItems.from.find((x) => x._id === request.splitItem); const itemToSplit = inventoryItems.from.find(x => x._id === request.splitItem);
if (!itemToSplit) if (!itemToSplit)
{ {
const errorMessage = `Unable to split stack as source item: ${request.splitItem} cannot be found`; const errorMessage = `Unable to split stack as source item: ${request.splitItem} cannot be found`;
@ -259,7 +258,7 @@ export class InventoryController
const inventoryItems = this.inventoryHelper.getOwnerInventoryItems(body, sessionID); const inventoryItems = this.inventoryHelper.getOwnerInventoryItems(body, sessionID);
// Get source item (can be from player or trader or mail) // Get source item (can be from player or trader or mail)
const sourceItem = inventoryItems.from.find((x) => x._id === body.item); const sourceItem = inventoryItems.from.find(x => x._id === body.item);
if (!sourceItem) if (!sourceItem)
{ {
const errorMessage = `Unable to merge stacks as source item: ${body.with} cannot be found`; const errorMessage = `Unable to merge stacks as source item: ${body.with} cannot be found`;
@ -271,7 +270,7 @@ export class InventoryController
} }
// Get item being merged into // Get item being merged into
const destinationItem = inventoryItems.to.find((x) => x._id === body.with); const destinationItem = inventoryItems.to.find(x => x._id === body.with);
if (!destinationItem) if (!destinationItem)
{ {
const errorMessage = `Unable to merge stacks as destination item: ${body.with} cannot be found`; const errorMessage = `Unable to merge stacks as destination item: ${body.with} cannot be found`;
@ -282,7 +281,7 @@ export class InventoryController
return output; return output;
} }
if (!(destinationItem.upd?.StackObjectsCount)) if (!destinationItem.upd?.StackObjectsCount)
{ {
// No stackcount on destination, add one // No stackcount on destination, add one
destinationItem.upd = { StackObjectsCount: 1 }; destinationItem.upd = { StackObjectsCount: 1 };
@ -307,7 +306,7 @@ export class InventoryController
destinationItem.upd.StackObjectsCount += sourceItem.upd.StackObjectsCount; // Add source stackcount to destination destinationItem.upd.StackObjectsCount += sourceItem.upd.StackObjectsCount; // Add source stackcount to destination
output.profileChanges[sessionID].items.del.push({ _id: sourceItem._id }); // Inform client source item being deleted output.profileChanges[sessionID].items.del.push({ _id: sourceItem._id }); // Inform client source item being deleted
const indexOfItemToRemove = inventoryItems.from.findIndex((x) => x._id === sourceItem._id); const indexOfItemToRemove = inventoryItems.from.findIndex(x => x._id === sourceItem._id);
if (indexOfItemToRemove === -1) if (indexOfItemToRemove === -1)
{ {
const errorMessage = `Unable to find item: ${sourceItem._id} to remove from sender inventory`; const errorMessage = `Unable to find item: ${sourceItem._id} to remove from sender inventory`;
@ -340,8 +339,8 @@ export class InventoryController
): IItemEventRouterResponse ): IItemEventRouterResponse
{ {
const inventoryItems = this.inventoryHelper.getOwnerInventoryItems(body, sessionID); const inventoryItems = this.inventoryHelper.getOwnerInventoryItems(body, sessionID);
const sourceItem = inventoryItems.from.find((item) => item._id === body.item); const sourceItem = inventoryItems.from.find(item => item._id === body.item);
const destinationItem = inventoryItems.to.find((item) => item._id === body.with); const destinationItem = inventoryItems.to.find(item => item._id === body.with);
if (sourceItem === null) if (sourceItem === null)
{ {
@ -397,13 +396,13 @@ export class InventoryController
*/ */
public swapItem(pmcData: IPmcData, request: IInventorySwapRequestData, sessionID: string): IItemEventRouterResponse public swapItem(pmcData: IPmcData, request: IInventorySwapRequestData, sessionID: string): IItemEventRouterResponse
{ {
const itemOne = pmcData.Inventory.items.find((x) => x._id === request.item); const itemOne = pmcData.Inventory.items.find(x => x._id === request.item);
if (!itemOne) if (!itemOne)
{ {
this.logger.error(`Unable to find item: ${request.item} to swap positions with: ${request.item2}`); this.logger.error(`Unable to find item: ${request.item} to swap positions with: ${request.item2}`);
} }
const itemTwo = pmcData.Inventory.items.find((x) => x._id === request.item2); const itemTwo = pmcData.Inventory.items.find(x => x._id === request.item2);
if (!itemTwo) if (!itemTwo)
{ {
this.logger.error(`Unable to find item: ${request.item2} to swap positions with: ${request.item}`); this.logger.error(`Unable to find item: ${request.item2} to swap positions with: ${request.item}`);
@ -454,7 +453,7 @@ export class InventoryController
playerData = this.profileHelper.getScavProfile(sessionID); playerData = this.profileHelper.getScavProfile(sessionID);
} }
const itemToFold = playerData.Inventory.items.find((item) => item?._id === request.item); const itemToFold = playerData.Inventory.items.find(item => item?._id === request.item);
if (!itemToFold) if (!itemToFold)
{ {
// Item not found // Item not found
@ -488,7 +487,7 @@ export class InventoryController
playerData = this.profileHelper.getScavProfile(sessionID); playerData = this.profileHelper.getScavProfile(sessionID);
} }
const itemToToggle = playerData.Inventory.items.find((x) => x._id === body.item); const itemToToggle = playerData.Inventory.items.find(x => x._id === body.item);
if (itemToToggle) if (itemToToggle)
{ {
this.itemHelper.addUpdObjectToItem( this.itemHelper.addUpdObjectToItem(
@ -689,15 +688,15 @@ export class InventoryController
if (request.fromOwner.id === Traders.FENCE) if (request.fromOwner.id === Traders.FENCE)
{ {
// Get tpl from fence assorts // Get tpl from fence assorts
return this.fenceService.getRawFenceAssorts().items.find((x) => x._id === request.item)._tpl; return this.fenceService.getRawFenceAssorts().items.find(x => x._id === request.item)._tpl;
} }
if (request.fromOwner.type === "Trader") if (request.fromOwner.type === "Trader")
{ {
// Not fence // Not fence
// get tpl from trader assort // get tpl from trader assort
return this.databaseServer.getTables().traders[request.fromOwner.id].assort.items.find((item) => return this.databaseServer.getTables().traders[request.fromOwner.id].assort.items.find(item =>
item._id === request.item item._id === request.item,
)._tpl; )._tpl;
} }
@ -718,7 +717,7 @@ export class InventoryController
} }
// Try find examine item inside offer items array // Try find examine item inside offer items array
const matchingItem = offer.items.find((offerItem) => offerItem._id === request.item); const matchingItem = offer.items.find(offerItem => offerItem._id === request.item);
if (matchingItem) if (matchingItem)
{ {
return matchingItem._tpl; return matchingItem._tpl;
@ -754,7 +753,7 @@ export class InventoryController
{ {
for (const change of request.changedItems) for (const change of request.changedItems)
{ {
const inventoryItem = pmcData.Inventory.items.find((x) => x._id === change._id); const inventoryItem = pmcData.Inventory.items.find(x => x._id === change._id);
if (!inventoryItem) if (!inventoryItem)
{ {
this.logger.error( this.logger.error(
@ -793,7 +792,7 @@ export class InventoryController
): void ): void
{ {
// Get map from inventory // Get map from inventory
const mapItem = pmcData.Inventory.items.find((i) => i._id === request.item); const mapItem = pmcData.Inventory.items.find(i => i._id === request.item);
// add marker // add marker
mapItem.upd.Map = mapItem.upd.Map || { Markers: [] }; mapItem.upd.Map = mapItem.upd.Map || { Markers: [] };
@ -819,7 +818,7 @@ export class InventoryController
): void ): void
{ {
// Get map from inventory // Get map from inventory
const mapItem = pmcData.Inventory.items.find((i) => i._id === request.item); const mapItem = pmcData.Inventory.items.find(i => i._id === request.item);
// remove marker // remove marker
const markers = mapItem.upd.Map.Markers.filter((marker) => const markers = mapItem.upd.Map.Markers.filter((marker) =>
@ -847,10 +846,10 @@ export class InventoryController
): void ): void
{ {
// Get map from inventory // Get map from inventory
const mapItem = pmcData.Inventory.items.find((i) => i._id === request.item); const mapItem = pmcData.Inventory.items.find(i => i._id === request.item);
// edit marker // edit marker
const indexOfExistingNote = mapItem.upd.Map.Markers.findIndex((m) => m.X === request.X && m.Y === request.Y); const indexOfExistingNote = mapItem.upd.Map.Markers.findIndex(m => m.X === request.X && m.Y === request.Y);
request.mapMarker.Note = this.sanitiseMapMarkerText(request.mapMarker.Note); request.mapMarker.Note = this.sanitiseMapMarkerText(request.mapMarker.Note);
mapItem.upd.Map.Markers[indexOfExistingNote] = request.mapMarker; mapItem.upd.Map.Markers[indexOfExistingNote] = request.mapMarker;
@ -884,7 +883,7 @@ export class InventoryController
): void ): void
{ {
/** Container player opened in their inventory */ /** Container player opened in their inventory */
const openedItem = pmcData.Inventory.items.find((item) => item._id === body.item); const openedItem = pmcData.Inventory.items.find(item => item._id === body.item);
const containerDetailsDb = this.itemHelper.getItem(openedItem._tpl); const containerDetailsDb = this.itemHelper.getItem(openedItem._tpl);
const isSealedWeaponBox = containerDetailsDb[1]._name.includes("event_container_airdrop"); const isSealedWeaponBox = containerDetailsDb[1]._name.includes("event_container_airdrop");
@ -935,8 +934,8 @@ export class InventoryController
// Hard coded to `SYSTEM` for now // Hard coded to `SYSTEM` for now
// TODO: make this dynamic // TODO: make this dynamic
const dialog = fullProfile.dialogues["59e7125688a45068a6249071"]; const dialog = fullProfile.dialogues["59e7125688a45068a6249071"];
const mail = dialog.messages.find((x) => x._id === event.MessageId); const mail = dialog.messages.find(x => x._id === event.MessageId);
const mailEvent = mail.profileChangeEvents.find((x) => x._id === event.EventId); const mailEvent = mail.profileChangeEvents.find(x => x._id === event.EventId);
switch (mailEvent.Type) switch (mailEvent.Type)
{ {
@ -955,15 +954,15 @@ export class InventoryController
break; break;
case "SkillPoints": case "SkillPoints":
{ {
const profileSkill = pmcData.Skills.Common.find((x) => x.Id === mailEvent.entity); const profileSkill = pmcData.Skills.Common.find(x => x.Id === mailEvent.entity);
profileSkill.Progress = mailEvent.value; profileSkill.Progress = mailEvent.value;
this.logger.success(`Set profile skill: ${mailEvent.entity} to: ${mailEvent.value}`); this.logger.success(`Set profile skill: ${mailEvent.entity} to: ${mailEvent.value}`);
break; break;
} }
case "ExamineAllItems": case "ExamineAllItems":
{ {
const itemsToInspect = this.itemHelper.getItems().filter((x) => x._type !== "Node"); const itemsToInspect = this.itemHelper.getItems().filter(x => x._type !== "Node");
this.flagItemsAsInspectedAndRewardXp(itemsToInspect.map((x) => x._id), fullProfile); this.flagItemsAsInspectedAndRewardXp(itemsToInspect.map(x => x._id), fullProfile);
this.logger.success(`Flagged ${itemsToInspect.length} items as examined`); this.logger.success(`Flagged ${itemsToInspect.length} items as examined`);
break; break;
} }
@ -988,7 +987,7 @@ export class InventoryController
for (const itemId of request.items) for (const itemId of request.items)
{ {
// If id already exists in array, we're removing it // If id already exists in array, we're removing it
const indexOfItemAlreadyFavorited = pmcData.Inventory.favoriteItems.findIndex((x) => x === itemId); const indexOfItemAlreadyFavorited = pmcData.Inventory.favoriteItems.findIndex(x => x === itemId);
if (indexOfItemAlreadyFavorited > -1) if (indexOfItemAlreadyFavorited > -1)
{ {
pmcData.Inventory.favoriteItems.splice(indexOfItemAlreadyFavorited, 1); pmcData.Inventory.favoriteItems.splice(indexOfItemAlreadyFavorited, 1);

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper"; import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper";
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper"; import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
import { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader"; import { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ApplicationContext } from "@spt-aki/context/ApplicationContext"; import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
import { ContextVariableType } from "@spt-aki/context/ContextVariableType"; import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
import { LocationGenerator } from "@spt-aki/generators/LocationGenerator"; import { LocationGenerator } from "@spt-aki/generators/LocationGenerator";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ApplicationContext } from "@spt-aki/context/ApplicationContext"; import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
import { ContextVariableType } from "@spt-aki/context/ContextVariableType"; import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
import { LootGenerator } from "@spt-aki/generators/LootGenerator"; import { LootGenerator } from "@spt-aki/generators/LootGenerator";
@ -191,7 +190,7 @@ export class MatchController
return false; return false;
} }
return (this.inRaidConfig.coopExtracts.includes(extractName.trim())); return this.inRaidConfig.coopExtracts.includes(extractName.trim());
} }
protected sendCoopTakenFenceMessage(sessionId: string): void protected sendCoopTakenFenceMessage(sessionId: string): void

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { Note } from "@spt-aki/models/eft/common/tables/IBotBase"; import { Note } from "@spt-aki/models/eft/common/tables/IBotBase";
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse"; import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper"; import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper";
import { NotifierHelper } from "@spt-aki/helpers/NotifierHelper"; import { NotifierHelper } from "@spt-aki/helpers/NotifierHelper";
import { INotifierChannel } from "@spt-aki/models/eft/notifier/INotifier"; import { INotifierChannel } from "@spt-aki/models/eft/notifier/INotifier";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { PresetHelper } from "@spt-aki/helpers/PresetHelper"; import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
import { IPreset } from "@spt-aki/models/eft/common/IGlobals"; import { IPreset } from "@spt-aki/models/eft/common/IGlobals";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { PlayerScavGenerator } from "@spt-aki/generators/PlayerScavGenerator"; import { PlayerScavGenerator } from "@spt-aki/generators/PlayerScavGenerator";
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper"; import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
@ -81,7 +80,7 @@ export class ProfileController
const pmc = profile.characters.pmc; const pmc = profile.characters.pmc;
// make sure character completed creation // make sure character completed creation
if (!(pmc?.Info?.Level)) if (!pmc?.Info?.Level)
{ {
return { return {
username: profile.info.username, username: profile.info.username,
@ -104,7 +103,7 @@ export class ProfileController
side: pmc.Info.Side, side: pmc.Info.Side,
currlvl: pmc.Info.Level, currlvl: pmc.Info.Level,
currexp: pmc.Info.Experience ?? 0, currexp: pmc.Info.Experience ?? 0,
prevexp: (currlvl === 0) ? 0 : this.profileHelper.getExperience(currlvl), prevexp: currlvl === 0 ? 0 : this.profileHelper.getExperience(currlvl),
nextlvl: nextlvl, nextlvl: nextlvl,
maxlvl: maxlvl, maxlvl: maxlvl,
akiData: profile.aki, akiData: profile.aki,
@ -130,8 +129,10 @@ export class ProfileController
public createProfile(info: IProfileCreateRequestData, sessionID: string): string public createProfile(info: IProfileCreateRequestData, sessionID: string): string
{ {
const account = this.saveServer.getProfile(sessionID).info; const account = this.saveServer.getProfile(sessionID).info;
const profile: ITemplateSide = const profile: ITemplateSide = this.databaseServer
this.databaseServer.getTables().templates.profiles[account.edition][info.side.toLowerCase()]; .getTables()
.templates
.profiles[account.edition][info.side.toLowerCase()];
const pmcData = profile.character; const pmcData = profile.character;
// Delete existing profile // Delete existing profile
@ -151,7 +152,7 @@ export class ProfileController
pmcData.Customization.Head = info.headId; pmcData.Customization.Head = info.headId;
pmcData.Health.UpdateTime = this.timeUtil.getTimestamp(); pmcData.Health.UpdateTime = this.timeUtil.getTimestamp();
pmcData.Quests = []; pmcData.Quests = [];
pmcData.Hideout.Seed = this.timeUtil.getTimestamp() + (8 * 60 * 60 * 24 * 365); // 8 years in future why? who knows, we saw it in live pmcData.Hideout.Seed = this.timeUtil.getTimestamp() + 8 * 60 * 60 * 24 * 365; // 8 years in future why? who knows, we saw it in live
pmcData.RepeatableQuests = []; pmcData.RepeatableQuests = [];
pmcData.CarExtractCounts = {}; pmcData.CarExtractCounts = {};
pmcData.CoopExtractCounts = {}; pmcData.CoopExtractCounts = {};
@ -458,7 +459,7 @@ export class ProfileController
skills: playerPmc.Skills, skills: playerPmc.Skills,
equipment: { equipment: {
// Default inventory tpl // Default inventory tpl
Id: playerPmc.Inventory.items.find((x) => x._tpl === "55d7217a4bdc2d86028b456d")._id, Id: playerPmc.Inventory.items.find(x => x._tpl === "55d7217a4bdc2d86028b456d")._id,
Items: playerPmc.Inventory.items, Items: playerPmc.Inventory.items,
}, },
achievements: playerPmc.Achievements, achievements: playerPmc.Achievements,

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper"; import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper"; import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
@ -79,7 +78,7 @@ export class QuestController
for (const quest of allQuests) for (const quest of allQuests)
{ {
// Player already accepted the quest, show it regardless of status // Player already accepted the quest, show it regardless of status
const questInProfile = profile.Quests.find((x) => x.qid === quest._id); const questInProfile = profile.Quests.find(x => x.qid === quest._id);
if (questInProfile) if (questInProfile)
{ {
quest.sptStatus = questInProfile.status; quest.sptStatus = questInProfile.status;
@ -137,8 +136,8 @@ export class QuestController
for (const conditionToFulfil of questRequirements) for (const conditionToFulfil of questRequirements)
{ {
// If the previous quest isn't in the user profile, it hasn't been completed or started // If the previous quest isn't in the user profile, it hasn't been completed or started
const prerequisiteQuest = profile.Quests.find((profileQuest) => const prerequisiteQuest = profile.Quests.find(profileQuest =>
conditionToFulfil.target.includes(profileQuest.qid) conditionToFulfil.target.includes(profileQuest.qid),
); );
if (!prerequisiteQuest) if (!prerequisiteQuest)
{ {
@ -148,7 +147,7 @@ export class QuestController
// Prereq does not have its status requirement fulfilled // Prereq does not have its status requirement fulfilled
// Some bsg status ids are strings, MUST convert to number before doing includes check // Some bsg status ids are strings, MUST convert to number before doing includes check
if (!conditionToFulfil.status.map((status) => Number(status)).includes(prerequisiteQuest.status)) if (!conditionToFulfil.status.map(status => Number(status)).includes(prerequisiteQuest.status))
{ {
haveCompletedPreviousQuest = false; haveCompletedPreviousQuest = false;
break; break;
@ -292,7 +291,7 @@ export class QuestController
// Does quest exist in profile // Does quest exist in profile
// Restarting a failed quest can mean quest exists in profile // Restarting a failed quest can mean quest exists in profile
const existingQuestStatus = pmcData.Quests.find((x) => x.qid === acceptedQuest.qid); const existingQuestStatus = pmcData.Quests.find(x => x.qid === acceptedQuest.qid);
if (existingQuestStatus) if (existingQuestStatus)
{ {
// Update existing // Update existing
@ -399,15 +398,15 @@ export class QuestController
fullProfile.characters.scav.Quests.push(newRepeatableQuest); fullProfile.characters.scav.Quests.push(newRepeatableQuest);
} }
const repeatableSettings = pmcData.RepeatableQuests.find((x) => const repeatableSettings = pmcData.RepeatableQuests.find(x =>
x.name === repeatableQuestProfile.sptRepatableGroupName x.name === repeatableQuestProfile.sptRepatableGroupName,
); );
const change = {}; const change = {};
change[repeatableQuestProfile._id] = repeatableSettings.changeRequirement[repeatableQuestProfile._id]; change[repeatableQuestProfile._id] = repeatableSettings.changeRequirement[repeatableQuestProfile._id];
const responseData: IPmcDataRepeatableQuest = { const responseData: IPmcDataRepeatableQuest = {
id: repeatableSettings.id ?? this.questConfig.repeatableQuests.find((x) => id: repeatableSettings.id ?? this.questConfig.repeatableQuests.find(x =>
x.name === repeatableQuestProfile.sptRepatableGroupName x.name === repeatableQuestProfile.sptRepatableGroupName,
).id, ).id,
name: repeatableSettings.name, name: repeatableSettings.name,
endTime: repeatableSettings.endTime, endTime: repeatableSettings.endTime,
@ -435,7 +434,7 @@ export class QuestController
{ {
for (const repeatableQuest of pmcData.RepeatableQuests) for (const repeatableQuest of pmcData.RepeatableQuests)
{ {
const matchingQuest = repeatableQuest.activeQuests.find((x) => x._id === acceptedQuest.qid); const matchingQuest = repeatableQuest.activeQuests.find(x => x._id === acceptedQuest.qid);
if (matchingQuest) if (matchingQuest)
{ {
this.logger.debug(`Accepted repeatable quest ${acceptedQuest.qid} from ${repeatableQuest.name}`); this.logger.debug(`Accepted repeatable quest ${acceptedQuest.qid} from ${repeatableQuest.name}`);
@ -504,8 +503,8 @@ export class QuestController
// Check if it's a repeatable quest. If so, remove from Quests // Check if it's a repeatable quest. If so, remove from Quests
for (const currentRepeatable of pmcData.RepeatableQuests) for (const currentRepeatable of pmcData.RepeatableQuests)
{ {
const repeatableQuest = currentRepeatable.activeQuests.find((activeRepeatable) => const repeatableQuest = currentRepeatable.activeQuests.find(activeRepeatable =>
activeRepeatable._id === completedQuestId activeRepeatable._id === completedQuestId,
); );
if (repeatableQuest) if (repeatableQuest)
{ {
@ -548,15 +547,15 @@ export class QuestController
// Quest already failed in profile, skip // Quest already failed in profile, skip
if ( if (
pmcProfile.Quests.some((profileQuest) => pmcProfile.Quests.some(profileQuest =>
profileQuest.qid === quest._id && profileQuest.status === QuestStatus.Fail profileQuest.qid === quest._id && profileQuest.status === QuestStatus.Fail,
) )
) )
{ {
return false; return false;
} }
return quest.conditions.Fail.some((condition) => condition.target?.includes(completedQuestId)); return quest.conditions.Fail.some(condition => condition.target?.includes(completedQuestId));
}); });
} }
@ -568,7 +567,7 @@ export class QuestController
protected removeQuestFromScavProfile(sessionId: string, questIdToRemove: string): void protected removeQuestFromScavProfile(sessionId: string, questIdToRemove: string): void
{ {
const fullProfile = this.profileHelper.getFullProfile(sessionId); const fullProfile = this.profileHelper.getFullProfile(sessionId);
const repeatableInScavProfile = fullProfile.characters.scav.Quests?.find((x) => x.qid === questIdToRemove); const repeatableInScavProfile = fullProfile.characters.scav.Quests?.find(x => x.qid === questIdToRemove);
if (!repeatableInScavProfile) if (!repeatableInScavProfile)
{ {
this.logger.warning( this.logger.warning(
@ -600,7 +599,7 @@ export class QuestController
for (const quest of postQuestStatuses) for (const quest of postQuestStatuses)
{ {
// Add quest if status differs or quest not found // Add quest if status differs or quest not found
const preQuest = preQuestStatusus.find((x) => x.qid === quest.qid); const preQuest = preQuestStatusus.find(x => x.qid === quest.qid);
if (!preQuest || preQuest.status !== quest.status) if (!preQuest || preQuest.status !== quest.status)
{ {
result.push(quest); result.push(quest);
@ -653,8 +652,8 @@ export class QuestController
for (const quest of quests) for (const quest of quests)
{ {
// If quest has prereq of completed quest + availableAfter value > 0 (quest has wait time) // If quest has prereq of completed quest + availableAfter value > 0 (quest has wait time)
const nextQuestWaitCondition = quest.conditions.AvailableForStart.find((x) => const nextQuestWaitCondition = quest.conditions.AvailableForStart.find(x =>
x.target?.includes(completedQuestId) && x.availableAfter > 0 x.target?.includes(completedQuestId) && x.availableAfter > 0,
); );
if (nextQuestWaitCondition) if (nextQuestWaitCondition)
{ {
@ -662,7 +661,7 @@ export class QuestController
const availableAfterTimestamp = this.timeUtil.getTimestamp() + nextQuestWaitCondition.availableAfter; const availableAfterTimestamp = this.timeUtil.getTimestamp() + nextQuestWaitCondition.availableAfter;
// Update quest in profile with status of AvailableAfter // Update quest in profile with status of AvailableAfter
const existingQuestInProfile = pmcData.Quests.find((x) => x.qid === quest._id); const existingQuestInProfile = pmcData.Quests.find(x => x.qid === quest._id);
if (existingQuestInProfile) if (existingQuestInProfile)
{ {
existingQuestInProfile.availableAfter = availableAfterTimestamp; existingQuestInProfile.availableAfter = availableAfterTimestamp;
@ -679,7 +678,7 @@ export class QuestController
status: QuestStatus.AvailableAfter, status: QuestStatus.AvailableAfter,
statusTimers: { statusTimers: {
// eslint-disable-next-line @typescript-eslint/naming-convention // eslint-disable-next-line @typescript-eslint/naming-convention
"9": this.timeUtil.getTimestamp(), 9: this.timeUtil.getTimestamp(),
}, },
availableAfter: availableAfterTimestamp, availableAfter: availableAfterTimestamp,
}); });
@ -705,12 +704,12 @@ export class QuestController
for (const questToFail of questsToFail) for (const questToFail of questsToFail)
{ {
// Skip failing a quest that has a fail status of something other than success // Skip failing a quest that has a fail status of something other than success
if (questToFail.conditions.Fail?.some((x) => x.status?.some((status) => status !== QuestStatus.Success))) if (questToFail.conditions.Fail?.some(x => x.status?.some(status => status !== QuestStatus.Success)))
{ {
continue; continue;
} }
const isActiveQuestInPlayerProfile = pmcData.Quests.find((quest) => quest.qid === questToFail._id); const isActiveQuestInPlayerProfile = pmcData.Quests.find(quest => quest.qid === questToFail._id);
if (isActiveQuestInPlayerProfile) if (isActiveQuestInPlayerProfile)
{ {
if (isActiveQuestInPlayerProfile.status !== QuestStatus.Fail) if (isActiveQuestInPlayerProfile.status !== QuestStatus.Fail)
@ -772,7 +771,7 @@ export class QuestController
isItemHandoverQuest = condition.conditionType === handoverQuestTypes[0]; isItemHandoverQuest = condition.conditionType === handoverQuestTypes[0];
handoverRequirements = condition; handoverRequirements = condition;
const profileCounter = (handoverQuestRequest.conditionId in pmcData.TaskConditionCounters) const profileCounter = handoverQuestRequest.conditionId in pmcData.TaskConditionCounters
? pmcData.TaskConditionCounters[handoverQuestRequest.conditionId].value ? pmcData.TaskConditionCounters[handoverQuestRequest.conditionId].value
: 0; : 0;
handedInCount -= profileCounter; handedInCount -= profileCounter;
@ -806,7 +805,7 @@ export class QuestController
let totalItemCountToRemove = 0; let totalItemCountToRemove = 0;
for (const itemHandover of handoverQuestRequest.items) for (const itemHandover of handoverQuestRequest.items)
{ {
const matchingItemInProfile = pmcData.Inventory.items.find((item) => item._id === itemHandover.id); const matchingItemInProfile = pmcData.Inventory.items.find(item => item._id === itemHandover.id);
if (!(matchingItemInProfile && handoverRequirements.target.includes(matchingItemInProfile._tpl))) if (!(matchingItemInProfile && handoverRequirements.target.includes(matchingItemInProfile._tpl)))
{ {
// Item handed in by player doesnt match what was requested // Item handed in by player doesnt match what was requested

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { RagfairOfferGenerator } from "@spt-aki/generators/RagfairOfferGenerator"; import { RagfairOfferGenerator } from "@spt-aki/generators/RagfairOfferGenerator";
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper"; import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper"; import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
@ -160,7 +159,7 @@ export class RagfairController
public getOfferById(sessionId: string, request: IGetRagfairOfferByIdRequest): IRagfairOffer public getOfferById(sessionId: string, request: IGetRagfairOfferByIdRequest): IRagfairOffer
{ {
const offers = this.ragfairOfferService.getOffers(); const offers = this.ragfairOfferService.getOffers();
const offerToReturn = offers.find((x) => x.intId === request.id); const offerToReturn = offers.find(x => x.intId === request.id);
return offerToReturn; return offerToReturn;
} }
@ -208,14 +207,18 @@ export class RagfairController
): Record<string, number> ): Record<string, number>
{ {
// Linked/required search categories // Linked/required search categories
const playerHasFleaUnlocked = const playerHasFleaUnlocked = pmcProfile.Info.Level >= this.databaseServer
pmcProfile.Info.Level >= this.databaseServer.getTables().globals.config.RagFair.minUserLevel; .getTables()
.globals
.config
.RagFair
.minUserLevel;
let offerPool = []; let offerPool = [];
if (this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest)) if (this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest))
{ {
offerPool = offers; offerPool = offers;
} }
else if ((!(this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest)))) else if (!(this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest)))
{ {
// Get all categories // Get all categories
offerPool = this.ragfairOfferService.getOffers(); offerPool = this.ragfairOfferService.getOffers();
@ -260,7 +263,7 @@ export class RagfairController
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items; const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items;
const assortId = offer.items[0]._id; const assortId = offer.items[0]._id;
const assortData = traderAssorts.find((x) => x._id === assortId); const assortData = traderAssorts.find(x => x._id === assortId);
// Use value stored in profile, otherwise use value directly from in-memory trader assort data // Use value stored in profile, otherwise use value directly from in-memory trader assort data
offer.buyRestrictionCurrent = fullProfile.traderPurchases[offer.user.id][assortId] offer.buyRestrictionCurrent = fullProfile.traderPurchases[offer.user.id][assortId]
@ -279,7 +282,7 @@ export class RagfairController
const firstItem = offer.items[0]; const firstItem = offer.items[0];
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items; const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items;
const assortPurchased = traderAssorts.find((x) => x._id === offer.items[0]._id); const assortPurchased = traderAssorts.find(x => x._id === offer.items[0]._id);
if (!assortPurchased) if (!assortPurchased)
{ {
this.logger.warning( this.logger.warning(
@ -357,7 +360,7 @@ export class RagfairController
const avg = offers.reduce((sum, offer) => const avg = offers.reduce((sum, offer) =>
{ {
// Exclude barter items, they tend to have outrageous equivalent prices // Exclude barter items, they tend to have outrageous equivalent prices
if (offer.requirements.some((req) => !this.paymentHelper.isMoneyTpl(req._tpl))) if (offer.requirements.some(req => !this.paymentHelper.isMoneyTpl(req._tpl)))
{ {
return sum; return sum;
} }
@ -456,15 +459,15 @@ export class RagfairController
// Multiply single item price by stack count and quality // Multiply single item price by stack count and quality
averageOfferPrice *= rootItem.upd.StackObjectsCount * qualityMultiplier; averageOfferPrice *= rootItem.upd.StackObjectsCount * qualityMultiplier;
const itemStackCount = (offerRequest.sellInOnePiece) ? 1 : rootItem.upd.StackObjectsCount; const itemStackCount = offerRequest.sellInOnePiece ? 1 : rootItem.upd.StackObjectsCount;
// Get averaged price of a single item being listed // Get averaged price of a single item being listed
const averageSingleItemPrice = (offerRequest.sellInOnePiece) const averageSingleItemPrice = offerRequest.sellInOnePiece
? averageOfferPrice / rootItem.upd.StackObjectsCount // Packs are a single offer made of many items ? averageOfferPrice / rootItem.upd.StackObjectsCount // Packs are a single offer made of many items
: averageOfferPrice / itemStackCount; : averageOfferPrice / itemStackCount;
// Get averaged price of listing // Get averaged price of listing
const averagePlayerListedPriceInRub = (offerRequest.sellInOnePiece) const averagePlayerListedPriceInRub = offerRequest.sellInOnePiece
? playerListedPriceInRub / rootItem.upd.StackObjectsCount ? playerListedPriceInRub / rootItem.upd.StackObjectsCount
: playerListedPriceInRub; : playerListedPriceInRub;
@ -540,7 +543,7 @@ export class RagfairController
offerRequest.sellInOnePiece, offerRequest.sellInOnePiece,
); );
this.logger.debug(`Offer tax to charge: ${tax}, pulled from client: ${(!!storedClientTaxValue)}`); this.logger.debug(`Offer tax to charge: ${tax}, pulled from client: ${!!storedClientTaxValue}`);
// cleanup of cache now we've used the tax value from it // cleanup of cache now we've used the tax value from it
this.ragfairTaxService.clearStoredOfferTaxById(offerRequest.items[0]); this.ragfairTaxService.clearStoredOfferTaxById(offerRequest.items[0]);
@ -602,8 +605,8 @@ export class RagfairController
} }
else else
{ {
requirementsPriceInRub += this.ragfairPriceService.getDynamicPriceForItem(requestedItemTpl) requirementsPriceInRub += this.ragfairPriceService
* item.count; .getDynamicPriceForItem(requestedItemTpl) * item.count;
} }
} }
@ -619,7 +622,7 @@ export class RagfairController
protected getItemsToListOnFleaFromInventory( protected getItemsToListOnFleaFromInventory(
pmcData: IPmcData, pmcData: IPmcData,
itemIdsFromFleaOfferRequest: string[], itemIdsFromFleaOfferRequest: string[],
): { items: Item[] | null; errorMessage: string | null; } ): { items: Item[] | null, errorMessage: string | null }
{ {
const itemsToReturn = []; const itemsToReturn = [];
let errorMessage: string | null = null; let errorMessage: string | null = null;
@ -627,7 +630,7 @@ export class RagfairController
// Count how many items are being sold and multiply the requested amount accordingly // Count how many items are being sold and multiply the requested amount accordingly
for (const itemId of itemIdsFromFleaOfferRequest) for (const itemId of itemIdsFromFleaOfferRequest)
{ {
let item = pmcData.Inventory.items.find((i) => i._id === itemId); let item = pmcData.Inventory.items.find(i => i._id === itemId);
if (!item) if (!item)
{ {
errorMessage = this.localisationService.getText("ragfair-unable_to_find_item_in_inventory", { errorMessage = this.localisationService.getText("ragfair-unable_to_find_item_in_inventory", {
@ -663,7 +666,7 @@ export class RagfairController
const loyalLevel = 1; const loyalLevel = 1;
const formattedItems: Item[] = items.map((item) => const formattedItems: Item[] = items.map((item) =>
{ {
const isChild = items.find((it) => it._id === item.parentId); const isChild = items.find(it => it._id === item.parentId);
return { return {
_id: item._id, _id: item._id,
@ -724,7 +727,7 @@ export class RagfairController
pmcData.RagfairInfo.offers = []; pmcData.RagfairInfo.offers = [];
} }
const playerOfferIndex = playerProfileOffers.findIndex((offer) => offer._id === removeRequest.offerId); const playerOfferIndex = playerProfileOffers.findIndex(offer => offer._id === removeRequest.offerId);
if (playerOfferIndex === -1) if (playerOfferIndex === -1)
{ {
this.logger.error( this.logger.error(
@ -761,7 +764,7 @@ export class RagfairController
const pmcData = this.saveServer.getProfile(sessionId).characters.pmc; const pmcData = this.saveServer.getProfile(sessionId).characters.pmc;
const playerOffers = pmcData.RagfairInfo.offers; const playerOffers = pmcData.RagfairInfo.offers;
const playerOfferIndex = playerOffers.findIndex((offer) => offer._id === extendRequest.offerId); const playerOfferIndex = playerOffers.findIndex(offer => offer._id === extendRequest.offerId);
const secondsToAdd = extendRequest.renewalTime * TimeUtil.ONE_HOUR_AS_SECONDS; const secondsToAdd = extendRequest.renewalTime * TimeUtil.ONE_HOUR_AS_SECONDS;
if (playerOfferIndex === -1) if (playerOfferIndex === -1)

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper"; import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
import { QuestHelper } from "@spt-aki/helpers/QuestHelper"; import { QuestHelper } from "@spt-aki/helpers/QuestHelper";
import { RepairHelper } from "@spt-aki/helpers/RepairHelper"; import { RepairHelper } from "@spt-aki/helpers/RepairHelper";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { RepeatableQuestGenerator } from "@spt-aki/generators/RepeatableQuestGenerator"; import { RepeatableQuestGenerator } from "@spt-aki/generators/RepeatableQuestGenerator";
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper"; import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
import { QuestHelper } from "@spt-aki/helpers/QuestHelper"; import { QuestHelper } from "@spt-aki/helpers/QuestHelper";
@ -83,15 +82,15 @@ export class RepeatableQuestController
* @param {string} _info Request from client * @param {string} _info Request from client
* @param {string} sessionID Player's session id * @param {string} sessionID Player's session id
* *
* @returns {array} Array of "repeatableQuestObjects" as descibed above * @returns {array} Array of "repeatableQuestObjects" as described above
*/ */
public getClientRepeatableQuests(_info: IEmptyRequestData, sessionID: string): IPmcDataRepeatableQuest[] public getClientRepeatableQuests(_info: IEmptyRequestData, sessionID: string): IPmcDataRepeatableQuest[]
{ {
const returnData: Array<IPmcDataRepeatableQuest> = []; const returnData: Array<IPmcDataRepeatableQuest> = [];
const pmcData = this.profileHelper.getPmcProfile(sessionID); const pmcData = this.profileHelper.getPmcProfile(sessionID);
const time = this.timeUtil.getTimestamp(); const time = this.timeUtil.getTimestamp();
const scavQuestUnlocked = const scavQuestUnlocked
pmcData?.Hideout?.Areas?.find((hideoutArea) => hideoutArea.type === HideoutAreas.INTEL_CENTER)?.level >= 1; = pmcData?.Hideout?.Areas?.find(hideoutArea => hideoutArea.type === HideoutAreas.INTEL_CENTER)?.level >= 1;
// Daily / weekly / Daily_Savage // Daily / weekly / Daily_Savage
for (const repeatableConfig of this.questConfig.repeatableQuests) for (const repeatableConfig of this.questConfig.repeatableQuests)
@ -119,7 +118,7 @@ export class RepeatableQuestController
for (const activeQuest of currentRepeatableQuestType.activeQuests) for (const activeQuest of currentRepeatableQuestType.activeQuests)
{ {
// Keep finished quests in list so player can hand in // Keep finished quests in list so player can hand in
const quest = pmcData.Quests.find((quest) => quest.qid === activeQuest._id); const quest = pmcData.Quests.find(quest => quest.qid === activeQuest._id);
if (quest) if (quest)
{ {
if (quest.status === QuestStatus.AvailableForFinish) if (quest.status === QuestStatus.AvailableForFinish)
@ -135,7 +134,7 @@ export class RepeatableQuestController
this.profileFixerService.removeDanglingConditionCounters(pmcData); this.profileFixerService.removeDanglingConditionCounters(pmcData);
// Remove expired quest from pmc.quest array // Remove expired quest from pmc.quest array
pmcData.Quests = pmcData.Quests.filter((quest) => quest.qid !== activeQuest._id); pmcData.Quests = pmcData.Quests.filter(quest => quest.qid !== activeQuest._id);
currentRepeatableQuestType.inactiveQuests.push(activeQuest); currentRepeatableQuestType.inactiveQuests.push(activeQuest);
} }
currentRepeatableQuestType.activeQuests = questsToKeep; currentRepeatableQuestType.activeQuests = questsToKeep;
@ -217,9 +216,14 @@ export class RepeatableQuestController
) )
{ {
// Elite charisma skill gives extra daily quest(s) // Elite charisma skill gives extra daily quest(s)
return repeatableConfig.numQuests return repeatableConfig.numQuests + this.databaseServer.getTables()
+ this.databaseServer.getTables().globals.config.SkillsSettings.Charisma.BonusSettings .globals
.EliteBonusSettings.RepeatableQuestExtraCount; .config
.SkillsSettings
.Charisma
.BonusSettings
.EliteBonusSettings
.RepeatableQuestExtraCount;
} }
return repeatableConfig.numQuests; return repeatableConfig.numQuests;
@ -237,7 +241,7 @@ export class RepeatableQuestController
): IPmcDataRepeatableQuest ): IPmcDataRepeatableQuest
{ {
// Get from profile, add if missing // Get from profile, add if missing
let repeatableQuestDetails = pmcData.RepeatableQuests.find((x) => x.name === repeatableConfig.name); let repeatableQuestDetails = pmcData.RepeatableQuests.find(x => x.name === repeatableConfig.name);
if (!repeatableQuestDetails) if (!repeatableQuestDetails)
{ {
repeatableQuestDetails = { repeatableQuestDetails = {
@ -327,8 +331,8 @@ export class RepeatableQuestController
const possibleLocations = Object.keys(locations); const possibleLocations = Object.keys(locations);
// Set possible locations for elimination task, if target is savage, exclude labs from locations // Set possible locations for elimination task, if target is savage, exclude labs from locations
questPool.pool.Elimination.targets[probabilityObject.key] = (probabilityObject.key === "Savage") questPool.pool.Elimination.targets[probabilityObject.key] = probabilityObject.key === "Savage"
? { locations: possibleLocations.filter((x) => x !== "laboratory") } ? { locations: possibleLocations.filter(x => x !== "laboratory") }
: { locations: possibleLocations }; : { locations: possibleLocations };
} }
} }
@ -396,7 +400,7 @@ export class RepeatableQuestController
return true; return true;
} }
return (pmcLevel <= locationBase.RequiredPlayerLevelMax && pmcLevel >= locationBase.RequiredPlayerLevelMin); return pmcLevel <= locationBase.RequiredPlayerLevelMax && pmcLevel >= locationBase.RequiredPlayerLevelMin;
} }
public debugLogRepeatableQuestIds(pmcData: IPmcData): void public debugLogRepeatableQuestIds(pmcData: IPmcData): void
@ -439,7 +443,7 @@ export class RepeatableQuestController
for (const currentRepeatablePool of pmcData.RepeatableQuests) for (const currentRepeatablePool of pmcData.RepeatableQuests)
{ {
// Check for existing quest in (daily/weekly/scav arrays) // Check for existing quest in (daily/weekly/scav arrays)
const questToReplace = currentRepeatablePool.activeQuests.find((x) => x._id === changeRequest.qid); const questToReplace = currentRepeatablePool.activeQuests.find(x => x._id === changeRequest.qid);
if (!questToReplace) if (!questToReplace)
{ {
continue; continue;
@ -449,8 +453,8 @@ export class RepeatableQuestController
replacedQuestTraderId = questToReplace.traderId; replacedQuestTraderId = questToReplace.traderId;
// Update active quests to exclude the quest we're replacing // Update active quests to exclude the quest we're replacing
currentRepeatablePool.activeQuests = currentRepeatablePool.activeQuests.filter((x) => currentRepeatablePool.activeQuests = currentRepeatablePool.activeQuests.filter(x =>
x._id !== changeRequest.qid x._id !== changeRequest.qid,
); );
// Get cost to replace existing quest // Get cost to replace existing quest
@ -458,8 +462,8 @@ export class RepeatableQuestController
delete currentRepeatablePool.changeRequirement[changeRequest.qid]; delete currentRepeatablePool.changeRequirement[changeRequest.qid];
// TODO: somehow we need to reduce the questPool by the currently active quests (for all repeatables) // TODO: somehow we need to reduce the questPool by the currently active quests (for all repeatables)
const repeatableConfig = this.questConfig.repeatableQuests.find((x) => const repeatableConfig = this.questConfig.repeatableQuests.find(x =>
x.name === currentRepeatablePool.name x.name === currentRepeatablePool.name,
); );
const questTypePool = this.generateQuestPool(repeatableConfig, pmcData.Info.Level); const questTypePool = this.generateQuestPool(repeatableConfig, pmcData.Info.Level);
const newRepeatableQuest = this.attemptToGenerateRepeatableQuest(pmcData, questTypePool, repeatableConfig); const newRepeatableQuest = this.attemptToGenerateRepeatableQuest(pmcData, questTypePool, repeatableConfig);

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper"; import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
import { TradeHelper } from "@spt-aki/helpers/TradeHelper"; import { TradeHelper } from "@spt-aki/helpers/TradeHelper";
@ -294,7 +293,7 @@ export class TradeController
this.traderHelper.getTraderById(trader), this.traderHelper.getTraderById(trader),
MessageType.MESSAGE_WITH_ITEMS, MessageType.MESSAGE_WITH_ITEMS,
this.randomUtil.getArrayValue(this.databaseServer.getTables().traders[trader].dialogue.soldItems), this.randomUtil.getArrayValue(this.databaseServer.getTables().traders[trader].dialogue.soldItems),
curencyReward.flatMap((x) => x), curencyReward.flatMap(x => x),
this.timeUtil.getHoursAsSeconds(72), this.timeUtil.getHoursAsSeconds(72),
); );
} }
@ -320,12 +319,12 @@ export class TradeController
for (const itemToSell of itemWithChildren) for (const itemToSell of itemWithChildren)
{ {
const itemDetails = this.itemHelper.getItem(itemToSell._tpl); const itemDetails = this.itemHelper.getItem(itemToSell._tpl);
if ( if (!(itemDetails[0] && this.itemHelper.isOfBaseclasses(
!(itemDetails[0] itemDetails[1]._id,
&& this.itemHelper.isOfBaseclasses(itemDetails[1]._id, traderDetails.items_buy.category)) traderDetails.items_buy.category,
) )))
{ {
// Skip if tpl isnt item OR item doesn't fulfill match traders buy categories // Skip if tpl isn't item OR item doesn't fulfil match traders buy categories
continue; continue;
} }

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { FenceBaseAssortGenerator } from "@spt-aki/generators/FenceBaseAssortGenerator"; import { FenceBaseAssortGenerator } from "@spt-aki/generators/FenceBaseAssortGenerator";
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper"; import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
import { TraderAssortHelper } from "@spt-aki/helpers/TraderAssortHelper"; import { TraderAssortHelper } from "@spt-aki/helpers/TraderAssortHelper";
@ -30,8 +29,7 @@ export class TraderController
@inject("ProfileHelper") protected profileHelper: ProfileHelper, @inject("ProfileHelper") protected profileHelper: ProfileHelper,
@inject("TraderHelper") protected traderHelper: TraderHelper, @inject("TraderHelper") protected traderHelper: TraderHelper,
@inject("TraderAssortService") protected traderAssortService: TraderAssortService, @inject("TraderAssortService") protected traderAssortService: TraderAssortService,
@inject("TraderPurchasePersisterService") protected traderPurchasePersisterService: @inject("TraderPurchasePersisterService") protected traderPurchasePersisterService: TraderPurchasePersisterService,
TraderPurchasePersisterService,
@inject("FenceService") protected fenceService: FenceService, @inject("FenceService") protected fenceService: FenceService,
@inject("FenceBaseAssortGenerator") protected fenceBaseAssortGenerator: FenceBaseAssortGenerator, @inject("FenceBaseAssortGenerator") protected fenceBaseAssortGenerator: FenceBaseAssortGenerator,
@inject("JsonUtil") protected jsonUtil: JsonUtil, @inject("JsonUtil") protected jsonUtil: JsonUtil,

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { WeatherGenerator } from "@spt-aki/generators/WeatherGenerator"; import { WeatherGenerator } from "@spt-aki/generators/WeatherGenerator";
import { IWeatherData } from "@spt-aki/models/eft/weather/IWeatherData"; import { IWeatherData } from "@spt-aki/models/eft/weather/IWeatherData";
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse"; import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
import { IWishlistActionData } from "@spt-aki/models/eft/wishlist/IWishlistActionData"; import { IWishlistActionData } from "@spt-aki/models/eft/wishlist/IWishlistActionData";

View File

@ -1,5 +1,4 @@
import { DependencyContainer, Lifecycle } from "tsyringe"; import { DependencyContainer, Lifecycle } from "tsyringe";
import { AchievementCallbacks } from "@spt-aki/callbacks/AchievementCallbacks"; import { AchievementCallbacks } from "@spt-aki/callbacks/AchievementCallbacks";
import { BotCallbacks } from "@spt-aki/callbacks/BotCallbacks"; import { BotCallbacks } from "@spt-aki/callbacks/BotCallbacks";
import { BuildsCallbacks } from "@spt-aki/callbacks/BuildsCallbacks"; import { BuildsCallbacks } from "@spt-aki/callbacks/BuildsCallbacks";
@ -71,18 +70,18 @@ import { BotWeaponGenerator } from "@spt-aki/generators/BotWeaponGenerator";
import { FenceBaseAssortGenerator } from "@spt-aki/generators/FenceBaseAssortGenerator"; import { FenceBaseAssortGenerator } from "@spt-aki/generators/FenceBaseAssortGenerator";
import { LocationGenerator } from "@spt-aki/generators/LocationGenerator"; import { LocationGenerator } from "@spt-aki/generators/LocationGenerator";
import { LootGenerator } from "@spt-aki/generators/LootGenerator"; import { LootGenerator } from "@spt-aki/generators/LootGenerator";
import { PMCLootGenerator } from "@spt-aki/generators/PMCLootGenerator";
import { PlayerScavGenerator } from "@spt-aki/generators/PlayerScavGenerator"; import { PlayerScavGenerator } from "@spt-aki/generators/PlayerScavGenerator";
import { PMCLootGenerator } from "@spt-aki/generators/PMCLootGenerator";
import { RagfairAssortGenerator } from "@spt-aki/generators/RagfairAssortGenerator"; import { RagfairAssortGenerator } from "@spt-aki/generators/RagfairAssortGenerator";
import { RagfairOfferGenerator } from "@spt-aki/generators/RagfairOfferGenerator"; import { RagfairOfferGenerator } from "@spt-aki/generators/RagfairOfferGenerator";
import { RepeatableQuestGenerator } from "@spt-aki/generators/RepeatableQuestGenerator"; import { RepeatableQuestGenerator } from "@spt-aki/generators/RepeatableQuestGenerator";
import { RepeatableQuestRewardGenerator } from "@spt-aki/generators/RepeatableQuestRewardGenerator"; import { RepeatableQuestRewardGenerator } from "@spt-aki/generators/RepeatableQuestRewardGenerator";
import { ScavCaseRewardGenerator } from "@spt-aki/generators/ScavCaseRewardGenerator"; import { ScavCaseRewardGenerator } from "@spt-aki/generators/ScavCaseRewardGenerator";
import { WeatherGenerator } from "@spt-aki/generators/WeatherGenerator";
import { BarrelInventoryMagGen } from "@spt-aki/generators/weapongen/implementations/BarrelInventoryMagGen"; import { BarrelInventoryMagGen } from "@spt-aki/generators/weapongen/implementations/BarrelInventoryMagGen";
import { ExternalInventoryMagGen } from "@spt-aki/generators/weapongen/implementations/ExternalInventoryMagGen"; import { ExternalInventoryMagGen } from "@spt-aki/generators/weapongen/implementations/ExternalInventoryMagGen";
import { InternalMagazineInventoryMagGen } from "@spt-aki/generators/weapongen/implementations/InternalMagazineInventoryMagGen"; import { InternalMagazineInventoryMagGen } from "@spt-aki/generators/weapongen/implementations/InternalMagazineInventoryMagGen";
import { UbglExternalMagGen } from "@spt-aki/generators/weapongen/implementations/UbglExternalMagGen"; import { UbglExternalMagGen } from "@spt-aki/generators/weapongen/implementations/UbglExternalMagGen";
import { WeatherGenerator } from "@spt-aki/generators/WeatherGenerator";
import { AssortHelper } from "@spt-aki/helpers/AssortHelper"; import { AssortHelper } from "@spt-aki/helpers/AssortHelper";
import { BotDifficultyHelper } from "@spt-aki/helpers/BotDifficultyHelper"; import { BotDifficultyHelper } from "@spt-aki/helpers/BotDifficultyHelper";
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper"; import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
@ -133,10 +132,6 @@ import { PostAkiModLoader } from "@spt-aki/loaders/PostAkiModLoader";
import { PostDBModLoader } from "@spt-aki/loaders/PostDBModLoader"; import { PostDBModLoader } from "@spt-aki/loaders/PostDBModLoader";
import { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader"; import { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader";
import { IAsyncQueue } from "@spt-aki/models/spt/utils/IAsyncQueue"; import { IAsyncQueue } from "@spt-aki/models/spt/utils/IAsyncQueue";
import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder";
import { HttpRouter } from "@spt-aki/routers/HttpRouter";
import { ImageRouter } from "@spt-aki/routers/ImageRouter";
import { ItemEventRouter } from "@spt-aki/routers/ItemEventRouter";
import { BotDynamicRouter } from "@spt-aki/routers/dynamic/BotDynamicRouter"; import { BotDynamicRouter } from "@spt-aki/routers/dynamic/BotDynamicRouter";
import { BundleDynamicRouter } from "@spt-aki/routers/dynamic/BundleDynamicRouter"; import { BundleDynamicRouter } from "@spt-aki/routers/dynamic/BundleDynamicRouter";
import { CustomizationDynamicRouter } from "@spt-aki/routers/dynamic/CustomizationDynamicRouter"; import { CustomizationDynamicRouter } from "@spt-aki/routers/dynamic/CustomizationDynamicRouter";
@ -146,6 +141,9 @@ import { InraidDynamicRouter } from "@spt-aki/routers/dynamic/InraidDynamicRoute
import { LocationDynamicRouter } from "@spt-aki/routers/dynamic/LocationDynamicRouter"; import { LocationDynamicRouter } from "@spt-aki/routers/dynamic/LocationDynamicRouter";
import { NotifierDynamicRouter } from "@spt-aki/routers/dynamic/NotifierDynamicRouter"; import { NotifierDynamicRouter } from "@spt-aki/routers/dynamic/NotifierDynamicRouter";
import { TraderDynamicRouter } from "@spt-aki/routers/dynamic/TraderDynamicRouter"; import { TraderDynamicRouter } from "@spt-aki/routers/dynamic/TraderDynamicRouter";
import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder";
import { HttpRouter } from "@spt-aki/routers/HttpRouter";
import { ImageRouter } from "@spt-aki/routers/ImageRouter";
import { CustomizationItemEventRouter } from "@spt-aki/routers/item_events/CustomizationItemEventRouter"; import { CustomizationItemEventRouter } from "@spt-aki/routers/item_events/CustomizationItemEventRouter";
import { HealthItemEventRouter } from "@spt-aki/routers/item_events/HealthItemEventRouter"; import { HealthItemEventRouter } from "@spt-aki/routers/item_events/HealthItemEventRouter";
import { HideoutItemEventRouter } from "@spt-aki/routers/item_events/HideoutItemEventRouter"; import { HideoutItemEventRouter } from "@spt-aki/routers/item_events/HideoutItemEventRouter";
@ -157,6 +155,7 @@ import { RagfairItemEventRouter } from "@spt-aki/routers/item_events/RagfairItem
import { RepairItemEventRouter } from "@spt-aki/routers/item_events/RepairItemEventRouter"; import { RepairItemEventRouter } from "@spt-aki/routers/item_events/RepairItemEventRouter";
import { TradeItemEventRouter } from "@spt-aki/routers/item_events/TradeItemEventRouter"; import { TradeItemEventRouter } from "@spt-aki/routers/item_events/TradeItemEventRouter";
import { WishlistItemEventRouter } from "@spt-aki/routers/item_events/WishlistItemEventRouter"; import { WishlistItemEventRouter } from "@spt-aki/routers/item_events/WishlistItemEventRouter";
import { ItemEventRouter } from "@spt-aki/routers/ItemEventRouter";
import { HealthSaveLoadRouter } from "@spt-aki/routers/save_load/HealthSaveLoadRouter"; import { HealthSaveLoadRouter } from "@spt-aki/routers/save_load/HealthSaveLoadRouter";
import { InraidSaveLoadRouter } from "@spt-aki/routers/save_load/InraidSaveLoadRouter"; import { InraidSaveLoadRouter } from "@spt-aki/routers/save_load/InraidSaveLoadRouter";
import { InsuranceSaveLoadRouter } from "@spt-aki/routers/save_load/InsuranceSaveLoadRouter"; import { InsuranceSaveLoadRouter } from "@spt-aki/routers/save_load/InsuranceSaveLoadRouter";
@ -188,16 +187,18 @@ import { TraderStaticRouter } from "@spt-aki/routers/static/TraderStaticRouter";
import { WeatherStaticRouter } from "@spt-aki/routers/static/WeatherStaticRouter"; import { WeatherStaticRouter } from "@spt-aki/routers/static/WeatherStaticRouter";
import { ConfigServer } from "@spt-aki/servers/ConfigServer"; import { ConfigServer } from "@spt-aki/servers/ConfigServer";
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer"; import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
import { AkiHttpListener } from "@spt-aki/servers/http/AkiHttpListener";
import { HttpServer } from "@spt-aki/servers/HttpServer"; import { HttpServer } from "@spt-aki/servers/HttpServer";
import { RagfairServer } from "@spt-aki/servers/RagfairServer"; import { RagfairServer } from "@spt-aki/servers/RagfairServer";
import { SaveServer } from "@spt-aki/servers/SaveServer"; import { SaveServer } from "@spt-aki/servers/SaveServer";
import { WebSocketServer } from "@spt-aki/servers/WebSocketServer"; import { WebSocketServer } from "@spt-aki/servers/WebSocketServer";
import { AkiHttpListener } from "@spt-aki/servers/http/AkiHttpListener";
import { BotEquipmentFilterService } from "@spt-aki/services/BotEquipmentFilterService"; import { BotEquipmentFilterService } from "@spt-aki/services/BotEquipmentFilterService";
import { BotEquipmentModPoolService } from "@spt-aki/services/BotEquipmentModPoolService"; import { BotEquipmentModPoolService } from "@spt-aki/services/BotEquipmentModPoolService";
import { BotGenerationCacheService } from "@spt-aki/services/BotGenerationCacheService"; import { BotGenerationCacheService } from "@spt-aki/services/BotGenerationCacheService";
import { BotLootCacheService } from "@spt-aki/services/BotLootCacheService"; import { BotLootCacheService } from "@spt-aki/services/BotLootCacheService";
import { BotWeaponModLimitService } from "@spt-aki/services/BotWeaponModLimitService"; import { BotWeaponModLimitService } from "@spt-aki/services/BotWeaponModLimitService";
import { BundleHashCacheService } from "@spt-aki/services/cache/BundleHashCacheService";
import { ModHashCacheService } from "@spt-aki/services/cache/ModHashCacheService";
import { CustomLocationWaveService } from "@spt-aki/services/CustomLocationWaveService"; import { CustomLocationWaveService } from "@spt-aki/services/CustomLocationWaveService";
import { FenceService } from "@spt-aki/services/FenceService"; import { FenceService } from "@spt-aki/services/FenceService";
import { GiftService } from "@spt-aki/services/GiftService"; import { GiftService } from "@spt-aki/services/GiftService";
@ -209,6 +210,13 @@ import { LocalisationService } from "@spt-aki/services/LocalisationService";
import { MailSendService } from "@spt-aki/services/MailSendService"; import { MailSendService } from "@spt-aki/services/MailSendService";
import { MatchBotDetailsCacheService } from "@spt-aki/services/MatchBotDetailsCacheService"; import { MatchBotDetailsCacheService } from "@spt-aki/services/MatchBotDetailsCacheService";
import { MatchLocationService } from "@spt-aki/services/MatchLocationService"; import { MatchLocationService } from "@spt-aki/services/MatchLocationService";
import { CustomItemService } from "@spt-aki/services/mod/CustomItemService";
import { DynamicRouterModService } from "@spt-aki/services/mod/dynamicRouter/DynamicRouterModService";
import { HttpListenerModService } from "@spt-aki/services/mod/httpListener/HttpListenerModService";
import { ImageRouteService } from "@spt-aki/services/mod/image/ImageRouteService";
import { OnLoadModService } from "@spt-aki/services/mod/onLoad/OnLoadModService";
import { OnUpdateModService } from "@spt-aki/services/mod/onUpdate/OnUpdateModService";
import { StaticRouterModService } from "@spt-aki/services/mod/staticRouter/StaticRouterModService";
import { ModCompilerService } from "@spt-aki/services/ModCompilerService"; import { ModCompilerService } from "@spt-aki/services/ModCompilerService";
import { NotificationService } from "@spt-aki/services/NotificationService"; import { NotificationService } from "@spt-aki/services/NotificationService";
import { OpenZoneService } from "@spt-aki/services/OpenZoneService"; import { OpenZoneService } from "@spt-aki/services/OpenZoneService";
@ -230,15 +238,6 @@ import { SeasonalEventService } from "@spt-aki/services/SeasonalEventService";
import { TraderAssortService } from "@spt-aki/services/TraderAssortService"; import { TraderAssortService } from "@spt-aki/services/TraderAssortService";
import { TraderPurchasePersisterService } from "@spt-aki/services/TraderPurchasePersisterService"; import { TraderPurchasePersisterService } from "@spt-aki/services/TraderPurchasePersisterService";
import { TraderServicesService } from "@spt-aki/services/TraderServicesService"; import { TraderServicesService } from "@spt-aki/services/TraderServicesService";
import { BundleHashCacheService } from "@spt-aki/services/cache/BundleHashCacheService";
import { ModHashCacheService } from "@spt-aki/services/cache/ModHashCacheService";
import { CustomItemService } from "@spt-aki/services/mod/CustomItemService";
import { DynamicRouterModService } from "@spt-aki/services/mod/dynamicRouter/DynamicRouterModService";
import { HttpListenerModService } from "@spt-aki/services/mod/httpListener/HttpListenerModService";
import { ImageRouteService } from "@spt-aki/services/mod/image/ImageRouteService";
import { OnLoadModService } from "@spt-aki/services/mod/onLoad/OnLoadModService";
import { OnUpdateModService } from "@spt-aki/services/mod/onUpdate/OnUpdateModService";
import { StaticRouterModService } from "@spt-aki/services/mod/staticRouter/StaticRouterModService";
import { App } from "@spt-aki/utils/App"; import { App } from "@spt-aki/utils/App";
import { AsyncQueue } from "@spt-aki/utils/AsyncQueue"; import { AsyncQueue } from "@spt-aki/utils/AsyncQueue";
import { CompareUtil } from "@spt-aki/utils/CompareUtil"; import { CompareUtil } from "@spt-aki/utils/CompareUtil";
@ -249,14 +248,14 @@ import { HttpFileUtil } from "@spt-aki/utils/HttpFileUtil";
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil"; import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
import { ImporterUtil } from "@spt-aki/utils/ImporterUtil"; import { ImporterUtil } from "@spt-aki/utils/ImporterUtil";
import { JsonUtil } from "@spt-aki/utils/JsonUtil"; import { JsonUtil } from "@spt-aki/utils/JsonUtil";
import { WinstonMainLogger } from "@spt-aki/utils/logging/WinstonMainLogger";
import { WinstonRequestLogger } from "@spt-aki/utils/logging/WinstonRequestLogger";
import { MathUtil } from "@spt-aki/utils/MathUtil"; import { MathUtil } from "@spt-aki/utils/MathUtil";
import { ObjectId } from "@spt-aki/utils/ObjectId"; import { ObjectId } from "@spt-aki/utils/ObjectId";
import { RandomUtil } from "@spt-aki/utils/RandomUtil"; import { RandomUtil } from "@spt-aki/utils/RandomUtil";
import { TimeUtil } from "@spt-aki/utils/TimeUtil"; import { TimeUtil } from "@spt-aki/utils/TimeUtil";
import { VFS } from "@spt-aki/utils/VFS"; import { VFS } from "@spt-aki/utils/VFS";
import { Watermark, WatermarkLocale } from "@spt-aki/utils/Watermark"; import { Watermark, WatermarkLocale } from "@spt-aki/utils/Watermark";
import { WinstonMainLogger } from "@spt-aki/utils/logging/WinstonMainLogger";
import { WinstonRequestLogger } from "@spt-aki/utils/logging/WinstonRequestLogger";
/** /**
* Handle the registration of classes to be used by the Dependency Injection code * Handle the registration of classes to be used by the Dependency Injection code

View File

@ -1,5 +1,5 @@
export interface OnLoad export interface OnLoad
{ {
onLoad(): Promise<void>; onLoad(): Promise<void>
getRoute(): string; getRoute(): string
} }

View File

@ -1,5 +1,5 @@
export interface OnUpdate export interface OnUpdate
{ {
onUpdate(timeSinceLastRun: number): Promise<boolean>; onUpdate(timeSinceLastRun: number): Promise<boolean>
getRoute(): string; getRoute(): string
} }

View File

@ -29,9 +29,9 @@ export class Router
{ {
if (partialMatch) if (partialMatch)
{ {
return this.getInternalHandledRoutes().filter((r) => r.dynamic).some((r) => url.includes(r.route)); return this.getInternalHandledRoutes().filter(r => r.dynamic).some(r => url.includes(r.route));
} }
return this.getInternalHandledRoutes().filter((r) => !r.dynamic).some((r) => r.route === url); return this.getInternalHandledRoutes().filter(r => !r.dynamic).some(r => r.route === url);
} }
} }
@ -44,12 +44,12 @@ export class StaticRouter extends Router
public async handleStatic(url: string, info: any, sessionID: string, output: string): Promise<any> public async handleStatic(url: string, info: any, sessionID: string, output: string): Promise<any>
{ {
return this.routes.find((route) => route.url === url).action(url, info, sessionID, output); return this.routes.find(route => route.url === url).action(url, info, sessionID, output);
} }
public override getHandledRoutes(): HandledRoute[] public override getHandledRoutes(): HandledRoute[]
{ {
return this.routes.map((route) => new HandledRoute(route.url, false)); return this.routes.map(route => new HandledRoute(route.url, false));
} }
} }
@ -62,12 +62,12 @@ export class DynamicRouter extends Router
public async handleDynamic(url: string, info: any, sessionID: string, output: string): Promise<any> public async handleDynamic(url: string, info: any, sessionID: string, output: string): Promise<any>
{ {
return this.routes.find((r) => url.includes(r.url)).action(url, info, sessionID, output); return this.routes.find(r => url.includes(r.url)).action(url, info, sessionID, output);
} }
public override getHandledRoutes(): HandledRoute[] public override getHandledRoutes(): HandledRoute[]
{ {
return this.routes.map((route) => new HandledRoute(route.url, true)); return this.routes.map(route => new HandledRoute(route.url, true));
} }
} }

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper"; import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
import { BotHelper } from "@spt-aki/helpers/BotHelper"; import { BotHelper } from "@spt-aki/helpers/BotHelper";
import { BotWeaponGeneratorHelper } from "@spt-aki/helpers/BotWeaponGeneratorHelper"; import { BotWeaponGeneratorHelper } from "@spt-aki/helpers/BotWeaponGeneratorHelper";
@ -234,8 +233,8 @@ export class BotEquipmentModGenerator
} }
// Get the front/back/side weights based on bots level // Get the front/back/side weights based on bots level
const plateSlotWeights = settings.botEquipmentConfig?.armorPlateWeighting?.find((armorWeight) => const plateSlotWeights = settings.botEquipmentConfig?.armorPlateWeighting?.find(armorWeight =>
settings.botLevel >= armorWeight.levelRange.min && settings.botLevel <= armorWeight.levelRange.max settings.botLevel >= armorWeight.levelRange.min && settings.botLevel <= armorWeight.levelRange.max,
); );
if (!plateSlotWeights) if (!plateSlotWeights)
{ {
@ -261,17 +260,17 @@ export class BotEquipmentModGenerator
const chosenArmorPlateLevel = this.weightedRandomHelper.getWeightedValue<string>(plateWeights); const chosenArmorPlateLevel = this.weightedRandomHelper.getWeightedValue<string>(plateWeights);
// Convert the array of ids into database items // Convert the array of ids into database items
const platesFromDb = existingPlateTplPool.map((plateTpl) => this.itemHelper.getItem(plateTpl)[1]); const platesFromDb = existingPlateTplPool.map(plateTpl => this.itemHelper.getItem(plateTpl)[1]);
// Filter plates to the chosen level based on its armorClass property // Filter plates to the chosen level based on its armorClass property
const filteredPlates = platesFromDb.filter((item) => item._props.armorClass === chosenArmorPlateLevel); const filteredPlates = platesFromDb.filter(item => item._props.armorClass === chosenArmorPlateLevel);
if (filteredPlates.length === 0) if (filteredPlates.length === 0)
{ {
this.logger.debug( this.logger.debug(
`Plate filter was too restrictive for armor: ${armorItem._id}, unable to find plates of level: ${chosenArmorPlateLevel}. Using mod items default plate`, `Plate filter was too restrictive for armor: ${armorItem._id}, unable to find plates of level: ${chosenArmorPlateLevel}. Using mod items default plate`,
); );
const relatedItemDbModSlot = armorItem._props.Slots.find((slot) => slot._name.toLowerCase() === modSlot); const relatedItemDbModSlot = armorItem._props.Slots.find(slot => slot._name.toLowerCase() === modSlot);
const defaultPlate = relatedItemDbModSlot._props.filters[0].Plate; const defaultPlate = relatedItemDbModSlot._props.filters[0].Plate;
if (!defaultPlate) if (!defaultPlate)
{ {
@ -281,8 +280,8 @@ export class BotEquipmentModGenerator
const defaultPreset = this.presetHelper.getDefaultPreset(armorItem._id); const defaultPreset = this.presetHelper.getDefaultPreset(armorItem._id);
if (defaultPreset) if (defaultPreset)
{ {
const relatedPresetSlot = defaultPreset._items.find((item) => const relatedPresetSlot = defaultPreset._items.find(item =>
item.slotId?.toLowerCase() === modSlot item.slotId?.toLowerCase() === modSlot,
); );
if (relatedPresetSlot) if (relatedPresetSlot)
{ {
@ -306,7 +305,7 @@ export class BotEquipmentModGenerator
// Only return the items ids // Only return the items ids
result.result = Result.SUCCESS; result.result = Result.SUCCESS;
result.plateModTpls = filteredPlates.map((item) => item._id); result.plateModTpls = filteredPlates.map(item => item._id);
return result; return result;
} }
@ -346,8 +345,8 @@ export class BotEquipmentModGenerator
const compatibleModsPool = modPool[parentTemplate._id]; const compatibleModsPool = modPool[parentTemplate._id];
if ( if (
!((parentTemplate._props.Slots.length || parentTemplate._props.Cartridges?.length) !(parentTemplate._props.Slots.length || parentTemplate._props.Cartridges?.length
|| parentTemplate._props.Chambers?.length) || parentTemplate._props.Chambers?.length)
) )
{ {
this.logger.error( this.logger.error(
@ -468,10 +467,10 @@ export class BotEquipmentModGenerator
// Handguard mod can take a sub handguard mod + weapon has no UBGL (takes same slot) // Handguard mod can take a sub handguard mod + weapon has no UBGL (takes same slot)
// Force spawn chance to be 100% to ensure it gets added // Force spawn chance to be 100% to ensure it gets added
if ( if (
modSlot === "mod_handguard" && modToAddTemplate._props.Slots.find((slot) => modSlot === "mod_handguard" && modToAddTemplate._props.Slots.find(slot =>
slot._name === "mod_handguard" slot._name === "mod_handguard",
) )
&& !weapon.find((item) => item.slotId === "mod_launcher") && !weapon.find(item => item.slotId === "mod_launcher")
) )
{ {
// Needed for handguards with lower // Needed for handguards with lower
@ -481,9 +480,9 @@ export class BotEquipmentModGenerator
// If stock mod can take a sub stock mod, force spawn chance to be 100% to ensure sub-stock gets added // If stock mod can take a sub stock mod, force spawn chance to be 100% to ensure sub-stock gets added
// Or if mod_stock is configured to be forced on // Or if mod_stock is configured to be forced on
if ( if (
modSlot === "mod_stock" && (modToAddTemplate._props.Slots.find((slot) => modSlot === "mod_stock" && modToAddTemplate._props.Slots.find(slot =>
slot._name.includes("mod_stock") || botEquipConfig.forceStock slot._name.includes("mod_stock") || botEquipConfig.forceStock,
)) )
) )
{ {
// Stock mod can take additional stocks, could be a locking device, force 100% chance // Stock mod can take additional stocks, could be a locking device, force 100% chance
@ -700,11 +699,11 @@ export class BotEquipmentModGenerator
case "patron_in_weapon": case "patron_in_weapon":
case "patron_in_weapon_000": case "patron_in_weapon_000":
case "patron_in_weapon_001": case "patron_in_weapon_001":
return parentTemplate._props.Chambers.find((chamber) => chamber._name.includes(modSlotLower)); return parentTemplate._props.Chambers.find(chamber => chamber._name.includes(modSlotLower));
case "cartridges": case "cartridges":
return parentTemplate._props.Cartridges.find((c) => c._name.toLowerCase() === modSlotLower); return parentTemplate._props.Cartridges.find(c => c._name.toLowerCase() === modSlotLower);
default: default:
return parentTemplate._props.Slots.find((s) => s._name.toLowerCase() === modSlotLower); return parentTemplate._props.Slots.find(s => s._name.toLowerCase() === modSlotLower);
} }
} }
@ -762,7 +761,7 @@ export class BotEquipmentModGenerator
): [boolean, ITemplateItem] ): [boolean, ITemplateItem]
{ {
/** Slot mod will fill */ /** Slot mod will fill */
const parentSlot = parentTemplate._props.Slots.find((i) => i._name === modSlot); const parentSlot = parentTemplate._props.Slots.find(i => i._name === modSlot);
const weaponTemplate = this.itemHelper.getItem(weapon[0]._tpl)[1]; const weaponTemplate = this.itemHelper.getItem(weapon[0]._tpl)[1];
// It's ammo, use predefined ammo parameter // It's ammo, use predefined ammo parameter
@ -950,8 +949,8 @@ export class BotEquipmentModGenerator
if (modSpawnResult === ModSpawn.DEFAULT_MOD) if (modSpawnResult === ModSpawn.DEFAULT_MOD)
{ {
const matchingPreset = this.getMatchingPreset(weaponTemplate, parentTemplate._id); const matchingPreset = this.getMatchingPreset(weaponTemplate, parentTemplate._id);
const matchingMod = matchingPreset._items.find((item) => const matchingMod = matchingPreset._items.find(item =>
item?.slotId?.toLowerCase() === modSlot.toLowerCase() item?.slotId?.toLowerCase() === modSlot.toLowerCase(),
); );
// Only filter mods down to single default item if it already exists in existing itemModPool, OR the default item has no children // Only filter mods down to single default item if it already exists in existing itemModPool, OR the default item has no children
@ -967,8 +966,8 @@ export class BotEquipmentModGenerator
} }
// Check the filter of the slot to ensure a chosen mod fits // Check the filter of the slot to ensure a chosen mod fits
const parentSlotCompatibleItems = parentTemplate._props.Slots?.find((slot) => const parentSlotCompatibleItems = parentTemplate._props.Slots?.find(slot =>
slot._name.toLowerCase() === modSlot.toLowerCase() slot._name.toLowerCase() === modSlot.toLowerCase(),
)._props.filters[0].Filter; )._props.filters[0].Filter;
// Mod isnt in existing pool, only add if it has no children and matches parent filter // Mod isnt in existing pool, only add if it has no children and matches parent filter
@ -1176,7 +1175,7 @@ export class BotEquipmentModGenerator
botEquipBlacklist: EquipmentFilterDetails, botEquipBlacklist: EquipmentFilterDetails,
): void ): void
{ {
const desiredSlotObject = modTemplate._props.Slots.find((slot) => slot._name.includes(desiredSlotName)); const desiredSlotObject = modTemplate._props.Slots.find(slot => slot._name.includes(desiredSlotName));
if (desiredSlotObject) if (desiredSlotObject)
{ {
const supportedSubMods = desiredSlotObject._props.filters[0].Filter; const supportedSubMods = desiredSlotObject._props.filters[0].Filter;
@ -1262,7 +1261,7 @@ export class BotEquipmentModGenerator
const blacklist = this.itemFilterService.getBlacklistedItems().concat( const blacklist = this.itemFilterService.getBlacklistedItems().concat(
botEquipBlacklist.equipment[modSlot] || [], botEquipBlacklist.equipment[modSlot] || [],
); );
result = allowedMods.filter((tpl) => !blacklist.includes(tpl)); result = allowedMods.filter(tpl => !blacklist.includes(tpl));
return result; return result;
} }
@ -1288,7 +1287,7 @@ export class BotEquipmentModGenerator
weaponName: parentTemplate._name, weaponName: parentTemplate._name,
}), }),
); );
const camoraSlots = parentTemplate._props.Slots.filter((slot) => slot._name.startsWith("camora")); const camoraSlots = parentTemplate._props.Slots.filter(slot => slot._name.startsWith("camora"));
// Attempt to generate camora slots for item // Attempt to generate camora slots for item
modPool[parentTemplate._id] = {}; modPool[parentTemplate._id] = {};
@ -1422,17 +1421,17 @@ export class BotEquipmentModGenerator
{ {
// Check to see if mount has a scope slot (only include primary slot, ignore the rest like the backup sight slots) // Check to see if mount has a scope slot (only include primary slot, ignore the rest like the backup sight slots)
// Should only find 1 as there's currently no items with a mod_scope AND a mod_scope_000 // Should only find 1 as there's currently no items with a mod_scope AND a mod_scope_000
const scopeSlot = itemDetails._props.Slots.filter((slot) => const scopeSlot = itemDetails._props.Slots.filter(slot =>
["mod_scope", "mod_scope_000"].includes(slot._name) ["mod_scope", "mod_scope_000"].includes(slot._name),
); );
// Mods scope slot found must allow ALL whitelisted scope types OR be a mount // Mods scope slot found must allow ALL whitelisted scope types OR be a mount
if ( if (
scopeSlot?.every((slot) => scopeSlot?.every(slot =>
slot._props.filters[0].Filter.every((tpl) => slot._props.filters[0].Filter.every(tpl =>
this.itemHelper.isOfBaseclasses(tpl, whitelistedSightTypes) this.itemHelper.isOfBaseclasses(tpl, whitelistedSightTypes)
|| this.itemHelper.isOfBaseclass(tpl, BaseClasses.MOUNT) || this.itemHelper.isOfBaseclass(tpl, BaseClasses.MOUNT),
) ),
) )
) )
{ {

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { BotInventoryGenerator } from "@spt-aki/generators/BotInventoryGenerator"; import { BotInventoryGenerator } from "@spt-aki/generators/BotInventoryGenerator";
import { BotLevelGenerator } from "@spt-aki/generators/BotLevelGenerator"; import { BotLevelGenerator } from "@spt-aki/generators/BotLevelGenerator";
import { BotDifficultyHelper } from "@spt-aki/helpers/BotDifficultyHelper"; import { BotDifficultyHelper } from "@spt-aki/helpers/BotDifficultyHelper";
@ -111,7 +110,7 @@ export class BotGenerator
// Get raw json data for bot (Cloned) // Get raw json data for bot (Cloned)
const botJsonTemplateClone = this.jsonUtil.clone( const botJsonTemplateClone = this.jsonUtil.clone(
this.botHelper.getBotTemplate((botGenerationDetails.isPmc) ? bot.Info.Side : botGenerationDetails.role), this.botHelper.getBotTemplate(botGenerationDetails.isPmc ? bot.Info.Side : botGenerationDetails.role),
); );
bot = this.generateBot(sessionId, bot, botJsonTemplateClone, botGenerationDetails); bot = this.generateBot(sessionId, bot, botJsonTemplateClone, botGenerationDetails);
@ -446,7 +445,7 @@ export class BotGenerator
} }
return skillToAdd; return skillToAdd;
}).filter((x) => x !== null); }).filter(x => x !== null);
} }
/** /**
@ -546,7 +545,7 @@ export class BotGenerator
Nickname: bot.Info.Nickname, Nickname: bot.Info.Nickname,
Side: bot.Info.Side, Side: bot.Info.Side,
Level: bot.Info.Level, Level: bot.Info.Level,
Time: (new Date().toISOString()), Time: new Date().toISOString(),
Status: "Killed by ", Status: "Killed by ",
KillerAccountId: "Unknown", KillerAccountId: "Unknown",
KillerProfileId: "Unknown", KillerProfileId: "Unknown",
@ -557,7 +556,7 @@ export class BotGenerator
const inventoryItem: Item = { const inventoryItem: Item = {
_id: this.hashUtil.generate(), _id: this.hashUtil.generate(),
_tpl: ((bot.Info.Side === "Usec") ? BaseClasses.DOG_TAG_USEC : BaseClasses.DOG_TAG_BEAR), _tpl: bot.Info.Side === "Usec" ? BaseClasses.DOG_TAG_USEC : BaseClasses.DOG_TAG_BEAR,
parentId: bot.Inventory.equipment, parentId: bot.Inventory.equipment,
slotId: "Dogtag", slotId: "Dogtag",
location: undefined, location: undefined,

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { BotEquipmentModGenerator } from "@spt-aki/generators/BotEquipmentModGenerator"; import { BotEquipmentModGenerator } from "@spt-aki/generators/BotEquipmentModGenerator";
import { BotLootGenerator } from "@spt-aki/generators/BotLootGenerator"; import { BotLootGenerator } from "@spt-aki/generators/BotLootGenerator";
import { BotWeaponGenerator } from "@spt-aki/generators/BotWeaponGenerator"; import { BotWeaponGenerator } from "@spt-aki/generators/BotWeaponGenerator";
@ -308,12 +307,11 @@ export class BotInventoryGenerator
*/ */
protected generateEquipment(settings: IGenerateEquipmentProperties): boolean protected generateEquipment(settings: IGenerateEquipmentProperties): boolean
{ {
const spawnChance = const spawnChance = ([EquipmentSlots.POCKETS, EquipmentSlots.SECURED_CONTAINER] as string[])
([EquipmentSlots.POCKETS, EquipmentSlots.SECURED_CONTAINER] as string[]).includes( .includes(settings.rootEquipmentSlot)
settings.rootEquipmentSlot, ? 100
) : settings.spawnChances.equipment[settings.rootEquipmentSlot];
? 100
: settings.spawnChances.equipment[settings.rootEquipmentSlot];
if (typeof spawnChance === "undefined") if (typeof spawnChance === "undefined")
{ {
this.logger.warning( this.logger.warning(
@ -444,7 +442,7 @@ export class BotInventoryGenerator
for (const modSlot of Object.keys(modPool ?? [])) for (const modSlot of Object.keys(modPool ?? []))
{ {
const blacklistedMods = equipmentBlacklist[0]?.equipment[modSlot] || []; const blacklistedMods = equipmentBlacklist[0]?.equipment[modSlot] || [];
const filteredMods = modPool[modSlot].filter((x) => !blacklistedMods.includes(x)); const filteredMods = modPool[modSlot].filter(x => !blacklistedMods.includes(x));
if (filteredMods.length > 0) if (filteredMods.length > 0)
{ {
@ -503,7 +501,7 @@ export class BotInventoryGenerator
* @param equipmentChances Chances bot has certain equipment * @param equipmentChances Chances bot has certain equipment
* @returns What slots bot should have weapons generated for * @returns What slots bot should have weapons generated for
*/ */
protected getDesiredWeaponsForBot(equipmentChances: Chances): { slot: EquipmentSlots; shouldSpawn: boolean; }[] protected getDesiredWeaponsForBot(equipmentChances: Chances): { slot: EquipmentSlots, shouldSpawn: boolean }[]
{ {
const shouldSpawnPrimary = this.randomUtil.getChance100(equipmentChances.equipment.FirstPrimaryWeapon); const shouldSpawnPrimary = this.randomUtil.getChance100(equipmentChances.equipment.FirstPrimaryWeapon);
return [{ slot: EquipmentSlots.FIRST_PRIMARY_WEAPON, shouldSpawn: shouldSpawnPrimary }, { return [{ slot: EquipmentSlots.FIRST_PRIMARY_WEAPON, shouldSpawn: shouldSpawnPrimary }, {
@ -532,7 +530,7 @@ export class BotInventoryGenerator
*/ */
protected addWeaponAndMagazinesToInventory( protected addWeaponAndMagazinesToInventory(
sessionId: string, sessionId: string,
weaponSlot: { slot: EquipmentSlots; shouldSpawn: boolean; }, weaponSlot: { slot: EquipmentSlots, shouldSpawn: boolean },
templateInventory: Inventory, templateInventory: Inventory,
botInventory: PmcInventory, botInventory: PmcInventory,
equipmentChances: Chances, equipmentChances: Chances,
@ -567,18 +565,18 @@ export class BotInventoryGenerator
export interface IGenerateEquipmentProperties export interface IGenerateEquipmentProperties
{ {
/** Root Slot being generated */ /** Root Slot being generated */
rootEquipmentSlot: string; rootEquipmentSlot: string
/** Equipment pool for root slot being generated */ /** Equipment pool for root slot being generated */
rootEquipmentPool: Record<string, number>; rootEquipmentPool: Record<string, number>
modPool: Mods; modPool: Mods
/** Dictionary of mod items and their chance to spawn for this bot type */ /** Dictionary of mod items and their chance to spawn for this bot type */
spawnChances: Chances; spawnChances: Chances
/** Role being generated for */ /** Role being generated for */
botRole: string; botRole: string
/** Level of bot being generated */ /** Level of bot being generated */
botLevel: number; botLevel: number
inventory: PmcInventory; inventory: PmcInventory
botEquipmentConfig: EquipmentFilters; botEquipmentConfig: EquipmentFilters
/** Settings from bot.json to adjust how item is generated */ /** Settings from bot.json to adjust how item is generated */
randomisationDetails: RandomisationDetails; randomisationDetails: RandomisationDetails
} }

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { MinMax } from "@spt-aki/models/common/MinMax"; import { MinMax } from "@spt-aki/models/common/MinMax";
import { IRandomisedBotLevelResult } from "@spt-aki/models/eft/bot/IRandomisedBotLevelResult"; import { IRandomisedBotLevelResult } from "@spt-aki/models/eft/bot/IRandomisedBotLevelResult";
import { IBotBase } from "@spt-aki/models/eft/common/tables/IBotBase"; import { IBotBase } from "@spt-aki/models/eft/common/tables/IBotBase";
@ -66,7 +65,7 @@ export class BotLevelGenerator
maxLevel: number, maxLevel: number,
): number ): number
{ {
const maxPossibleLevel = (botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride) const maxPossibleLevel = botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride
? Math.min(botGenerationDetails.locationSpecificPmcLevelOverride.max, maxLevel) // Was a PMC and they have a level override ? Math.min(botGenerationDetails.locationSpecificPmcLevelOverride.max, maxLevel) // Was a PMC and they have a level override
: Math.min(levelDetails.max, maxLevel); // Not pmc with override or non-pmc : Math.min(levelDetails.max, maxLevel); // Not pmc with override or non-pmc
@ -92,7 +91,7 @@ export class BotLevelGenerator
maxlevel: number, maxlevel: number,
): number ): number
{ {
const minPossibleLevel = (botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride) const minPossibleLevel = botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride
? Math.min( ? Math.min(
Math.max(levelDetails.min, botGenerationDetails.locationSpecificPmcLevelOverride.min), // Biggest between json min and the botgen min Math.max(levelDetails.min, botGenerationDetails.locationSpecificPmcLevelOverride.min), // Biggest between json min and the botgen min
maxlevel, // Fallback if value above is crazy (default is 79) maxlevel, // Fallback if value above is crazy (default is 79)

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { BotWeaponGenerator } from "@spt-aki/generators/BotWeaponGenerator"; import { BotWeaponGenerator } from "@spt-aki/generators/BotWeaponGenerator";
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper"; import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
import { BotHelper } from "@spt-aki/helpers/BotHelper"; import { BotHelper } from "@spt-aki/helpers/BotHelper";
@ -292,7 +291,7 @@ export class BotLootGenerator
// Secure // Secure
// only add if not a pmc or is pmc and flag is true // only add if not a pmc or is pmc and flag is true
if (!isPmc || (isPmc && this.pmcConfig.addSecureContainerLootFromBotConfig)) if (!isPmc || isPmc && this.pmcConfig.addSecureContainerLootFromBotConfig)
{ {
this.addLootFromPool( this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.SECURE, botJsonTemplate), this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.SECURE, botJsonTemplate),
@ -317,12 +316,12 @@ export class BotLootGenerator
{ {
const result = [EquipmentSlots.POCKETS]; const result = [EquipmentSlots.POCKETS];
if (botInventory.items.find((item) => item.slotId === EquipmentSlots.TACTICAL_VEST)) if (botInventory.items.find(item => item.slotId === EquipmentSlots.TACTICAL_VEST))
{ {
result.push(EquipmentSlots.TACTICAL_VEST); result.push(EquipmentSlots.TACTICAL_VEST);
} }
if (botInventory.items.find((item) => item.slotId === EquipmentSlots.BACKPACK)) if (botInventory.items.find(item => item.slotId === EquipmentSlots.BACKPACK))
{ {
result.push(EquipmentSlots.BACKPACK); result.push(EquipmentSlots.BACKPACK);
} }
@ -476,7 +475,7 @@ export class BotLootGenerator
); );
} }
itemWithChildrenToAdd.push(...itemsToAdd.flatMap((moneyStack) => moneyStack)); itemWithChildrenToAdd.push(...itemsToAdd.flatMap(moneyStack => moneyStack));
} }
} }
} }

View File

@ -1,5 +1,4 @@
import { inject, injectAll, injectable } from "tsyringe"; import { inject, injectAll, injectable } from "tsyringe";
import { BotEquipmentModGenerator } from "@spt-aki/generators/BotEquipmentModGenerator"; import { BotEquipmentModGenerator } from "@spt-aki/generators/BotEquipmentModGenerator";
import { IInventoryMagGen } from "@spt-aki/generators/weapongen/IInventoryMagGen"; import { IInventoryMagGen } from "@spt-aki/generators/weapongen/IInventoryMagGen";
import { InventoryMagGen } from "@spt-aki/generators/weapongen/InventoryMagGen"; import { InventoryMagGen } from "@spt-aki/generators/weapongen/InventoryMagGen";
@ -200,7 +199,7 @@ export class BotWeaponGenerator
} }
// Fill existing magazines to full and sync ammo type // Fill existing magazines to full and sync ammo type
for (const magazine of weaponWithModsArray.filter((item) => item.slotId === this.modMagazineSlotId)) for (const magazine of weaponWithModsArray.filter(item => item.slotId === this.modMagazineSlotId))
{ {
this.fillExistingMagazines(weaponWithModsArray, magazine, ammoTpl); this.fillExistingMagazines(weaponWithModsArray, magazine, ammoTpl);
} }
@ -212,12 +211,12 @@ export class BotWeaponGenerator
) )
{ {
// Guns have variety of possible Chamber ids, patron_in_weapon/patron_in_weapon_000/patron_in_weapon_001 // Guns have variety of possible Chamber ids, patron_in_weapon/patron_in_weapon_000/patron_in_weapon_001
const chamberSlotNames = weaponItemTemplate._props.Chambers.map((x) => x._name); const chamberSlotNames = weaponItemTemplate._props.Chambers.map(x => x._name);
this.addCartridgeToChamber(weaponWithModsArray, ammoTpl, chamberSlotNames); this.addCartridgeToChamber(weaponWithModsArray, ammoTpl, chamberSlotNames);
} }
// Fill UBGL if found // Fill UBGL if found
const ubglMod = weaponWithModsArray.find((x) => x.slotId === "mod_launcher"); const ubglMod = weaponWithModsArray.find(x => x.slotId === "mod_launcher");
let ubglAmmoTpl: string = undefined; let ubglAmmoTpl: string = undefined;
if (ubglMod) if (ubglMod)
{ {
@ -246,7 +245,7 @@ export class BotWeaponGenerator
{ {
for (const slotId of chamberSlotIds) for (const slotId of chamberSlotIds)
{ {
const existingItemWithSlot = weaponWithModsArray.find((x) => x.slotId === slotId); const existingItemWithSlot = weaponWithModsArray.find(x => x.slotId === slotId);
if (!existingItemWithSlot) if (!existingItemWithSlot)
{ {
// Not found, add new slot to weapon // Not found, add new slot to weapon
@ -367,11 +366,11 @@ export class BotWeaponGenerator
} }
// Iterate over required slots in db item, check mod exists for that slot // Iterate over required slots in db item, check mod exists for that slot
for (const modSlotTemplate of modTemplate._props.Slots.filter((slot) => slot._required)) for (const modSlotTemplate of modTemplate._props.Slots.filter(slot => slot._required))
{ {
const slotName = modSlotTemplate._name; const slotName = modSlotTemplate._name;
const weaponSlotItem = weaponItemArray.find((weaponItem) => const weaponSlotItem = weaponItemArray.find(weaponItem =>
weaponItem.parentId === mod._id && weaponItem.slotId === slotName weaponItem.parentId === mod._id && weaponItem.slotId === slotName,
); );
if (!weaponSlotItem) if (!weaponSlotItem)
{ {
@ -442,7 +441,7 @@ export class BotWeaponGenerator
ammoTemplate, ammoTemplate,
inventory, inventory,
); );
this.inventoryMagGenComponents.find((v) => v.canHandleInventoryMagGen(inventoryMagGenModel)).process( this.inventoryMagGenComponents.find(v => v.canHandleInventoryMagGen(inventoryMagGenModel)).process(
inventoryMagGenModel, inventoryMagGenModel,
); );
@ -468,13 +467,13 @@ export class BotWeaponGenerator
): void ): void
{ {
// Find ubgl mod item + get details of it from db // Find ubgl mod item + get details of it from db
const ubglMod = weaponMods.find((x) => x.slotId === "mod_launcher"); const ubglMod = weaponMods.find(x => x.slotId === "mod_launcher");
const ubglDbTemplate = this.itemHelper.getItem(ubglMod._tpl)[1]; const ubglDbTemplate = this.itemHelper.getItem(ubglMod._tpl)[1];
// Define min/max of how many grenades bot will have // Define min/max of how many grenades bot will have
const ubglMinMax: GenerationData = { const ubglMinMax: GenerationData = {
// eslint-disable-next-line @typescript-eslint/naming-convention // eslint-disable-next-line @typescript-eslint/naming-convention
weights: { "1": 1, "2": 1 }, weights: { 1: 1, 2: 1 },
whitelist: {}, whitelist: {},
}; };
@ -489,7 +488,7 @@ export class BotWeaponGenerator
ubglAmmoDbTemplate, ubglAmmoDbTemplate,
inventory, inventory,
); );
this.inventoryMagGenComponents.find((v) => v.canHandleInventoryMagGen(ubglAmmoGenModel)).process( this.inventoryMagGenComponents.find(v => v.canHandleInventoryMagGen(ubglAmmoGenModel)).process(
ubglAmmoGenModel, ubglAmmoGenModel,
); );
@ -537,7 +536,7 @@ export class BotWeaponGenerator
botRole: string, botRole: string,
): string ): string
{ {
const magazine = weaponMods.find((m) => m.slotId === this.modMagazineSlotId); const magazine = weaponMods.find(m => m.slotId === this.modMagazineSlotId);
if (!magazine) if (!magazine)
{ {
// Edge case - magazineless chamber loaded weapons dont have magazines, e.g. mp18 // Edge case - magazineless chamber loaded weapons dont have magazines, e.g. mp18
@ -737,8 +736,8 @@ export class BotWeaponGenerator
magazineTemplate: ITemplateItem, magazineTemplate: ITemplateItem,
): void ): void
{ {
const magazineCartridgeChildItem = weaponWithMods.find((m) => const magazineCartridgeChildItem = weaponWithMods.find(m =>
m.parentId === magazine._id && m.slotId === "cartridges" m.parentId === magazine._id && m.slotId === "cartridges",
); );
if (magazineCartridgeChildItem) if (magazineCartridgeChildItem)
{ {
@ -767,7 +766,7 @@ export class BotWeaponGenerator
// for CylinderMagazine we exchange the ammo in the "camoras". // for CylinderMagazine we exchange the ammo in the "camoras".
// This might not be necessary since we already filled the camoras with a random whitelisted and compatible ammo type, // This might not be necessary since we already filled the camoras with a random whitelisted and compatible ammo type,
// but I'm not sure whether this is also used elsewhere // but I'm not sure whether this is also used elsewhere
const camoras = weaponMods.filter((x) => x.parentId === magazineId && x.slotId.startsWith("camora")); const camoras = weaponMods.filter(x => x.parentId === magazineId && x.slotId.startsWith("camora"));
for (const camora of camoras) for (const camora of camoras)
{ {
camora._tpl = ammoTpl; camora._tpl = ammoTpl;

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper"; import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { PresetHelper } from "@spt-aki/helpers/PresetHelper"; import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
@ -50,7 +49,7 @@ export class FenceBaseAssortGenerator
const blockedSeasonalItems = this.seasonalEventService.getInactiveSeasonalEventItems(); const blockedSeasonalItems = this.seasonalEventService.getInactiveSeasonalEventItems();
const baseFenceAssort = this.databaseServer.getTables().traders[Traders.FENCE].assort; const baseFenceAssort = this.databaseServer.getTables().traders[Traders.FENCE].assort;
for (const rootItemDb of this.itemHelper.getItems().filter((item) => this.isValidFenceItem(item))) for (const rootItemDb of this.itemHelper.getItems().filter(item => this.isValidFenceItem(item)))
{ {
// Skip blacklisted items // Skip blacklisted items
if (this.itemFilterService.isItemBlacklisted(rootItemDb._id)) if (this.itemFilterService.isItemBlacklisted(rootItemDb._id))
@ -144,7 +143,7 @@ export class FenceBaseAssortGenerator
for (const defaultPreset of defaultPresets) for (const defaultPreset of defaultPresets)
{ {
// Skip presets we've already added // Skip presets we've already added
if (baseFenceAssort.items.some((item) => item.upd && item.upd.sptPresetId === defaultPreset._id)) if (baseFenceAssort.items.some(item => item.upd && item.upd.sptPresetId === defaultPreset._id))
{ {
continue; continue;
} }
@ -252,7 +251,7 @@ export class FenceBaseAssortGenerator
} }
// Check for and add required soft inserts to armors // Check for and add required soft inserts to armors
const requiredSlots = itemDbDetails._props.Slots.filter((slot) => slot._required); const requiredSlots = itemDbDetails._props.Slots.filter(slot => slot._required);
const hasRequiredSlots = requiredSlots.length > 0; const hasRequiredSlots = requiredSlots.length > 0;
if (hasRequiredSlots) if (hasRequiredSlots)
{ {
@ -284,8 +283,8 @@ export class FenceBaseAssortGenerator
} }
// Check for and add plate items // Check for and add plate items
const plateSlots = itemDbDetails._props.Slots.filter((slot) => const plateSlots = itemDbDetails._props.Slots.filter(slot =>
this.itemHelper.isRemovablePlateSlot(slot._name) this.itemHelper.isRemovablePlateSlot(slot._name),
); );
if (plateSlots.length > 0) if (plateSlots.length > 0)
{ {

View File

@ -1,7 +1,7 @@
export interface IFilterPlateModsForSlotByLevelResult export interface IFilterPlateModsForSlotByLevelResult
{ {
result: Result; result: Result
plateModTpls: string[]; plateModTpls: string[]
} }
export enum Result export enum Result

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ContainerHelper } from "@spt-aki/helpers/ContainerHelper"; import { ContainerHelper } from "@spt-aki/helpers/ContainerHelper";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { PresetHelper } from "@spt-aki/helpers/PresetHelper"; import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
@ -31,17 +30,17 @@ import { ProbabilityObject, ProbabilityObjectArray, RandomUtil } from "@spt-aki/
export interface IContainerItem export interface IContainerItem
{ {
items: Item[]; items: Item[]
width: number; width: number
height: number; height: number
} }
export interface IContainerGroupCount export interface IContainerGroupCount
{ {
/** Containers this group has + probabilty to spawn */ /** Containers this group has + probabilty to spawn */
containerIdsWithProbability: Record<string, number>; containerIdsWithProbability: Record<string, number>
/** How many containers the map should spawn with this group id */ /** How many containers the map should spawn with this group id */
chosenCount: number; chosenCount: number
} }
@injectable() @injectable()
@ -136,7 +135,7 @@ export class LocationGenerator
// Randomisation is turned off globally or just turned off for this map // Randomisation is turned off globally or just turned off for this map
if ( if (
!(this.locationConfig.containerRandomisationSettings.enabled !(this.locationConfig.containerRandomisationSettings.enabled
&& this.locationConfig.containerRandomisationSettings.maps[locationId]) && this.locationConfig.containerRandomisationSettings.maps[locationId])
) )
{ {
this.logger.debug( this.logger.debug(
@ -219,8 +218,8 @@ export class LocationGenerator
for (const chosenContainerId of chosenContainerIds) for (const chosenContainerId of chosenContainerIds)
{ {
// Look up container object from full list of containers on map // Look up container object from full list of containers on map
const containerObject = staticRandomisableContainersOnMap.find((staticContainer) => const containerObject = staticRandomisableContainersOnMap.find(staticContainer =>
staticContainer.template.Id === chosenContainerId staticContainer.template.Id === chosenContainerId,
); );
if (!containerObject) if (!containerObject)
{ {
@ -263,11 +262,11 @@ export class LocationGenerator
*/ */
protected getRandomisableContainersOnMap(staticContainers: IStaticContainerData[]): IStaticContainerData[] protected getRandomisableContainersOnMap(staticContainers: IStaticContainerData[]): IStaticContainerData[]
{ {
return staticContainers.filter((staticContainer) => return staticContainers.filter(staticContainer =>
staticContainer.probability !== 1 && !staticContainer.template.IsAlwaysSpawn staticContainer.probability !== 1 && !staticContainer.template.IsAlwaysSpawn
&& !this.locationConfig.containerRandomisationSettings.containerTypesToNotRandomise.includes( && !this.locationConfig.containerRandomisationSettings.containerTypesToNotRandomise.includes(
staticContainer.template.Items[0]._tpl, staticContainer.template.Items[0]._tpl,
) ),
); );
} }
@ -278,11 +277,11 @@ export class LocationGenerator
*/ */
protected getGuaranteedContainers(staticContainersOnMap: IStaticContainerData[]): IStaticContainerData[] protected getGuaranteedContainers(staticContainersOnMap: IStaticContainerData[]): IStaticContainerData[]
{ {
return staticContainersOnMap.filter((staticContainer) => return staticContainersOnMap.filter(staticContainer =>
staticContainer.probability === 1 || staticContainer.template.IsAlwaysSpawn staticContainer.probability === 1 || staticContainer.template.IsAlwaysSpawn
|| this.locationConfig.containerRandomisationSettings.containerTypesToNotRandomise.includes( || this.locationConfig.containerRandomisationSettings.containerTypesToNotRandomise.includes(
staticContainer.template.Items[0]._tpl, staticContainer.template.Items[0]._tpl,
) ),
); );
} }
@ -339,11 +338,11 @@ export class LocationGenerator
chosenCount: this.randomUtil.getInt( chosenCount: this.randomUtil.getInt(
Math.round( Math.round(
groupData.minContainers groupData.minContainers
* this.locationConfig.containerRandomisationSettings.containerGroupMinSizeMultiplier, * this.locationConfig.containerRandomisationSettings.containerGroupMinSizeMultiplier,
), ),
Math.round( Math.round(
groupData.maxContainers groupData.maxContainers
* this.locationConfig.containerRandomisationSettings.containerGroupMaxSizeMultiplier, * this.locationConfig.containerRandomisationSettings.containerGroupMaxSizeMultiplier,
), ),
), ),
}; };
@ -413,9 +412,9 @@ export class LocationGenerator
const containerLootPool = this.getPossibleLootItemsForContainer(containerTpl, staticLootDist); const containerLootPool = this.getPossibleLootItemsForContainer(containerTpl, staticLootDist);
// Some containers need to have items forced into it (quest keys etc) // Some containers need to have items forced into it (quest keys etc)
const tplsForced = staticForced.filter((forcedStaticProp) => const tplsForced = staticForced.filter(forcedStaticProp =>
forcedStaticProp.containerId === containerClone.template.Id forcedStaticProp.containerId === containerClone.template.Id,
).map((x) => x.itemTpl); ).map(x => x.itemTpl);
// Draw random loot // Draw random loot
// Money spawn more than once in container // Money spawn more than once in container
@ -428,7 +427,7 @@ export class LocationGenerator
itemCountToAdd, itemCountToAdd,
this.locationConfig.allowDuplicateItemsInStaticContainers, this.locationConfig.allowDuplicateItemsInStaticContainers,
locklist, locklist,
).filter((tpl) => !tplsForced.includes(tpl)); ).filter(tpl => !tplsForced.includes(tpl));
// Add forced loot to chosen item pool // Add forced loot to chosen item pool
const tplsToAddToContainer = tplsForced.concat(chosenTpls); const tplsToAddToContainer = tplsForced.concat(chosenTpls);
@ -598,7 +597,7 @@ export class LocationGenerator
// Build the list of forced loot from both `spawnpointsForced` and any point marked `IsAlwaysSpawn` // Build the list of forced loot from both `spawnpointsForced` and any point marked `IsAlwaysSpawn`
dynamicForcedSpawnPoints.push(...dynamicLootDist.spawnpointsForced); dynamicForcedSpawnPoints.push(...dynamicLootDist.spawnpointsForced);
dynamicForcedSpawnPoints.push(...dynamicLootDist.spawnpoints.filter((point) => point.template.IsAlwaysSpawn)); dynamicForcedSpawnPoints.push(...dynamicLootDist.spawnpoints.filter(point => point.template.IsAlwaysSpawn));
// Add forced loot // Add forced loot
this.addForcedLoot(loot, dynamicForcedSpawnPoints, locationName); this.addForcedLoot(loot, dynamicForcedSpawnPoints, locationName);
@ -608,10 +607,10 @@ export class LocationGenerator
// Draw from random distribution // Draw from random distribution
const desiredSpawnpointCount = Math.round( const desiredSpawnpointCount = Math.round(
this.getLooseLootMultiplerForLocation(locationName) this.getLooseLootMultiplerForLocation(locationName)
* this.randomUtil.getNormallyDistributedRandomNumber( * this.randomUtil.getNormallyDistributedRandomNumber(
dynamicLootDist.spawnpointCount.mean, dynamicLootDist.spawnpointCount.mean,
dynamicLootDist.spawnpointCount.std, dynamicLootDist.spawnpointCount.std,
), ),
); );
// Positions not in forced but have 100% chance to spawn // Positions not in forced but have 100% chance to spawn
@ -661,11 +660,11 @@ export class LocationGenerator
// Filter out duplicate locationIds // Filter out duplicate locationIds
chosenSpawnpoints = [ chosenSpawnpoints = [
...new Map(chosenSpawnpoints.map((spawnPoint) => [spawnPoint.locationId, spawnPoint])).values(), ...new Map(chosenSpawnpoints.map(spawnPoint => [spawnPoint.locationId, spawnPoint])).values(),
]; ];
// Do we have enough items in pool to fulfill requirement // Do we have enough items in pool to fulfill requirement
const tooManySpawnPointsRequested = (desiredSpawnpointCount - chosenSpawnpoints.length) > 0; const tooManySpawnPointsRequested = desiredSpawnpointCount - chosenSpawnpoints.length > 0;
if (tooManySpawnPointsRequested) if (tooManySpawnPointsRequested)
{ {
this.logger.debug( this.logger.debug(
@ -705,7 +704,7 @@ export class LocationGenerator
{ {
if ( if (
!seasonalEventActive && seasonalItemTplBlacklist.includes( !seasonalEventActive && seasonalItemTplBlacklist.includes(
spawnPoint.template.Items.find((item) => item._id === itemDist.composedKey.key)._tpl, spawnPoint.template.Items.find(item => item._id === itemDist.composedKey.key)._tpl,
) )
) )
{ {
@ -756,8 +755,8 @@ export class LocationGenerator
for (const itemTpl of lootToForceSingleAmountOnMap) for (const itemTpl of lootToForceSingleAmountOnMap)
{ {
// Get all spawn positions for item tpl in forced loot array // Get all spawn positions for item tpl in forced loot array
const items = forcedSpawnPoints.filter((forcedSpawnPoint) => const items = forcedSpawnPoints.filter(forcedSpawnPoint =>
forcedSpawnPoint.template.Items[0]._tpl === itemTpl forcedSpawnPoint.template.Items[0]._tpl === itemTpl,
); );
if (!items || items.length === 0) if (!items || items.length === 0)
{ {
@ -781,7 +780,7 @@ export class LocationGenerator
// Choose 1 out of all found spawn positions for spawn id and add to loot array // Choose 1 out of all found spawn positions for spawn id and add to loot array
for (const spawnPointLocationId of spawnpointArray.draw(1, false)) for (const spawnPointLocationId of spawnpointArray.draw(1, false))
{ {
const itemToAdd = items.find((item) => item.locationId === spawnPointLocationId); const itemToAdd = items.find(item => item.locationId === spawnPointLocationId);
const lootItem = itemToAdd.template; const lootItem = itemToAdd.template;
lootItem.Root = this.objectId.generate(); lootItem.Root = this.objectId.generate();
lootItem.Items[0]._id = lootItem.Root; lootItem.Items[0]._id = lootItem.Root;
@ -817,8 +816,8 @@ export class LocationGenerator
locationTemplateToAdd.Items[0]._id = locationTemplateToAdd.Root; locationTemplateToAdd.Items[0]._id = locationTemplateToAdd.Root;
// Push forced location into array as long as it doesnt exist already // Push forced location into array as long as it doesnt exist already
const existingLocation = lootLocationTemplates.find((spawnPoint) => const existingLocation = lootLocationTemplates.find(spawnPoint =>
spawnPoint.Id === locationTemplateToAdd.Id spawnPoint.Id === locationTemplateToAdd.Id,
); );
if (!existingLocation) if (!existingLocation)
{ {
@ -846,7 +845,7 @@ export class LocationGenerator
staticAmmoDist: Record<string, IStaticAmmoDetails[]>, staticAmmoDist: Record<string, IStaticAmmoDetails[]>,
): IContainerItem ): IContainerItem
{ {
const chosenItem = spawnPoint.template.Items.find((item) => item._id === chosenComposedKey); const chosenItem = spawnPoint.template.Items.find(item => item._id === chosenComposedKey);
const chosenTpl = chosenItem._tpl; const chosenTpl = chosenItem._tpl;
const itemTemplate = this.itemHelper.getItem(chosenTpl)[1]; const itemTemplate = this.itemHelper.getItem(chosenTpl)[1];
@ -946,10 +945,10 @@ export class LocationGenerator
{ {
if (this.itemHelper.isOfBaseclass(chosenTpl, BaseClasses.WEAPON)) if (this.itemHelper.isOfBaseclass(chosenTpl, BaseClasses.WEAPON))
{ {
return items.find((v) => v._tpl === chosenTpl && v.parentId === undefined); return items.find(v => v._tpl === chosenTpl && v.parentId === undefined);
} }
return items.find((item) => item._tpl === chosenTpl); return items.find(item => item._tpl === chosenTpl);
} }
// TODO: rewrite, BIG yikes // TODO: rewrite, BIG yikes
@ -1053,7 +1052,7 @@ export class LocationGenerator
// it can handle revolver ammo (it's not restructured to be used here yet.) // it can handle revolver ammo (it's not restructured to be used here yet.)
// General: Make a WeaponController for Ragfair preset stuff and the generating weapons and ammo stuff from // General: Make a WeaponController for Ragfair preset stuff and the generating weapons and ammo stuff from
// BotGenerator // BotGenerator
const magazine = items.filter((item) => item.slotId === "mod_magazine")[0]; const magazine = items.filter(item => item.slotId === "mod_magazine")[0];
// some weapon presets come without magazine; only fill the mag if it exists // some weapon presets come without magazine; only fill the mag if it exists
if (magazine) if (magazine)
{ {

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper"; import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { PresetHelper } from "@spt-aki/helpers/PresetHelper"; import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
@ -21,7 +20,7 @@ import { HashUtil } from "@spt-aki/utils/HashUtil";
import { JsonUtil } from "@spt-aki/utils/JsonUtil"; import { JsonUtil } from "@spt-aki/utils/JsonUtil";
import { RandomUtil } from "@spt-aki/utils/RandomUtil"; import { RandomUtil } from "@spt-aki/utils/RandomUtil";
type ItemLimit = { current: number; max: number; }; type ItemLimit = { current: number, max: number };
@injectable() @injectable()
export class LootGenerator export class LootGenerator
@ -74,8 +73,8 @@ export class LootGenerator
if (desiredWeaponCrateCount > 0) if (desiredWeaponCrateCount > 0)
{ {
// Get list of all sealed containers from db // Get list of all sealed containers from db
const sealedWeaponContainerPool = Object.values(tables.templates.items).filter((x) => const sealedWeaponContainerPool = Object.values(tables.templates.items).filter(x =>
x._name.includes("event_container_airdrop") x._name.includes("event_container_airdrop"),
); );
for (let index = 0; index < desiredWeaponCrateCount; index++) for (let index = 0; index < desiredWeaponCrateCount; index++)
@ -92,11 +91,11 @@ export class LootGenerator
} }
// Get items from items.json that have a type of item + not in global blacklist + basetype is in whitelist // Get items from items.json that have a type of item + not in global blacklist + basetype is in whitelist
const items = Object.entries(tables.templates.items).filter((x) => const items = Object.entries(tables.templates.items).filter(x =>
!itemBlacklist.has(x[1]._id) !itemBlacklist.has(x[1]._id)
&& x[1]._type.toLowerCase() === "item" && x[1]._type.toLowerCase() === "item"
&& !x[1]._props.QuestItem && !x[1]._props.QuestItem
&& options.itemTypeWhitelist.includes(x[1]._parent) && options.itemTypeWhitelist.includes(x[1]._parent),
); );
if (items.length > 0) if (items.length > 0)
@ -122,8 +121,8 @@ export class LootGenerator
); );
if (randomisedWeaponPresetCount > 0) if (randomisedWeaponPresetCount > 0)
{ {
const weaponDefaultPresets = globalDefaultPresets.filter((preset) => const weaponDefaultPresets = globalDefaultPresets.filter(preset =>
this.itemHelper.isOfBaseclass(preset._encyclopedia, BaseClasses.WEAPON) this.itemHelper.isOfBaseclass(preset._encyclopedia, BaseClasses.WEAPON),
); );
if (weaponDefaultPresets.length > 0) if (weaponDefaultPresets.length > 0)
@ -153,11 +152,11 @@ export class LootGenerator
); );
if (randomisedArmorPresetCount > 0) if (randomisedArmorPresetCount > 0)
{ {
const armorDefaultPresets = globalDefaultPresets.filter((preset) => const armorDefaultPresets = globalDefaultPresets.filter(preset =>
this.itemHelper.armorItemCanHoldMods(preset._encyclopedia) this.itemHelper.armorItemCanHoldMods(preset._encyclopedia),
); );
const levelFilteredArmorPresets = armorDefaultPresets.filter((armor) => const levelFilteredArmorPresets = armorDefaultPresets.filter(armor =>
this.armorIsDesiredProtectionLevel(armor, options) this.armorIsDesiredProtectionLevel(armor, options),
); );
// Add some armors to rewards // Add some armors to rewards
@ -192,21 +191,21 @@ export class LootGenerator
*/ */
protected armorIsDesiredProtectionLevel(armor: IPreset, options: LootRequest): boolean protected armorIsDesiredProtectionLevel(armor: IPreset, options: LootRequest): boolean
{ {
const frontPlate = armor._items.find((mod) => mod?.slotId?.toLowerCase() === "front_plate"); const frontPlate = armor._items.find(mod => mod?.slotId?.toLowerCase() === "front_plate");
if (frontPlate) if (frontPlate)
{ {
const plateDb = this.itemHelper.getItem(frontPlate._tpl); const plateDb = this.itemHelper.getItem(frontPlate._tpl);
return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any)); return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any));
} }
const helmetTop = armor._items.find((mod) => mod?.slotId?.toLowerCase() === "helmet_top"); const helmetTop = armor._items.find(mod => mod?.slotId?.toLowerCase() === "helmet_top");
if (helmetTop) if (helmetTop)
{ {
const plateDb = this.itemHelper.getItem(helmetTop._tpl); const plateDb = this.itemHelper.getItem(helmetTop._tpl);
return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any)); return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any));
} }
const softArmorFront = armor._items.find((mod) => mod?.slotId?.toLowerCase() === "soft_armor_front"); const softArmorFront = armor._items.find(mod => mod?.slotId?.toLowerCase() === "soft_armor_front");
if (softArmorFront) if (softArmorFront)
{ {
const plateDb = this.itemHelper.getItem(softArmorFront._tpl); const plateDb = this.itemHelper.getItem(softArmorFront._tpl);
@ -242,7 +241,7 @@ export class LootGenerator
*/ */
protected findAndAddRandomItemToLoot( protected findAndAddRandomItemToLoot(
items: [string, ITemplateItem][], items: [string, ITemplateItem][],
itemTypeCounts: Record<string, { current: number; max: number; }>, itemTypeCounts: Record<string, { current: number, max: number }>,
options: LootRequest, options: LootRequest,
result: LootItem[], result: LootItem[],
): boolean ): boolean
@ -317,7 +316,7 @@ export class LootGenerator
*/ */
protected findAndAddRandomPresetToLoot( protected findAndAddRandomPresetToLoot(
presetPool: IPreset[], presetPool: IPreset[],
itemTypeCounts: Record<string, { current: number; max: number; }>, itemTypeCounts: Record<string, { current: number, max: number }>,
itemBlacklist: string[], itemBlacklist: string[],
result: LootItem[], result: LootItem[],
): boolean ): boolean
@ -408,7 +407,7 @@ export class LootGenerator
} }
// Get weapon preset - default or choose a random one from globals.json preset pool // Get weapon preset - default or choose a random one from globals.json preset pool
let chosenWeaponPreset = (containerSettings.defaultPresetsOnly) let chosenWeaponPreset = containerSettings.defaultPresetsOnly
? this.presetHelper.getDefaultPreset(chosenWeaponTpl) ? this.presetHelper.getDefaultPreset(chosenWeaponTpl)
: this.randomUtil.getArrayValue(this.presetHelper.getPresets(chosenWeaponTpl)); : this.randomUtil.getArrayValue(this.presetHelper.getPresets(chosenWeaponTpl));
@ -473,7 +472,7 @@ export class LootGenerator
// Need to find boxes that matches weapons caliber // Need to find boxes that matches weapons caliber
const weaponCaliber = weaponDetailsDb._props.ammoCaliber; const weaponCaliber = weaponDetailsDb._props.ammoCaliber;
const ammoBoxesMatchingCaliber = ammoBoxesDetails.filter((x) => x._props.ammoCaliber === weaponCaliber); const ammoBoxesMatchingCaliber = ammoBoxesDetails.filter(x => x._props.ammoCaliber === weaponCaliber);
if (ammoBoxesMatchingCaliber.length === 0) if (ammoBoxesMatchingCaliber.length === 0)
{ {
this.logger.debug(`No ammo box with caliber ${weaponCaliber} found, skipping`); this.logger.debug(`No ammo box with caliber ${weaponCaliber} found, skipping`);
@ -493,12 +492,12 @@ export class LootGenerator
} }
// Get all items of the desired type + not quest items + not globally blacklisted // Get all items of the desired type + not quest items + not globally blacklisted
const rewardItemPool = Object.values(this.databaseServer.getTables().templates.items).filter((x) => const rewardItemPool = Object.values(this.databaseServer.getTables().templates.items).filter(x =>
x._parent === rewardTypeId x._parent === rewardTypeId
&& x._type.toLowerCase() === "item" && x._type.toLowerCase() === "item"
&& !this.itemFilterService.isItemBlacklisted(x._id) && !this.itemFilterService.isItemBlacklisted(x._id)
&& (!(containerSettings.allowBossItems || this.itemFilterService.isBossItem(x._id))) && !(containerSettings.allowBossItems || this.itemFilterService.isBossItem(x._id))
&& !x._props.QuestItem && !x._props.QuestItem,
); );
if (rewardItemPool.length === 0) if (rewardItemPool.length === 0)
@ -547,8 +546,8 @@ export class LootGenerator
} }
// Get items that fulfil reward type criteria from items that fit on gun // Get items that fulfil reward type criteria from items that fit on gun
const relatedItems = linkedItemsToWeapon.filter((x) => const relatedItems = linkedItemsToWeapon.filter(x =>
x._parent === rewardTypeId && !this.itemFilterService.isItemBlacklisted(x._id) x._parent === rewardTypeId && !this.itemFilterService.isItemBlacklisted(x._id),
); );
if (!relatedItems || relatedItems.length === 0) if (!relatedItems || relatedItems.length === 0)
{ {

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper"; import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem"; import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem";
@ -48,8 +47,8 @@ export class PMCLootGenerator
if (Object.keys(this.pocketLootPool).length === 0) if (Object.keys(this.pocketLootPool).length === 0)
{ {
const items = this.databaseServer.getTables().templates.items; const items = this.databaseServer.getTables().templates.items;
const pmcPriceOverrides = const pmcPriceOverrides
this.databaseServer.getTables().bots.types[botRole === "sptBear" ? "bear" : "usec"].inventory.items = this.databaseServer.getTables().bots.types[botRole === "sptBear" ? "bear" : "usec"].inventory.items
.Pockets; .Pockets;
const allowedItemTypes = this.pmcConfig.pocketLoot.whitelist; const allowedItemTypes = this.pmcConfig.pocketLoot.whitelist;
@ -59,13 +58,13 @@ export class PMCLootGenerator
// Blacklist inactive seasonal items // Blacklist inactive seasonal items
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems()); itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
const itemsToAdd = Object.values(items).filter((item) => const itemsToAdd = Object.values(items).filter(item =>
allowedItemTypes.includes(item._parent) allowedItemTypes.includes(item._parent)
&& this.itemHelper.isValidItem(item._id) && this.itemHelper.isValidItem(item._id)
&& !pmcItemBlacklist.includes(item._id) && !pmcItemBlacklist.includes(item._id)
&& !itemBlacklist.includes(item._id) && !itemBlacklist.includes(item._id)
&& item._props.Width === 1 && item._props.Width === 1
&& item._props.Height === 1 && item._props.Height === 1,
); );
for (const itemToAdd of itemsToAdd) for (const itemToAdd of itemsToAdd)
@ -88,7 +87,7 @@ export class PMCLootGenerator
{ {
// Invert price so cheapest has a larger weight // Invert price so cheapest has a larger weight
// Times by highest price so most expensive item has weight of 1 // Times by highest price so most expensive item has weight of 1
this.pocketLootPool[key] = Math.round((1 / this.pocketLootPool[key]) * highestPrice); this.pocketLootPool[key] = Math.round(1 / this.pocketLootPool[key] * highestPrice);
} }
this.weightedRandomHelper.reduceWeightValues(this.pocketLootPool); this.weightedRandomHelper.reduceWeightValues(this.pocketLootPool);
@ -107,8 +106,8 @@ export class PMCLootGenerator
if (Object.keys(this.vestLootPool).length === 0) if (Object.keys(this.vestLootPool).length === 0)
{ {
const items = this.databaseServer.getTables().templates.items; const items = this.databaseServer.getTables().templates.items;
const pmcPriceOverrides = const pmcPriceOverrides
this.databaseServer.getTables().bots.types[botRole === "sptBear" ? "bear" : "usec"].inventory.items = this.databaseServer.getTables().bots.types[botRole === "sptBear" ? "bear" : "usec"].inventory.items
.TacticalVest; .TacticalVest;
const allowedItemTypes = this.pmcConfig.vestLoot.whitelist; const allowedItemTypes = this.pmcConfig.vestLoot.whitelist;
@ -118,12 +117,12 @@ export class PMCLootGenerator
// Blacklist seasonal items // Blacklist seasonal items
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems()); itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
const itemsToAdd = Object.values(items).filter((item) => const itemsToAdd = Object.values(items).filter(item =>
allowedItemTypes.includes(item._parent) allowedItemTypes.includes(item._parent)
&& this.itemHelper.isValidItem(item._id) && this.itemHelper.isValidItem(item._id)
&& !pmcItemBlacklist.includes(item._id) && !pmcItemBlacklist.includes(item._id)
&& !itemBlacklist.includes(item._id) && !itemBlacklist.includes(item._id)
&& this.itemFitsInto2By2Slot(item) && this.itemFitsInto2By2Slot(item),
); );
for (const itemToAdd of itemsToAdd) for (const itemToAdd of itemsToAdd)
@ -146,7 +145,7 @@ export class PMCLootGenerator
{ {
// Invert price so cheapest has a larger weight // Invert price so cheapest has a larger weight
// Times by highest price so most expensive item has weight of 1 // Times by highest price so most expensive item has weight of 1
this.vestLootPool[key] = Math.round((1 / this.vestLootPool[key]) * highestPrice); this.vestLootPool[key] = Math.round(1 / this.vestLootPool[key] * highestPrice);
} }
this.weightedRandomHelper.reduceWeightValues(this.vestLootPool); this.weightedRandomHelper.reduceWeightValues(this.vestLootPool);
@ -176,8 +175,8 @@ export class PMCLootGenerator
if (Object.keys(this.backpackLootPool).length === 0) if (Object.keys(this.backpackLootPool).length === 0)
{ {
const items = this.databaseServer.getTables().templates.items; const items = this.databaseServer.getTables().templates.items;
const pmcPriceOverrides = const pmcPriceOverrides
this.databaseServer.getTables().bots.types[botRole === "sptBear" ? "bear" : "usec"].inventory.items = this.databaseServer.getTables().bots.types[botRole === "sptBear" ? "bear" : "usec"].inventory.items
.Backpack; .Backpack;
const allowedItemTypes = this.pmcConfig.backpackLoot.whitelist; const allowedItemTypes = this.pmcConfig.backpackLoot.whitelist;
@ -187,11 +186,11 @@ export class PMCLootGenerator
// Blacklist seasonal items // Blacklist seasonal items
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems()); itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
const itemsToAdd = Object.values(items).filter((item) => const itemsToAdd = Object.values(items).filter(item =>
allowedItemTypes.includes(item._parent) allowedItemTypes.includes(item._parent)
&& this.itemHelper.isValidItem(item._id) && this.itemHelper.isValidItem(item._id)
&& !pmcItemBlacklist.includes(item._id) && !pmcItemBlacklist.includes(item._id)
&& !itemBlacklist.includes(item._id) && !itemBlacklist.includes(item._id),
); );
for (const itemToAdd of itemsToAdd) for (const itemToAdd of itemsToAdd)
@ -214,7 +213,7 @@ export class PMCLootGenerator
{ {
// Invert price so cheapest has a larger weight // Invert price so cheapest has a larger weight
// Times by highest price so most expensive item has weight of 1 // Times by highest price so most expensive item has weight of 1
this.backpackLootPool[key] = Math.round((1 / this.backpackLootPool[key]) * highestPrice); this.backpackLootPool[key] = Math.round(1 / this.backpackLootPool[key] * highestPrice);
} }
this.weightedRandomHelper.reduceWeightValues(this.backpackLootPool); this.weightedRandomHelper.reduceWeightValues(this.backpackLootPool);

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { BotGenerator } from "@spt-aki/generators/BotGenerator"; import { BotGenerator } from "@spt-aki/generators/BotGenerator";
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper"; import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
import { BotHelper } from "@spt-aki/helpers/BotHelper"; import { BotHelper } from "@spt-aki/helpers/BotHelper";
@ -310,7 +309,7 @@ export class PlayerScavGenerator
protected getScavLevel(scavProfile: IPmcData): number protected getScavLevel(scavProfile: IPmcData): number
{ {
// Info can be null on initial account creation // Info can be null on initial account creation
if (!(scavProfile.Info?.Level)) if (!scavProfile.Info?.Level)
{ {
return 1; return 1;
} }
@ -321,7 +320,7 @@ export class PlayerScavGenerator
protected getScavExperience(scavProfile: IPmcData): number protected getScavExperience(scavProfile: IPmcData): number
{ {
// Info can be null on initial account creation // Info can be null on initial account creation
if (!(scavProfile.Info?.Experience)) if (!scavProfile.Info?.Experience)
{ {
return 0; return 0;
} }
@ -364,7 +363,7 @@ export class PlayerScavGenerator
scavLockDuration = 10; scavLockDuration = 10;
} }
scavData.Info.SavageLockTime = (Date.now() / 1000) + scavLockDuration; scavData.Info.SavageLockTime = Date.now() / 1000 + scavLockDuration;
return scavData; return scavData;
} }

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { PresetHelper } from "@spt-aki/helpers/PresetHelper"; import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
import { IPreset } from "@spt-aki/models/eft/common/IGlobals"; import { IPreset } from "@spt-aki/models/eft/common/IGlobals";
@ -75,7 +74,7 @@ export class RagfairAssortGenerator
const results: Item[][] = []; const results: Item[][] = [];
/** Get cloned items from db */ /** Get cloned items from db */
const dbItemsClone = this.itemHelper.getItems().filter((item) => item._type !== "Node"); const dbItemsClone = this.itemHelper.getItems().filter(item => item._type !== "Node");
/** Store processed preset tpls so we dont add them when procesing non-preset items */ /** Store processed preset tpls so we dont add them when procesing non-preset items */
const processedArmorItems: string[] = []; const processedArmorItems: string[] = [];
@ -136,7 +135,7 @@ export class RagfairAssortGenerator
*/ */
protected getPresetsToAdd(): IPreset[] protected getPresetsToAdd(): IPreset[]
{ {
return (this.ragfairConfig.dynamic.showDefaultPresetsOnly) return this.ragfairConfig.dynamic.showDefaultPresetsOnly
? Object.values(this.presetHelper.getDefaultPresets()) ? Object.values(this.presetHelper.getDefaultPresets())
: this.presetHelper.getAllPresets(); : this.presetHelper.getAllPresets();
} }

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { RagfairAssortGenerator } from "@spt-aki/generators/RagfairAssortGenerator"; import { RagfairAssortGenerator } from "@spt-aki/generators/RagfairAssortGenerator";
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper"; import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
@ -37,7 +36,7 @@ import { TimeUtil } from "@spt-aki/utils/TimeUtil";
export class RagfairOfferGenerator export class RagfairOfferGenerator
{ {
protected ragfairConfig: IRagfairConfig; protected ragfairConfig: IRagfairConfig;
protected allowedFleaPriceItemsForBarter: { tpl: string; price: number; }[]; protected allowedFleaPriceItemsForBarter: { tpl: string, price: number }[];
/** Internal counter to ensure each offer created has a unique value for its intId property */ /** Internal counter to ensure each offer created has a unique value for its intId property */
protected offerCounter = 0; protected offerCounter = 0;
@ -136,7 +135,7 @@ export class RagfairOfferGenerator
} }
} }
const itemCount = items.filter((x) => x.slotId === "hideout").length; const itemCount = items.filter(x => x.slotId === "hideout").length;
const roublePrice = Math.round(this.convertOfferRequirementsIntoRoubles(offerRequirements)); const roublePrice = Math.round(this.convertOfferRequirementsIntoRoubles(offerRequirements));
const offer: IRagfairOffer = { const offer: IRagfairOffer = {
@ -144,7 +143,7 @@ export class RagfairOfferGenerator
intId: this.offerCounter, intId: this.offerCounter,
user: { user: {
id: this.getTraderId(userID), id: this.getTraderId(userID),
memberType: (userID === "ragfair") memberType: userID === "ragfair"
? MemberCategory.DEFAULT ? MemberCategory.DEFAULT
: this.ragfairServerHelper.getMemberType(userID), : this.ragfairServerHelper.getMemberType(userID),
nickname: this.ragfairServerHelper.getNickname(userID), nickname: this.ragfairServerHelper.getNickname(userID),
@ -297,8 +296,8 @@ export class RagfairOfferGenerator
if (this.ragfairServerHelper.isPlayer(userID)) if (this.ragfairServerHelper.isPlayer(userID))
{ {
// Player offer = current time + offerDurationTimeInHour; // Player offer = current time + offerDurationTimeInHour;
const offerDurationTimeHours = const offerDurationTimeHours
this.databaseServer.getTables().globals.config.RagFair.offerDurationTimeInHour; = this.databaseServer.getTables().globals.config.RagFair.offerDurationTimeInHour;
return this.timeUtil.getTimestamp() + Math.round(offerDurationTimeHours * TimeUtil.ONE_HOUR_AS_SECONDS); return this.timeUtil.getTimestamp() + Math.round(offerDurationTimeHours * TimeUtil.ONE_HOUR_AS_SECONDS);
} }
@ -311,10 +310,10 @@ export class RagfairOfferGenerator
// Generated fake-player offer // Generated fake-player offer
return Math.round( return Math.round(
time time
+ this.randomUtil.getInt( + this.randomUtil.getInt(
this.ragfairConfig.dynamic.endTimeSeconds.min, this.ragfairConfig.dynamic.endTimeSeconds.min,
this.ragfairConfig.dynamic.endTimeSeconds.max, this.ragfairConfig.dynamic.endTimeSeconds.max,
), ),
); );
} }
@ -411,8 +410,8 @@ export class RagfairOfferGenerator
return false; return false;
} }
const plateSlots = presetWithChildren.filter((item) => const plateSlots = presetWithChildren.filter(item =>
this.itemHelper.getRemovablePlateSlotIds().includes(item.slotId?.toLowerCase()) this.itemHelper.getRemovablePlateSlotIds().includes(item.slotId?.toLowerCase()),
); );
if (plateSlots.length === 0) if (plateSlots.length === 0)
{ {
@ -461,12 +460,12 @@ export class RagfairOfferGenerator
const isBarterOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.barter.chancePercent); const isBarterOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.barter.chancePercent);
const isPackOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.pack.chancePercent) const isPackOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.pack.chancePercent)
&& !isBarterOffer && !isBarterOffer
&& itemWithChildren.length === 1 && itemWithChildren.length === 1
&& this.itemHelper.isOfBaseclasses( && this.itemHelper.isOfBaseclasses(
itemWithChildren[0]._tpl, itemWithChildren[0]._tpl,
this.ragfairConfig.dynamic.pack.itemTypeWhitelist, this.ragfairConfig.dynamic.pack.itemTypeWhitelist,
); );
const randomUserId = this.hashUtil.generate(); const randomUserId = this.hashUtil.generate();
@ -478,8 +477,8 @@ export class RagfairOfferGenerator
const shouldRemovePlates = this.randomUtil.getChance100(armorConfig.removeRemovablePlateChance); const shouldRemovePlates = this.randomUtil.getChance100(armorConfig.removeRemovablePlateChance);
if (shouldRemovePlates && this.itemHelper.armorItemHasRemovablePlateSlots(itemWithChildren[0]._tpl)) if (shouldRemovePlates && this.itemHelper.armorItemHasRemovablePlateSlots(itemWithChildren[0]._tpl))
{ {
const offerItemPlatesToRemove = itemWithChildren.filter((item) => const offerItemPlatesToRemove = itemWithChildren.filter(item =>
armorConfig.plateSlotIdToRemovePool.includes(item.slotId?.toLowerCase()) armorConfig.plateSlotIdToRemovePool.includes(item.slotId?.toLowerCase()),
); );
for (const plateItem of offerItemPlatesToRemove) for (const plateItem of offerItemPlatesToRemove)
@ -684,8 +683,8 @@ export class RagfairOfferGenerator
this.randomiseArmorDurabilityValues(itemWithMods, currentMultiplier, maxMultiplier); this.randomiseArmorDurabilityValues(itemWithMods, currentMultiplier, maxMultiplier);
// Add hits to visor // Add hits to visor
const visorMod = itemWithMods.find((item) => const visorMod = itemWithMods.find(item =>
item.parentId === BaseClasses.ARMORED_EQUIPMENT && item.slotId === "mod_equipment_000" item.parentId === BaseClasses.ARMORED_EQUIPMENT && item.slotId === "mod_equipment_000",
); );
if (this.randomUtil.getChance100(25) && visorMod) if (this.randomUtil.getChance100(25) && visorMod)
{ {
@ -717,7 +716,7 @@ export class RagfairOfferGenerator
{ {
// randomize key uses // randomize key uses
rootItem.upd.Key.NumberOfUsages = Math.round(itemDetails._props.MaximumNumberOfUsage * (1 - maxMultiplier)) rootItem.upd.Key.NumberOfUsages = Math.round(itemDetails._props.MaximumNumberOfUsage * (1 - maxMultiplier))
|| 0; || 0;
return; return;
} }
@ -789,12 +788,12 @@ export class RagfairOfferGenerator
for (const armorItem of armorWithMods) for (const armorItem of armorWithMods)
{ {
const itemDbDetails = this.itemHelper.getItem(armorItem._tpl)[1]; const itemDbDetails = this.itemHelper.getItem(armorItem._tpl)[1];
if ((Number.parseInt(<string>itemDbDetails._props.armorClass)) > 1) if (Number.parseInt(<string>itemDbDetails._props.armorClass) > 1)
{ {
this.itemHelper.addUpdObjectToItem(armorItem); this.itemHelper.addUpdObjectToItem(armorItem);
const lowestMaxDurability = this.randomUtil.getFloat(maxMultiplier, 1) const lowestMaxDurability = this.randomUtil.getFloat(maxMultiplier, 1)
* itemDbDetails._props.MaxDurability; * itemDbDetails._props.MaxDurability;
const chosenMaxDurability = Math.round( const chosenMaxDurability = Math.round(
this.randomUtil.getFloat(lowestMaxDurability, itemDbDetails._props.MaxDurability), this.randomUtil.getFloat(lowestMaxDurability, itemDbDetails._props.MaxDurability),
); );
@ -888,9 +887,9 @@ export class RagfairOfferGenerator
const fleaPrices = this.getFleaPricesAsArray(); const fleaPrices = this.getFleaPricesAsArray();
// Filter possible barters to items that match the price range + not itself // Filter possible barters to items that match the price range + not itself
const filtered = fleaPrices.filter((x) => const filtered = fleaPrices.filter(x =>
x.price >= desiredItemCost - offerCostVariance && x.price <= desiredItemCost + offerCostVariance x.price >= desiredItemCost - offerCostVariance && x.price <= desiredItemCost + offerCostVariance
&& x.tpl !== offerItems[0]._tpl && x.tpl !== offerItems[0]._tpl,
); );
// No items on flea have a matching price, fall back to currency // No items on flea have a matching price, fall back to currency
@ -909,7 +908,7 @@ export class RagfairOfferGenerator
* Get an array of flea prices + item tpl, cached in generator class inside `allowedFleaPriceItemsForBarter` * Get an array of flea prices + item tpl, cached in generator class inside `allowedFleaPriceItemsForBarter`
* @returns array with tpl/price values * @returns array with tpl/price values
*/ */
protected getFleaPricesAsArray(): { tpl: string; price: number; }[] protected getFleaPricesAsArray(): { tpl: string, price: number }[]
{ {
// Generate if needed // Generate if needed
if (!this.allowedFleaPriceItemsForBarter) if (!this.allowedFleaPriceItemsForBarter)
@ -918,10 +917,10 @@ export class RagfairOfferGenerator
const fleaArray = Object.entries(fleaPrices).map(([tpl, price]) => ({ tpl: tpl, price: price })); const fleaArray = Object.entries(fleaPrices).map(([tpl, price]) => ({ tpl: tpl, price: price }));
// Only get item prices for items that also exist in items.json // Only get item prices for items that also exist in items.json
const filteredItems = fleaArray.filter((x) => this.itemHelper.getItem(x.tpl)[0]); const filteredItems = fleaArray.filter(x => this.itemHelper.getItem(x.tpl)[0]);
this.allowedFleaPriceItemsForBarter = filteredItems.filter((x) => this.allowedFleaPriceItemsForBarter = filteredItems.filter(x =>
!this.itemHelper.isOfBaseclasses(x.tpl, this.ragfairConfig.dynamic.barter.itemTypeBlacklist) !this.itemHelper.isOfBaseclasses(x.tpl, this.ragfairConfig.dynamic.barter.itemTypeBlacklist),
); );
} }
@ -943,7 +942,7 @@ export class RagfairOfferGenerator
{ {
const currency = this.ragfairServerHelper.getDynamicOfferCurrency(); const currency = this.ragfairServerHelper.getDynamicOfferCurrency();
const price = this.ragfairPriceService.getDynamicOfferPriceForOffer(offerWithChildren, currency, isPackOffer) const price = this.ragfairPriceService.getDynamicOfferPriceForOffer(offerWithChildren, currency, isPackOffer)
* multipler; * multipler;
return [{ count: price, _tpl: currency }]; return [{ count: price, _tpl: currency }];
} }

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { RepeatableQuestRewardGenerator } from "@spt-aki/generators/RepeatableQuestRewardGenerator"; import { RepeatableQuestRewardGenerator } from "@spt-aki/generators/RepeatableQuestRewardGenerator";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { RepeatableQuestHelper } from "@spt-aki/helpers/RepeatableQuestHelper"; import { RepeatableQuestHelper } from "@spt-aki/helpers/RepeatableQuestHelper";
@ -42,7 +41,7 @@ export class RepeatableQuestGenerator
@inject("ObjectId") protected objectId: ObjectId, @inject("ObjectId") protected objectId: ObjectId,
@inject("RepeatableQuestHelper") protected repeatableQuestHelper: RepeatableQuestHelper, @inject("RepeatableQuestHelper") protected repeatableQuestHelper: RepeatableQuestHelper,
@inject("RepeatableQuestRewardGenerator") protected repeatableQuestRewardGenerator: @inject("RepeatableQuestRewardGenerator") protected repeatableQuestRewardGenerator:
RepeatableQuestRewardGenerator, RepeatableQuestRewardGenerator,
@inject("ConfigServer") protected configServer: ConfigServer, @inject("ConfigServer") protected configServer: ConfigServer,
) )
{ {
@ -68,11 +67,11 @@ export class RepeatableQuestGenerator
const questType = this.randomUtil.drawRandomFromList<string>(questTypePool.types)[0]; const questType = this.randomUtil.drawRandomFromList<string>(questTypePool.types)[0];
// get traders from whitelist and filter by quest type availability // get traders from whitelist and filter by quest type availability
let traders = repeatableConfig.traderWhitelist.filter((x) => x.questTypes.includes(questType)).map((x) => let traders = repeatableConfig.traderWhitelist.filter(x => x.questTypes.includes(questType)).map(x =>
x.traderId x.traderId,
); );
// filter out locked traders // filter out locked traders
traders = traders.filter((x) => pmcTraderInfo[x].unlocked); traders = traders.filter(x => pmcTraderInfo[x].unlocked);
const traderId = this.randomUtil.drawRandomFromList(traders)[0]; const traderId = this.randomUtil.drawRandomFromList(traders)[0];
switch (questType) switch (questType)
@ -159,15 +158,15 @@ export class RepeatableQuestGenerator
return Math.sqrt(Math.sqrt(target) + bodyPart + dist + weaponRequirement) * kill; return Math.sqrt(Math.sqrt(target) + bodyPart + dist + weaponRequirement) * kill;
} }
targetsConfig = targetsConfig.filter((x) => targetsConfig = targetsConfig.filter(x =>
Object.keys(questTypePool.pool.Elimination.targets).includes(x.key) Object.keys(questTypePool.pool.Elimination.targets).includes(x.key),
); );
if (targetsConfig.length === 0 || targetsConfig.every((x) => x.data.isBoss)) if (targetsConfig.length === 0 || targetsConfig.every(x => x.data.isBoss))
{ {
// There are no more targets left for elimination; delete it as a possible quest type // There are no more targets left for elimination; delete it as a possible quest type
// also if only bosses are left we need to leave otherwise it's a guaranteed boss elimination // also if only bosses are left we need to leave otherwise it's a guaranteed boss elimination
// -> then it would not be a quest with low probability anymore // -> then it would not be a quest with low probability anymore
questTypePool.types = questTypePool.types.filter((t) => t !== "Elimination"); questTypePool.types = questTypePool.types.filter(t => t !== "Elimination");
return null; return null;
} }
@ -189,12 +188,12 @@ export class RepeatableQuestGenerator
} }
else else
{ {
locations = locations.filter((l) => l !== "any"); locations = locations.filter(l => l !== "any");
if (locations.length > 0) if (locations.length > 0)
{ {
locationKey = this.randomUtil.drawRandomFromList<string>(locations)[0]; locationKey = this.randomUtil.drawRandomFromList<string>(locations)[0];
questTypePool.pool.Elimination.targets[targetKey].locations = locations.filter((l) => questTypePool.pool.Elimination.targets[targetKey].locations = locations.filter(l =>
l !== locationKey l !== locationKey,
); );
if (questTypePool.pool.Elimination.targets[targetKey].locations.length === 0) if (questTypePool.pool.Elimination.targets[targetKey].locations.length === 0)
{ {
@ -239,18 +238,18 @@ export class RepeatableQuestGenerator
if (targetsConfig.data(targetKey).isBoss) if (targetsConfig.data(targetKey).isBoss)
{ {
// Get all boss spawn information // Get all boss spawn information
const bossSpawns = Object.values(this.databaseServer.getTables().locations).filter((x) => const bossSpawns = Object.values(this.databaseServer.getTables().locations).filter(x =>
"base" in x && "Id" in x.base "base" in x && "Id" in x.base,
).map((x) => ({ Id: x.base.Id, BossSpawn: x.base.BossLocationSpawn })); ).map(x => ({ Id: x.base.Id, BossSpawn: x.base.BossLocationSpawn }));
// filter for the current boss to spawn on map // filter for the current boss to spawn on map
const thisBossSpawns = bossSpawns.map((x) => ({ const thisBossSpawns = bossSpawns.map(x => ({
Id: x.Id, Id: x.Id,
BossSpawn: x.BossSpawn.filter((e) => e.BossName === targetKey), BossSpawn: x.BossSpawn.filter(e => e.BossName === targetKey),
})).filter((x) => x.BossSpawn.length > 0); })).filter(x => x.BossSpawn.length > 0);
// remove blacklisted locations // remove blacklisted locations
const allowedSpawns = thisBossSpawns.filter((x) => !eliminationConfig.distLocationBlacklist.includes(x.Id)); const allowedSpawns = thisBossSpawns.filter(x => !eliminationConfig.distLocationBlacklist.includes(x.Id));
// if the boss spawns on nom-blacklisted locations and the current location is allowed we can generate a distance kill requirement // if the boss spawns on nom-blacklisted locations and the current location is allowed we can generate a distance kill requirement
isDistanceRequirementAllowed = isDistanceRequirementAllowed && (allowedSpawns.length > 0); isDistanceRequirementAllowed = isDistanceRequirementAllowed && allowedSpawns.length > 0;
} }
if (eliminationConfig.distProb > Math.random() && isDistanceRequirementAllowed) if (eliminationConfig.distProb > Math.random() && isDistanceRequirementAllowed)
@ -258,7 +257,7 @@ export class RepeatableQuestGenerator
// Random distance with lower values more likely; simple distribution for starters... // Random distance with lower values more likely; simple distribution for starters...
distance = Math.floor( distance = Math.floor(
Math.abs(Math.random() - Math.random()) * (1 + eliminationConfig.maxDist - eliminationConfig.minDist) Math.abs(Math.random() - Math.random()) * (1 + eliminationConfig.maxDist - eliminationConfig.minDist)
+ eliminationConfig.minDist, + eliminationConfig.minDist,
); );
distance = Math.ceil(distance / 5) * 5; distance = Math.ceil(distance / 5) * 5;
distanceDifficulty = maxDistDifficulty * distance / eliminationConfig.maxDist; distanceDifficulty = maxDistDifficulty * distance / eliminationConfig.maxDist;
@ -270,14 +269,14 @@ export class RepeatableQuestGenerator
// Filter out close range weapons from far distance requirement // Filter out close range weapons from far distance requirement
if (distance > 50) if (distance > 50)
{ {
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter((category) => weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter(category =>
["Shotgun", "Pistol"].includes(category.key) ["Shotgun", "Pistol"].includes(category.key),
); );
} }
else if (distance < 20) else if (distance < 20)
{ // Filter out far range weapons from close distance requirement { // Filter out far range weapons from close distance requirement
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter((category) => weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter(category =>
["MarksmanRifle", "DMR"].includes(category.key) ["MarksmanRifle", "DMR"].includes(category.key),
); );
} }
@ -310,7 +309,7 @@ export class RepeatableQuestGenerator
bodyPartDifficulty / maxBodyPartsDifficulty, bodyPartDifficulty / maxBodyPartsDifficulty,
distanceDifficulty / maxDistDifficulty, distanceDifficulty / maxDistDifficulty,
killDifficulty / maxKillDifficulty, killDifficulty / maxKillDifficulty,
(allowedWeaponsCategory || allowedWeapon) ? 1 : 0, allowedWeaponsCategory || allowedWeapon ? 1 : 0,
); );
// Aforementioned issue makes it a bit crazy since now all easier quests give significantly lower rewards than Completion / Exploration // Aforementioned issue makes it a bit crazy since now all easier quests give significantly lower rewards than Completion / Exploration
@ -498,27 +497,27 @@ export class RepeatableQuestGenerator
this.mathUtil.interp1(pmcLevel, levelsConfig, roublesConfig) * this.randomUtil.getFloat(0.5, 1), this.mathUtil.interp1(pmcLevel, levelsConfig, roublesConfig) * this.randomUtil.getFloat(0.5, 1),
); );
roublesBudget = Math.max(roublesBudget, 5000); roublesBudget = Math.max(roublesBudget, 5000);
let itemSelection = possibleItemsToRetrievePool.filter((x) => let itemSelection = possibleItemsToRetrievePool.filter(x =>
this.itemHelper.getItemPrice(x[0]) < roublesBudget this.itemHelper.getItemPrice(x[0]) < roublesBudget,
); );
// We also have the option to use whitelist and/or blacklist which is defined in repeatableQuests.json as // We also have the option to use whitelist and/or blacklist which is defined in repeatableQuests.json as
// [{"minPlayerLevel": 1, "itemIds": ["id1",...]}, {"minPlayerLevel": 15, "itemIds": ["id3",...]}] // [{"minPlayerLevel": 1, "itemIds": ["id1",...]}, {"minPlayerLevel": 15, "itemIds": ["id3",...]}]
if (repeatableConfig.questConfig.Completion.useWhitelist) if (repeatableConfig.questConfig.Completion.useWhitelist)
{ {
const itemWhitelist = const itemWhitelist
this.databaseServer.getTables().templates.repeatableQuests.data.Completion.itemsWhitelist; = this.databaseServer.getTables().templates.repeatableQuests.data.Completion.itemsWhitelist;
// Filter and concatenate the arrays according to current player level // Filter and concatenate the arrays according to current player level
const itemIdsWhitelisted = itemWhitelist.filter((p) => p.minPlayerLevel <= pmcLevel).reduce( const itemIdsWhitelisted = itemWhitelist.filter(p => p.minPlayerLevel <= pmcLevel).reduce(
(a, p) => a.concat(p.itemIds), (a, p) => a.concat(p.itemIds),
[], [],
); );
itemSelection = itemSelection.filter((x) => itemSelection = itemSelection.filter((x) =>
{ {
// Whitelist can contain item tpls and item base type ids // Whitelist can contain item tpls and item base type ids
return (itemIdsWhitelisted.some((v) => this.itemHelper.isOfBaseclass(x[0], v)) return itemIdsWhitelisted.some(v => this.itemHelper.isOfBaseclass(x[0], v))
|| itemIdsWhitelisted.includes(x[0])); || itemIdsWhitelisted.includes(x[0]);
}); });
// check if items are missing // check if items are missing
// const flatList = itemSelection.reduce((a, il) => a.concat(il[0]), []); // const flatList = itemSelection.reduce((a, il) => a.concat(il[0]), []);
@ -527,19 +526,19 @@ export class RepeatableQuestGenerator
if (repeatableConfig.questConfig.Completion.useBlacklist) if (repeatableConfig.questConfig.Completion.useBlacklist)
{ {
const itemBlacklist = const itemBlacklist
this.databaseServer.getTables().templates.repeatableQuests.data.Completion.itemsBlacklist; = this.databaseServer.getTables().templates.repeatableQuests.data.Completion.itemsBlacklist;
// we filter and concatenate the arrays according to current player level // we filter and concatenate the arrays according to current player level
const itemIdsBlacklisted = itemBlacklist.filter((p) => p.minPlayerLevel <= pmcLevel).reduce( const itemIdsBlacklisted = itemBlacklist.filter(p => p.minPlayerLevel <= pmcLevel).reduce(
(a, p) => a.concat(p.itemIds), (a, p) => a.concat(p.itemIds),
[], [],
); );
itemSelection = itemSelection.filter((x) => itemSelection = itemSelection.filter((x) =>
{ {
return itemIdsBlacklisted.every((v) => !this.itemHelper.isOfBaseclass(x[0], v)) return itemIdsBlacklisted.every(v => !this.itemHelper.isOfBaseclass(x[0], v))
|| !itemIdsBlacklisted.includes(x[0]); || !itemIdsBlacklisted.includes(x[0]);
}); });
} }
@ -602,7 +601,7 @@ export class RepeatableQuestGenerator
if (roublesBudget > 0) if (roublesBudget > 0)
{ {
// reduce the list possible items to fulfill the new budget constraint // reduce the list possible items to fulfill the new budget constraint
itemSelection = itemSelection.filter((x) => this.itemHelper.getItemPrice(x[0]) < roublesBudget); itemSelection = itemSelection.filter(x => this.itemHelper.getItemPrice(x[0]) < roublesBudget);
if (itemSelection.length === 0) if (itemSelection.length === 0)
{ {
break; break;
@ -687,13 +686,13 @@ export class RepeatableQuestGenerator
): IRepeatableQuest ): IRepeatableQuest
{ {
const explorationConfig = repeatableConfig.questConfig.Exploration; const explorationConfig = repeatableConfig.questConfig.Exploration;
const requiresSpecificExtract = const requiresSpecificExtract
Math.random() < repeatableConfig.questConfig.Exploration.specificExits.probability; = Math.random() < repeatableConfig.questConfig.Exploration.specificExits.probability;
if (Object.keys(questTypePool.pool.Exploration.locations).length === 0) if (Object.keys(questTypePool.pool.Exploration.locations).length === 0)
{ {
// there are no more locations left for exploration; delete it as a possible quest type // there are no more locations left for exploration; delete it as a possible quest type
questTypePool.types = questTypePool.types.filter((t) => t !== "Exploration"); questTypePool.types = questTypePool.types.filter(t => t !== "Exploration");
return null; return null;
} }
@ -738,15 +737,13 @@ export class RepeatableQuestGenerator
const mapExits = this.getLocationExitsForSide(locationKey, repeatableConfig.side); const mapExits = this.getLocationExitsForSide(locationKey, repeatableConfig.side);
// Only get exits that have a greater than 0% chance to spawn // Only get exits that have a greater than 0% chance to spawn
const exitPool = mapExits.filter((exit) => exit.Chance > 0); const exitPool = mapExits.filter(exit => exit.Chance > 0);
// Exclude exits with a requirement to leave (e.g. car extracts) // Exclude exits with a requirement to leave (e.g. car extracts)
const possibleExits = exitPool.filter(( const possibleExits = exitPool.filter(exit => !("PassageRequirement" in exit)
exit, || repeatableConfig.questConfig.Exploration.specificExits.passageRequirementWhitelist.includes(
) => (!("PassageRequirement" in exit) exit.PassageRequirement,
|| repeatableConfig.questConfig.Exploration.specificExits.passageRequirementWhitelist.includes( ),
exit.PassageRequirement,
))
); );
if (possibleExits.length === 0) if (possibleExits.length === 0)
@ -791,7 +788,7 @@ export class RepeatableQuestGenerator
const mapExtracts = this.databaseServer.getTables().locations[locationKey.toLocaleLowerCase()] const mapExtracts = this.databaseServer.getTables().locations[locationKey.toLocaleLowerCase()]
.allExtracts as Exit[]; .allExtracts as Exit[];
return mapExtracts.filter((exit) => exit.Side === playerSide); return mapExtracts.filter(exit => exit.Side === playerSide);
} }
protected generatePickupQuest( protected generatePickupQuest(
@ -814,18 +811,18 @@ export class RepeatableQuestGenerator
// const locationKey: string = this.randomUtil.drawRandomFromDict(questTypePool.pool.Pickup.locations)[0]; // const locationKey: string = this.randomUtil.drawRandomFromDict(questTypePool.pool.Pickup.locations)[0];
// const locationTarget = questTypePool.pool.Pickup.locations[locationKey]; // const locationTarget = questTypePool.pool.Pickup.locations[locationKey];
const findCondition = quest.conditions.AvailableForFinish.find((x) => x.conditionType === "FindItem"); const findCondition = quest.conditions.AvailableForFinish.find(x => x.conditionType === "FindItem");
findCondition.target = [itemTypeToFetchWithCount.itemType]; findCondition.target = [itemTypeToFetchWithCount.itemType];
findCondition.value = itemCountToFetch; findCondition.value = itemCountToFetch;
const counterCreatorCondition = quest.conditions.AvailableForFinish.find((x) => const counterCreatorCondition = quest.conditions.AvailableForFinish.find(x =>
x.conditionType === "CounterCreator" x.conditionType === "CounterCreator",
); );
// const locationCondition = counterCreatorCondition._props.counter.conditions.find(x => x._parent === "Location"); // const locationCondition = counterCreatorCondition._props.counter.conditions.find(x => x._parent === "Location");
// (locationCondition._props as ILocationConditionProps).target = [...locationTarget]; // (locationCondition._props as ILocationConditionProps).target = [...locationTarget];
const equipmentCondition = counterCreatorCondition.counter.conditions.find((x) => const equipmentCondition = counterCreatorCondition.counter.conditions.find(x =>
x.conditionType === "Equipment" x.conditionType === "Equipment",
); );
equipmentCondition.equipmentInclusive = [[itemTypeToFetchWithCount.itemType]]; equipmentCondition.equipmentInclusive = [[itemTypeToFetchWithCount.itemType]];

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper"; import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { PresetHelper } from "@spt-aki/helpers/PresetHelper"; import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
@ -96,20 +95,20 @@ export class RepeatableQuestRewardGenerator
// rewards are generated based on pmcLevel, difficulty and a random spread // rewards are generated based on pmcLevel, difficulty and a random spread
const rewardXP = Math.floor( const rewardXP = Math.floor(
effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, xpConfig) effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, xpConfig)
* this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig), * this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig),
); );
const rewardRoubles = Math.floor( const rewardRoubles = Math.floor(
effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, roublesConfig) effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, roublesConfig)
* this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig), * this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig),
); );
const rewardNumItems = this.randomUtil.randInt( const rewardNumItems = this.randomUtil.randInt(
1, 1,
Math.round(this.mathUtil.interp1(pmcLevel, levelsConfig, itemsConfig)) + 1, Math.round(this.mathUtil.interp1(pmcLevel, levelsConfig, itemsConfig)) + 1,
); );
const rewardReputation = const rewardReputation
Math.round( = Math.round(
100 * effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, reputationConfig) 100 * effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, reputationConfig)
* this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig), * this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig),
) / 100; ) / 100;
const skillRewardChance = this.mathUtil.interp1(pmcLevel, levelsConfig, skillRewardChanceConfig); const skillRewardChance = this.mathUtil.interp1(pmcLevel, levelsConfig, skillRewardChanceConfig);
const skillPointReward = this.mathUtil.interp1(pmcLevel, levelsConfig, skillPointRewardConfig); const skillPointReward = this.mathUtil.interp1(pmcLevel, levelsConfig, skillPointRewardConfig);
@ -135,7 +134,7 @@ export class RepeatableQuestRewardGenerator
this.addMoneyReward(traderId, rewards, rewardRoubles, rewardIndex); this.addMoneyReward(traderId, rewards, rewardRoubles, rewardIndex);
rewardIndex++; rewardIndex++;
const traderWhitelistDetails = repeatableConfig.traderWhitelist.find((x) => x.traderId === traderId); const traderWhitelistDetails = repeatableConfig.traderWhitelist.find(x => x.traderId === traderId);
if ( if (
traderWhitelistDetails.rewardCanBeWeapon traderWhitelistDetails.rewardCanBeWeapon
&& this.randomUtil.getChance100(traderWhitelistDetails.weaponRewardChancePercent) && this.randomUtil.getChance100(traderWhitelistDetails.weaponRewardChancePercent)
@ -151,7 +150,7 @@ export class RepeatableQuestRewardGenerator
while (defaultPresetPool.hasValues()) while (defaultPresetPool.hasValues())
{ {
const randomPreset = defaultPresetPool.getRandomValue(); const randomPreset = defaultPresetPool.getRandomValue();
const tpls = randomPreset._items.map((item) => item._tpl); const tpls = randomPreset._items.map(item => item._tpl);
const presetPrice = this.itemHelper.getItemAndChildrenPrice(tpls); const presetPrice = this.itemHelper.getItemAndChildrenPrice(tpls);
if (presetPrice <= roublesBudget) if (presetPrice <= roublesBudget)
{ {
@ -309,13 +308,13 @@ export class RepeatableQuestRewardGenerator
protected canIncreaseRewardItemStackSize(item: ITemplateItem, maxRoublePriceToStack: number): boolean protected canIncreaseRewardItemStackSize(item: ITemplateItem, maxRoublePriceToStack: number): boolean
{ {
return this.presetHelper.getDefaultPresetOrItemPrice(item._id) < maxRoublePriceToStack return this.presetHelper.getDefaultPresetOrItemPrice(item._id) < maxRoublePriceToStack
&& !this.itemHelper.isOfBaseclasses(item._id, [ && !this.itemHelper.isOfBaseclasses(item._id, [
BaseClasses.WEAPON, BaseClasses.WEAPON,
BaseClasses.ARMORED_EQUIPMENT, BaseClasses.ARMORED_EQUIPMENT,
BaseClasses.AMMO, BaseClasses.AMMO,
]) ])
&& !this.itemHelper.itemRequiresSoftInserts(item._id) && !this.itemHelper.itemRequiresSoftInserts(item._id)
&& this.randomUtil.getChance100(25); && this.randomUtil.getChance100(25);
} }
protected calculateAmmoStackSizeThatFitsBudget( protected calculateAmmoStackSizeThatFitsBudget(
@ -355,7 +354,7 @@ export class RepeatableQuestRewardGenerator
const rewardableItemPool = this.getRewardableItems(repeatableConfig, traderId); const rewardableItemPool = this.getRewardableItems(repeatableConfig, traderId);
const minPrice = Math.min(25000, 0.5 * roublesBudget); const minPrice = Math.min(25000, 0.5 * roublesBudget);
let rewardableItemPoolWithinBudget = rewardableItemPool.map((x) => x[1]); let rewardableItemPoolWithinBudget = rewardableItemPool.map(x => x[1]);
rewardableItemPoolWithinBudget = this.filterRewardPoolWithinBudget( rewardableItemPoolWithinBudget = this.filterRewardPoolWithinBudget(
rewardableItemPoolWithinBudget, rewardableItemPoolWithinBudget,
roublesBudget, roublesBudget,
@ -370,9 +369,9 @@ export class RepeatableQuestRewardGenerator
}), }),
); );
// In case we don't find any items in the price range // In case we don't find any items in the price range
rewardableItemPoolWithinBudget = rewardableItemPool.filter((x) => rewardableItemPoolWithinBudget = rewardableItemPool.filter(x =>
this.itemHelper.getItemPrice(x[0]) < roublesBudget this.itemHelper.getItemPrice(x[0]) < roublesBudget,
).map((x) => x[1]); ).map(x => x[1]);
} }
return rewardableItemPoolWithinBudget; return rewardableItemPoolWithinBudget;
@ -393,7 +392,7 @@ export class RepeatableQuestRewardGenerator
if (preset) if (preset)
{ {
const rootItem = preset.find((x) => x._tpl === tpl); const rootItem = preset.find(x => x._tpl === tpl);
rewardItem.items = this.itemHelper.reparentItemAndChildren(rootItem, preset); rewardItem.items = this.itemHelper.reparentItemAndChildren(rootItem, preset);
rewardItem.target = rootItem._id; // Target property and root items id must match rewardItem.target = rootItem._id; // Target property and root items id must match
} }
@ -436,8 +435,8 @@ export class RepeatableQuestRewardGenerator
return false; return false;
} }
const traderWhitelist = repeatableQuestConfig.traderWhitelist.find((trader) => const traderWhitelist = repeatableQuestConfig.traderWhitelist.find(trader =>
trader.traderId === traderId trader.traderId === traderId,
); );
return this.isValidRewardItem(tpl, repeatableQuestConfig, traderWhitelist?.rewardBaseWhitelist); return this.isValidRewardItem(tpl, repeatableQuestConfig, traderWhitelist?.rewardBaseWhitelist);
}, },

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { PresetHelper } from "@spt-aki/helpers/PresetHelper"; import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
import { Product } from "@spt-aki/models/eft/common/tables/IBotBase"; import { Product } from "@spt-aki/models/eft/common/tables/IBotBase";
@ -61,7 +60,7 @@ export class ScavCaseRewardGenerator
this.cacheDbItems(); this.cacheDbItems();
// Get scavcase details from hideout/scavcase.json // Get scavcase details from hideout/scavcase.json
const scavCaseDetails = this.databaseServer.getTables().hideout.scavcase.find((r) => r._id === recipeId); const scavCaseDetails = this.databaseServer.getTables().hideout.scavcase.find(r => r._id === recipeId);
const rewardItemCounts = this.getScavCaseRewardCountsAndPrices(scavCaseDetails); const rewardItemCounts = this.getScavCaseRewardCountsAndPrices(scavCaseDetails);
// Get items that fit the price criteria as set by the scavCase config // Get items that fit the price criteria as set by the scavCase config
@ -122,7 +121,7 @@ export class ScavCaseRewardGenerator
// Skip item if item id is on blacklist // Skip item if item id is on blacklist
if ( if (
(item._type !== "Item") item._type !== "Item"
|| this.scavCaseConfig.rewardItemBlacklist.includes(item._id) || this.scavCaseConfig.rewardItemBlacklist.includes(item._id)
|| this.itemFilterService.isItemBlacklisted(item._id) || this.itemFilterService.isItemBlacklisted(item._id)
) )

View File

@ -1,5 +1,4 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ApplicationContext } from "@spt-aki/context/ApplicationContext"; import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
import { ContextVariableType } from "@spt-aki/context/ContextVariableType"; import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper"; import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
@ -78,10 +77,10 @@ export class WeatherGenerator
public getInRaidTime(): Date public getInRaidTime(): Date
{ {
// tarkov time = (real time * 7 % 24 hr) + 3 hour // tarkov time = (real time * 7 % 24 hr) + 3 hour
const russiaOffset = (this.timeUtil.getHoursAsSeconds(3)) * 1000; const russiaOffset = this.timeUtil.getHoursAsSeconds(3) * 1000;
return new Date( return new Date(
(russiaOffset + (new Date().getTime() * this.weatherConfig.acceleration)) (russiaOffset + new Date().getTime() * this.weatherConfig.acceleration)
% (this.timeUtil.getHoursAsSeconds(24) * 1000), % (this.timeUtil.getHoursAsSeconds(24) * 1000),
); );
} }
@ -109,7 +108,7 @@ export class WeatherGenerator
wind_direction: this.getWeightedWindDirection(), wind_direction: this.getWeightedWindDirection(),
wind_gustiness: this.getRandomFloat("windGustiness"), wind_gustiness: this.getRandomFloat("windGustiness"),
rain: rain, rain: rain,
rain_intensity: (rain > 1) ? this.getRandomFloat("rainIntensity") : 0, rain_intensity: rain > 1 ? this.getRandomFloat("rainIntensity") : 0,
fog: this.getWeightedFog(), fog: this.getWeightedFog(),
temp: this.getRandomFloat("temp"), temp: this.getRandomFloat("temp"),
pressure: this.getRandomFloat("pressure"), pressure: this.getRandomFloat("pressure"),

Some files were not shown because too many files have changed in this diff Show More