diff --git a/.gitea/workflows/run-lint.yaml b/.gitea/workflows/run-lint.yaml new file mode 100644 index 00000000..2891f190 --- /dev/null +++ b/.gitea/workflows/run-lint.yaml @@ -0,0 +1,58 @@ +name: Run Code Linter + +on: + push: + branches: '*' + pull_request: + branches: '*' + +jobs: + biome: + 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/SPT-AKI/Server.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: Run Linter + id: run-tests + run: | + cd /workspace/SPT-AKI/Build/server/project + npm run lint + shell: bash + + - name: Fix Instructions + if: failure() && steps.run-tests.outcome == 'failure' + 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 "Consistency is professionalism.™" + shell: bash diff --git a/.gitea/workflows/run-style.yaml b/.gitea/workflows/run-style.yaml new file mode 100644 index 00000000..4a5a24ab --- /dev/null +++ b/.gitea/workflows/run-style.yaml @@ -0,0 +1,59 @@ +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/SPT-AKI/Server.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 diff --git a/.gitea/workflows/run-test.yaml b/.gitea/workflows/run-test.yaml new file mode 100644 index 00000000..73a51cf7 --- /dev/null +++ b/.gitea/workflows/run-test.yaml @@ -0,0 +1,58 @@ +name: Run Tests + +on: + push: + branches: '*' + pull_request: + branches: '*' + +jobs: + vitest: + 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/SPT-AKI/Server.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: Run Tests + id: run-tests + run: | + cd /workspace/SPT-AKI/Build/server/project + npm run test + shell: bash + + - name: Fix Instructions + if: failure() && steps.run-tests.outcome == 'failure' + run: | + echo -e "Automated tests have failed. This could point to an issue with the commited code, or an updated test that has yet to be updated. Please look into resolving these test failures. The testing suite has a GUI to aid in writing tests. You can launch this by running the following command from within the 'project' directory.\n\nnpm run test:ui\n" + echo -e "A test written today is a bug prevented tomorrow.™" + shell: bash diff --git a/project/assets/configs/bot.json b/project/assets/configs/bot.json index e70d2471..b7e78f0c 100644 --- a/project/assets/configs/bot.json +++ b/project/assets/configs/bot.json @@ -324,7 +324,9 @@ "5d08d21286f774736e7c94c3": 1, "5c94bbff86f7747ee735c08f": 1 }, - "bosssanitar": {}, + "bosssanitar": { + "5efde6b4f5448336730dbd61": 1 + }, "bosstagilla": {}, "bossknight": {}, "bosszryachiy": {}, @@ -387,8 +389,12 @@ "pmcbot": { "60098ad7c2240c0fe85c570a": 2 }, - "arenafighterevent": {}, - "arenafighter": {}, + "arenafighterevent": { + "5734758f24597738025ee253": 1 + }, + "arenafighter": { + "5734758f24597738025ee253": 1 + }, "crazyassaultevent": {}, "assaultgroup": {}, "gifter": {}, diff --git a/project/assets/configs/core.json b/project/assets/configs/core.json index a57d01c0..8becd0be 100644 --- a/project/assets/configs/core.json +++ b/project/assets/configs/core.json @@ -5,6 +5,7 @@ "serverName": "SPT Server", "profileSaveIntervalSeconds": 15, "sptFriendNickname": "SPT", + "allowProfileWipe": true, "bsgLogging": { "verbosity": 6, "sendToServer": false diff --git a/project/assets/configs/hideout.json b/project/assets/configs/hideout.json index b5e229f9..b28f446e 100644 --- a/project/assets/configs/hideout.json +++ b/project/assets/configs/hideout.json @@ -1,9 +1,12 @@ { "runIntervalSeconds": 10, "hoursForSkillCrafting": 28800, - "runIntervalValues": { + "runIntervalValues": { "inRaid": 60, "outOfRaid": 10 }, - "expCraftAmount": 10 + "expCraftAmount": 10, + "overrideCraftTimeSeconds": -1, + "overrideBuildTimeSeconds": -1, + "updateProfileHideoutWhenActiveWithinMinutes": 90 } \ No newline at end of file diff --git a/project/assets/configs/http.json b/project/assets/configs/http.json index 97892786..a6defa80 100644 --- a/project/assets/configs/http.json +++ b/project/assets/configs/http.json @@ -1,6 +1,8 @@ { "ip": "127.0.0.1", "port": 6969, + "backendIp": "127.0.0.1", + "backendPort": 6969, "webSocketPingDelayMs": 90000, "logRequests": true, "serverImagePathOverride": {} diff --git a/project/assets/configs/inraid.json b/project/assets/configs/inraid.json index 5bbe48cc..97085b3d 100644 --- a/project/assets/configs/inraid.json +++ b/project/assets/configs/inraid.json @@ -11,8 +11,7 @@ "randomTime": false }, "save": { - "loot": true, - "durability": true + "loot": true }, "carExtracts": [ "Dorms V-Ex", diff --git a/project/assets/configs/item.json b/project/assets/configs/item.json index 40845135..584aa85a 100644 --- a/project/assets/configs/item.json +++ b/project/assets/configs/item.json @@ -50,6 +50,7 @@ "5580239d4bdc2de7118b4583" ], "rewardItemBlacklist": [ + "58ac60eb86f77401897560ff", "5e997f0b86f7741ac73993e2", "5b44abe986f774283e2e3512", "5e99711486f7744bfc4af328", diff --git a/project/assets/configs/location.json b/project/assets/configs/location.json index 9308a5c8..e518d8c7 100644 --- a/project/assets/configs/location.json +++ b/project/assets/configs/location.json @@ -1146,6 +1146,7 @@ "minFillStaticMagazinePercent": 50, "allowDuplicateItemsInStaticContainers": true, "magazineLootHasAmmoChancePercent": 50, + "staticMagazineLootHasAmmoChancePercent": 0, "looseLootBlacklist": {}, "scavRaidTimeSettings": { "settings": { diff --git a/project/assets/configs/trader.json b/project/assets/configs/trader.json index 2144725a..7a2e57ec 100644 --- a/project/assets/configs/trader.json +++ b/project/assets/configs/trader.json @@ -157,7 +157,7 @@ "543be6564bdc2df4348b4568": 0, "5448ecbe4bdc2d60728b4568": 0, "5671435f4bdc2d96058b4569": 0, - "543be5cb4bdc2deb348b4568": 3, + "543be5cb4bdc2deb348b4568": 5, "5448e53e4bdc2d60728b4567": 7 }, "preventDuplicateOffersOfCategory": [ @@ -319,6 +319,7 @@ "left_side_plate": 75, "right_side_plate": 75 }, + "ammoMaxPenLimit": 20, "blacklistSeasonalItems": true, "blacklist": [ "5c164d2286f774194c5e69fa", @@ -342,7 +343,8 @@ "5a341c4086f77401f2541505", "5422acb9af1c889c16000029", "64d0b40fbe2eed70e254e2d4", - "5fc22d7c187fea44d52eda44" + "5fc22d7c187fea44d52eda44", + "646372518610c40fc20204e8" ], "coopExtractGift": { "sendGift": true, @@ -351,7 +353,11 @@ "5da89b3a86f7742f9026cb83 0" ], "giftExpiryHours": 168, - "presetCount": { + "weaponPresetCount": { + "min": 0, + "max": 0 + }, + "armorPresetCount": { "min": 0, "max": 0 }, @@ -423,4 +429,4 @@ }, "btrDeliveryExpireHours": 240 } -} \ No newline at end of file +} diff --git a/project/assets/database/bots/types/arenafighterevent.json b/project/assets/database/bots/types/arenafighterevent.json index 93f77a42..2feae98d 100644 --- a/project/assets/database/bots/types/arenafighterevent.json +++ b/project/assets/database/bots/types/arenafighterevent.json @@ -2110,6 +2110,22 @@ "2": 0 }, "whitelist": [] + }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] }, "grenades": { "weights": { diff --git a/project/assets/database/bots/types/assault.json b/project/assets/database/bots/types/assault.json index 78393ef7..010bc214 100644 --- a/project/assets/database/bots/types/assault.json +++ b/project/assets/database/bots/types/assault.json @@ -2347,6 +2347,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 30, @@ -2355,6 +2363,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 8, diff --git a/project/assets/database/bots/types/bear.json b/project/assets/database/bots/types/bear.json index c3707080..e30473de 100644 --- a/project/assets/database/bots/types/bear.json +++ b/project/assets/database/bots/types/bear.json @@ -2188,7 +2188,7 @@ "Basuro", "Bepis", "Baliston", - "Pessin", + "Crow", "Aki-chan", "Fin", "Gatsu66", @@ -2481,9 +2481,11 @@ "Brin", "Belette", "Agnotology", - "All_Heil_Lord_Ppepe", - "ixcetotis", - "btdc00" + "All_Heil_Lord_Pepe", + "ixcetotis", + "btdc00", + "Bnuy", + "Choccy" ], "generation": { "items": { @@ -2508,11 +2510,27 @@ "2": 1 }, "whitelist": [] + }, + "food": { + "weights": { + "0": 6, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, + "drink": { + "weights": { + "0": 6, + "1": 5, + "2": 1 + }, + "whitelist": [] }, "grenades": { "weights": { - "0": 1, - "1": 4, + "0": 2, + "1": 6, "2": 5, "3": 2, "4": 1 @@ -2988,9 +3006,9 @@ "5ac66d9b5acfc4001633997a": 5, "5ae08f0a5acfc408fb1398a1": 4, "5b0bbe4e5acfc40dc528a72d": 4, - "5ba26383d4351e00334c93d9": 5, + "5ba26383d4351e00334c93d9": 4, "5bb2475ed4351e00853264e3": 4, - "5bd70322209c4d00d7167b8f": 5, + "5bd70322209c4d00d7167b8f": 4, "5beed0f50db834001c062b12": 3, "5bf3e03b0db834001d2c4a9c": 5, "5bf3e0490db83400196199af": 5, diff --git a/project/assets/database/bots/types/bossboar.json b/project/assets/database/bots/types/bossboar.json index 0c193649..9e9275a2 100644 --- a/project/assets/database/bots/types/bossboar.json +++ b/project/assets/database/bots/types/bossboar.json @@ -2302,6 +2302,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2310,6 +2318,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/bossboarsniper.json b/project/assets/database/bots/types/bossboarsniper.json index 2edd63cb..f68d230d 100644 --- a/project/assets/database/bots/types/bossboarsniper.json +++ b/project/assets/database/bots/types/bossboarsniper.json @@ -2038,6 +2038,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2046,6 +2054,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/bossbully.json b/project/assets/database/bots/types/bossbully.json index 83ebfb9d..ef295a8b 100644 --- a/project/assets/database/bots/types/bossbully.json +++ b/project/assets/database/bots/types/bossbully.json @@ -2029,6 +2029,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2036,6 +2044,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/bossgluhar.json b/project/assets/database/bots/types/bossgluhar.json index 9ea7ff2d..d272f56b 100644 --- a/project/assets/database/bots/types/bossgluhar.json +++ b/project/assets/database/bots/types/bossgluhar.json @@ -2317,6 +2317,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2324,6 +2332,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/bosskilla.json b/project/assets/database/bots/types/bosskilla.json index 75d0547e..bc2eed39 100644 --- a/project/assets/database/bots/types/bosskilla.json +++ b/project/assets/database/bots/types/bosskilla.json @@ -2019,6 +2019,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2026,6 +2034,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/bossknight.json b/project/assets/database/bots/types/bossknight.json index 764cc833..94da417b 100644 --- a/project/assets/database/bots/types/bossknight.json +++ b/project/assets/database/bots/types/bossknight.json @@ -2167,6 +2167,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2175,6 +2183,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/bosskojaniy.json b/project/assets/database/bots/types/bosskojaniy.json index 80888a6b..507f96e9 100644 --- a/project/assets/database/bots/types/bosskojaniy.json +++ b/project/assets/database/bots/types/bosskojaniy.json @@ -2070,6 +2070,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2078,6 +2086,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/bosskolontay.json b/project/assets/database/bots/types/bosskolontay.json index c2da4729..bc63f661 100644 --- a/project/assets/database/bots/types/bosskolontay.json +++ b/project/assets/database/bots/types/bosskolontay.json @@ -2322,6 +2322,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2330,6 +2338,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/bosssanitar.json b/project/assets/database/bots/types/bosssanitar.json index 46b5e082..aef86e92 100644 --- a/project/assets/database/bots/types/bosssanitar.json +++ b/project/assets/database/bots/types/bosssanitar.json @@ -2114,6 +2114,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2122,6 +2130,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/bosstagilla.json b/project/assets/database/bots/types/bosstagilla.json index 0ec8b5cf..29aff717 100644 --- a/project/assets/database/bots/types/bosstagilla.json +++ b/project/assets/database/bots/types/bosstagilla.json @@ -2113,6 +2113,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2121,6 +2129,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/bosstest.json b/project/assets/database/bots/types/bosstest.json index e065fa11..42e2e553 100644 --- a/project/assets/database/bots/types/bosstest.json +++ b/project/assets/database/bots/types/bosstest.json @@ -1946,6 +1946,22 @@ "healing": { "max": 2, "min": 1 + }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] }, "looseLoot": { "max": 3, diff --git a/project/assets/database/bots/types/bosszryachiy.json b/project/assets/database/bots/types/bosszryachiy.json index 36df4eb2..9726cbd5 100644 --- a/project/assets/database/bots/types/bosszryachiy.json +++ b/project/assets/database/bots/types/bosszryachiy.json @@ -2024,6 +2024,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2032,6 +2040,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/crazyassaultevent.json b/project/assets/database/bots/types/crazyassaultevent.json index a83d5f67..760544df 100644 --- a/project/assets/database/bots/types/crazyassaultevent.json +++ b/project/assets/database/bots/types/crazyassaultevent.json @@ -2365,6 +2365,22 @@ "2": 0 }, "whitelist": [] + }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] }, "grenades": { "weights": { diff --git a/project/assets/database/bots/types/cursedassault.json b/project/assets/database/bots/types/cursedassault.json index a8bbbba4..c747193a 100644 --- a/project/assets/database/bots/types/cursedassault.json +++ b/project/assets/database/bots/types/cursedassault.json @@ -2391,6 +2391,22 @@ "2": 0 }, "whitelist": [] + }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] }, "grenades": { "weights": { diff --git a/project/assets/database/bots/types/exusec.json b/project/assets/database/bots/types/exusec.json index c2c3d2a1..74d5ac3a 100644 --- a/project/assets/database/bots/types/exusec.json +++ b/project/assets/database/bots/types/exusec.json @@ -2254,6 +2254,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2261,6 +2269,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/followerbigpipe.json b/project/assets/database/bots/types/followerbigpipe.json index e71353f4..8f3a4ad0 100644 --- a/project/assets/database/bots/types/followerbigpipe.json +++ b/project/assets/database/bots/types/followerbigpipe.json @@ -2053,6 +2053,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2061,6 +2069,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/followerbirdeye.json b/project/assets/database/bots/types/followerbirdeye.json index e8c3893a..193ed57b 100644 --- a/project/assets/database/bots/types/followerbirdeye.json +++ b/project/assets/database/bots/types/followerbirdeye.json @@ -2085,6 +2085,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2093,6 +2101,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/followerboar.json b/project/assets/database/bots/types/followerboar.json index f0901c0a..0052c387 100644 --- a/project/assets/database/bots/types/followerboar.json +++ b/project/assets/database/bots/types/followerboar.json @@ -2253,6 +2253,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 9, @@ -2263,6 +2271,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/followerboarclose1.json b/project/assets/database/bots/types/followerboarclose1.json index e63103ff..823228c1 100644 --- a/project/assets/database/bots/types/followerboarclose1.json +++ b/project/assets/database/bots/types/followerboarclose1.json @@ -2173,6 +2173,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2181,6 +2189,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/followerboarclose2.json b/project/assets/database/bots/types/followerboarclose2.json index 9584a752..197acfb2 100644 --- a/project/assets/database/bots/types/followerboarclose2.json +++ b/project/assets/database/bots/types/followerboarclose2.json @@ -2173,6 +2173,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2181,6 +2189,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/followerbully.json b/project/assets/database/bots/types/followerbully.json index ba12478a..1f0549c9 100644 --- a/project/assets/database/bots/types/followerbully.json +++ b/project/assets/database/bots/types/followerbully.json @@ -2044,6 +2044,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2052,6 +2060,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/followergluharassault.json b/project/assets/database/bots/types/followergluharassault.json index c8442a6c..7db40c2d 100644 --- a/project/assets/database/bots/types/followergluharassault.json +++ b/project/assets/database/bots/types/followergluharassault.json @@ -2212,6 +2212,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2220,6 +2228,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/followergluharscout.json b/project/assets/database/bots/types/followergluharscout.json index d83921e3..4b0eba82 100644 --- a/project/assets/database/bots/types/followergluharscout.json +++ b/project/assets/database/bots/types/followergluharscout.json @@ -2214,6 +2214,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2222,6 +2230,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/followergluharsecurity.json b/project/assets/database/bots/types/followergluharsecurity.json index a17e285f..9d5d212e 100644 --- a/project/assets/database/bots/types/followergluharsecurity.json +++ b/project/assets/database/bots/types/followergluharsecurity.json @@ -2217,6 +2217,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2225,6 +2233,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/followerkojaniy.json b/project/assets/database/bots/types/followerkojaniy.json index 4100dc55..cced9139 100644 --- a/project/assets/database/bots/types/followerkojaniy.json +++ b/project/assets/database/bots/types/followerkojaniy.json @@ -2099,6 +2099,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2107,6 +2115,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/followerkolontayassault.json b/project/assets/database/bots/types/followerkolontayassault.json index f9e57771..199ae92e 100644 --- a/project/assets/database/bots/types/followerkolontayassault.json +++ b/project/assets/database/bots/types/followerkolontayassault.json @@ -2232,6 +2232,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2240,6 +2248,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/followerkolontaysecurity.json b/project/assets/database/bots/types/followerkolontaysecurity.json index 5eeecb7e..7233ecaa 100644 --- a/project/assets/database/bots/types/followerkolontaysecurity.json +++ b/project/assets/database/bots/types/followerkolontaysecurity.json @@ -2245,6 +2245,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2253,6 +2261,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/followersanitar.json b/project/assets/database/bots/types/followersanitar.json index 25e684f6..ee087bb3 100644 --- a/project/assets/database/bots/types/followersanitar.json +++ b/project/assets/database/bots/types/followersanitar.json @@ -2144,6 +2144,22 @@ "2": 0 }, "whitelist": [] + }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] }, "grenades": { "weights": { diff --git a/project/assets/database/bots/types/followerzryachiy.json b/project/assets/database/bots/types/followerzryachiy.json index 89c58121..3782be29 100644 --- a/project/assets/database/bots/types/followerzryachiy.json +++ b/project/assets/database/bots/types/followerzryachiy.json @@ -2003,6 +2003,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2011,6 +2019,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/gifter.json b/project/assets/database/bots/types/gifter.json index 44f245c1..471652f3 100644 --- a/project/assets/database/bots/types/gifter.json +++ b/project/assets/database/bots/types/gifter.json @@ -2064,6 +2064,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2072,6 +2080,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/marksman.json b/project/assets/database/bots/types/marksman.json index 21fd26cc..a5df557a 100644 --- a/project/assets/database/bots/types/marksman.json +++ b/project/assets/database/bots/types/marksman.json @@ -2302,6 +2302,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2310,6 +2318,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, @@ -2341,10 +2357,10 @@ }, "pocketLoot": { "weights": { - "0": 3, - "1": 10, + "0": 10, + "1": 35, "2": 3, - "3": 1, + "3": 2, "4": 1 }, "whitelist": [] diff --git a/project/assets/database/bots/types/peacefullzryachiyevent.json b/project/assets/database/bots/types/peacefullzryachiyevent.json index ce87db85..e931986c 100644 --- a/project/assets/database/bots/types/peacefullzryachiyevent.json +++ b/project/assets/database/bots/types/peacefullzryachiyevent.json @@ -2004,33 +2004,108 @@ ], "generation": { "items": { + "backpackLoot": { + "weights": { + "0": 1, + "1": 1, + "2": 2, + "3": 1, + "4": 1, + "5": 1, + "6": 1, + "7": 0 + }, + "whitelist": [] + }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { - "max": 1, - "min": 0 + "weights": { + "0": 1, + "1": 2, + "2": 0 + }, + "whitelist": [] + }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] }, "grenades": { - "max": 5, - "min": 0 + "weights": { + "0": 1, + "1": 2, + "2": 1, + "3": 1, + "4": 0, + "5": 0 + }, + "whitelist": [] }, "healing": { - "max": 2, - "min": 1 + "weights": { + "0": 1, + "1": 2, + "2": 1 }, - "looseLoot": { - "max": 3, - "min": 0 + "whitelist": [] }, "magazines": { - "max": 4, - "min": 2 + "weights": { + "0": 0, + "1": 0, + "2": 1, + "3": 3, + "4": 1 + }, + "whitelist": [] + }, + "pocketLoot": { + "weights": { + "0": 1, + "1": 6, + "2": 3, + "3": 1, + "4": 1 + }, + "whitelist": [] }, "specialItems": { - "max": 0, - "min": 0 + "weights": { + "0": 1, + "1": 0 + }, + "whitelist": [] }, "stims": { - "max": 1, - "min": 0 + "weights": { + "0": 2, + "1": 1, + "2": 0 + }, + "whitelist": [] + }, + "vestLoot": { + "weights": { + "0": 1, + "1": 1, + "2": 2, + "3": 1, + "4": 0, + "5": 0, + "6": 0 + }, + "whitelist": [] } } }, diff --git a/project/assets/database/bots/types/pmcbot.json b/project/assets/database/bots/types/pmcbot.json index c3f83657..6306a51c 100644 --- a/project/assets/database/bots/types/pmcbot.json +++ b/project/assets/database/bots/types/pmcbot.json @@ -2119,6 +2119,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2127,6 +2135,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/ravangezryachiyevent.json b/project/assets/database/bots/types/ravangezryachiyevent.json index 30c8c85f..8e92b5b8 100644 --- a/project/assets/database/bots/types/ravangezryachiyevent.json +++ b/project/assets/database/bots/types/ravangezryachiyevent.json @@ -2085,6 +2085,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2093,6 +2101,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/sectantpriest.json b/project/assets/database/bots/types/sectantpriest.json index f89ec5cb..8bf5f722 100644 --- a/project/assets/database/bots/types/sectantpriest.json +++ b/project/assets/database/bots/types/sectantpriest.json @@ -2101,6 +2101,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2109,6 +2117,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/sectantwarrior.json b/project/assets/database/bots/types/sectantwarrior.json index ea59e008..9b520b83 100644 --- a/project/assets/database/bots/types/sectantwarrior.json +++ b/project/assets/database/bots/types/sectantwarrior.json @@ -2112,6 +2112,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2120,6 +2128,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/shooterbtr.json b/project/assets/database/bots/types/shooterbtr.json index dcf0f809..ee6adc72 100644 --- a/project/assets/database/bots/types/shooterbtr.json +++ b/project/assets/database/bots/types/shooterbtr.json @@ -2146,6 +2146,14 @@ }, "whitelist": [] }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "drugs": { "weights": { "0": 1, @@ -2154,6 +2162,14 @@ }, "whitelist": [] }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, "grenades": { "weights": { "0": 1, diff --git a/project/assets/database/bots/types/test.json b/project/assets/database/bots/types/test.json index e065fa11..a6756872 100644 --- a/project/assets/database/bots/types/test.json +++ b/project/assets/database/bots/types/test.json @@ -1938,6 +1938,22 @@ "drugs": { "max": 1, "min": 0 + }, + "drink": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, + "food": { + "weights": { + "0": 10, + "1": 5, + "2": 2 + }, + "whitelist": [] }, "grenades": { "max": 5, diff --git a/project/assets/database/bots/types/usec.json b/project/assets/database/bots/types/usec.json index f896fc54..e7e353fc 100644 --- a/project/assets/database/bots/types/usec.json +++ b/project/assets/database/bots/types/usec.json @@ -2185,7 +2185,7 @@ "Basuro", "Bepis", "Baliston", - "Pessin", + "Crow", "Aki-chan", "Fin", "Gatsu66", @@ -2478,9 +2478,11 @@ "Brin", "Belette", "Agnotology", - "All_Heil_Lord_Ppepe", - "ixcetotis", - "btdc00" + "All_Heil_Lord_Pepe", + "ixcetotis", + "btdc00", + "Bnuy", + "Choccy" ], "generation": { "items": { @@ -2505,11 +2507,27 @@ "2": 1 }, "whitelist": [] + }, + "food": { + "weights": { + "0": 6, + "1": 5, + "2": 2 + }, + "whitelist": [] + }, + "drink": { + "weights": { + "0": 6, + "1": 5, + "2": 1 + }, + "whitelist": [] }, "grenades": { "weights": { - "0": 1, - "1": 4, + "0": 2, + "1": 6, "2": 5, "3": 2, "4": 1 @@ -2985,9 +3003,9 @@ "5ac66d9b5acfc4001633997a": 5, "5ae08f0a5acfc408fb1398a1": 4, "5b0bbe4e5acfc40dc528a72d": 4, - "5ba26383d4351e00334c93d9": 5, + "5ba26383d4351e00334c93d9": 4, "5bb2475ed4351e00853264e3": 4, - "5bd70322209c4d00d7167b8f": 5, + "5bd70322209c4d00d7167b8f": 4, "5beed0f50db834001c062b12": 3, "5bf3e03b0db834001d2c4a9c": 5, "5bf3e0490db83400196199af": 5, diff --git a/project/assets/database/templates/profiles.json b/project/assets/database/templates/profiles.json index 613c80f4..66e4fbf5 100644 --- a/project/assets/database/templates/profiles.json +++ b/project/assets/database/templates/profiles.json @@ -19946,3418 +19946,2773 @@ }, "InsuredItems": [], "Inventory": { - "equipment": "5fe49444ae6628187a2e77b8", + "equipment": "6613bb72b5b0ba138a0fa9f4", "fastPanel": {}, + "favoriteItems": [], "hideoutAreaStashes": {}, - "items": [{ - "_id": "5fe49444ae6628187a2e77b8", - "_tpl": "55d7217a4bdc2d86028b456d" - }, { - "_id": "63db64cbf9963741dc0d741f", - "_tpl": "6401c7b213d9b818bf0e7dd7" - }, { - "_id": "a797e819df958aad39cdbd3c", - "_tpl": "5ac4cd105acfc40016339859", - "parentId": "5fe49444ae6628187a2e77b8", - "slotId": "FirstPrimaryWeapon", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Foldable": { - "Folded": false - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "43e3a7bd752424eaa0c800e0", - "_tpl": "59c6633186f7740cf0493bb9", - "parentId": "a797e819df958aad39cdbd3c", - "slotId": "mod_gas_block" - }, { - "_id": "1cdd4c79345d24be45ae4e5f", - "_tpl": "5648b1504bdc2d9d488b4584", - "parentId": "43e3a7bd752424eaa0c800e0", - "slotId": "mod_handguard" - }, { - "_id": "a20279119c4931eceb8a097e", - "_tpl": "5ac7655e5acfc40016339a19", - "parentId": "a797e819df958aad39cdbd3c", - "slotId": "mod_muzzle" - }, { - "_id": "b2430220da94fb22c0d65693", - "_tpl": "5649ade84bdc2d1b2b8b4587", - "parentId": "a797e819df958aad39cdbd3c", - "slotId": "mod_pistol_grip" - }, { - "_id": "94751193011013ee7734b4fe", - "_tpl": "5ac50da15acfc4001718d287", - "parentId": "a797e819df958aad39cdbd3c", - "slotId": "mod_reciever" - }, { - "_id": "276460f843affd97cad97da7", - "_tpl": "5ac72e475acfc400180ae6fe", - "parentId": "a797e819df958aad39cdbd3c", - "slotId": "mod_sight_rear" - }, { - "_id": "8cf886617f5211d237aa5a1f", - "_tpl": "5ac50c185acfc400163398d4", - "parentId": "a797e819df958aad39cdbd3c", - "slotId": "mod_stock" - }, { - "_id": "a9cb81802a05229cb65b11ef", - "_tpl": "55d480c04bdc2d1d4e8b456a", - "parentId": "a797e819df958aad39cdbd3c", - "slotId": "mod_magazine" - }, { - "_id": "909e88f6ba6571e5ab4a3476", - "_tpl": "56dfef82d2720bbd668b4567", - "parentId": "a9cb81802a05229cb65b11ef", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "0250844ab4d1320f304fdfcb", - "_tpl": "5bffdc370db834001d23eca8", - "parentId": "5fe49444ae6628187a2e77b8", - "slotId": "Scabbard", - "upd": { - "Repairable": { - "Durability": 80, - "MaxDurability": 80 - } - } - }, { - "_id": "03470cbbef724cc5017f6538", - "_tpl": "5b40e5e25acfc4001a599bea", - "parentId": "5fe49444ae6628187a2e77b8", - "slotId": "Headwear", - "upd": { - "Repairable": { - "Durability": 10, - "MaxDurability": 10 - } - } - }, { - "_id": "490e6180d045eeaf5cef9073", - "_tpl": "5ca20abf86f77418567a43f2", - "parentId": "5fe49444ae6628187a2e77b8", - "slotId": "TacticalVest" - }, { - "_id": "9c22fdef66c45863afa4a8de", - "_tpl": "55d480c04bdc2d1d4e8b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "490e6180d045eeaf5cef9073", - "slotId": "1" - }, { - "_id": "11eadc612502a26aeb1611df", - "_tpl": "56dff3afd2720bba668b4567", - "parentId": "9c22fdef66c45863afa4a8de", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "01ea8735feb7d3b5ab772dde", - "_tpl": "55d480c04bdc2d1d4e8b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "490e6180d045eeaf5cef9073", - "slotId": "2" - }, { - "_id": "28605b3f275070610f47af1b", - "_tpl": "56dff3afd2720bba668b4567", - "parentId": "01ea8735feb7d3b5ab772dde", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "98f1e5b11f4f85e12db463cf", - "_tpl": "55d480c04bdc2d1d4e8b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "490e6180d045eeaf5cef9073", - "slotId": "3" - }, { - "_id": "62c13892d6d745050dad38b0", - "_tpl": "56dff3afd2720bba668b4567", - "parentId": "98f1e5b11f4f85e12db463cf", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "dbda40032725eb2924b01fbe", - "_tpl": "5755356824597772cb798962", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "490e6180d045eeaf5cef9073", - "slotId": "4", - "upd": { - "MedKit": { - "HpResource": 100 - } - } - }, { - "_id": "f5e6bdac05e699d687993249", - "_tpl": "5857a8bc2459772bad15db29", - "parentId": "5fe49444ae6628187a2e77b8", - "slotId": "SecuredContainer" - }, { - "_id": "13117a5a113a6246a2db5fff", - "_tpl": "5ca20d5986f774331e7c9602", - "parentId": "5fe49444ae6628187a2e77b8", - "slotId": "Backpack" - }, { - "_id": "8b6f0bac70f8f2d91c2a0c74", - "_tpl": "56dff3afd2720bba668b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 0 - }, - "parentId": "13117a5a113a6246a2db5fff", - "slotId": "main", - "upd": { - "StackObjectsCount": 60 - } - }, { - "_id": "c063ca857d900564f913197f", - "_tpl": "56dfef82d2720bbd668b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 1 - }, - "parentId": "13117a5a113a6246a2db5fff", - "slotId": "main", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "b4bef7715cfbfde49f9deb57", - "_tpl": "5448fee04bdc2dbc018b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "13117a5a113a6246a2db5fff", - "slotId": "main", - "upd": { - "FoodDrink": { - "HpPercent": 60 - } - } - }, { - "_id": "4ea0df06a22b64ea321dafec", - "_tpl": "590c5d4b86f774784e1b9c45", - "location": { - "isSearched": true, - "r": 0, - "x": 1, - "y": 0 - }, - "parentId": "13117a5a113a6246a2db5fff", - "slotId": "main", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "af4d8b34228a85208fb85895", - "_tpl": "5648a7494bdc2d9d488b4583", - "parentId": "5fe49444ae6628187a2e77b8", - "slotId": "ArmorVest", - "upd": { - "Repairable": { - "Durability": 50, - "MaxDurability": 50 - } - } - }, { - "_id": "658c3f38bb2016e5630bdbe5", - "_tpl": "65703d866584602f7d057a8a", - "parentId": "af4d8b34228a85208fb85895", - "slotId": "Soft_armor_front" - }, { - "_id": "658c3f38bb2016e5630bdbe6", - "_tpl": "65703fa06584602f7d057a8e", - "parentId": "af4d8b34228a85208fb85895", - "slotId": "Soft_armor_back" - }, { - "_id": "658c3f38bb2016e5630bdbe7", - "_tpl": "65703fe46a912c8b5c03468b", - "parentId": "af4d8b34228a85208fb85895", - "slotId": "Soft_armor_left" - }, { - "_id": "658c3f38bb2016e5630bdbe8", - "_tpl": "657040374e67e8ec7a0d261c", - "parentId": "af4d8b34228a85208fb85895", - "slotId": "soft_armor_right" - }, { - "_id": "01e9d751f10e4e9aebdd94d5", - "_tpl": "627a4e6b255f7527fb05a0f6", - "parentId": "5fe49444ae6628187a2e77b8", - "slotId": "Pockets" - }, { - "_id": "4ca0cf14b0ae5bd2753a0a87", - "_tpl": "544fb3364bdc2d34748b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "01e9d751f10e4e9aebdd94d5", - "slotId": "pocket1" - }, { - "_id": "749309e76ce2fdcf316f29fe", - "_tpl": "544fb37f4bdc2dee738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "01e9d751f10e4e9aebdd94d5", - "slotId": "pocket2", - "upd": { - "MedKit": { - "HpResource": 4 - } - } - }, { - "_id": "729ecfc38cce5672b1dc1ad1", - "_tpl": "5751a25924597722c463c472", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "01e9d751f10e4e9aebdd94d5", - "slotId": "pocket3", - "upd": { - "MedKit": { - "HpResource": 2 - } - } - }, { - "_id": "ad076f81dc918f5e4c7fbd18", - "_tpl": "5645bcc04bdc2d363b8b4572", - "parentId": "5fe49444ae6628187a2e77b8", - "slotId": "Earpiece" - }, { - "_id": "5fe49444ae6628187a2e78b8", - "_tpl": "5811ce772459770e9e5f9532" - }, { - "_id": "702bdc5dfd91ed316b175b3c", - "_tpl": "5755356824597772cb798962", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 34 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 100 - } - } - }, { - "_id": "fb08ac9e01a36533563a4389", - "_tpl": "5648a7494bdc2d9d488b4583", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 50, - "MaxDurability": 50 - } - } - }, { - "_id": "658c3f38bb2016e5630bdbe5", - "_tpl": "65703d866584602f7d057a8a", - "parentId": "fb08ac9e01a36533563a4389", - "slotId": "Soft_armor_front" - }, { - "_id": "658c3f38bb2016e5630bdbe6", - "_tpl": "65703fa06584602f7d057a8e", - "parentId": "fb08ac9e01a36533563a4389", - "slotId": "Soft_armor_back" - }, { - "_id": "658c3f38bb2016e5630bdbe7", - "_tpl": "65703fe46a912c8b5c03468b", - "parentId": "fb08ac9e01a36533563a4389", - "slotId": "Soft_armor_left" - }, { - "_id": "658c3f38bb2016e5630bdbe8", - "_tpl": "657040374e67e8ec7a0d261c", - "parentId": "fb08ac9e01a36533563a4389", - "slotId": "soft_armor_right" - }, { - "_id": "686cfcc458f923cb2e76b8d7", - "_tpl": "5710c24ad2720bc3458b45a3", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 13 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "1936371534d82e70c76a7645", - "_tpl": "5b432b965acfc47a8774094e", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 9 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "12be6d1147d04252aacaa083", - "_tpl": "5ca20abf86f77418567a43f2", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 0 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "6342de84cd397d00cb31e87f", - "_tpl": "557ff21e4bdc2d89578b4586", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 22 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "81a756ebe7ce1ea490962f9e", - "_tpl": "5710c24ad2720bc3458b45a3", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 13 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "a9bccb7b590bf286c6e0a0c3", - "_tpl": "5ca20abf86f77418567a43f2", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 3 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "cfd59c8e3cd5cce89c53b10f", - "_tpl": "5755356824597772cb798962", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 34 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 100 - } - } - }, { - "_id": "b2fe6975cd7ba911fbf6bf42", - "_tpl": "5d40407c86f774318526545a", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 0 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "f587cf58fc9d1c6cf7899bf1", - "_tpl": "5449016a4bdc2d6f028b456f", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 1 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 250000 - } - }, { - "_id": "26578d87ce5797ff5e87fd3c", - "_tpl": "599860ac86f77436b225ed1a", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 8 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "feb9c6ec3ad0f62f2cac447c", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "26578d87ce5797ff5e87fd3c", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "7a3a6fdbd690c6e3767a096d", - "_tpl": "5648a7494bdc2d9d488b4583", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 3 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 50, - "MaxDurability": 50 - } - } - }, { - "_id": "658c3f38bb2016e5630bdbe5", - "_tpl": "65703d866584602f7d057a8a", - "parentId": "7a3a6fdbd690c6e3767a096d", - "slotId": "Soft_armor_front" - }, { - "_id": "658c3f38bb2016e5630bdbe6", - "_tpl": "65703fa06584602f7d057a8e", - "parentId": "7a3a6fdbd690c6e3767a096d", - "slotId": "Soft_armor_back" - }, { - "_id": "658c3f38bb2016e5630bdbe7", - "_tpl": "65703fe46a912c8b5c03468b", - "parentId": "7a3a6fdbd690c6e3767a096d", - "slotId": "Soft_armor_left" - }, { - "_id": "658c3f38bb2016e5630bdbe8", - "_tpl": "657040374e67e8ec7a0d261c", - "parentId": "7a3a6fdbd690c6e3767a096d", - "slotId": "soft_armor_right" - }, { - "_id": "a498d5c84a16a8700486b51e", - "_tpl": "5b40e5e25acfc4001a599bea", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 0 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 10, - "MaxDurability": 10 - } - } - }, { - "_id": "90ceaf3a032fbddb4d8ba181", - "_tpl": "5b40e5e25acfc4001a599bea", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 0 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 10, - "MaxDurability": 10 - } - } - }, { - "_id": "106af131dbdc7fd37bd14dfb", - "_tpl": "5b432b965acfc47a8774094e", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 11 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "78a938654650e34abbc5b8ba", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 1, - "y": 10 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 50 - } - }, { - "_id": "d74a1797a4c614b767fc3bae", - "_tpl": "576a5ed62459771e9c2096cb", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 3 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "90770873e582d91803aab334", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "d74a1797a4c614b767fc3bae", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 18 - } - }, { - "_id": "d9cbc2cd84237f98ff2755c3", - "_tpl": "576a5ed62459771e9c2096cb", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 4 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "8f79a44ad63d889117296f4c", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "d9cbc2cd84237f98ff2755c3", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 18 - } - }, { - "_id": "2812b9183017676294379dca", - "_tpl": "576a5ed62459771e9c2096cb", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 6 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "d8f30bca23ad344542332c2b", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "2812b9183017676294379dca", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 18 - } - }, { - "_id": "793165a59cd9851376721225", - "_tpl": "576a5ed62459771e9c2096cb", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 5 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "a8063d54da55fb4f5f65e5db", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "793165a59cd9851376721225", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 18 - } - }, { - "_id": "5c38985edc19d2dcabbae35c", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 10 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 25 - } - }, { - "_id": "e1ea22ee08f9df9510ba0d78", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 10 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 25 - } - }, { - "_id": "cfefb0ba82b5146fc31a6950", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 10 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 50 - } - }, { - "_id": "b6672157bc48c99a22bddfc0", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 10 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 50 - } - }, { - "_id": "eb9fdb0d060da5428fda443c", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 8 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 25 - } - }, { - "_id": "79d2d8c7e5beea7eacdd182b", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 10 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 25 - } - }, { - "_id": "627d2a20092c113b5becf64d", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 8 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 25 - } - }, { - "_id": "ca80652ee36de43007d8efcc", - "_tpl": "599860ac86f77436b225ed1a", - "location": { - "isSearched": true, - "r": 0, - "x": 1, - "y": 8 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "008684957ef010140bcaab5d", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "ca80652ee36de43007d8efcc", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "a3c7c8cc79286d6977471596", - "_tpl": "599860ac86f77436b225ed1a", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 8 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "0ec7e3bf2f3c7c3ba38239eb", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "a3c7c8cc79286d6977471596", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "feb6dfb5498cd78530ef127c", - "_tpl": "599860ac86f77436b225ed1a", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 8 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "e8bb934c6185c10053db2644", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "feb6dfb5498cd78530ef127c", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "98f8acadeebdbfc5dc71e3d1", - "_tpl": "599860ac86f77436b225ed1a", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 8 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "5d1d600c9966b2a55a7b2753", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "98f8acadeebdbfc5dc71e3d1", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "865d1f2ad642b3b4f1215069", - "_tpl": "599860ac86f77436b225ed1a", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 8 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "b66581c029631a7b55a32047", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "865d1f2ad642b3b4f1215069", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "84e1c2763a73328da1f12d47", - "_tpl": "5ca20d5986f774331e7c9602", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 11 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "a41d51a5df91ab76147f4f67", - "_tpl": "5ca20d5986f774331e7c9602", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 11 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "da12ff8da976f0b65169a4c6", - "_tpl": "56dfef82d2720bbd668b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 17 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "cff77612829a2bca05bb12fe", - "_tpl": "590c661e86f7741e566b646a", - "location": { - "isSearched": true, - "r": 1, - "x": 8, - "y": 32 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 220 - } - } - }, { - "_id": "bf4e22ad1b7491a3b64952f0", - "_tpl": "5449016a4bdc2d6f028b456f", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 1 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 250000 - } - }, { - "_id": "0d433004c6fbce3e87cab553", - "_tpl": "590c661e86f7741e566b646a", - "location": { - "isSearched": true, - "r": 1, - "x": 8, - "y": 30 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 220 - } - } - }, { - "_id": "45f4260eb5b8f95b76169117", - "_tpl": "5755383e24597772cb798966", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 36 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 6 - } - } - }, { - "_id": "5b5939c98d57a378a0028aab", - "_tpl": "56dff3afd2720bba668b4567", - "location": { - "isSearched": true, - "r": "Horizontal", - "x": 9, - "y": 21 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "6090c8f36c2c7ea96450338f", - "_tpl": "5a0c27731526d80618476ac4", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 15 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "ab849c066c608b391089b7ec", - "_tpl": "5a0c27731526d80618476ac4", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 15 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "778249f3797805c34e11eb12", - "_tpl": "55d480c04bdc2d1d4e8b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 16 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "62357ba0ab9508b9dd3122e6", - "_tpl": "56dff3afd2720bba668b4567", - "parentId": "778249f3797805c34e11eb12", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "e7758bee1260861bf7002b97", - "_tpl": "55d480c04bdc2d1d4e8b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 16 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "44919bf9dd35679ad2f2f05a", - "_tpl": "56dff3afd2720bba668b4567", - "parentId": "e7758bee1260861bf7002b97", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "fa48d505a5d4b745d87738db", - "_tpl": "55d480c04bdc2d1d4e8b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 16 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "6f052efd98ed56034614d0c8", - "_tpl": "56dff3afd2720bba668b4567", - "parentId": "fa48d505a5d4b745d87738db", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "791c40db74e01311fe25e1f6", - "_tpl": "56dfef82d2720bbd668b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 16 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "ae94aebd712a154aa5507d95", - "_tpl": "55d480c04bdc2d1d4e8b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 16 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "ff0ff90e0cf7c5e3e7010ea4", - "_tpl": "56dff3afd2720bba668b4567", - "parentId": "ae94aebd712a154aa5507d95", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "08dfb883d785b8f6c2cb3c55", - "_tpl": "590c5d4b86f774784e1b9c45", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 30 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "d669a3bb766f4b5372d397c8", - "_tpl": "590c5d4b86f774784e1b9c45", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 30 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "151c9e54ab15b0671f73dbc8", - "_tpl": "590c5d4b86f774784e1b9c45", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 30 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "ab975022dba4a048a89bab1f", - "_tpl": "5448fee04bdc2dbc018b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 32 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 60 - } - } - }, { - "_id": "6e7c46c087fbb3c5c75d8289", - "_tpl": "5448fee04bdc2dbc018b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 32 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 60 - } - } - }, { - "_id": "2c2328ec1d21a33e4672ff5d", - "_tpl": "5448fee04bdc2dbc018b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 32 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 60 - } - } - }, { - "_id": "7f0dce2c6b47b1eeac74f3fd", - "_tpl": "57347da92459774491567cf5", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 29 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "f34845e66c2fb4d3a724610e", - "_tpl": "57347da92459774491567cf5", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 29 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "14d7acac0cfb3b83a75f338e", - "_tpl": "5e831507ea0a7c419c2f9bd9", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 35 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "e9a6f02b0bdcb5396e649244", - "_tpl": "5e831507ea0a7c419c2f9bd9", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 35 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "370172a19dfd4e467aef1dbe", - "_tpl": "5e831507ea0a7c419c2f9bd9", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 35 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "d4dce1062cb9cc8a826ea03b", - "_tpl": "544fb3364bdc2d34748b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 36 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "d3ce4df1bc5894e2f78882f3", - "_tpl": "544fb3364bdc2d34748b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 36 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "ae8149b8dc0ae253f174b6f4", - "_tpl": "544fb3364bdc2d34748b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 36 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "4daad698cf5b72487346e0d5", - "_tpl": "5755356824597772cb798962", - "location": { - "isSearched": true, - "r": 0, - "x": 1, - "y": 34 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 100 - } - } - }, { - "_id": "f880ae41ce81ab084a2f4eab", - "_tpl": "5755356824597772cb798962", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 34 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 100 - } - } - }, { - "_id": "64277b11e912b968a9c41b3b", - "_tpl": "544fb25a4bdc2dfb738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 37 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "239a4b43740b84e90db4fb17", - "_tpl": "544fb25a4bdc2dfb738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 37 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "c4332600c7ea3d4dc9a3eeeb", - "_tpl": "544fb25a4bdc2dfb738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 36 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "87961dd2d7e7ee05db9e45c9", - "_tpl": "576a5ed62459771e9c2096cb", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 7 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "9dd9d821cffb585482fd1389", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "87961dd2d7e7ee05db9e45c9", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 18 - } - }, { - "_id": "9417e493bc4c277a6adee960", - "_tpl": "576a5ed62459771e9c2096cb", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 6 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "9492c6ec9a2a58c03fb3ae07", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "9417e493bc4c277a6adee960", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 18 - } - }, { - "_id": "50e24912547aecad4244f96c", - "_tpl": "560d5e524bdc2d25448b4571", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 18 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "bf299763ba7c6d6130aeb67c", - "_tpl": "5a0c27731526d80618476ac4", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 14 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "169fca7757fa58518380f4ed", - "_tpl": "5a0c27731526d80618476ac4", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 14 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "94614a61c5f560ec575b96f5", - "_tpl": "57347da92459774491567cf5", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 28 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "a9f69caa9c291288d3af3f70", - "_tpl": "5d02778e86f774203e7dedbe", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 36 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 5 - } - } - }, { - "_id": "86c426e5603f11f3973a7c2e", - "_tpl": "544fb45d4bdc2dee738b4568", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 36 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 400 - } - } - }, { - "_id": "423c59d7d0be625133067ff9", - "_tpl": "5e831507ea0a7c419c2f9bd9", - "location": { - "isSearched": true, - "r": 0, - "x": 1, - "y": 35 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "d987a0a70512510f633e21d5", - "_tpl": "590c695186f7741e566b64a2", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 37 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "d51b419b7f442422bcf2fab6", - "_tpl": "590c695186f7741e566b64a2", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 37 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "03cd7851e89f43020e24bafb", - "_tpl": "5751a25924597722c463c472", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 34 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 2 - } - } - }, { - "_id": "57daa3f963e75470cebe4fef", - "_tpl": "5751a25924597722c463c472", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 34 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 2 - } - } - }, { - "_id": "e63b5a4e5a3c84dde743edd1", - "_tpl": "5696686a4bdc2da3298b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 2 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 500 - } - }, { - "_id": "4c138d4262cfdd01efc8145a", - "_tpl": "5696686a4bdc2da3298b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 2 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 500 - } - }, { - "_id": "f0f9c3ff0b3b1dbdeffee6ea", - "_tpl": "560d5e524bdc2d25448b4571", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 18 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "a8b2466d0350461c4b04fd2c", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 10 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 50 - } - }, { - "_id": "fe4dbfce77eb6008a8f4d09d", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 10 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 25 - } - }, { - "_id": "11ae2930e3accdc5f124876b", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 9 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 25 - } - }, { - "_id": "c8a0ba51f519cfde0fe997e8", - "_tpl": "5c0e53c886f7747fa54205c7", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 19 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 47, - "MaxDurability": 47 - } - } - }, { - "_id": "658c3f38bb2016e5630bdca8", - "_tpl": "656f603f94b480b8a500c0d6", - "parentId": "c8a0ba51f519cfde0fe997e8", - "slotId": "front_plate" - }, { - "_id": "658c3f38bb2016e5630bdca9", - "_tpl": "656efd66034e8e01c407f35c", - "parentId": "c8a0ba51f519cfde0fe997e8", - "slotId": "back_plate" - }, { - "_id": "658c3f38bb2016e5630bdcaa", - "_tpl": "654a8b0b0337d53f9102c2ae", - "parentId": "c8a0ba51f519cfde0fe997e8", - "slotId": "soft_armor_front" - }, { - "_id": "658c3f38bb2016e5630bdcab", - "_tpl": "654a8976f414fcea4004d78b", - "parentId": "c8a0ba51f519cfde0fe997e8", - "slotId": "soft_armor_back" - }, { - "_id": "658c3f38bb2016e5630bdcac", - "_tpl": "654a8b3df414fcea4004d78f", - "parentId": "c8a0ba51f519cfde0fe997e8", - "slotId": "soft_armor_left" - }, { - "_id": "658c3f38bb2016e5630bdcad", - "_tpl": "654a8b80f414fcea4004d797", - "parentId": "c8a0ba51f519cfde0fe997e8", - "slotId": "soft_armor_right" - }, { - "_id": "658c3f38bb2016e5630bdcae", - "_tpl": "654a8ae00337d53f9102c2aa", - "parentId": "c8a0ba51f519cfde0fe997e8", - "slotId": "Collar" - }, { - "_id": "658c3f38bb2016e5630bdcaf", - "_tpl": "654a8bc5f414fcea4004d79b", - "parentId": "c8a0ba51f519cfde0fe997e8", - "slotId": "Groin" - }, { - "_id": "cd688bf5123e7f7b524bf826", - "_tpl": "560d5e524bdc2d25448b4571", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 18 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "44ebc2c1ad7f620ebe405367", - "_tpl": "5d1b36a186f7742523398433", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 38 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Resource": { - "Value": 100 - } - } - }, { - "_id": "c71ab08b792188701a79e839", - "_tpl": "5d1b371186f774253763a656", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 38 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Resource": { - "Value": 60 - } - } - }, { - "_id": "719317c75d4325f6a48a14a6", - "_tpl": "5d0a3e8cd7ad1a6f6a3d35bd", - "parentId": "f5de5b058e07bcacee8c97d0", - "slotId": "mod_scope", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "f5de5b058e07bcacee8c97d0", - "_tpl": "5d0a29fed7ad1a002769ad08", - "parentId": "60c86df7ed1a4e3ce394a0f6", - "slotId": "mod_scope" - }, { - "_id": "612d78111fdcbf34bd2d7b28", - "_tpl": "5710c24ad2720bc3458b45a3", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 21 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "100de389aa4e70a171270a83", - "_tpl": "5710c24ad2720bc3458b45a3", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 21 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "e58c0f483fce36e55aec165e", - "_tpl": "559ba5b34bdc2d1f1a8b4582", - "location": { - "isSearched": true, - "r": "Horizontal", - "x": 8, - "y": 18 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "e20ddc9d3b8849fbdc251ea0", - "_tpl": "5887431f2459777e1612938f", - "parentId": "e58c0f483fce36e55aec165e", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 10 - } - }, { - "_id": "dd6cb088cfc11365f794ec4b", - "_tpl": "559ba5b34bdc2d1f1a8b4582", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 20 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "da6373f4e09dd3d4eea68bf0", - "_tpl": "5887431f2459777e1612938f", - "parentId": "dd6cb088cfc11365f794ec4b", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 10 - } - }, { - "_id": "9cad0271722c938b71f12f95", - "_tpl": "559ba5b34bdc2d1f1a8b4582", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 19 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "d9d62e8db1303bbf4a88c7e9", - "_tpl": "5887431f2459777e1612938f", - "parentId": "9cad0271722c938b71f12f95", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 10 - } - }, { - "_id": "25a617ea956575203cdf0a09", - "_tpl": "5d02778e86f774203e7dedbe", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 35 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 5 - } - } - }, { - "_id": "deed2ec92f8ebf37cf3e639a", - "_tpl": "5af0454c86f7746bf20992e8", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 34 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 5 - } - } - }, { - "_id": "e4c6958acc50164d2387b53a", - "_tpl": "5aa7cfc0e5b5b00015693143", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 23 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 25, - "MaxDurability": 25 - } - } - }, { - "_id": "658c3f38bb2016e5630bdc64", - "_tpl": "657baaf0b7e9ca9a02045c02", - "parentId": "e4c6958acc50164d2387b53a", - "slotId": "Helmet_top" - }, { - "_id": "658c3f38bb2016e5630bdc65", - "_tpl": "657bab6ec6f689d3a205b85f", - "parentId": "e4c6958acc50164d2387b53a", - "slotId": "Helmet_back" - }, { - "_id": "658c3f38bb2016e5630bdc66", - "_tpl": "657babc6f58ba5a6250107a2", - "parentId": "e4c6958acc50164d2387b53a", - "slotId": "Helmet_ears" - }, { - "_id": "599a234277a564d9dd5bdd1c", - "_tpl": "5ab8f39486f7745cd93a1cca", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 22 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "8683fa7212c9bdd366063dd0", - "_tpl": "544fb37f4bdc2dee738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 32 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 4 - } - } - }, { - "_id": "4abf4d970ec5b19afe8e126d", - "_tpl": "569668774bdc2da2298b4568", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 2 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 500 - } - }, { - "_id": "7ca437210f63ee92275b37fe", - "_tpl": "544fb45d4bdc2dee738b4568", - "location": { - "isSearched": true, - "r": 0, - "x": 1, - "y": 36 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 400 - } - } - }, { - "_id": "7ad655c1e45bc6a9f49b4b99", - "_tpl": "544fb45d4bdc2dee738b4568", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 36 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 400 - } - } - }, { - "_id": "f602250b1405f266cfe696f7", - "_tpl": "5af0454c86f7746bf20992e8", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 34 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 5 - } - } - }, { - "_id": "8b672ab1e2278d787bed7cf9", - "_tpl": "5d5d940f86f7742797262046", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 29 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "da478b8f22969edb7af064a8", - "_tpl": "57cd379a24597778e7682ecf", - "location": { - "isSearched": true, - "r": 1, - "x": 4, - "y": 23 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "49fbfbdeed8888564938c8cb", - "_tpl": "5710c24ad2720bc3458b45a3", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 21 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "8da531704ee0e9cabfc6dce2", - "_tpl": "5710c24ad2720bc3458b45a3", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 22 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "3cd0e5ffd24f9e4c1f206741", - "_tpl": "5ab8f39486f7745cd93a1cca", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 21 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "24f71b418e8670d740e6024b", - "_tpl": "5e2af4a786f7746d3f3c3400", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 40 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Resource": { - "Value": 0 - } - } - }, { - "_id": "17f350695fd709de9e868610", - "_tpl": "5d5d85c586f774279a21cbdb", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 25 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "380b954613fc6559dee3e19e", - "_tpl": "5c0e722886f7740458316a57", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 25 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 65, - "MaxDurability": 65 - } - } - }, { - "_id": "658c3f38bb2016e5630bdcb1", - "_tpl": "656fa0fb498d1b7e3e071d9c", - "parentId": "380b954613fc6559dee3e19e", - "slotId": "Front_plate" - }, { - "_id": "658c3f38bb2016e5630bdcb2", - "_tpl": "656fa0fb498d1b7e3e071d9c", - "parentId": "380b954613fc6559dee3e19e", - "slotId": "Back_plate" - }, { - "_id": "658c3f38bb2016e5630bdcb3", - "_tpl": "65730c0e292ecadbfa09ad49", - "parentId": "380b954613fc6559dee3e19e", - "slotId": "Soft_armor_front" - }, { - "_id": "658c3f38bb2016e5630bdcb4", - "_tpl": "65730c2213a2f660f60bea96", - "parentId": "380b954613fc6559dee3e19e", - "slotId": "Soft_armor_back" - }, { - "_id": "658c3f38bb2016e5630bdcb5", - "_tpl": "65730c2b292ecadbfa09ad50", - "parentId": "380b954613fc6559dee3e19e", - "slotId": "Soft_armor_left" - }, { - "_id": "658c3f38bb2016e5630bdcb6", - "_tpl": "65730c35292ecadbfa09ad54", - "parentId": "380b954613fc6559dee3e19e", - "slotId": "soft_armor_right" - }, { - "_id": "b410bdab51c195ffe3c83d1b", - "_tpl": "5b432d215acfc4771e1c6624", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 23 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 30, - "MaxDurability": 30 - } - } - }, { - "_id": "658c3f38bb2016e5630bdc75", - "_tpl": "657bb92fa1c61ee0c303631f", - "parentId": "b410bdab51c195ffe3c83d1b", - "slotId": "Helmet_top" - }, { - "_id": "658c3f38bb2016e5630bdc76", - "_tpl": "657bb99db30eca976305117f", - "parentId": "b410bdab51c195ffe3c83d1b", - "slotId": "Helmet_back" - }, { - "_id": "172f0b166eec3c78e6c3ea84", - "_tpl": "5e8488fa988a8701445df1e4", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 37 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 3 - } - } - }, { - "_id": "ccac1906f229352147a9934b", - "_tpl": "5e8488fa988a8701445df1e4", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 37 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 3 - } - } - }, { - "_id": "c728563377b6a440482d77b9", - "_tpl": "590c678286f77426c9660122", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 38 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 300 - } - } - }, { - "_id": "b43973e59452e707816a5857", - "_tpl": "590c678286f77426c9660122", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 39 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 300 - } - } - }, { - "_id": "dd039504d446bd7af0992a1b", - "_tpl": "590c678286f77426c9660122", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 38 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 300 - } - } - }, { - "_id": "dc189c626993ff517fc61236", - "_tpl": "55d480c04bdc2d1d4e8b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 28 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "7d644abc323d82b9ba729740", - "_tpl": "56dff3afd2720bba668b4567", - "parentId": "dc189c626993ff517fc61236", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "661a3936e62f490e219582dc", - "_tpl": "56dff3afd2720bba668b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 28 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 60 - } - }, { - "_id": "449d62388f2f639a64045d71", - "_tpl": "56dff3afd2720bba668b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 28 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 60 - } - }, { - "_id": "52399e2f1a3044a514b2030b", - "_tpl": "55d480c04bdc2d1d4e8b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 23 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "467a6cdeeb6cd75a7c538872", - "_tpl": "56dff3afd2720bba668b4567", - "parentId": "52399e2f1a3044a514b2030b", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "e0419baa0c2d4f3619acb5cc", - "_tpl": "5c0e530286f7747fa1419862", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 35 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "1e4a2fd745c006867fb88f79", - "_tpl": "5c0e530286f7747fa1419862", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 35 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "5784837a07c8f380cb2950cd", - "_tpl": "559ba5b34bdc2d1f1a8b4582", - "parentId": "60c86df7ed1a4e3ce394a0f6", - "slotId": "mod_magazine" - }, { - "_id": "de67e78c4fb859322f766194", - "_tpl": "5887431f2459777e1612938f", - "parentId": "5784837a07c8f380cb2950cd", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 10 - } - }, { - "_id": "1eb47c86694ab2fce9904af6", - "_tpl": "5c0505e00db834001b735073", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 24 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "1772d219adce434a029346c1", - "_tpl": "55d480c04bdc2d1d4e8b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 25 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "b04747fbdbeb0707a3f7340d", - "_tpl": "56dff3afd2720bba668b4567", - "parentId": "1772d219adce434a029346c1", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "12572b486734c09b8839733d", - "_tpl": "55d480c04bdc2d1d4e8b456a", - "location": { - "isSearched": true, - "r": 1, - "x": 5, - "y": 24 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "8f08e02573f940e71f37feb2", - "_tpl": "56dff3afd2720bba668b4567", - "parentId": "12572b486734c09b8839733d", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "4da90923d1e3133f938bdeec", - "_tpl": "590c657e86f77412b013051d", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 38 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 1800 - } - } - }, { - "_id": "c6d58ede5aa9d24744187054", - "_tpl": "5af0454c86f7746bf20992e8", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 34 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 5 - } - } - }, { - "_id": "0bc3a80d48bac27550c6a15a", - "_tpl": "5b432b965acfc47a8774094e", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 21 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "5f13a6fbf32fbcd1c5796899", - "_tpl": "57347da92459774491567cf5", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 27 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "f0c60e3787fa3aca66dcc74a", - "_tpl": "5887431f2459777e1612938f", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 22 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 40 - } - }, { - "_id": "44e01b1a96be81711f7dc93e", - "_tpl": "544fb37f4bdc2dee738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 34 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 4 - } - } - }, { - "_id": "7dd0fe67076e301ba04210dc", - "_tpl": "544fb37f4bdc2dee738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 33 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 4 - } - } - }, { - "_id": "5253b6b2ca3428ab303af52b", - "_tpl": "5e2af47786f7746d404f3aaa", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 38 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Resource": { - "Value": 0 - } - } - }, { - "_id": "99eaa80a461346eda014048d", - "_tpl": "5e2af47786f7746d404f3aaa", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 39 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Resource": { - "Value": 0 - } - } - }, { - "_id": "9812a8a58953878fa4242cd3", - "_tpl": "5e2af4a786f7746d3f3c3400", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 40 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "Resource": { - "Value": 0 - } - } - }, { - "_id": "1f7bfa7312cdaa64f4133089", - "_tpl": "544fb3f34bdc2d03748b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 35 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "04e14fd3d1294042f7cb618d", - "_tpl": "544fb3f34bdc2d03748b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 35 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "93ca8f31b67632bc7f8caf74", - "_tpl": "576a5ed62459771e9c2096cb", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 6 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "d96c035dd972bb5b42a7951a", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "93ca8f31b67632bc7f8caf74", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 18 - } - }, { - "_id": "217bde33f66867ae88e11af1", - "_tpl": "576a5ed62459771e9c2096cb", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 6 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "d7ab0baf36814edcd1c33e20", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "217bde33f66867ae88e11af1", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 18 - } - }, { - "_id": "32c8f2ea6a975dafe2f4daba", - "_tpl": "576a5ed62459771e9c2096cb", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 7 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "97861a122e2e3e84c07e34b3", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "32c8f2ea6a975dafe2f4daba", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 18 - } - }, { - "_id": "6c232b354c34836ee2627544", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 8 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 25 - } - }, { - "_id": "e4d6da7d7327f32138181741", - "_tpl": "5645bcc04bdc2d363b8b4572", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 23 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "8698b23a78a8dc22f4c69609", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 9 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 25 - } - }, { - "_id": "3497bff150a35f338ca823f6", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 8 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 25 - } - }, { - "_id": "9942ed330f84122f06ba4db4", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 7 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 25 - } - }, { - "_id": "bc683f19adbaab56ff115d51", - "_tpl": "56d59d3ad2720bdb418b4577", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 7 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 25 - } - }, { - "_id": "1064afb08ab86ccac101d94f", - "_tpl": "57347da92459774491567cf5", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 30 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "c844cb2dba7d609cbcba4770", - "_tpl": "57347da92459774491567cf5", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 31 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "5ed1e6bac123c3b2c9eeaf35", - "_tpl": "544fb25a4bdc2dfb738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 37 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "033a831eee25432724e8b1e9", - "_tpl": "576a581d2459771e7b1bc4f1", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 4 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "4040d36d8534fae91fb683d9", - "_tpl": "576a5ed62459771e9c2096cb", - "parentId": "033a831eee25432724e8b1e9", - "slotId": "mod_magazine" - }, { - "_id": "b1c5d10c0b6bb788d1a1d032", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "4040d36d8534fae91fb683d9", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 18 - } - }, { - "_id": "cbd1aa819fe0cf71f0d23ccd", - "_tpl": "576a63cd2459771e796e0e11", - "parentId": "033a831eee25432724e8b1e9", - "slotId": "mod_pistol_grip" - }, { - "_id": "aee2db2a5b61e09942c5b7d7", - "_tpl": "59984ab886f7743e98271174", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 6 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Foldable": { - "Folded": false - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "e73fe8ced9426d992f6bb3c0", - "_tpl": "5998517986f7746017232f7e", - "parentId": "aee2db2a5b61e09942c5b7d7", - "slotId": "mod_pistol_grip" - }, { - "_id": "88641f60682745d0bf04747e", - "_tpl": "599851db86f77467372f0a18", - "parentId": "aee2db2a5b61e09942c5b7d7", - "slotId": "mod_stock" - }, { - "_id": "6393b7d3728b809b054baa31", - "_tpl": "599860ac86f77436b225ed1a", - "parentId": "aee2db2a5b61e09942c5b7d7", - "slotId": "mod_magazine" - }, { - "_id": "77489a635cff7fb941b58382", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "6393b7d3728b809b054baa31", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "54d27d8d60eb93aa6598377a", - "_tpl": "5998597786f77414ea6da093", - "parentId": "aee2db2a5b61e09942c5b7d7", - "slotId": "mod_muzzle" - }, { - "_id": "249ccd46eb7413434545be77", - "_tpl": "59985a8086f77414ec448d1a", - "parentId": "aee2db2a5b61e09942c5b7d7", - "slotId": "mod_reciever" - }, { - "_id": "673088d03e5d01e4138ef4ab", - "_tpl": "599860e986f7743bb57573a6", - "parentId": "aee2db2a5b61e09942c5b7d7", - "slotId": "mod_sight_rear", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "e629647af1a768658f2576a9", - "_tpl": "59ccd11386f77428f24a488f", - "parentId": "aee2db2a5b61e09942c5b7d7", - "slotId": "mod_gas_block" - }, { - "_id": "6ae2eff0b14c553cdaf9c4be", - "_tpl": "5648b1504bdc2d9d488b4584", - "parentId": "e629647af1a768658f2576a9", - "slotId": "mod_handguard" - }, { - "_id": "48116a27afe5a51c917c10dd", - "_tpl": "576a581d2459771e7b1bc4f1", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 3 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "492f1602f7df59c0ff58bb91", - "_tpl": "576a5ed62459771e9c2096cb", - "parentId": "48116a27afe5a51c917c10dd", - "slotId": "mod_magazine" - }, { - "_id": "2d1261c888e045fc764e4a11", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "492f1602f7df59c0ff58bb91", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 18 - } - }, { - "_id": "c68ed794aa5be082ab90220e", - "_tpl": "576a63cd2459771e796e0e11", - "parentId": "48116a27afe5a51c917c10dd", - "slotId": "mod_pistol_grip" - }, { - "_id": "04f8a1021e1cef21b5347758", - "_tpl": "576a581d2459771e7b1bc4f1", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 5 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "1ae4bba45f10fc2012f3a5b1", - "_tpl": "576a5ed62459771e9c2096cb", - "parentId": "04f8a1021e1cef21b5347758", - "slotId": "mod_magazine" - }, { - "_id": "5dbe4c5e5b4795f82ed6144a", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "1ae4bba45f10fc2012f3a5b1", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 18 - } - }, { - "_id": "ca2a633299f9f33af985b298", - "_tpl": "576a63cd2459771e796e0e11", - "parentId": "04f8a1021e1cef21b5347758", - "slotId": "mod_pistol_grip" - }, { - "_id": "b81104333cd5e913c1abd001", - "_tpl": "59984ab886f7743e98271174", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 6 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Foldable": { - "Folded": false - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "caae6d1eec454357902beeba", - "_tpl": "5998517986f7746017232f7e", - "parentId": "b81104333cd5e913c1abd001", - "slotId": "mod_pistol_grip" - }, { - "_id": "d1904664ab60713b9fd815be", - "_tpl": "599851db86f77467372f0a18", - "parentId": "b81104333cd5e913c1abd001", - "slotId": "mod_stock" - }, { - "_id": "9dad59f2a5e9ff7e955c5a56", - "_tpl": "599860ac86f77436b225ed1a", - "parentId": "b81104333cd5e913c1abd001", - "slotId": "mod_magazine" - }, { - "_id": "0a21f9564f0c58050b5dd2d2", - "_tpl": "56d59d3ad2720bdb418b4577", - "parentId": "9dad59f2a5e9ff7e955c5a56", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "ae896c83b9422ef05d676b06", - "_tpl": "5998597786f77414ea6da093", - "parentId": "b81104333cd5e913c1abd001", - "slotId": "mod_muzzle" - }, { - "_id": "fc407b8aa1339bba319c2ef6", - "_tpl": "59985a8086f77414ec448d1a", - "parentId": "b81104333cd5e913c1abd001", - "slotId": "mod_reciever" - }, { - "_id": "6a7502a02962e7c027c15a63", - "_tpl": "599860e986f7743bb57573a6", - "parentId": "b81104333cd5e913c1abd001", - "slotId": "mod_sight_rear", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "67fe260376be3f6cb6ded9cf", - "_tpl": "59ccd11386f77428f24a488f", - "parentId": "b81104333cd5e913c1abd001", - "slotId": "mod_gas_block" - }, { - "_id": "f19cdda8faee5021d4a08f81", - "_tpl": "5648b1504bdc2d9d488b4584", - "parentId": "67fe260376be3f6cb6ded9cf", - "slotId": "mod_handguard" - }, { - "_id": "88d67c13e89abba40c550ef1", - "_tpl": "5ac4cd105acfc40016339859", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 16 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Foldable": { - "Folded": false - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "ec876c03e80b8c3c46e59399", - "_tpl": "59c6633186f7740cf0493bb9", - "parentId": "88d67c13e89abba40c550ef1", - "slotId": "mod_gas_block" - }, { - "_id": "da186a0d6c299a65a317ed61", - "_tpl": "5648b1504bdc2d9d488b4584", - "parentId": "ec876c03e80b8c3c46e59399", - "slotId": "mod_handguard" - }, { - "_id": "cfacc8f134240e1223fcb615", - "_tpl": "5ac7655e5acfc40016339a19", - "parentId": "88d67c13e89abba40c550ef1", - "slotId": "mod_muzzle" - }, { - "_id": "cc181f04ada4abe087e17234", - "_tpl": "5649ade84bdc2d1b2b8b4587", - "parentId": "88d67c13e89abba40c550ef1", - "slotId": "mod_pistol_grip" - }, { - "_id": "d8c5662e3f953c5e4c9f4613", - "_tpl": "5ac50da15acfc4001718d287", - "parentId": "88d67c13e89abba40c550ef1", - "slotId": "mod_reciever" - }, { - "_id": "ad816afec6245fb529b58600", - "_tpl": "5ac72e475acfc400180ae6fe", - "parentId": "88d67c13e89abba40c550ef1", - "slotId": "mod_sight_rear", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "fec1cfe279af3d3258bd0c90", - "_tpl": "5ac50c185acfc400163398d4", - "parentId": "88d67c13e89abba40c550ef1", - "slotId": "mod_stock" - }, { - "_id": "a4e24ac95eb0f569a1866bf3", - "_tpl": "55d480c04bdc2d1d4e8b456a", - "parentId": "88d67c13e89abba40c550ef1", - "slotId": "mod_magazine" - }, { - "_id": "2d1395cba72107e1c9162cf3", - "_tpl": "56dfef82d2720bbd668b4567", - "parentId": "a4e24ac95eb0f569a1866bf3", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "1c25a131cbb81b7961ef203b", - "_tpl": "5e870397991fd70db46995c8", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 18 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5df1457876ccab711e118c24", - "_tpl": "5e87071478f43e51ca2de5e1", - "parentId": "1c25a131cbb81b7961ef203b", - "slotId": "mod_barrel" - }, { - "_id": "c0ca8f4dea05e26d4e806a4c", - "_tpl": "5e8708d4ae379e67d22e0102", - "parentId": "5df1457876ccab711e118c24", - "slotId": "mod_sight_front", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "6919532db9870495a2a7a7c8", - "_tpl": "5e87076ce2db31558c75a11d", - "parentId": "1c25a131cbb81b7961ef203b", - "slotId": "mod_handguard" - }, { - "_id": "90e4e6856f705bedd86f56c2", - "_tpl": "5e87080c81c4ed43e83cefda", - "parentId": "1c25a131cbb81b7961ef203b", - "slotId": "mod_magazine" - }, { - "_id": "d8f540e6cfb57e776d01e3ce", - "_tpl": "560d5e524bdc2d25448b4571", - "parentId": "90e4e6856f705bedd86f56c2", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 8 - } - }, { - "_id": "ce990869892535be8644a87d", - "_tpl": "5e87116b81c4ed43e83cefdd", - "parentId": "1c25a131cbb81b7961ef203b", - "slotId": "mod_stock" - }, { - "_id": "65c7752f89afb6e9fc368d54", - "_tpl": "5e87114fe2db31558c75a120", - "parentId": "1c25a131cbb81b7961ef203b", - "slotId": "mod_mount", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "2fee9ee8b89eb2bc60279765", - "_tpl": "560d5e524bdc2d25448b4571", - "parentId": "1c25a131cbb81b7961ef203b", - "slotId": "patron_in_weapon" - }, { - "_id": "0263e3bc89cb651c5139987e", - "_tpl": "559ba5b34bdc2d1f1a8b4582", - "location": { - "isSearched": true, - "r": "Horizontal", - "x": 9, - "y": 18 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout" - }, { - "_id": "769a6f15a9b3c58ce40e75ac", - "_tpl": "5887431f2459777e1612938f", - "parentId": "0263e3bc89cb651c5139987e", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 10 - } - }, { - "_id": "b2edecbf14e5350dfd6e6e5e", - "_tpl": "6499849fc93611967b034949", - "location": { - "isSearched": true, - "r": 1, - "x": 7, - "y": 25 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Foldable": { - "Folded": false - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - },{ - "_id": "1424076063149bbbc18be043", - "_tpl": "649ec107961514b22506b10c", - "parentId": "b2edecbf14e5350dfd6e6e5e", - "slotId": "mod_gas_block", - "upd": { - "StackObjectsCount": 1 - } - }, { - "_id": "4d80308cb8a6857a9d83bbc6", - "_tpl": "5beec8ea0db834001a6f9dbf", - "parentId": "b2edecbf14e5350dfd6e6e5e", - "slotId": "mod_pistol_grip", - "upd": { - "StackObjectsCount": 1 - } - }, { - "_id": "a025f2dbc9f08b942a4c6e9b", - "_tpl": "649ec127c93611967b034957", - "parentId": "b2edecbf14e5350dfd6e6e5e", - "slotId": "mod_handguard", - "upd": { - "StackObjectsCount": 1 - } - }, { - "_id": "4604eba2de0c758ccba0a192", - "_tpl": "649ec2af961514b22506b10f", - "parentId": "b2edecbf14e5350dfd6e6e5e", - "slotId": "mod_muzzle", - "upd": { - "StackObjectsCount": 1 - } - }, { - "_id": "d29933d494ea298f19db3aeb", - "_tpl": "649ec2f3961514b22506b111", - "parentId": "b2edecbf14e5350dfd6e6e5e", - "slotId": "mod_reciever", - "upd": { - "StackObjectsCount": 1 - } - }, { - "_id": "9808b23de6d06cbcf1dfb99e", - "_tpl": "649ec30cb013f04a700e60fb", - "parentId": "b2edecbf14e5350dfd6e6e5e", - "slotId": "mod_magazine", - "upd": { - "StackObjectsCount": 1 - } - }, { - "_id": "c63e9186930f29c20f9d0fe4", - "_tpl": "649ec87d8007560a9001ab36", - "parentId": "b2edecbf14e5350dfd6e6e5e", - "slotId": "mod_stock_001", - "upd": { - "StackObjectsCount": 1 - } - }, { - "_id": "81c613b056072a70d6c26e1f", - "_tpl": "5beecbb80db834001d2c465e", - "parentId": "a025f2dbc9f08b942a4c6e9b", - "slotId": "mod_mount_001", - "upd": { - "StackObjectsCount": 1 - } - }, { - "_id": "20c4a8f521c8aed8176d3870", - "_tpl": "649ec2da59cbb3c813042dca", - "parentId": "d29933d494ea298f19db3aeb", - "slotId": "mod_sight_rear", - "upd": { - "StackObjectsCount": 1 - } - }, { - "_id": "5c730026306a7c56490e5f3e", - "_tpl": "5beec8c20db834001d2c465c", - "parentId": "c63e9186930f29c20f9d0fe4", - "slotId": "mod_stock", - "upd": { - "StackObjectsCount": 1 - } - }, { - "_id": "bcb76cd884032f340f0f7a01", - "_tpl": "649ec2cec93611967b03495e", - "parentId": "20c4a8f521c8aed8176d3870", - "slotId": "mod_sight_rear", - "upd": { - "StackObjectsCount": 1 - } - }, { - "_id": "0bc701a7ea93ee76e18ebb0e", - "_tpl": "56dff3afd2720bba668b4567", - "parentId": "9808b23de6d06cbcf1dfb99e", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49444ae6628187a2e78ba", - "_tpl": "5963866b86f7747bfa1c4462" - }, { - "_id": "5fe49444ae6628187a2e78b9", - "_tpl": "5963866286f7747bf429b572" - }, { - "_id": "60dca3da42ad9b706b369aca", - "_tpl": "602543c13fee350cd564d032" - }, { - "_id": "60c86df7ed1a4e3ce394a0f6", - "_tpl": "55801eed4bdc2d89578b4588", - "location": { - "isSearched": true, - "r": "Horizontal", - "x": 4, - "y": 19 - }, - "parentId": "5fe49444ae6628187a2e78b8", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - }, - "StackObjectsCount": 1 - } - }, { - "_id": "645a3bf083b382035fcd50c3", - "_tpl": "56083eab4bdc2d26448b456a", - "parentId": "60c86df7ed1a4e3ce394a0f6", - "slotId": "mod_tactical", - "upd": { - "StackObjectsCount": 1 - } - }, { - "_id": "f230be53d0fb90f23ac0005e", - "_tpl": "560e620e4bdc2d724b8b456b", - "parentId": "60c86df7ed1a4e3ce394a0f6", - "slotId": "mod_muzzle", - "upd": { - "StackObjectsCount": 1 - } - }, { - "_id": "3da4a360d74f2f9628bc5dd2", - "_tpl": "61faa91878830f069b6b7967", - "parentId": "60c86df7ed1a4e3ce394a0f6", - "slotId": "mod_stock", - "upd": { - "StackObjectsCount": 1 - } - }, { - "_id": "969ff4763565268bc52e4d2e", - "_tpl": "56ea8222d2720b69698b4567", - "parentId": "3da4a360d74f2f9628bc5dd2", - "slotId": "mod_bipod", - "upd": { - "StackObjectsCount": 1 - } + "items": [ + { + "_id": "6613bb72b5b0ba138a0fa9f4", + "_tpl": "55d7217a4bdc2d86028b456d" + }, { + "_id": "6613bb72b5b0ba138a0fa9d9", + "_tpl": "5ac4cd105acfc40016339859", + "parentId": "6613bb72b5b0ba138a0fa9f4", + "slotId": "FirstPrimaryWeapon" + }, { + "_id": "6613bb72b5b0ba138a0fa9d1", + "_tpl": "59c6633186f7740cf0493bb9", + "parentId": "6613bb72b5b0ba138a0fa9d9", + "slotId": "mod_gas_block" + }, { + "_id": "6613bb72b5b0ba138a0fa9d0", + "_tpl": "5648b1504bdc2d9d488b4584", + "parentId": "6613bb72b5b0ba138a0fa9d1", + "slotId": "mod_handguard" + }, { + "_id": "6613bb72b5b0ba138a0fa9d2", + "_tpl": "5ac7655e5acfc40016339a19", + "parentId": "6613bb72b5b0ba138a0fa9d9", + "slotId": "mod_muzzle" + }, { + "_id": "6613bb72b5b0ba138a0fa9d3", + "_tpl": "5649ade84bdc2d1b2b8b4587", + "parentId": "6613bb72b5b0ba138a0fa9d9", + "slotId": "mod_pistol_grip" + }, { + "_id": "6613bb72b5b0ba138a0fa9d4", + "_tpl": "5ac50da15acfc4001718d287", + "parentId": "6613bb72b5b0ba138a0fa9d9", + "slotId": "mod_reciever" + }, { + "_id": "6613bb72b5b0ba138a0fa9d5", + "_tpl": "5ac72e475acfc400180ae6fe", + "parentId": "6613bb72b5b0ba138a0fa9d9", + "slotId": "mod_sight_rear" + }, { + "_id": "6613bb72b5b0ba138a0fa9d6", + "_tpl": "5ac50c185acfc400163398d4", + "parentId": "6613bb72b5b0ba138a0fa9d9", + "slotId": "mod_stock" + }, { + "_id": "6613bb72b5b0ba138a0fa9d8", + "_tpl": "55d480c04bdc2d1d4e8b456a", + "parentId": "6613bb72b5b0ba138a0fa9d9", + "slotId": "mod_magazine" + }, { + "_id": "6613bb72b5b0ba138a0fa9d7", + "_tpl": "56dfef82d2720bbd668b4567", + "parentId": "6613bb72b5b0ba138a0fa9d8", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 } - ], - "questRaidItems": "5fe49444ae6628187a2e78b9", - "questStashItems": "5fe49444ae6628187a2e78ba", - "sortingTable": "60dca3da42ad9b706b369aca", - "stash": "5fe49444ae6628187a2e78b8" + }, { + "_id": "6613bb72b5b0ba138a0fa9da", + "_tpl": "5bffdc370db834001d23eca8", + "parentId": "6613bb72b5b0ba138a0fa9f4", + "slotId": "Scabbard" + }, { + "_id": "6613bb72b5b0ba138a0fa9db", + "_tpl": "5b40e5e25acfc4001a599bea", + "parentId": "6613bb72b5b0ba138a0fa9f4", + "slotId": "Headwear" + }, { + "_id": "6613bb72b5b0ba138a0fa9e3", + "_tpl": "5ca20abf86f77418567a43f2", + "parentId": "6613bb72b5b0ba138a0fa9f4", + "slotId": "TacticalVest" + }, { + "_id": "6613bb72b5b0ba138a0fa9dd", + "_tpl": "55d480c04bdc2d1d4e8b456a", + "parentId": "6613bb72b5b0ba138a0fa9e3", + "slotId": "1", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9dc", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0fa9dd", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0fa9df", + "_tpl": "55d480c04bdc2d1d4e8b456a", + "parentId": "6613bb72b5b0ba138a0fa9e3", + "slotId": "2", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9de", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0fa9df", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0fa9e1", + "_tpl": "55d480c04bdc2d1d4e8b456a", + "parentId": "6613bb72b5b0ba138a0fa9e3", + "slotId": "3", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9e0", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0fa9e1", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0fa9e2", + "_tpl": "5755356824597772cb798962", + "parentId": "6613bb72b5b0ba138a0fa9e3", + "slotId": "4", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9e4", + "_tpl": "5857a8bc2459772bad15db29", + "parentId": "6613bb72b5b0ba138a0fa9f4", + "slotId": "SecuredContainer" + }, { + "_id": "6613bb72b5b0ba138a0fa9e9", + "_tpl": "5ca20d5986f774331e7c9602", + "parentId": "6613bb72b5b0ba138a0fa9f4", + "slotId": "Backpack" + }, { + "_id": "6613bb72b5b0ba138a0fa9e5", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0fa9e9", + "slotId": "main", + "location": { + "x": 2, + "y": 0, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0fa9e6", + "_tpl": "56dfef82d2720bbd668b4567", + "parentId": "6613bb72b5b0ba138a0fa9e9", + "slotId": "main", + "location": { + "x": 2, + "y": 1, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0fa9e7", + "_tpl": "5448fee04bdc2dbc018b4567", + "parentId": "6613bb72b5b0ba138a0fa9e9", + "slotId": "main", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9e8", + "_tpl": "590c5d4b86f774784e1b9c45", + "parentId": "6613bb72b5b0ba138a0fa9e9", + "slotId": "main", + "location": { + "x": 1, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9ee", + "_tpl": "5648a7494bdc2d9d488b4583", + "parentId": "6613bb72b5b0ba138a0fa9f4", + "slotId": "ArmorVest" + }, { + "_id": "6613bb72b5b0ba138a0fa9ea", + "_tpl": "65703d866584602f7d057a8a", + "parentId": "6613bb72b5b0ba138a0fa9ee", + "slotId": "Soft_armor_front" + }, { + "_id": "6613bb72b5b0ba138a0fa9eb", + "_tpl": "65703fa06584602f7d057a8e", + "parentId": "6613bb72b5b0ba138a0fa9ee", + "slotId": "Soft_armor_back" + }, { + "_id": "6613bb72b5b0ba138a0fa9ec", + "_tpl": "65703fe46a912c8b5c03468b", + "parentId": "6613bb72b5b0ba138a0fa9ee", + "slotId": "Soft_armor_left" + }, { + "_id": "6613bb72b5b0ba138a0fa9ed", + "_tpl": "657040374e67e8ec7a0d261c", + "parentId": "6613bb72b5b0ba138a0fa9ee", + "slotId": "soft_armor_right" + }, { + "_id": "6613bb72b5b0ba138a0fa9f2", + "_tpl": "627a4e6b255f7527fb05a0f6", + "parentId": "6613bb72b5b0ba138a0fa9f4", + "slotId": "Pockets" + }, { + "_id": "6613bb72b5b0ba138a0fa9ef", + "_tpl": "544fb3364bdc2d34748b456a", + "parentId": "6613bb72b5b0ba138a0fa9f2", + "slotId": "pocket1", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9f0", + "_tpl": "544fb37f4bdc2dee738b4567", + "parentId": "6613bb72b5b0ba138a0fa9f2", + "slotId": "pocket2", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9f1", + "_tpl": "5751a25924597722c463c472", + "parentId": "6613bb72b5b0ba138a0fa9f2", + "slotId": "pocket3", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9f3", + "_tpl": "5645bcc04bdc2d363b8b4572", + "parentId": "6613bb72b5b0ba138a0fa9f4", + "slotId": "Earpiece" + }, { + "_id": "6613bb72b5b0ba138a0fab07", + "_tpl": "5811ce772459770e9e5f9532" + }, { + "_id": "6613bb72b5b0ba138a0fa9f5", + "_tpl": "5755356824597772cb798962", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9fa", + "_tpl": "5648a7494bdc2d9d488b4583", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9f6", + "_tpl": "65703d866584602f7d057a8a", + "parentId": "6613bb72b5b0ba138a0fa9fa", + "slotId": "Soft_armor_front" + }, { + "_id": "6613bb72b5b0ba138a0fa9f7", + "_tpl": "65703fa06584602f7d057a8e", + "parentId": "6613bb72b5b0ba138a0fa9fa", + "slotId": "Soft_armor_back" + }, { + "_id": "6613bb72b5b0ba138a0fa9f8", + "_tpl": "65703fe46a912c8b5c03468b", + "parentId": "6613bb72b5b0ba138a0fa9fa", + "slotId": "Soft_armor_left" + }, { + "_id": "6613bb72b5b0ba138a0fa9f9", + "_tpl": "657040374e67e8ec7a0d261c", + "parentId": "6613bb72b5b0ba138a0fa9fa", + "slotId": "soft_armor_right" + }, { + "_id": "6613bb72b5b0ba138a0fa9fb", + "_tpl": "5710c24ad2720bc3458b45a3", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 10, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9fc", + "_tpl": "5b432b965acfc47a8774094e", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 8, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9fd", + "_tpl": "5ca20abf86f77418567a43f2", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9fe", + "_tpl": "557ff21e4bdc2d89578b4586", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 22, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0fa9ff", + "_tpl": "5710c24ad2720bc3458b45a3", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 10, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa00", + "_tpl": "5ca20abf86f77418567a43f2", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 3, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa01", + "_tpl": "5755356824597772cb798962", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 2, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa02", + "_tpl": "5d40407c86f774318526545a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa03", + "_tpl": "5449016a4bdc2d6f028b456f", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 1, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 250000 + } + }, { + "_id": "6613bb72b5b0ba138a0faa05", + "_tpl": "599860ac86f77436b225ed1a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 8, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa04", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa05", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faa0a", + "_tpl": "5648a7494bdc2d9d488b4583", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 3, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa06", + "_tpl": "65703d866584602f7d057a8a", + "parentId": "6613bb72b5b0ba138a0faa0a", + "slotId": "Soft_armor_front" + }, { + "_id": "6613bb72b5b0ba138a0faa07", + "_tpl": "65703fa06584602f7d057a8e", + "parentId": "6613bb72b5b0ba138a0faa0a", + "slotId": "Soft_armor_back" + }, { + "_id": "6613bb72b5b0ba138a0faa08", + "_tpl": "65703fe46a912c8b5c03468b", + "parentId": "6613bb72b5b0ba138a0faa0a", + "slotId": "Soft_armor_left" + }, { + "_id": "6613bb72b5b0ba138a0faa09", + "_tpl": "657040374e67e8ec7a0d261c", + "parentId": "6613bb72b5b0ba138a0faa0a", + "slotId": "soft_armor_right" + }, { + "_id": "6613bb72b5b0ba138a0faa0b", + "_tpl": "5b40e5e25acfc4001a599bea", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa0c", + "_tpl": "5b40e5e25acfc4001a599bea", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa0d", + "_tpl": "5b432b965acfc47a8774094e", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 8, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa0e", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 1, + "y": 10, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613bb72b5b0ba138a0faa10", + "_tpl": "576a5ed62459771e9c2096cb", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 3, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa0f", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa10", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 18 + } + }, { + "_id": "6613bb72b5b0ba138a0faa12", + "_tpl": "576a5ed62459771e9c2096cb", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 4, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa11", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa12", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 18 + } + }, { + "_id": "6613bb72b5b0ba138a0faa14", + "_tpl": "576a5ed62459771e9c2096cb", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 6, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa13", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa14", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 18 + } + }, { + "_id": "6613bb72b5b0ba138a0faa16", + "_tpl": "576a5ed62459771e9c2096cb", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 5, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa15", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa16", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 18 + } + }, { + "_id": "6613bb72b5b0ba138a0faa17", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 2, + "y": 10, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613bb72b5b0ba138a0faa18", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 7, + "y": 10, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613bb72b5b0ba138a0faa19", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 10, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613bb72b5b0ba138a0faa1a", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 10, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613bb72b5b0ba138a0faa1c", + "_tpl": "599860ac86f77436b225ed1a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 1, + "y": 8, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa1b", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa1c", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faa1e", + "_tpl": "599860ac86f77436b225ed1a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 2, + "y": 8, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa1d", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa1e", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faa20", + "_tpl": "599860ac86f77436b225ed1a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 8, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa1f", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa20", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faa22", + "_tpl": "599860ac86f77436b225ed1a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 8, + "y": 8, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa21", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa22", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faa24", + "_tpl": "599860ac86f77436b225ed1a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 7, + "y": 8, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa23", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa24", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faa25", + "_tpl": "5ca20d5986f774331e7c9602", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 11, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa26", + "_tpl": "5ca20d5986f774331e7c9602", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 11, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa27", + "_tpl": "5710c24ad2720bc3458b45a3", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 21, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa28", + "_tpl": "590c661e86f7741e566b646a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 8, + "y": 32, + "r": 1, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa29", + "_tpl": "5449016a4bdc2d6f028b456f", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 1, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 250000 + } + }, { + "_id": "6613bb72b5b0ba138a0faa2a", + "_tpl": "590c661e86f7741e566b646a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 8, + "y": 30, + "r": 1, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa2b", + "_tpl": "5755383e24597772cb798966", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa2c", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 17, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 60 + } + }, { + "_id": "6613bb72b5b0ba138a0faa2d", + "_tpl": "5a0c27731526d80618476ac4", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 12, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa2e", + "_tpl": "5a0c27731526d80618476ac4", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 12, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa30", + "_tpl": "55d480c04bdc2d1d4e8b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 16, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa2f", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0faa30", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faa32", + "_tpl": "55d480c04bdc2d1d4e8b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 16, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa31", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0faa32", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faa34", + "_tpl": "55d480c04bdc2d1d4e8b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 7, + "y": 16, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa33", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0faa34", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faa35", + "_tpl": "56dfef82d2720bbd668b4567", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 16, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 60 + } + }, { + "_id": "6613bb72b5b0ba138a0faa37", + "_tpl": "55d480c04bdc2d1d4e8b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 8, + "y": 16, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa36", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0faa37", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faa38", + "_tpl": "590c5d4b86f774784e1b9c45", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 30, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa39", + "_tpl": "590c5d4b86f774784e1b9c45", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 30, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa3a", + "_tpl": "590c5d4b86f774784e1b9c45", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 7, + "y": 30, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa3b", + "_tpl": "5448fee04bdc2dbc018b4567", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 7, + "y": 32, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa3c", + "_tpl": "5448fee04bdc2dbc018b4567", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 32, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa3d", + "_tpl": "5448fee04bdc2dbc018b4567", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 32, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa3e", + "_tpl": "57347da92459774491567cf5", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 29, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa3f", + "_tpl": "57347da92459774491567cf5", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 29, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa40", + "_tpl": "5e831507ea0a7c419c2f9bd9", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa41", + "_tpl": "5e831507ea0a7c419c2f9bd9", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa42", + "_tpl": "5e831507ea0a7c419c2f9bd9", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 2, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa43", + "_tpl": "544fb3364bdc2d34748b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 7, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa44", + "_tpl": "544fb3364bdc2d34748b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 8, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa45", + "_tpl": "544fb3364bdc2d34748b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa46", + "_tpl": "5755356824597772cb798962", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 1, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa47", + "_tpl": "5755356824597772cb798962", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa48", + "_tpl": "544fb25a4bdc2dfb738b4567", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 37, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa49", + "_tpl": "544fb25a4bdc2dfb738b4567", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 37, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa4a", + "_tpl": "544fb25a4bdc2dfb738b4567", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa4c", + "_tpl": "576a5ed62459771e9c2096cb", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 7, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa4b", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa4c", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 18 + } + }, { + "_id": "6613bb72b5b0ba138a0faa4e", + "_tpl": "576a5ed62459771e9c2096cb", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 6, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa4d", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa4e", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 18 + } + }, { + "_id": "6613bb72b5b0ba138a0faa4f", + "_tpl": "560d5e524bdc2d25448b4571", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 7, + "y": 18, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613bb72b5b0ba138a0faa50", + "_tpl": "5a0c27731526d80618476ac4", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 11, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa51", + "_tpl": "5a0c27731526d80618476ac4", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 11, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa52", + "_tpl": "57347da92459774491567cf5", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 28, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa53", + "_tpl": "5d02778e86f774203e7dedbe", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa54", + "_tpl": "60098ad7c2240c0fe85c570a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa55", + "_tpl": "5e831507ea0a7c419c2f9bd9", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 1, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa56", + "_tpl": "590c695186f7741e566b64a2", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 37, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa57", + "_tpl": "590c695186f7741e566b64a2", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 7, + "y": 37, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa58", + "_tpl": "5751a25924597722c463c472", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 8, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa59", + "_tpl": "5751a25924597722c463c472", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 7, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa5a", + "_tpl": "5696686a4bdc2da3298b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 2, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 500 + } + }, { + "_id": "6613bb72b5b0ba138a0faa5b", + "_tpl": "5696686a4bdc2da3298b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 2, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 500 + } + }, { + "_id": "6613bb72b5b0ba138a0faa5c", + "_tpl": "560d5e524bdc2d25448b4571", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 18, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613bb72b5b0ba138a0faa5d", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 8, + "y": 10, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613bb72b5b0ba138a0faa5e", + "_tpl": "560d5e524bdc2d25448b4571", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 18, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613bb72b5b0ba138a0faa5f", + "_tpl": "5d1b36a186f7742523398433", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 13, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa60", + "_tpl": "5d1b371186f774253763a656", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 2, + "y": 38, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa62", + "_tpl": "559ba5b34bdc2d1f1a8b4582", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 20, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa61", + "_tpl": "5887431f2459777e1612938f", + "parentId": "6613bb72b5b0ba138a0faa62", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 10 + } + }, { + "_id": "6613bb72b5b0ba138a0faa64", + "_tpl": "559ba5b34bdc2d1f1a8b4582", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 19, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa63", + "_tpl": "5887431f2459777e1612938f", + "parentId": "6613bb72b5b0ba138a0faa64", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 10 + } + }, { + "_id": "6613bb72b5b0ba138a0faa65", + "_tpl": "5710c24ad2720bc3458b45a3", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 21, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa66", + "_tpl": "5710c24ad2720bc3458b45a3", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 21, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa67", + "_tpl": "5d02778e86f774203e7dedbe", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa68", + "_tpl": "5af0454c86f7746bf20992e8", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa6c", + "_tpl": "5aa7cfc0e5b5b00015693143", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 23, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa69", + "_tpl": "657baaf0b7e9ca9a02045c02", + "parentId": "6613bb72b5b0ba138a0faa6c", + "slotId": "Helmet_top" + }, { + "_id": "6613bb72b5b0ba138a0faa6a", + "_tpl": "657bab6ec6f689d3a205b85f", + "parentId": "6613bb72b5b0ba138a0faa6c", + "slotId": "Helmet_back" + }, { + "_id": "6613bb72b5b0ba138a0faa6b", + "_tpl": "657babc6f58ba5a6250107a2", + "parentId": "6613bb72b5b0ba138a0faa6c", + "slotId": "Helmet_ears" + }, { + "_id": "6613bb72b5b0ba138a0faa6d", + "_tpl": "5ab8f39486f7745cd93a1cca", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 22, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa6e", + "_tpl": "544fb37f4bdc2dee738b4567", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 32, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa6f", + "_tpl": "569668774bdc2da2298b4568", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 2, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 500 + } + }, { + "_id": "6613bb72b5b0ba138a0faa70", + "_tpl": "60098ad7c2240c0fe85c570a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 21, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa71", + "_tpl": "60098ad7c2240c0fe85c570a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 1, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa72", + "_tpl": "5af0454c86f7746bf20992e8", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa73", + "_tpl": "5d5d940f86f7742797262046", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 29, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa74", + "_tpl": "57cd379a24597778e7682ecf", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 23, + "r": 1, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa75", + "_tpl": "5887431f2459777e1612938f", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 22, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 40 + } + }, { + "_id": "6613bb72b5b0ba138a0faa76", + "_tpl": "5710c24ad2720bc3458b45a3", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 22, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa77", + "_tpl": "5ab8f39486f7745cd93a1cca", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 21, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa78", + "_tpl": "5e2af4a786f7746d3f3c3400", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 39, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa79", + "_tpl": "5d5d85c586f774279a21cbdb", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 25, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa7c", + "_tpl": "5b432d215acfc4771e1c6624", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 2, + "y": 23, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa7a", + "_tpl": "657bb92fa1c61ee0c303631f", + "parentId": "6613bb72b5b0ba138a0faa7c", + "slotId": "Helmet_top" + }, { + "_id": "6613bb72b5b0ba138a0faa7b", + "_tpl": "657bb99db30eca976305117f", + "parentId": "6613bb72b5b0ba138a0faa7c", + "slotId": "Helmet_back" + }, { + "_id": "6613bb72b5b0ba138a0faa7d", + "_tpl": "5e8488fa988a8701445df1e4", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 37, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa7e", + "_tpl": "5e8488fa988a8701445df1e4", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 8, + "y": 37, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa7f", + "_tpl": "590c678286f77426c9660122", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 2, + "y": 37, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa80", + "_tpl": "590c678286f77426c9660122", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 37, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa81", + "_tpl": "590c678286f77426c9660122", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 1, + "y": 37, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa83", + "_tpl": "55d480c04bdc2d1d4e8b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 28, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa82", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0faa83", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faa84", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 28, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 60 + } + }, { + "_id": "6613bb72b5b0ba138a0faa85", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 28, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 60 + } + }, { + "_id": "6613bb72b5b0ba138a0faa87", + "_tpl": "55d480c04bdc2d1d4e8b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 23, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa86", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0faa87", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faa88", + "_tpl": "5c0e530286f7747fa1419862", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 8, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa89", + "_tpl": "5c0e530286f7747fa1419862", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa8a", + "_tpl": "5c0505e00db834001b735073", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 24, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa8c", + "_tpl": "55d480c04bdc2d1d4e8b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 25, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa8b", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0faa8c", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faa8e", + "_tpl": "55d480c04bdc2d1d4e8b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 24, + "r": 1, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa8d", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0faa8e", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faa8f", + "_tpl": "590c657e86f77412b013051d", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 38, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa90", + "_tpl": "5af0454c86f7746bf20992e8", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa91", + "_tpl": "5b432b965acfc47a8774094e", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 7, + "y": 21, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa92", + "_tpl": "57347da92459774491567cf5", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 27, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa93", + "_tpl": "544fb37f4bdc2dee738b4567", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa94", + "_tpl": "544fb37f4bdc2dee738b4567", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 33, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa95", + "_tpl": "5e2af47786f7746d404f3aaa", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 38, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa96", + "_tpl": "5e2af47786f7746d404f3aaa", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 39, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa97", + "_tpl": "5e2af4a786f7746d3f3c3400", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 38, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa98", + "_tpl": "544fb3f34bdc2d03748b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa99", + "_tpl": "544fb3f34bdc2d03748b456a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 7, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa9b", + "_tpl": "576a5ed62459771e9c2096cb", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 6, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa9a", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa9b", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 18 + } + }, { + "_id": "6613bb72b5b0ba138a0faa9d", + "_tpl": "576a5ed62459771e9c2096cb", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 6, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa9c", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa9d", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 18 + } + }, { + "_id": "6613bb72b5b0ba138a0faa9f", + "_tpl": "576a5ed62459771e9c2096cb", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 7, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faa9e", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faa9f", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 18 + } + }, { + "_id": "6613bb72b5b0ba138a0faaa0", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 6, + "y": 10, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613bb72b5b0ba138a0faaa1", + "_tpl": "5645bcc04bdc2d363b8b4572", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 7, + "y": 23, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faaa2", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 10, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613bb72b5b0ba138a0faaa3", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 7, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613bb72b5b0ba138a0faaa4", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 7, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613bb72b5b0ba138a0faaa5", + "_tpl": "57347da92459774491567cf5", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 30, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faaa6", + "_tpl": "57347da92459774491567cf5", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 31, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faaa7", + "_tpl": "544fb25a4bdc2dfb738b4567", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 5, + "y": 37, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faaa9", + "_tpl": "559ba5b34bdc2d1f1a8b4582", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 8, + "y": 18, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faaa8", + "_tpl": "5887431f2459777e1612938f", + "parentId": "6613bb72b5b0ba138a0faaa9", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 10 + } + }, { + "_id": "6613bb72b5b0ba138a0faaab", + "_tpl": "559ba5b34bdc2d1f1a8b4582", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 9, + "y": 18, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faaaa", + "_tpl": "5887431f2459777e1612938f", + "parentId": "6613bb72b5b0ba138a0faaab", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 10 + } + }, { + "_id": "6613bb72b5b0ba138a0faaac", + "_tpl": "60098ad7c2240c0fe85c570a", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 2, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faab5", + "_tpl": "5c0e53c886f7747fa54205c7", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 19, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faaad", + "_tpl": "656f603f94b480b8a500c0d6", + "parentId": "6613bb72b5b0ba138a0faab5", + "slotId": "front_plate" + }, { + "_id": "6613bb72b5b0ba138a0faaae", + "_tpl": "656efd66034e8e01c407f35c", + "parentId": "6613bb72b5b0ba138a0faab5", + "slotId": "back_plate" + }, { + "_id": "6613bb72b5b0ba138a0faaaf", + "_tpl": "654a8b0b0337d53f9102c2ae", + "parentId": "6613bb72b5b0ba138a0faab5", + "slotId": "soft_armor_front" + }, { + "_id": "6613bb72b5b0ba138a0faab0", + "_tpl": "654a8976f414fcea4004d78b", + "parentId": "6613bb72b5b0ba138a0faab5", + "slotId": "soft_armor_back" + }, { + "_id": "6613bb72b5b0ba138a0faab1", + "_tpl": "654a8b3df414fcea4004d78f", + "parentId": "6613bb72b5b0ba138a0faab5", + "slotId": "soft_armor_left" + }, { + "_id": "6613bb72b5b0ba138a0faab2", + "_tpl": "654a8b80f414fcea4004d797", + "parentId": "6613bb72b5b0ba138a0faab5", + "slotId": "soft_armor_right" + }, { + "_id": "6613bb72b5b0ba138a0faab3", + "_tpl": "654a8ae00337d53f9102c2aa", + "parentId": "6613bb72b5b0ba138a0faab5", + "slotId": "Collar" + }, { + "_id": "6613bb72b5b0ba138a0faab4", + "_tpl": "654a8bc5f414fcea4004d79b", + "parentId": "6613bb72b5b0ba138a0faab5", + "slotId": "Groin" + }, { + "_id": "6613bb72b5b0ba138a0faabc", + "_tpl": "5c0e722886f7740458316a57", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 25, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faab6", + "_tpl": "656fa0fb498d1b7e3e071d9c", + "parentId": "6613bb72b5b0ba138a0faabc", + "slotId": "Front_plate" + }, { + "_id": "6613bb72b5b0ba138a0faab7", + "_tpl": "656fa0fb498d1b7e3e071d9c", + "parentId": "6613bb72b5b0ba138a0faabc", + "slotId": "Back_plate" + }, { + "_id": "6613bb72b5b0ba138a0faab8", + "_tpl": "65730c0e292ecadbfa09ad49", + "parentId": "6613bb72b5b0ba138a0faabc", + "slotId": "Soft_armor_front" + }, { + "_id": "6613bb72b5b0ba138a0faab9", + "_tpl": "65730c2213a2f660f60bea96", + "parentId": "6613bb72b5b0ba138a0faabc", + "slotId": "Soft_armor_back" + }, { + "_id": "6613bb72b5b0ba138a0faaba", + "_tpl": "65730c2b292ecadbfa09ad50", + "parentId": "6613bb72b5b0ba138a0faabc", + "slotId": "Soft_armor_left" + }, { + "_id": "6613bb72b5b0ba138a0faabb", + "_tpl": "65730c35292ecadbfa09ad54", + "parentId": "6613bb72b5b0ba138a0faabc", + "slotId": "soft_armor_right" + }, { + "_id": "6613bb72b5b0ba138a0faac0", + "_tpl": "576a581d2459771e7b1bc4f1", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 4, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faabe", + "_tpl": "576a5ed62459771e9c2096cb", + "parentId": "6613bb72b5b0ba138a0faac0", + "slotId": "mod_magazine" + }, { + "_id": "6613bb72b5b0ba138a0faabd", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faabe", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 18 + } + }, { + "_id": "6613bb72b5b0ba138a0faabf", + "_tpl": "576a63cd2459771e796e0e11", + "parentId": "6613bb72b5b0ba138a0faac0", + "slotId": "mod_pistol_grip" + }, { + "_id": "6613bb72b5b0ba138a0faaca", + "_tpl": "59984ab886f7743e98271174", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 6, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faac1", + "_tpl": "5998517986f7746017232f7e", + "parentId": "6613bb72b5b0ba138a0faaca", + "slotId": "mod_pistol_grip" + }, { + "_id": "6613bb72b5b0ba138a0faac2", + "_tpl": "599851db86f77467372f0a18", + "parentId": "6613bb72b5b0ba138a0faaca", + "slotId": "mod_stock" + }, { + "_id": "6613bb72b5b0ba138a0faac4", + "_tpl": "599860ac86f77436b225ed1a", + "parentId": "6613bb72b5b0ba138a0faaca", + "slotId": "mod_magazine" + }, { + "_id": "6613bb72b5b0ba138a0faac3", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faac4", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faac5", + "_tpl": "5998597786f77414ea6da093", + "parentId": "6613bb72b5b0ba138a0faaca", + "slotId": "mod_muzzle" + }, { + "_id": "6613bb72b5b0ba138a0faac6", + "_tpl": "59985a8086f77414ec448d1a", + "parentId": "6613bb72b5b0ba138a0faaca", + "slotId": "mod_reciever" + }, { + "_id": "6613bb72b5b0ba138a0faac7", + "_tpl": "599860e986f7743bb57573a6", + "parentId": "6613bb72b5b0ba138a0faaca", + "slotId": "mod_sight_rear" + }, { + "_id": "6613bb72b5b0ba138a0faac9", + "_tpl": "59ccd11386f77428f24a488f", + "parentId": "6613bb72b5b0ba138a0faaca", + "slotId": "mod_gas_block" + }, { + "_id": "6613bb72b5b0ba138a0faac8", + "_tpl": "5648b1504bdc2d9d488b4584", + "parentId": "6613bb72b5b0ba138a0faac9", + "slotId": "mod_handguard" + }, { + "_id": "6613bb72b5b0ba138a0faace", + "_tpl": "576a581d2459771e7b1bc4f1", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 3, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faacc", + "_tpl": "576a5ed62459771e9c2096cb", + "parentId": "6613bb72b5b0ba138a0faace", + "slotId": "mod_magazine" + }, { + "_id": "6613bb72b5b0ba138a0faacb", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faacc", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 18 + } + }, { + "_id": "6613bb72b5b0ba138a0faacd", + "_tpl": "576a63cd2459771e796e0e11", + "parentId": "6613bb72b5b0ba138a0faace", + "slotId": "mod_pistol_grip" + }, { + "_id": "6613bb72b5b0ba138a0faad2", + "_tpl": "576a581d2459771e7b1bc4f1", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 3, + "y": 5, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faad0", + "_tpl": "576a5ed62459771e9c2096cb", + "parentId": "6613bb72b5b0ba138a0faad2", + "slotId": "mod_magazine" + }, { + "_id": "6613bb72b5b0ba138a0faacf", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faad0", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 18 + } + }, { + "_id": "6613bb72b5b0ba138a0faad1", + "_tpl": "576a63cd2459771e796e0e11", + "parentId": "6613bb72b5b0ba138a0faad2", + "slotId": "mod_pistol_grip" + }, { + "_id": "6613bb72b5b0ba138a0faadc", + "_tpl": "59984ab886f7743e98271174", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 7, + "y": 6, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faad3", + "_tpl": "5998517986f7746017232f7e", + "parentId": "6613bb72b5b0ba138a0faadc", + "slotId": "mod_pistol_grip" + }, { + "_id": "6613bb72b5b0ba138a0faad4", + "_tpl": "599851db86f77467372f0a18", + "parentId": "6613bb72b5b0ba138a0faadc", + "slotId": "mod_stock" + }, { + "_id": "6613bb72b5b0ba138a0faad6", + "_tpl": "599860ac86f77436b225ed1a", + "parentId": "6613bb72b5b0ba138a0faadc", + "slotId": "mod_magazine" + }, { + "_id": "6613bb72b5b0ba138a0faad5", + "_tpl": "56d59d3ad2720bdb418b4577", + "parentId": "6613bb72b5b0ba138a0faad6", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faad7", + "_tpl": "5998597786f77414ea6da093", + "parentId": "6613bb72b5b0ba138a0faadc", + "slotId": "mod_muzzle" + }, { + "_id": "6613bb72b5b0ba138a0faad8", + "_tpl": "59985a8086f77414ec448d1a", + "parentId": "6613bb72b5b0ba138a0faadc", + "slotId": "mod_reciever" + }, { + "_id": "6613bb72b5b0ba138a0faad9", + "_tpl": "599860e986f7743bb57573a6", + "parentId": "6613bb72b5b0ba138a0faadc", + "slotId": "mod_sight_rear" + }, { + "_id": "6613bb72b5b0ba138a0faadb", + "_tpl": "59ccd11386f77428f24a488f", + "parentId": "6613bb72b5b0ba138a0faadc", + "slotId": "mod_gas_block" + }, { + "_id": "6613bb72b5b0ba138a0faada", + "_tpl": "5648b1504bdc2d9d488b4584", + "parentId": "6613bb72b5b0ba138a0faadb", + "slotId": "mod_handguard" + }, { + "_id": "6613bb72b5b0ba138a0faae6", + "_tpl": "5ac4cd105acfc40016339859", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 16, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faade", + "_tpl": "59c6633186f7740cf0493bb9", + "parentId": "6613bb72b5b0ba138a0faae6", + "slotId": "mod_gas_block" + }, { + "_id": "6613bb72b5b0ba138a0faadd", + "_tpl": "5648b1504bdc2d9d488b4584", + "parentId": "6613bb72b5b0ba138a0faade", + "slotId": "mod_handguard" + }, { + "_id": "6613bb72b5b0ba138a0faadf", + "_tpl": "5ac7655e5acfc40016339a19", + "parentId": "6613bb72b5b0ba138a0faae6", + "slotId": "mod_muzzle" + }, { + "_id": "6613bb72b5b0ba138a0faae0", + "_tpl": "5649ade84bdc2d1b2b8b4587", + "parentId": "6613bb72b5b0ba138a0faae6", + "slotId": "mod_pistol_grip" + }, { + "_id": "6613bb72b5b0ba138a0faae1", + "_tpl": "5ac50da15acfc4001718d287", + "parentId": "6613bb72b5b0ba138a0faae6", + "slotId": "mod_reciever" + }, { + "_id": "6613bb72b5b0ba138a0faae2", + "_tpl": "5ac72e475acfc400180ae6fe", + "parentId": "6613bb72b5b0ba138a0faae6", + "slotId": "mod_sight_rear" + }, { + "_id": "6613bb72b5b0ba138a0faae3", + "_tpl": "5ac50c185acfc400163398d4", + "parentId": "6613bb72b5b0ba138a0faae6", + "slotId": "mod_stock" + }, { + "_id": "6613bb72b5b0ba138a0faae5", + "_tpl": "55d480c04bdc2d1d4e8b456a", + "parentId": "6613bb72b5b0ba138a0faae6", + "slotId": "mod_magazine" + }, { + "_id": "6613bb72b5b0ba138a0faae4", + "_tpl": "56dfef82d2720bbd668b4567", + "parentId": "6613bb72b5b0ba138a0faae5", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faaef", + "_tpl": "5e870397991fd70db46995c8", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 0, + "y": 18, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faae8", + "_tpl": "5e87071478f43e51ca2de5e1", + "parentId": "6613bb72b5b0ba138a0faaef", + "slotId": "mod_barrel" + }, { + "_id": "6613bb72b5b0ba138a0faae7", + "_tpl": "5e8708d4ae379e67d22e0102", + "parentId": "6613bb72b5b0ba138a0faae8", + "slotId": "mod_sight_front" + }, { + "_id": "6613bb72b5b0ba138a0faae9", + "_tpl": "5e87076ce2db31558c75a11d", + "parentId": "6613bb72b5b0ba138a0faaef", + "slotId": "mod_handguard" + }, { + "_id": "6613bb72b5b0ba138a0faaeb", + "_tpl": "5e87080c81c4ed43e83cefda", + "parentId": "6613bb72b5b0ba138a0faaef", + "slotId": "mod_magazine" + }, { + "_id": "6613bb72b5b0ba138a0faaea", + "_tpl": "560d5e524bdc2d25448b4571", + "parentId": "6613bb72b5b0ba138a0faaeb", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 8 + } + }, { + "_id": "6613bb72b5b0ba138a0faaec", + "_tpl": "5e87116b81c4ed43e83cefdd", + "parentId": "6613bb72b5b0ba138a0faaef", + "slotId": "mod_stock" + }, { + "_id": "6613bb72b5b0ba138a0faaed", + "_tpl": "5e87114fe2db31558c75a120", + "parentId": "6613bb72b5b0ba138a0faaef", + "slotId": "mod_mount" + }, { + "_id": "6613bb72b5b0ba138a0faaee", + "_tpl": "560d5e524bdc2d25448b4571", + "parentId": "6613bb72b5b0ba138a0faaef", + "slotId": "patron_in_weapon" + }, { + "_id": "6613bb72b5b0ba138a0faafd", + "_tpl": "6499849fc93611967b034949", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 7, + "y": 25, + "r": 1, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faaf0", + "_tpl": "649ec107961514b22506b10c", + "parentId": "6613bb72b5b0ba138a0faafd", + "slotId": "mod_gas_block" + }, { + "_id": "6613bb72b5b0ba138a0faaf1", + "_tpl": "649ec2af961514b22506b10f", + "parentId": "6613bb72b5b0ba138a0faafd", + "slotId": "mod_muzzle" + }, { + "_id": "6613bb72b5b0ba138a0faaf2", + "_tpl": "5beec8ea0db834001a6f9dbf", + "parentId": "6613bb72b5b0ba138a0faafd", + "slotId": "mod_pistol_grip" + }, { + "_id": "6613bb72b5b0ba138a0faaf5", + "_tpl": "649ec2f3961514b22506b111", + "parentId": "6613bb72b5b0ba138a0faafd", + "slotId": "mod_reciever" + }, { + "_id": "6613bb72b5b0ba138a0faaf4", + "_tpl": "649ec2da59cbb3c813042dca", + "parentId": "6613bb72b5b0ba138a0faaf5", + "slotId": "mod_sight_rear" + }, { + "_id": "6613bb72b5b0ba138a0faaf3", + "_tpl": "649ec2cec93611967b03495e", + "parentId": "6613bb72b5b0ba138a0faaf4", + "slotId": "mod_sight_rear" + }, { + "_id": "6613bb72b5b0ba138a0faaf7", + "_tpl": "649ec87d8007560a9001ab36", + "parentId": "6613bb72b5b0ba138a0faafd", + "slotId": "mod_stock_001" + }, { + "_id": "6613bb72b5b0ba138a0faaf6", + "_tpl": "5beec8c20db834001d2c465c", + "parentId": "6613bb72b5b0ba138a0faaf7", + "slotId": "mod_stock" + }, { + "_id": "6613bb72b5b0ba138a0faaf9", + "_tpl": "649ec30cb013f04a700e60fb", + "parentId": "6613bb72b5b0ba138a0faafd", + "slotId": "mod_magazine" + }, { + "_id": "6613bb72b5b0ba138a0faaf8", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0faaf9", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613bb72b5b0ba138a0faafb", + "_tpl": "649ec127c93611967b034957", + "parentId": "6613bb72b5b0ba138a0faafd", + "slotId": "mod_handguard" + }, { + "_id": "6613bb72b5b0ba138a0faafa", + "_tpl": "5beecbb80db834001d2c465e", + "parentId": "6613bb72b5b0ba138a0faafb", + "slotId": "mod_mount_001" + }, { + "_id": "6613bb72b5b0ba138a0faafc", + "_tpl": "56dff3afd2720bba668b4567", + "parentId": "6613bb72b5b0ba138a0faafd", + "slotId": "patron_in_weapon" + }, { + "_id": "6613bb72b5b0ba138a0fab06", + "_tpl": "55801eed4bdc2d89578b4588", + "parentId": "6613bb72b5b0ba138a0fab07", + "slotId": "hideout", + "location": { + "x": 4, + "y": 19, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613bb72b5b0ba138a0faaff", + "_tpl": "559ba5b34bdc2d1f1a8b4582", + "parentId": "6613bb72b5b0ba138a0fab06", + "slotId": "mod_magazine" + }, { + "_id": "6613bb72b5b0ba138a0faafe", + "_tpl": "5887431f2459777e1612938f", + "parentId": "6613bb72b5b0ba138a0faaff", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 10 + } + }, { + "_id": "6613bb72b5b0ba138a0fab01", + "_tpl": "5d0a29fed7ad1a002769ad08", + "parentId": "6613bb72b5b0ba138a0fab06", + "slotId": "mod_scope" + }, { + "_id": "6613bb72b5b0ba138a0fab00", + "_tpl": "5d0a3e8cd7ad1a6f6a3d35bd", + "parentId": "6613bb72b5b0ba138a0fab01", + "slotId": "mod_scope" + }, { + "_id": "6613bb72b5b0ba138a0fab02", + "_tpl": "56083eab4bdc2d26448b456a", + "parentId": "6613bb72b5b0ba138a0fab06", + "slotId": "mod_tactical" + }, { + "_id": "6613bb72b5b0ba138a0fab03", + "_tpl": "560e620e4bdc2d724b8b456b", + "parentId": "6613bb72b5b0ba138a0fab06", + "slotId": "mod_muzzle" + }, { + "_id": "6613bb72b5b0ba138a0fab05", + "_tpl": "61faa91878830f069b6b7967", + "parentId": "6613bb72b5b0ba138a0fab06", + "slotId": "mod_stock" + }, { + "_id": "6613bb72b5b0ba138a0fab04", + "_tpl": "56ea8222d2720b69698b4567", + "parentId": "6613bb72b5b0ba138a0fab05", + "slotId": "mod_bipod" + }, { + "_id": "6613bb72b5b0ba138a0fab0a", + "_tpl": "602543c13fee350cd564d032" + }, { + "_id": "6613bb72b5b0ba138a0fab09", + "_tpl": "5963866b86f7747bfa1c4462" + }, { + "_id": "6613bb72b5b0ba138a0fab08", + "_tpl": "5963866286f7747bf429b572" + } + ], + "questRaidItems": "6613bb72b5b0ba138a0fab08", + "questStashItems": "6613bb72b5b0ba138a0fab09", + "sortingTable": "6613bb72b5b0ba138a0fab0a", + "stash": "6613bb72b5b0ba138a0fab07" }, "Notes": { "Notes": [] @@ -24254,3548 +23609,2935 @@ }, "InsuredItems": [], "Inventory": { - "equipment": "5fe49a0e2694b0755a50476c", + "equipment": "6613e1cf291a2e76b00269a8", "fastPanel": {}, "hideoutAreaStashes": {}, - "items": [{ - "_id": "5fe49a0e2694b0755a50476c", - "_tpl": "55d7217a4bdc2d86028b456d" - }, { - "_id": "63db64cbf9963741dc0d741f", - "_tpl": "6401c7b213d9b818bf0e7dd7" - }, { - "_id": "5fe49a0e2694b0755a504755", - "_tpl": "5447a9cd4bdc2dbd208b4567", - "parentId": "5fe49a0e2694b0755a50476c", - "slotId": "FirstPrimaryWeapon", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a504749", - "_tpl": "55d4b9964bdc2d1d4e8b456e", - "parentId": "5fe49a0e2694b0755a504755", - "slotId": "mod_pistol_grip" - }, { - "_id": "5fe49a0e2694b0755a50474b", - "_tpl": "55d4887d4bdc2d962f8b4570", - "parentId": "5fe49a0e2694b0755a504755", - "slotId": "mod_magazine" - }, { - "_id": "5fe49a0e2694b0755a50474a", - "_tpl": "54527a984bdc2d4e668b4567", - "parentId": "5fe49a0e2694b0755a50474b", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a504751", - "_tpl": "55d355e64bdc2d962f8b4569", - "parentId": "5fe49a0e2694b0755a504755", - "slotId": "mod_reciever" - }, { - "_id": "5fe49a0e2694b0755a50474e", - "_tpl": "55d3632e4bdc2d972f8b4569", - "parentId": "5fe49a0e2694b0755a504751", - "slotId": "mod_barrel" - }, { - "_id": "5fe49a0e2694b0755a50474c", - "_tpl": "544a38634bdc2d58388b4568", - "parentId": "5fe49a0e2694b0755a50474e", - "slotId": "mod_muzzle" - }, { - "_id": "5fe49a0e2694b0755a50474d", - "_tpl": "5ae30e795acfc408fb139a0b", - "parentId": "5fe49a0e2694b0755a50474e", - "slotId": "mod_gas_block" - }, { - "_id": "5fe49a0e2694b0755a50474f", - "_tpl": "5ae30db85acfc408fb139a05", - "parentId": "5fe49a0e2694b0755a504751", - "slotId": "mod_handguard" - }, { - "_id": "6396b722d604e334650f972e", - "_tpl": "637f57a68d137b27f70c4968", - "parentId": "5fe49a0e2694b0755a50474f", - "slotId": "mod_handguard" - }, { - "_id": "5fe49a0e2694b0755a504750", - "_tpl": "5ae30bad5acfc400185c2dc4", - "parentId": "5fe49a0e2694b0755a504751", - "slotId": "mod_sight_rear", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a504753", - "_tpl": "5649be884bdc2d79388b4577", - "parentId": "5fe49a0e2694b0755a504755", - "slotId": "mod_stock" - }, { - "_id": "5fe49a0e2694b0755a504752", - "_tpl": "55d4ae6c4bdc2d8b2f8b456e", - "parentId": "5fe49a0e2694b0755a504753", - "slotId": "mod_stock_000" - }, { - "_id": "5fe49a0e2694b0755a504754", - "_tpl": "55d44fd14bdc2d962f8b456e", - "parentId": "5fe49a0e2694b0755a504755", - "slotId": "mod_charge" - }, { - "_id": "5fe49a0e2694b0755a504756", - "_tpl": "54491bb74bdc2d09088b4567", - "parentId": "5fe49a0e2694b0755a50476c", - "slotId": "Scabbard", - "upd": { - "Repairable": { - "Durability": 70, - "MaxDurability": 70 - } - } - }, { - "_id": "5fe49a0e2694b0755a504757", - "_tpl": "572b7fa524597762b747ce82", - "parentId": "5fe49a0e2694b0755a50476c", - "slotId": "FaceCover", - "upd": { - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a504758", - "_tpl": "5aa2a7e8e5b5b00016327c16", - "parentId": "5fe49a0e2694b0755a50476c", - "slotId": "Headwear", - "upd": { - "Repairable": { - "Durability": 10, - "MaxDurability": 10 - } - } - }, { - "_id": "5fe49a0e2694b0755a504760", - "_tpl": "5c0e9f2c86f77432297fe0a3", - "parentId": "5fe49a0e2694b0755a50476c", - "slotId": "TacticalVest" - }, { - "_id": "5fe49a0e2694b0755a50475a", - "_tpl": "55d4887d4bdc2d962f8b4570", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a504760", - "slotId": "1" - }, { - "_id": "5fe49a0e2694b0755a504759", - "_tpl": "54527a984bdc2d4e668b4567", - "parentId": "5fe49a0e2694b0755a50475a", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a50475c", - "_tpl": "55d4887d4bdc2d962f8b4570", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a504760", - "slotId": "2" - }, { - "_id": "5fe49a0e2694b0755a50475b", - "_tpl": "54527a984bdc2d4e668b4567", - "parentId": "5fe49a0e2694b0755a50475c", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a50475e", - "_tpl": "55d4887d4bdc2d962f8b4570", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a504760", - "slotId": "3" - }, { - "_id": "5fe49a0e2694b0755a50475d", - "_tpl": "54527a984bdc2d4e668b4567", - "parentId": "5fe49a0e2694b0755a50475e", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a50475f", - "_tpl": "5755356824597772cb798962", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a504760", - "slotId": "4", - "upd": { - "MedKit": { - "HpResource": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a504761", - "_tpl": "5857a8bc2459772bad15db29", - "parentId": "5fe49a0e2694b0755a50476c", - "slotId": "SecuredContainer" - }, { - "_id": "5fe49a0e2694b0755a504765", - "_tpl": "5e9dcf5986f7746c417435b3", - "parentId": "5fe49a0e2694b0755a50476c", - "slotId": "Backpack" - }, { - "_id": "5fe49a0e2694b0755a504762", - "_tpl": "5448fee04bdc2dbc018b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a504765", - "slotId": "main", - "upd": { - "FoodDrink": { - "HpPercent": 60 - } - } - }, { - "_id": "5fe49a0e2694b0755a504763", - "_tpl": "590c5f0d86f77413997acfab", - "location": { - "isSearched": true, - "r": 0, - "x": 1, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a504765", - "slotId": "main", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "5fe49a0e2694b0755a504764", - "_tpl": "54527a984bdc2d4e668b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a504765", - "slotId": "main", - "upd": { - "StackObjectsCount": 60 - } - }, { - "_id": "5fe49a0e2694b0755a504766", - "_tpl": "5648a7494bdc2d9d488b4583", - "parentId": "5fe49a0e2694b0755a50476c", - "slotId": "ArmorVest", - "upd": { - "Repairable": { - "Durability": 50, - "MaxDurability": 50 - } - } - }, { - "_id": "658c3f38bb2016e5630bdbe5", - "_tpl": "65703d866584602f7d057a8a", - "parentId": "5fe49a0e2694b0755a504766", - "slotId": "Soft_armor_front" - }, { - "_id": "658c3f38bb2016e5630bdbe6", - "_tpl": "65703fa06584602f7d057a8e", - "parentId": "5fe49a0e2694b0755a504766", - "slotId": "Soft_armor_back" - }, { - "_id": "658c3f38bb2016e5630bdbe7", - "_tpl": "65703fe46a912c8b5c03468b", - "parentId": "5fe49a0e2694b0755a504766", - "slotId": "Soft_armor_left" - }, { - "_id": "658c3f38bb2016e5630bdbe8", - "_tpl": "657040374e67e8ec7a0d261c", - "parentId": "5fe49a0e2694b0755a504766", - "slotId": "soft_armor_right" - }, { - "_id": "5fe49a0e2694b0755a50476a", - "_tpl": "627a4e6b255f7527fb05a0f6", - "parentId": "5fe49a0e2694b0755a50476c", - "slotId": "Pockets" - }, { - "_id": "5fe49a0e2694b0755a504767", - "_tpl": "544fb3364bdc2d34748b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a50476a", - "slotId": "pocket1" - }, { - "_id": "5fe49a0e2694b0755a504768", - "_tpl": "544fb37f4bdc2dee738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a50476a", - "slotId": "pocket2", - "upd": { - "MedKit": { - "HpResource": 4 - } - } - }, { - "_id": "5fe49a0e2694b0755a504769", - "_tpl": "5751a25924597722c463c472", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a50476a", - "slotId": "pocket3", - "upd": { - "MedKit": { - "HpResource": 2 - } - } - }, { - "_id": "5fe49a0e2694b0755a50476b", - "_tpl": "5645bcc04bdc2d363b8b4572", - "parentId": "5fe49a0e2694b0755a50476c", - "slotId": "Earpiece" - }, { - "_id": "5fe49a0e2694b0755a504876", - "_tpl": "5811ce772459770e9e5f9532" - }, { - "_id": "5fe49a0e2694b0755a50476d", - "_tpl": "590c5f0d86f77413997acfab", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 32 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "5fe49a0e2694b0755a50476e", - "_tpl": "5e9dcf5986f7746c417435b3", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 9 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a50476f", - "_tpl": "5a0c27731526d80618476ac4", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 14 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504771", - "_tpl": "5cadc2e0ae9215051e1c21e7", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 4 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504770", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a504771", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 17 - } - }, { - "_id": "5fe49a0e2694b0755a504773", - "_tpl": "55d4887d4bdc2d962f8b4570", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 14 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504772", - "_tpl": "54527a984bdc2d4e668b4567", - "parentId": "5fe49a0e2694b0755a504773", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a504774", - "_tpl": "54527a984bdc2d4e668b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 17 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 60 - } - }, { - "_id": "5fe49a0e2694b0755a504775", - "_tpl": "590c661e86f7741e566b646a", - "location": { - "isSearched": true, - "r": 1, - "x": 9, - "y": 31 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 220 - } - } - }, { - "_id": "5fe49a0e2694b0755a504776", - "_tpl": "5755356824597772cb798962", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 31 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a504777", - "_tpl": "544fb25a4bdc2dfb738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 35 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504779", - "_tpl": "55d4887d4bdc2d962f8b4570", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 15 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504778", - "_tpl": "54527a984bdc2d4e668b4567", - "parentId": "5fe49a0e2694b0755a504779", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a50477a", - "_tpl": "64b7bbb74b75259c590fa897", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 8 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 50 - } - }, { - "_id": "5fe49a0e2694b0755a50477b", - "_tpl": "590c5f0d86f77413997acfab", - "location": { - "isSearched": true, - "r": 0, - "x": 1, - "y": 32 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "5fe49a0e2694b0755a50477d", - "_tpl": "55d4887d4bdc2d962f8b4570", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 14 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a50477c", - "_tpl": "54527a984bdc2d4e668b4567", - "parentId": "5fe49a0e2694b0755a50477d", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a50477e", - "_tpl": "58d3db5386f77426186285a0", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 13 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a50477f", - "_tpl": "54527a984bdc2d4e668b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 17 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 60 - } - }, { - "_id": "5fe49a0e2694b0755a504780", - "_tpl": "590c661e86f7741e566b646a", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 32 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 220 - } - } - }, { - "_id": "5fe49a0e2694b0755a504781", - "_tpl": "5ab8f39486f7745cd93a1cca", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 25 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a504782", - "_tpl": "5a0c27731526d80618476ac4", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 14 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504783", - "_tpl": "58d3db5386f77426186285a0", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 13 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504785", - "_tpl": "5bfeaa0f0db834001b734927", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 20 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504784", - "_tpl": "58dd3ad986f77403051cba8f", - "parentId": "5fe49a0e2694b0755a504785", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 10 - } - }, { - "_id": "5fe49a0e2694b0755a504786", - "_tpl": "5e4d34ca86f774264f758330", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 11 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504787", - "_tpl": "5aa2a7e8e5b5b00016327c16", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 10, - "MaxDurability": 10 - } - } - }, { - "_id": "5fe49a0e2694b0755a504788", - "_tpl": "5c0e9f2c86f77432297fe0a3", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 3 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504789", - "_tpl": "590c5f0d86f77413997acfab", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 32 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "5fe49a0e2694b0755a50478a", - "_tpl": "5aa2a7e8e5b5b00016327c16", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 10, - "MaxDurability": 10 - } - } - }, { - "_id": "5fe49a0e2694b0755a50478b", - "_tpl": "5648a7494bdc2d9d488b4583", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 3 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 50, - "MaxDurability": 50 - } - } - }, { - "_id": "658c3f38bb2016e5630bdbe5", - "_tpl": "65703d866584602f7d057a8a", - "parentId": "5fe49a0e2694b0755a50478b", - "slotId": "Soft_armor_front" - }, { - "_id": "658c3f38bb2016e5630bdbe6", - "_tpl": "65703fa06584602f7d057a8e", - "parentId": "5fe49a0e2694b0755a50478b", - "slotId": "Soft_armor_back" - }, { - "_id": "658c3f38bb2016e5630bdbe7", - "_tpl": "65703fe46a912c8b5c03468b", - "parentId": "5fe49a0e2694b0755a50478b", - "slotId": "Soft_armor_left" - }, { - "_id": "658c3f38bb2016e5630bdbe8", - "_tpl": "657040374e67e8ec7a0d261c", - "parentId": "5fe49a0e2694b0755a50478b", - "slotId": "soft_armor_right" - }, { - "_id": "5fe49a0e2694b0755a50478c", - "_tpl": "5e831507ea0a7c419c2f9bd9", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 33 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a50478d", - "_tpl": "5755356824597772cb798962", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 31 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a50478f", - "_tpl": "5cadc2e0ae9215051e1c21e7", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 6 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a50478e", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a50478f", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 17 - } - }, { - "_id": "5fe49a0e2694b0755a504790", - "_tpl": "5e4d34ca86f774264f758330", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 9 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504791", - "_tpl": "5d403f9186f7743cac3f229b", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "5fe49a0e2694b0755a504792", - "_tpl": "5c0e9f2c86f77432297fe0a3", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504793", - "_tpl": "5648a7494bdc2d9d488b4583", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 0 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 50, - "MaxDurability": 50 - } - } - }, { - "_id": "658c3f38bb2016e5630bdbe5", - "_tpl": "65703d866584602f7d057a8a", - "parentId": "5fe49a0e2694b0755a504793", - "slotId": "Soft_armor_front" - }, { - "_id": "658c3f38bb2016e5630bdbe6", - "_tpl": "65703fa06584602f7d057a8e", - "parentId": "5fe49a0e2694b0755a504793", - "slotId": "Soft_armor_back" - }, { - "_id": "658c3f38bb2016e5630bdbe7", - "_tpl": "65703fe46a912c8b5c03468b", - "parentId": "5fe49a0e2694b0755a504793", - "slotId": "Soft_armor_left" - }, { - "_id": "658c3f38bb2016e5630bdbe8", - "_tpl": "657040374e67e8ec7a0d261c", - "parentId": "5fe49a0e2694b0755a504793", - "slotId": "soft_armor_right" - }, { - "_id": "5fe49a0e2694b0755a504794", - "_tpl": "5e831507ea0a7c419c2f9bd9", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 33 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504795", - "_tpl": "544fb3364bdc2d34748b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 34 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504796", - "_tpl": "544fb25a4bdc2dfb738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 35 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504797", - "_tpl": "544fb25a4bdc2dfb738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 35 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504798", - "_tpl": "5e831507ea0a7c419c2f9bd9", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 33 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504799", - "_tpl": "544fb37f4bdc2dee738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 34 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 4 - } - } - }, { - "_id": "5fe49a0e2694b0755a50479b", - "_tpl": "5cadc2e0ae9215051e1c21e7", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 5 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a50479a", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a50479b", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 17 - } - }, { - "_id": "5fe49a0e2694b0755a50479c", - "_tpl": "64b7bbb74b75259c590fa897", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 8 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 50 - } - }, { - "_id": "5fe49a0e2694b0755a50479d", - "_tpl": "5e9dcf5986f7746c417435b3", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 9 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a50479e", - "_tpl": "590c695186f7741e566b64a2", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 36 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a50479f", - "_tpl": "5751a25924597722c463c472", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 34 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 2 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047a0", - "_tpl": "590c695186f7741e566b64a2", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 36 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047a1", - "_tpl": "5751a25924597722c463c472", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 34 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 2 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047a3", - "_tpl": "5d2f213448f0355009199284", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 7 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047a2", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a5047a3", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a5047a5", - "_tpl": "5cadc2e0ae9215051e1c21e7", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 6 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047a4", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a5047a5", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 17 - } - }, { - "_id": "5fe49a0e2694b0755a5047a7", - "_tpl": "5d2f213448f0355009199284", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 7 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047a6", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a5047a7", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a5047a9", - "_tpl": "5d2f213448f0355009199284", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 7 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047a8", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a5047a9", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a5047ab", - "_tpl": "5d2f213448f0355009199284", - "location": { - "isSearched": true, - "r": 0, - "x": 1, - "y": 7 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047aa", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a5047ab", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a5047ac", - "_tpl": "5755383e24597772cb798966", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 36 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 6 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047ae", - "_tpl": "55d4887d4bdc2d962f8b4570", - "location": { - "isSearched": true, - "r": 1, - "x": 3, - "y": 25 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047ad", - "_tpl": "54527a984bdc2d4e668b4567", - "parentId": "5fe49a0e2694b0755a5047ae", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a5047af", - "_tpl": "64b7bbb74b75259c590fa897", - "location": { - "isSearched": true, - "r": 0, - "x": 1, - "y": 8 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 50 - } - }, { - "_id": "5fe49a0e2694b0755a5047b0", - "_tpl": "64b7bbb74b75259c590fa897", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 8 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 50 - } - }, { - "_id": "5fe49a0e2694b0755a5047b1", - "_tpl": "64b7bbb74b75259c590fa897", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 8 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 50 - } - }, { - "_id": "5fe49a0e2694b0755a5047b2", - "_tpl": "64b7bbb74b75259c590fa897", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 8 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 50 - } - }, { - "_id": "5fe49a0e2694b0755a5047b3", - "_tpl": "5696686a4bdc2da3298b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 2 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 500 - } - }, { - "_id": "5fe49a0e2694b0755a5047b4", - "_tpl": "64b7bbb74b75259c590fa897", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 8 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 50 - } - }, { - "_id": "5fe49a0e2694b0755a5047b6", - "_tpl": "5cadc2e0ae9215051e1c21e7", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 3 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047b5", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a5047b6", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 17 - } - }, { - "_id": "5fe49a0e2694b0755a5047b8", - "_tpl": "5d2f213448f0355009199284", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 7 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047b7", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a5047b8", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a5047b9", - "_tpl": "64b7bbb74b75259c590fa897", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 8 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 50 - } - }, { - "_id": "5fe49a0e2694b0755a5047ba", - "_tpl": "64b7bbb74b75259c590fa897", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 8 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 50 - } - }, { - "_id": "5fe49a0e2694b0755a5047bb", - "_tpl": "64b7bbb74b75259c590fa897", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 8 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 50 - } - }, { - "_id": "5fe49a0e2694b0755a5047bc", - "_tpl": "5755356824597772cb798962", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 31 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047bd", - "_tpl": "5e831507ea0a7c419c2f9bd9", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 33 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047be", - "_tpl": "5449016a4bdc2d6f028b456f", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 1 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 250000 - } - }, { - "_id": "5fe49a0e2694b0755a5047bf", - "_tpl": "5449016a4bdc2d6f028b456f", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 1 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 250000 - } - }, { - "_id": "5fe49a0e2694b0755a5047c1", - "_tpl": "55d4887d4bdc2d962f8b4570", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 14 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047c0", - "_tpl": "54527a984bdc2d4e668b4567", - "parentId": "5fe49a0e2694b0755a5047c1", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a5047c2", - "_tpl": "5e8488fa988a8701445df1e4", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 36 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 3 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047c3", - "_tpl": "569668774bdc2da2298b4568", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 2 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 500 - } - }, { - "_id": "5fe49a0e2694b0755a5047c5", - "_tpl": "5cadc2e0ae9215051e1c21e7", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 6 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047c4", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a5047c5", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 17 - } - }, { - "_id": "5fe49a0e2694b0755a5047c7", - "_tpl": "5d2f213448f0355009199284", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 7 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047c6", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a5047c7", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a5047c9", - "_tpl": "5cadc2e0ae9215051e1c21e7", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 7 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047c8", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a5047c9", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 17 - } - }, { - "_id": "5fe49a0e2694b0755a5047cb", - "_tpl": "5cadc2e0ae9215051e1c21e7", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 7 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047ca", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a5047cb", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 17 - } - }, { - "_id": "5fe49a0e2694b0755a5047cc", - "_tpl": "5a0c27731526d80618476ac4", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 16 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047cd", - "_tpl": "5a0c27731526d80618476ac4", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 15 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047ce", - "_tpl": "57347da92459774491567cf5", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 26 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047cf", - "_tpl": "57347da92459774491567cf5", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 28 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047d0", - "_tpl": "57347da92459774491567cf5", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 26 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047d1", - "_tpl": "57347da92459774491567cf5", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 27 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047d2", - "_tpl": "560d5e524bdc2d25448b4571", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 17 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a5047d3", - "_tpl": "560d5e524bdc2d25448b4571", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 17 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a5047d4", - "_tpl": "560d5e524bdc2d25448b4571", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 17 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a5047d5", - "_tpl": "544fb3364bdc2d34748b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 1, - "y": 34 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047d6", - "_tpl": "5755356824597772cb798962", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 31 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047d7", - "_tpl": "544fb45d4bdc2dee738b4568", - "location": { - "isSearched": true, - "r": 0, - "x": 1, - "y": 35 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 400 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047d8", - "_tpl": "5d02778e86f774203e7dedbe", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 32 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 5 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047d9", - "_tpl": "5c0e655586f774045612eeb2", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 17 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 85, - "MaxDurability": 85 - } - } - }, { - "_id": "658c3d4dab989d7f4805edbb", - "_tpl": "656fad8c498d1b7e3e071da0", - "parentId": "5fe49a0e2694b0755a5047d9", - "slotId": "Front_plate" - }, { - "_id": "658c3d4dab989d7f4805edbc", - "_tpl": "656fad8c498d1b7e3e071da0", - "parentId": "5fe49a0e2694b0755a5047d9", - "slotId": "Back_plate" - }, { - "_id": "658c3d4dab989d7f4805edbd", - "_tpl": "6570e025615f54368b04fcb0", - "parentId": "5fe49a0e2694b0755a5047d9", - "slotId": "Soft_armor_front" - }, { - "_id": "658c3d4dab989d7f4805edbe", - "_tpl": "6570e0610b57c03ec90b96ef", - "parentId": "5fe49a0e2694b0755a5047d9", - "slotId": "Soft_armor_back" - }, { - "_id": "5fe49a0e2694b0755a5047da", - "_tpl": "5c165d832e2216398b5a7e36", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 21 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047db", - "_tpl": "5af0454c86f7746bf20992e8", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 33 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 5 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047dc", - "_tpl": "5af0454c86f7746bf20992e8", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 33 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 5 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047dd", - "_tpl": "5af0454c86f7746bf20992e8", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 33 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 5 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047de", - "_tpl": "544fb45d4bdc2dee738b4568", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 35 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 400 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047df", - "_tpl": "5ab8f39486f7745cd93a1cca", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 25 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047e0", - "_tpl": "557ff21e4bdc2d89578b4586", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 22 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047e1", - "_tpl": "5bfebc5e0db834001a6694e5", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 19 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047e2", - "_tpl": "57c5ac0824597754771e88a9", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 16 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047e3", - "_tpl": "5aa7d03ae5b5b00016327db5", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 20 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 25, - "MaxDurability": 25 - } - } - }, { - "_id": "658c3d4dab989d7f4805edc9", - "_tpl": "654a90aff4f81a421b0a7c86", - "parentId": "5fe49a0e2694b0755a5047e3", - "slotId": "helmet_top" - }, { - "_id": "658c3d4dab989d7f4805edca", - "_tpl": "654a91068e1ce698150fd1e2", - "parentId": "5fe49a0e2694b0755a5047e3", - "slotId": "helmet_back" - }, { - "_id": "658c3d4dab989d7f4805edcb", - "_tpl": "654a9189bcc67a392b056c79", - "parentId": "5fe49a0e2694b0755a5047e3", - "slotId": "helmet_ears" - }, { - "_id": "5fe49a0e2694b0755a5047e4", - "_tpl": "5aa7d03ae5b5b00016327db5", - "location": { - "isSearched": true, - "r": 0, - "x": 2, - "y": 20 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 25, - "MaxDurability": 25 - } - } - }, { - "_id": "658c3d4dab989d7f4805edcd", - "_tpl": "654a90aff4f81a421b0a7c86", - "parentId": "5fe49a0e2694b0755a5047e4", - "slotId": "helmet_top" - }, { - "_id": "658c3d4dab989d7f4805edce", - "_tpl": "654a91068e1ce698150fd1e2", - "parentId": "5fe49a0e2694b0755a5047e4", - "slotId": "helmet_back" - }, { - "_id": "658c3d4dab989d7f4805edcf", - "_tpl": "654a9189bcc67a392b056c79", - "parentId": "5fe49a0e2694b0755a5047e4", - "slotId": "helmet_ears" - }, { - "_id": "5fe49a0e2694b0755a5047e5", - "_tpl": "544fb37f4bdc2dee738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 34 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 4 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047e6", - "_tpl": "544fb37f4bdc2dee738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 34 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 4 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047e7", - "_tpl": "58d3db5386f77426186285a0", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 19 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047e8", - "_tpl": "58d3db5386f77426186285a0", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 19 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047e9", - "_tpl": "58d3db5386f77426186285a0", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 20 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047eb", - "_tpl": "55d4887d4bdc2d962f8b4570", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 24 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047ea", - "_tpl": "54527a984bdc2d4e668b4567", - "parentId": "5fe49a0e2694b0755a5047eb", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a5047ec", - "_tpl": "5d1b371186f774253763a656", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 37 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Resource": { - "Value": 60 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047ed", - "_tpl": "5d1b36a186f7742523398433", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 37 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Resource": { - "Value": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047ee", - "_tpl": "544fb45d4bdc2dee738b4568", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 35 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 400 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047ef", - "_tpl": "557ff21e4bdc2d89578b4586", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 23 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047f0", - "_tpl": "5448fee04bdc2dbc018b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 29 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 60 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047f1", - "_tpl": "5d02778e86f774203e7dedbe", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 32 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 5 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047f2", - "_tpl": "5d5d940f86f7742797262046", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 27 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047f3", - "_tpl": "57cd379a24597778e7682ecf", - "location": { - "isSearched": true, - "r": 1, - "x": 0, - "y": 26 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047f4", - "_tpl": "544a5caa4bdc2d1a388b4568", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 22 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 70, - "MaxDurability": 70 - } - } - }, { - "_id": "658c3d4dab989d7f4805ede0", - "_tpl": "656f9fa0498d1b7e3e071d98", - "parentId": "5fe49a0e2694b0755a5047f4", - "slotId": "Front_plate" - }, { - "_id": "658c3d4dab989d7f4805ede1", - "_tpl": "656f9fa0498d1b7e3e071d98", - "parentId": "5fe49a0e2694b0755a5047f4", - "slotId": "Back_plate" - }, { - "_id": "658c3d4dab989d7f4805ede2", - "_tpl": "6570e83223c1f638ef0b0ede", - "parentId": "5fe49a0e2694b0755a5047f4", - "slotId": "Soft_armor_front" - }, { - "_id": "658c3d4dab989d7f4805ede3", - "_tpl": "6570e87c23c1f638ef0b0ee2", - "parentId": "5fe49a0e2694b0755a5047f4", - "slotId": "Soft_armor_back" - }, { - "_id": "658c3d4dab989d7f4805ede4", - "_tpl": "6570e90b3a5689d85f08db97", - "parentId": "5fe49a0e2694b0755a5047f4", - "slotId": "Groin" - }, { - "_id": "5fe49a0e2694b0755a5047f5", - "_tpl": "5d5d85c586f774279a21cbdb", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 22 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047f6", - "_tpl": "5e2af4a786f7746d3f3c3400", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 36 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Resource": { - "Value": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047f7", - "_tpl": "570fd6c2d2720bc6458b457f", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 26 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047f8", - "_tpl": "5448be9a4bdc2dfd2f8b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 20 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047f9", - "_tpl": "5448be9a4bdc2dfd2f8b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 21 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047fa", - "_tpl": "590c657e86f77412b013051d", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 37 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 1800 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047fb", - "_tpl": "5d5e9c74a4b9364855191c40", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 17 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Repairable": { - "Durability": 27, - "MaxDurability": 27 - } - } - }, { - "_id": "658c3d4dab989d7f4805edec", - "_tpl": "657f8b94f92cd718b70154ff", - "parentId": "5fe49a0e2694b0755a5047fb", - "slotId": "Helmet_top" - }, { - "_id": "658c3d4dab989d7f4805eded", - "_tpl": "657f8b43f92cd718b70154fb", - "parentId": "5fe49a0e2694b0755a5047fb", - "slotId": "Helmet_back" - }, { - "_id": "5fe49a0e2694b0755a5047fd", - "_tpl": "55d4887d4bdc2d962f8b4570", - "location": { - "isSearched": true, - "r": 1, - "x": 3, - "y": 26 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a5047fc", - "_tpl": "54527a984bdc2d4e668b4567", - "parentId": "5fe49a0e2694b0755a5047fd", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a5047fe", - "_tpl": "590c678286f77426c9660122", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 35 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 300 - } - } - }, { - "_id": "5fe49a0e2694b0755a5047ff", - "_tpl": "590c678286f77426c9660122", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 35 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 300 - } - } - }, { - "_id": "5fe49a0e2694b0755a504800", - "_tpl": "590c678286f77426c9660122", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 35 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 300 - } - } - }, { - "_id": "5fe49a0e2694b0755a504802", - "_tpl": "55d4887d4bdc2d962f8b4570", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 24 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504801", - "_tpl": "54527a984bdc2d4e668b4567", - "parentId": "5fe49a0e2694b0755a504802", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a504803", - "_tpl": "5448fee04bdc2dbc018b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 29 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 60 - } - } - }, { - "_id": "5fe49a0e2694b0755a504804", - "_tpl": "5e8488fa988a8701445df1e4", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 36 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "MedKit": { - "HpResource": 3 - } - } - }, { - "_id": "5fe49a0e2694b0755a504805", - "_tpl": "54527a984bdc2d4e668b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 26 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 60 - } - }, { - "_id": "5fe49a0e2694b0755a504806", - "_tpl": "54527a984bdc2d4e668b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 26 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a504807", - "_tpl": "5c0e530286f7747fa1419862", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 34 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504808", - "_tpl": "5c0e530286f7747fa1419862", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 34 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504809", - "_tpl": "54527a984bdc2d4e668b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 25 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a50480a", - "_tpl": "5696686a4bdc2da3298b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 2 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 500 - } - }, { - "_id": "5fe49a0e2694b0755a50480c", - "_tpl": "5bfeaa0f0db834001b734927", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 19 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a50480b", - "_tpl": "58dd3ad986f77403051cba8f", - "parentId": "5fe49a0e2694b0755a50480c", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 10 - } - }, { - "_id": "5fe49a0e2694b0755a50480e", - "_tpl": "5bfeaa0f0db834001b734927", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 19 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a50480d", - "_tpl": "58dd3ad986f77403051cba8f", - "parentId": "5fe49a0e2694b0755a50480e", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 10 - } - }, { - "_id": "5fe49a0e2694b0755a504810", - "_tpl": "5bfeaa0f0db834001b734927", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 20 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a50480f", - "_tpl": "58dd3ad986f77403051cba8f", - "parentId": "5fe49a0e2694b0755a504810", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 10 - } - }, { - "_id": "5fe49a0e2694b0755a504811", - "_tpl": "58dd3ad986f77403051cba8f", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 19 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a504812", - "_tpl": "5448fee04bdc2dbc018b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 29 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 60 - } - } - }, { - "_id": "5fe49a0e2694b0755a504813", - "_tpl": "544fb3364bdc2d34748b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 34 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504815", - "_tpl": "5d2f213448f0355009199284", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 7 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504814", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a504815", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a504817", - "_tpl": "5d2f213448f0355009199284", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 7 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504816", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a504817", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a504819", - "_tpl": "5cadc2e0ae9215051e1c21e7", - "location": { - "isSearched": true, - "r": 0, - "x": 6, - "y": 6 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504818", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a504819", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 17 - } - }, { - "_id": "5fe49a0e2694b0755a50481a", - "_tpl": "544fb3f34bdc2d03748b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 30 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a50481b", - "_tpl": "544fb3f34bdc2d03748b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 30 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a50481c", - "_tpl": "5e2af47786f7746d404f3aaa", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 38 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Resource": { - "Value": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a50481d", - "_tpl": "5e2af4a786f7746d3f3c3400", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 37 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Resource": { - "Value": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a50481e", - "_tpl": "5e2af47786f7746d404f3aaa", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 39 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "Resource": { - "Value": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a50481f", - "_tpl": "58dd3ad986f77403051cba8f", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 16 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a504820", - "_tpl": "5448be9a4bdc2dfd2f8b456a", - "location": { - "isSearched": true, - "r": 0, - "x": 4, - "y": 21 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504821", - "_tpl": "5645bcc04bdc2d363b8b4572", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 23 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a504822", - "_tpl": "57347da92459774491567cf5", - "location": { - "isSearched": true, - "r": 0, - "x": 8, - "y": 29 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "5fe49a0e2694b0755a504823", - "_tpl": "57347da92459774491567cf5", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 29 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FoodDrink": { - "HpPercent": 1 - } - } - }, { - "_id": "5fe49a0e2694b0755a504824", - "_tpl": "544fb25a4bdc2dfb738b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 9, - "y": 35 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout" - }, { - "_id": "5fe49a0e2694b0755a50482d", - "_tpl": "5cadc190ae921500103bb3b6", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 5 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a504826", - "_tpl": "5cadc1c6ae9215000f2775a4", - "parentId": "5fe49a0e2694b0755a50482d", - "slotId": "mod_barrel" - }, { - "_id": "5fe49a0e2694b0755a504825", - "_tpl": "5cadc390ae921500126a77f1", - "parentId": "5fe49a0e2694b0755a504826", - "slotId": "mod_muzzle" - }, { - "_id": "5fe49a0e2694b0755a504827", - "_tpl": "5cadc431ae921500113bb8d5", - "parentId": "5fe49a0e2694b0755a50482d", - "slotId": "mod_pistol_grip" - }, { - "_id": "5fe49a0e2694b0755a50482a", - "_tpl": "5cadc55cae921500103bb3be", - "parentId": "5fe49a0e2694b0755a50482d", - "slotId": "mod_reciever" - }, { - "_id": "5fe49a0e2694b0755a504828", - "_tpl": "5cadd940ae9215051e1c2316", - "parentId": "5fe49a0e2694b0755a50482a", - "slotId": "mod_sight_rear", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a504829", - "_tpl": "5cadd919ae921500126a77f3", - "parentId": "5fe49a0e2694b0755a50482a", - "slotId": "mod_sight_front", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a50482c", - "_tpl": "5cadc2e0ae9215051e1c21e7", - "parentId": "5fe49a0e2694b0755a50482d", - "slotId": "mod_magazine" - }, { - "_id": "5fe49a0e2694b0755a50482b", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a50482c", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 17 - } - }, { - "_id": "5fe49a0e2694b0755a504836", - "_tpl": "5cadc190ae921500103bb3b6", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 4 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a50482f", - "_tpl": "5cadc1c6ae9215000f2775a4", - "parentId": "5fe49a0e2694b0755a504836", - "slotId": "mod_barrel" - }, { - "_id": "5fe49a0e2694b0755a50482e", - "_tpl": "5cadc390ae921500126a77f1", - "parentId": "5fe49a0e2694b0755a50482f", - "slotId": "mod_muzzle" - }, { - "_id": "5fe49a0e2694b0755a504830", - "_tpl": "5cadc431ae921500113bb8d5", - "parentId": "5fe49a0e2694b0755a504836", - "slotId": "mod_pistol_grip" - }, { - "_id": "5fe49a0e2694b0755a504833", - "_tpl": "5cadc55cae921500103bb3be", - "parentId": "5fe49a0e2694b0755a504836", - "slotId": "mod_reciever" - }, { - "_id": "5fe49a0e2694b0755a504831", - "_tpl": "5cadd940ae9215051e1c2316", - "parentId": "5fe49a0e2694b0755a504833", - "slotId": "mod_sight_rear", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a504832", - "_tpl": "5cadd919ae921500126a77f3", - "parentId": "5fe49a0e2694b0755a504833", - "slotId": "mod_sight_front", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a504835", - "_tpl": "5cadc2e0ae9215051e1c21e7", - "parentId": "5fe49a0e2694b0755a504836", - "slotId": "mod_magazine" - }, { - "_id": "5fe49a0e2694b0755a504834", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a504835", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 17 - } - }, { - "_id": "5fe49a0e2694b0755a504843", - "_tpl": "5447a9cd4bdc2dbd208b4567", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 14 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a504837", - "_tpl": "55d4b9964bdc2d1d4e8b456e", - "parentId": "5fe49a0e2694b0755a504843", - "slotId": "mod_pistol_grip" - }, { - "_id": "5fe49a0e2694b0755a504839", - "_tpl": "55d4887d4bdc2d962f8b4570", - "parentId": "5fe49a0e2694b0755a504843", - "slotId": "mod_magazine" - }, { - "_id": "5fe49a0e2694b0755a504838", - "_tpl": "54527a984bdc2d4e668b4567", - "parentId": "5fe49a0e2694b0755a504839", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a50483f", - "_tpl": "55d355e64bdc2d962f8b4569", - "parentId": "5fe49a0e2694b0755a504843", - "slotId": "mod_reciever" - }, { - "_id": "5fe49a0e2694b0755a50483c", - "_tpl": "55d3632e4bdc2d972f8b4569", - "parentId": "5fe49a0e2694b0755a50483f", - "slotId": "mod_barrel" - }, { - "_id": "5fe49a0e2694b0755a50483a", - "_tpl": "544a38634bdc2d58388b4568", - "parentId": "5fe49a0e2694b0755a50483c", - "slotId": "mod_muzzle" - }, { - "_id": "5fe49a0e2694b0755a50483b", - "_tpl": "5ae30e795acfc408fb139a0b", - "parentId": "5fe49a0e2694b0755a50483c", - "slotId": "mod_gas_block" - }, { - "_id": "5fe49a0e2694b0755a50483d", - "_tpl": "5ae30db85acfc408fb139a05", - "parentId": "5fe49a0e2694b0755a50483f", - "slotId": "mod_handguard" - }, { - "_id": "6396b722d604e334650f972e", - "_tpl": "637f57a68d137b27f70c4968", - "parentId": "5fe49a0e2694b0755a50483d", - "slotId": "mod_handguard" - }, { - "_id": "5fe49a0e2694b0755a50483e", - "_tpl": "5ae30bad5acfc400185c2dc4", - "parentId": "5fe49a0e2694b0755a50483f", - "slotId": "mod_sight_rear", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a504841", - "_tpl": "5649be884bdc2d79388b4577", - "parentId": "5fe49a0e2694b0755a504843", - "slotId": "mod_stock" - }, { - "_id": "5fe49a0e2694b0755a504840", - "_tpl": "55d4ae6c4bdc2d8b2f8b456e", - "parentId": "5fe49a0e2694b0755a504841", - "slotId": "mod_stock_000" - }, { - "_id": "5fe49a0e2694b0755a504842", - "_tpl": "55d44fd14bdc2d962f8b456e", - "parentId": "5fe49a0e2694b0755a504843", - "slotId": "mod_charge" - }, { - "_id": "5fe49a0e2694b0755a50484c", - "_tpl": "5926bb2186f7744b1c6c6e60", - "location": { - "isSearched": true, - "r": 0, - "x": 7, - "y": 6 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a504845", - "_tpl": "5d2f213448f0355009199284", - "parentId": "5fe49a0e2694b0755a50484c", - "slotId": "mod_magazine" - }, { - "_id": "5fe49a0e2694b0755a504844", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a504845", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a50484a", - "_tpl": "5926c0df86f77462f647f764", - "parentId": "5fe49a0e2694b0755a50484c", - "slotId": "mod_reciever" - }, { - "_id": "5fe49a0e2694b0755a504846", - "_tpl": "5926c36d86f77467a92a8629", - "parentId": "5fe49a0e2694b0755a50484a", - "slotId": "mod_handguard" - }, { - "_id": "5fe49a0e2694b0755a504847", - "_tpl": "5926d2be86f774134d668e4e", - "parentId": "5fe49a0e2694b0755a50484a", - "slotId": "mod_sight_rear", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a504848", - "_tpl": "5926d3c686f77410de68ebc8", - "parentId": "5fe49a0e2694b0755a50484a", - "slotId": "mod_stock" - }, { - "_id": "5fe49a0e2694b0755a504849", - "_tpl": "5926e16e86f7742f5a0f7ecb", - "parentId": "5fe49a0e2694b0755a50484a", - "slotId": "mod_muzzle" - }, { - "_id": "5fe49a0e2694b0755a50484b", - "_tpl": "5926c32286f774616e42de99", - "parentId": "5fe49a0e2694b0755a50484c", - "slotId": "mod_charge" - }, { - "_id": "5fe49a0e2694b0755a504855", - "_tpl": "5926bb2186f7744b1c6c6e60", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 6 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a50484e", - "_tpl": "5d2f213448f0355009199284", - "parentId": "5fe49a0e2694b0755a504855", - "slotId": "mod_magazine" - }, { - "_id": "5fe49a0e2694b0755a50484d", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a50484e", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 20 - } - }, { - "_id": "5fe49a0e2694b0755a504853", - "_tpl": "5926c0df86f77462f647f764", - "parentId": "5fe49a0e2694b0755a504855", - "slotId": "mod_reciever" - }, { - "_id": "5fe49a0e2694b0755a50484f", - "_tpl": "5926c36d86f77467a92a8629", - "parentId": "5fe49a0e2694b0755a504853", - "slotId": "mod_handguard" - }, { - "_id": "5fe49a0e2694b0755a504850", - "_tpl": "5926d2be86f774134d668e4e", - "parentId": "5fe49a0e2694b0755a504853", - "slotId": "mod_sight_rear", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a504851", - "_tpl": "5926d3c686f77410de68ebc8", - "parentId": "5fe49a0e2694b0755a504853", - "slotId": "mod_stock" - }, { - "_id": "5fe49a0e2694b0755a504852", - "_tpl": "5926e16e86f7742f5a0f7ecb", - "parentId": "5fe49a0e2694b0755a504853", - "slotId": "mod_muzzle" - }, { - "_id": "5fe49a0e2694b0755a504854", - "_tpl": "5926c32286f774616e42de99", - "parentId": "5fe49a0e2694b0755a504855", - "slotId": "mod_charge" - }, { - "_id": "5fe49a0e2694b0755a50485e", - "_tpl": "5cadc190ae921500103bb3b6", - "location": { - "isSearched": true, - "r": 0, - "x": 3, - "y": 3 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a504857", - "_tpl": "5cadc1c6ae9215000f2775a4", - "parentId": "5fe49a0e2694b0755a50485e", - "slotId": "mod_barrel" - }, { - "_id": "5fe49a0e2694b0755a504856", - "_tpl": "5cadc390ae921500126a77f1", - "parentId": "5fe49a0e2694b0755a504857", - "slotId": "mod_muzzle" - }, { - "_id": "5fe49a0e2694b0755a504858", - "_tpl": "5cadc431ae921500113bb8d5", - "parentId": "5fe49a0e2694b0755a50485e", - "slotId": "mod_pistol_grip" - }, { - "_id": "5fe49a0e2694b0755a50485b", - "_tpl": "5cadc55cae921500103bb3be", - "parentId": "5fe49a0e2694b0755a50485e", - "slotId": "mod_reciever" - }, { - "_id": "5fe49a0e2694b0755a504859", - "_tpl": "5cadd940ae9215051e1c2316", - "parentId": "5fe49a0e2694b0755a50485b", - "slotId": "mod_sight_rear", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a50485a", - "_tpl": "5cadd919ae921500126a77f3", - "parentId": "5fe49a0e2694b0755a50485b", - "slotId": "mod_sight_front", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a50485d", - "_tpl": "5cadc2e0ae9215051e1c21e7", - "parentId": "5fe49a0e2694b0755a50485e", - "slotId": "mod_magazine" - }, { - "_id": "5fe49a0e2694b0755a50485c", - "_tpl": "64b7bbb74b75259c590fa897", - "parentId": "5fe49a0e2694b0755a50485d", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 17 - } - }, { - "_id": "5fe49a0e2694b0755a504867", - "_tpl": "5e870397991fd70db46995c8", - "location": { - "isSearched": true, - "r": 0, - "x": 0, - "y": 16 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a504860", - "_tpl": "5e87071478f43e51ca2de5e1", - "parentId": "5fe49a0e2694b0755a504867", - "slotId": "mod_barrel" - }, { - "_id": "5fe49a0e2694b0755a50485f", - "_tpl": "5e8708d4ae379e67d22e0102", - "parentId": "5fe49a0e2694b0755a504860", - "slotId": "mod_sight_front", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a504861", - "_tpl": "5e87076ce2db31558c75a11d", - "parentId": "5fe49a0e2694b0755a504867", - "slotId": "mod_handguard" - }, { - "_id": "5fe49a0e2694b0755a504863", - "_tpl": "5e87080c81c4ed43e83cefda", - "parentId": "5fe49a0e2694b0755a504867", - "slotId": "mod_magazine" - }, { - "_id": "5fe49a0e2694b0755a504862", - "_tpl": "560d5e524bdc2d25448b4571", - "parentId": "5fe49a0e2694b0755a504863", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 8 - } - }, { - "_id": "5fe49a0e2694b0755a504864", - "_tpl": "5e87116b81c4ed43e83cefdd", - "parentId": "5fe49a0e2694b0755a504867", - "slotId": "mod_stock" - }, { - "_id": "5fe49a0e2694b0755a504865", - "_tpl": "5e87114fe2db31558c75a120", - "parentId": "5fe49a0e2694b0755a504867", - "slotId": "mod_mount", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a504866", - "_tpl": "560d5e524bdc2d25448b4571", - "parentId": "5fe49a0e2694b0755a504867", - "slotId": "patron_in_weapon" - }, { - "_id": "5fe49a0e2694b0755a50486c", - "_tpl": "5bfea6e90db834001b7347f3", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 18 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a504869", - "_tpl": "5bfeaa0f0db834001b734927", - "parentId": "5fe49a0e2694b0755a50486c", - "slotId": "mod_magazine" - }, { - "_id": "5fe49a0e2694b0755a504868", - "_tpl": "58dd3ad986f77403051cba8f", - "parentId": "5fe49a0e2694b0755a504869", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 10 - } - }, { - "_id": "5fe49a0e2694b0755a50486a", - "_tpl": "5bfeb32b0db834001a6694d9", - "parentId": "5fe49a0e2694b0755a50486c", - "slotId": "mod_stock" - }, { - "_id": "5fe49a0e2694b0755a50486b", - "_tpl": "5bfebc320db8340019668d79", - "parentId": "5fe49a0e2694b0755a50486c", - "slotId": "mod_barrel" - }, { - "_id": "5fe49a0e2694b0755a504875", - "_tpl": "5c488a752e221602b412af63", - "location": { - "isSearched": true, - "r": 0, - "x": 5, - "y": 27 - }, - "parentId": "5fe49a0e2694b0755a504876", - "slotId": "hideout", - "upd": { - "FireMode": { - "FireMode": "single" - }, - "Repairable": { - "Durability": 100, - "MaxDurability": 100 - } - } - }, { - "_id": "5fe49a0e2694b0755a50486d", - "_tpl": "5c48a2c22e221602b313fb6c", - "parentId": "5fe49a0e2694b0755a504875", - "slotId": "mod_pistol_grip" - }, { - "_id": "5fe49a0e2694b0755a50486f", - "_tpl": "55d4887d4bdc2d962f8b4570", - "parentId": "5fe49a0e2694b0755a504875", - "slotId": "mod_magazine" - }, { - "_id": "5fe49a0e2694b0755a50486e", - "_tpl": "54527a984bdc2d4e668b4567", - "parentId": "5fe49a0e2694b0755a50486f", - "slotId": "cartridges", - "upd": { - "StackObjectsCount": 30 - } - }, { - "_id": "5fe49a0e2694b0755a504871", - "_tpl": "5c48a14f2e2216152006edd7", - "parentId": "5fe49a0e2694b0755a504875", - "slotId": "mod_handguard" - }, { - "_id": "5fe49a0e2694b0755a504870", - "_tpl": "5c18b90d2e2216152142466b", - "parentId": "5fe49a0e2694b0755a504871", - "slotId": "mod_sight_front", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a504873", - "_tpl": "5c48a2852e221602b21d5923", - "parentId": "5fe49a0e2694b0755a504875", - "slotId": "mod_barrel" - }, { - "_id": "5fe49a0e2694b0755a504872", - "_tpl": "5c48a2a42e221602b66d1e07", - "parentId": "5fe49a0e2694b0755a504873", - "slotId": "mod_muzzle" - }, { - "_id": "5fe49a0e2694b0755a504874", - "_tpl": "5c18b9192e2216398b5a8104", - "parentId": "5fe49a0e2694b0755a504875", - "slotId": "mod_sight_rear", - "upd": { - "Sight": { - "ScopesCurrentCalibPointIndexes": [ - 0 - ], - "ScopesSelectedModes": [ - 0 - ], - "SelectedScope": 0 - } - } - }, { - "_id": "5fe49a0e2694b0755a504878", - "_tpl": "5963866b86f7747bfa1c4462" - }, { - "_id": "5fe49a0e2694b0755a504877", - "_tpl": "5963866286f7747bf429b572" - }, { - "_id": "60dca3da42ad9b706b369aca", - "_tpl": "602543c13fee350cd564d032" + "favoriteItems": [], + "items": [ + { + "_id": "6613e1cf291a2e76b00269a8", + "_tpl": "55d7217a4bdc2d86028b456d" + }, { + "_id": "6613e1cf291a2e76b002698d", + "_tpl": "5447a9cd4bdc2dbd208b4567", + "parentId": "6613e1cf291a2e76b00269a8", + "slotId": "FirstPrimaryWeapon" + }, { + "_id": "6613e1cf291a2e76b0026980", + "_tpl": "55d4b9964bdc2d1d4e8b456e", + "parentId": "6613e1cf291a2e76b002698d", + "slotId": "mod_pistol_grip" + }, { + "_id": "6613e1cf291a2e76b0026982", + "_tpl": "55d4887d4bdc2d962f8b4570", + "parentId": "6613e1cf291a2e76b002698d", + "slotId": "mod_magazine" + }, { + "_id": "6613e1cf291a2e76b0026981", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026982", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 } - ], - "questRaidItems": "5fe49a0e2694b0755a504877", - "questStashItems": "5fe49a0e2694b0755a504878", - "sortingTable": "60dca3da42ad9b706b369aca", - "stash": "5fe49a0e2694b0755a504876" + }, { + "_id": "6613e1cf291a2e76b0026989", + "_tpl": "55d355e64bdc2d962f8b4569", + "parentId": "6613e1cf291a2e76b002698d", + "slotId": "mod_reciever" + }, { + "_id": "6613e1cf291a2e76b0026985", + "_tpl": "55d3632e4bdc2d972f8b4569", + "parentId": "6613e1cf291a2e76b0026989", + "slotId": "mod_barrel" + }, { + "_id": "6613e1cf291a2e76b0026983", + "_tpl": "544a38634bdc2d58388b4568", + "parentId": "6613e1cf291a2e76b0026985", + "slotId": "mod_muzzle" + }, { + "_id": "6613e1cf291a2e76b0026984", + "_tpl": "5ae30e795acfc408fb139a0b", + "parentId": "6613e1cf291a2e76b0026985", + "slotId": "mod_gas_block" + }, { + "_id": "6613e1cf291a2e76b0026987", + "_tpl": "5ae30db85acfc408fb139a05", + "parentId": "6613e1cf291a2e76b0026989", + "slotId": "mod_handguard" + }, { + "_id": "6613e1cf291a2e76b0026986", + "_tpl": "637f57a68d137b27f70c4968", + "parentId": "6613e1cf291a2e76b0026987", + "slotId": "mod_handguard" + }, { + "_id": "6613e1cf291a2e76b0026988", + "_tpl": "5ae30bad5acfc400185c2dc4", + "parentId": "6613e1cf291a2e76b0026989", + "slotId": "mod_sight_rear" + }, { + "_id": "6613e1cf291a2e76b002698b", + "_tpl": "5649be884bdc2d79388b4577", + "parentId": "6613e1cf291a2e76b002698d", + "slotId": "mod_stock" + }, { + "_id": "6613e1cf291a2e76b002698a", + "_tpl": "55d4ae6c4bdc2d8b2f8b456e", + "parentId": "6613e1cf291a2e76b002698b", + "slotId": "mod_stock_000" + }, { + "_id": "6613e1cf291a2e76b002698c", + "_tpl": "55d44fd14bdc2d962f8b456e", + "parentId": "6613e1cf291a2e76b002698d", + "slotId": "mod_charge" + }, { + "_id": "6613e1cf291a2e76b002698e", + "_tpl": "54491bb74bdc2d09088b4567", + "parentId": "6613e1cf291a2e76b00269a8", + "slotId": "Scabbard" + }, { + "_id": "6613e1cf291a2e76b002698f", + "_tpl": "572b7fa524597762b747ce82", + "parentId": "6613e1cf291a2e76b00269a8", + "slotId": "FaceCover" + }, { + "_id": "6613e1cf291a2e76b0026990", + "_tpl": "5aa2a7e8e5b5b00016327c16", + "parentId": "6613e1cf291a2e76b00269a8", + "slotId": "Headwear" + }, { + "_id": "6613e1cf291a2e76b0026998", + "_tpl": "5c0e9f2c86f77432297fe0a3", + "parentId": "6613e1cf291a2e76b00269a8", + "slotId": "TacticalVest" + }, { + "_id": "6613e1cf291a2e76b0026992", + "_tpl": "55d4887d4bdc2d962f8b4570", + "parentId": "6613e1cf291a2e76b0026998", + "slotId": "1", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026991", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026992", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b0026994", + "_tpl": "55d4887d4bdc2d962f8b4570", + "parentId": "6613e1cf291a2e76b0026998", + "slotId": "2", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026993", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026994", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b0026996", + "_tpl": "55d4887d4bdc2d962f8b4570", + "parentId": "6613e1cf291a2e76b0026998", + "slotId": "3", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026995", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026996", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b0026997", + "_tpl": "5755356824597772cb798962", + "parentId": "6613e1cf291a2e76b0026998", + "slotId": "4", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026999", + "_tpl": "5857a8bc2459772bad15db29", + "parentId": "6613e1cf291a2e76b00269a8", + "slotId": "SecuredContainer" + }, { + "_id": "6613e1cf291a2e76b002699d", + "_tpl": "5e9dcf5986f7746c417435b3", + "parentId": "6613e1cf291a2e76b00269a8", + "slotId": "Backpack" + }, { + "_id": "6613e1cf291a2e76b002699a", + "_tpl": "5448fee04bdc2dbc018b4567", + "parentId": "6613e1cf291a2e76b002699d", + "slotId": "main", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b002699b", + "_tpl": "590c5f0d86f77413997acfab", + "parentId": "6613e1cf291a2e76b002699d", + "slotId": "main", + "location": { + "x": 1, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b002699c", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b002699d", + "slotId": "main", + "location": { + "x": 2, + "y": 0, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 60 + } + }, { + "_id": "6613e1cf291a2e76b00269a2", + "_tpl": "5648a7494bdc2d9d488b4583", + "parentId": "6613e1cf291a2e76b00269a8", + "slotId": "ArmorVest" + }, { + "_id": "6613e1cf291a2e76b002699e", + "_tpl": "65703d866584602f7d057a8a", + "parentId": "6613e1cf291a2e76b00269a2", + "slotId": "Soft_armor_front" + }, { + "_id": "6613e1cf291a2e76b002699f", + "_tpl": "65703fa06584602f7d057a8e", + "parentId": "6613e1cf291a2e76b00269a2", + "slotId": "Soft_armor_back" + }, { + "_id": "6613e1cf291a2e76b00269a0", + "_tpl": "65703fe46a912c8b5c03468b", + "parentId": "6613e1cf291a2e76b00269a2", + "slotId": "Soft_armor_left" + }, { + "_id": "6613e1cf291a2e76b00269a1", + "_tpl": "657040374e67e8ec7a0d261c", + "parentId": "6613e1cf291a2e76b00269a2", + "slotId": "soft_armor_right" + }, { + "_id": "6613e1cf291a2e76b00269a6", + "_tpl": "627a4e6b255f7527fb05a0f6", + "parentId": "6613e1cf291a2e76b00269a8", + "slotId": "Pockets" + }, { + "_id": "6613e1cf291a2e76b00269a3", + "_tpl": "544fb3364bdc2d34748b456a", + "parentId": "6613e1cf291a2e76b00269a6", + "slotId": "pocket1", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269a4", + "_tpl": "544fb37f4bdc2dee738b4567", + "parentId": "6613e1cf291a2e76b00269a6", + "slotId": "pocket2", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269a5", + "_tpl": "5751a25924597722c463c472", + "parentId": "6613e1cf291a2e76b00269a6", + "slotId": "pocket3", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269a7", + "_tpl": "5645bcc04bdc2d363b8b4572", + "parentId": "6613e1cf291a2e76b00269a8", + "slotId": "Earpiece" + }, { + "_id": "6613e1cf291a2e76b0026acc", + "_tpl": "5811ce772459770e9e5f9532" + }, { + "_id": "6613e1cf291a2e76b00269a9", + "_tpl": "590c5f0d86f77413997acfab", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 2, + "y": 32, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269aa", + "_tpl": "5e9dcf5986f7746c417435b3", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 9, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269ab", + "_tpl": "5a0c27731526d80618476ac4", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 14, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269ad", + "_tpl": "5cadc2e0ae9215051e1c21e7", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 4, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269ac", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b00269ad", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 17 + } + }, { + "_id": "6613e1cf291a2e76b00269af", + "_tpl": "55d4887d4bdc2d962f8b4570", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 14, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269ae", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b00269af", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b00269b0", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 17, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 60 + } + }, { + "_id": "6613e1cf291a2e76b00269b1", + "_tpl": "590c661e86f7741e566b646a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 31, + "r": 1, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269b2", + "_tpl": "5755356824597772cb798962", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 31, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269b3", + "_tpl": "544fb25a4bdc2dfb738b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269b5", + "_tpl": "55d4887d4bdc2d962f8b4570", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 15, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269b4", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b00269b5", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b00269b6", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 8, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613e1cf291a2e76b00269b7", + "_tpl": "590c5f0d86f77413997acfab", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 1, + "y": 32, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269b9", + "_tpl": "55d4887d4bdc2d962f8b4570", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 14, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269b8", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b00269b9", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b00269ba", + "_tpl": "58d3db5386f77426186285a0", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 4, + "y": 13, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269bb", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 17, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 60 + } + }, { + "_id": "6613e1cf291a2e76b00269bc", + "_tpl": "590c661e86f7741e566b646a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 32, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269bd", + "_tpl": "5ab8f39486f7745cd93a1cca", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 25, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269be", + "_tpl": "5a0c27731526d80618476ac4", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 14, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269bf", + "_tpl": "58d3db5386f77426186285a0", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 13, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269c1", + "_tpl": "5bfeaa0f0db834001b734927", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 20, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269c0", + "_tpl": "58dd3ad986f77403051cba8f", + "parentId": "6613e1cf291a2e76b00269c1", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 10 + } + }, { + "_id": "6613e1cf291a2e76b00269c2", + "_tpl": "5e4d34ca86f774264f758330", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 4, + "y": 11, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269c3", + "_tpl": "5aa2a7e8e5b5b00016327c16", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269c4", + "_tpl": "5c0e9f2c86f77432297fe0a3", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 3, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269c5", + "_tpl": "590c5f0d86f77413997acfab", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 32, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269c6", + "_tpl": "5aa2a7e8e5b5b00016327c16", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269cb", + "_tpl": "5648a7494bdc2d9d488b4583", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269c7", + "_tpl": "65703d866584602f7d057a8a", + "parentId": "6613e1cf291a2e76b00269cb", + "slotId": "Soft_armor_front" + }, { + "_id": "6613e1cf291a2e76b00269c8", + "_tpl": "65703fa06584602f7d057a8e", + "parentId": "6613e1cf291a2e76b00269cb", + "slotId": "Soft_armor_back" + }, { + "_id": "6613e1cf291a2e76b00269c9", + "_tpl": "65703fe46a912c8b5c03468b", + "parentId": "6613e1cf291a2e76b00269cb", + "slotId": "Soft_armor_left" + }, { + "_id": "6613e1cf291a2e76b00269ca", + "_tpl": "657040374e67e8ec7a0d261c", + "parentId": "6613e1cf291a2e76b00269cb", + "slotId": "soft_armor_right" + }, { + "_id": "6613e1cf291a2e76b00269cc", + "_tpl": "5e831507ea0a7c419c2f9bd9", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 4, + "y": 33, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269cd", + "_tpl": "5755356824597772cb798962", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 31, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269cf", + "_tpl": "5cadc2e0ae9215051e1c21e7", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 4, + "y": 6, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269ce", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b00269cf", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 17 + } + }, { + "_id": "6613e1cf291a2e76b00269d0", + "_tpl": "5e4d34ca86f774264f758330", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 4, + "y": 9, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269d1", + "_tpl": "5d403f9186f7743cac3f229b", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 4, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269d2", + "_tpl": "5c0e9f2c86f77432297fe0a3", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 0, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269d7", + "_tpl": "5648a7494bdc2d9d488b4583", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 3, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269d3", + "_tpl": "65703d866584602f7d057a8a", + "parentId": "6613e1cf291a2e76b00269d7", + "slotId": "Soft_armor_front" + }, { + "_id": "6613e1cf291a2e76b00269d4", + "_tpl": "65703fa06584602f7d057a8e", + "parentId": "6613e1cf291a2e76b00269d7", + "slotId": "Soft_armor_back" + }, { + "_id": "6613e1cf291a2e76b00269d5", + "_tpl": "65703fe46a912c8b5c03468b", + "parentId": "6613e1cf291a2e76b00269d7", + "slotId": "Soft_armor_left" + }, { + "_id": "6613e1cf291a2e76b00269d6", + "_tpl": "657040374e67e8ec7a0d261c", + "parentId": "6613e1cf291a2e76b00269d7", + "slotId": "soft_armor_right" + }, { + "_id": "6613e1cf291a2e76b00269d8", + "_tpl": "5e831507ea0a7c419c2f9bd9", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 33, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269d9", + "_tpl": "544fb3364bdc2d34748b456a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 2, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269da", + "_tpl": "544fb25a4bdc2dfb738b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269db", + "_tpl": "544fb25a4bdc2dfb738b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269dc", + "_tpl": "5e831507ea0a7c419c2f9bd9", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 33, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269dd", + "_tpl": "544fb37f4bdc2dee738b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269df", + "_tpl": "5cadc2e0ae9215051e1c21e7", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 5, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269de", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b00269df", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 17 + } + }, { + "_id": "6613e1cf291a2e76b00269e0", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 8, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613e1cf291a2e76b00269e1", + "_tpl": "5e9dcf5986f7746c417435b3", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 9, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269e2", + "_tpl": "590c695186f7741e566b64a2", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269e3", + "_tpl": "5751a25924597722c463c472", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269e4", + "_tpl": "590c695186f7741e566b64a2", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269e5", + "_tpl": "5751a25924597722c463c472", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 4, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269e7", + "_tpl": "5d2f213448f0355009199284", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 2, + "y": 7, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269e6", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b00269e7", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b00269e9", + "_tpl": "5cadc2e0ae9215051e1c21e7", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 6, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269e8", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b00269e9", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 17 + } + }, { + "_id": "6613e1cf291a2e76b00269eb", + "_tpl": "5d2f213448f0355009199284", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 7, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269ea", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b00269eb", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b00269ed", + "_tpl": "5d2f213448f0355009199284", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 7, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269ec", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b00269ed", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b00269ef", + "_tpl": "5d2f213448f0355009199284", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 1, + "y": 7, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269ee", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b00269ef", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b00269f0", + "_tpl": "5755383e24597772cb798966", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269f2", + "_tpl": "55d4887d4bdc2d962f8b4570", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 25, + "r": 1, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269f1", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b00269f2", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b00269f3", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 8, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613e1cf291a2e76b00269f4", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 1, + "y": 8, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613e1cf291a2e76b00269f5", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 4, + "y": 8, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613e1cf291a2e76b00269f6", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 8, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613e1cf291a2e76b00269f7", + "_tpl": "5696686a4bdc2da3298b456a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 2, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 500 + } + }, { + "_id": "6613e1cf291a2e76b00269f8", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 8, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613e1cf291a2e76b00269fa", + "_tpl": "5cadc2e0ae9215051e1c21e7", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 3, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269f9", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b00269fa", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 17 + } + }, { + "_id": "6613e1cf291a2e76b00269fc", + "_tpl": "5d2f213448f0355009199284", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 7, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b00269fb", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b00269fc", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b00269fd", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 8, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613e1cf291a2e76b00269fe", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 2, + "y": 8, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613e1cf291a2e76b00269ff", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 8, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 50 + } + }, { + "_id": "6613e1cf291a2e76b0026a00", + "_tpl": "5755356824597772cb798962", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 31, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a01", + "_tpl": "5e831507ea0a7c419c2f9bd9", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 33, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a02", + "_tpl": "5449016a4bdc2d6f028b456f", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 1, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 250000 + } + }, { + "_id": "6613e1cf291a2e76b0026a03", + "_tpl": "5449016a4bdc2d6f028b456f", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 1, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 250000 + } + }, { + "_id": "6613e1cf291a2e76b0026a05", + "_tpl": "55d4887d4bdc2d962f8b4570", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 14, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a04", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026a05", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b0026a06", + "_tpl": "5e8488fa988a8701445df1e4", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a07", + "_tpl": "569668774bdc2da2298b4568", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 4, + "y": 2, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 500 + } + }, { + "_id": "6613e1cf291a2e76b0026a09", + "_tpl": "5cadc2e0ae9215051e1c21e7", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 6, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a08", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026a09", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 17 + } + }, { + "_id": "6613e1cf291a2e76b0026a0b", + "_tpl": "5d2f213448f0355009199284", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 7, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a0a", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026a0b", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b0026a0d", + "_tpl": "5cadc2e0ae9215051e1c21e7", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 7, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a0c", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026a0d", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 17 + } + }, { + "_id": "6613e1cf291a2e76b0026a0f", + "_tpl": "5cadc2e0ae9215051e1c21e7", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 4, + "y": 7, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a0e", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026a0f", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 17 + } + }, { + "_id": "6613e1cf291a2e76b0026a10", + "_tpl": "5a0c27731526d80618476ac4", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 16, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a11", + "_tpl": "5a0c27731526d80618476ac4", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 15, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a12", + "_tpl": "57347da92459774491567cf5", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 26, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a13", + "_tpl": "57347da92459774491567cf5", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 28, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a14", + "_tpl": "57347da92459774491567cf5", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 26, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a15", + "_tpl": "57347da92459774491567cf5", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 27, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a16", + "_tpl": "560d5e524bdc2d25448b4571", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 17, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b0026a17", + "_tpl": "560d5e524bdc2d25448b4571", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 17, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b0026a18", + "_tpl": "560d5e524bdc2d25448b4571", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 17, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b0026a19", + "_tpl": "544fb3364bdc2d34748b456a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 1, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a1a", + "_tpl": "5755356824597772cb798962", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 31, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a1b", + "_tpl": "60098ad7c2240c0fe85c570a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 2, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a1c", + "_tpl": "5d02778e86f774203e7dedbe", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 32, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a21", + "_tpl": "5c0e655586f774045612eeb2", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 17, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a1d", + "_tpl": "656fad8c498d1b7e3e071da0", + "parentId": "6613e1cf291a2e76b0026a21", + "slotId": "Front_plate" + }, { + "_id": "6613e1cf291a2e76b0026a1e", + "_tpl": "656fad8c498d1b7e3e071da0", + "parentId": "6613e1cf291a2e76b0026a21", + "slotId": "Back_plate" + }, { + "_id": "6613e1cf291a2e76b0026a1f", + "_tpl": "6570e025615f54368b04fcb0", + "parentId": "6613e1cf291a2e76b0026a21", + "slotId": "Soft_armor_front" + }, { + "_id": "6613e1cf291a2e76b0026a20", + "_tpl": "6570e0610b57c03ec90b96ef", + "parentId": "6613e1cf291a2e76b0026a21", + "slotId": "Soft_armor_back" + }, { + "_id": "6613e1cf291a2e76b0026a22", + "_tpl": "5c165d832e2216398b5a7e36", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 21, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a23", + "_tpl": "5af0454c86f7746bf20992e8", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 33, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a24", + "_tpl": "5af0454c86f7746bf20992e8", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 33, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a25", + "_tpl": "5af0454c86f7746bf20992e8", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 33, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a26", + "_tpl": "60098ad7c2240c0fe85c570a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 2, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a27", + "_tpl": "5ab8f39486f7745cd93a1cca", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 25, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a28", + "_tpl": "557ff21e4bdc2d89578b4586", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 22, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a29", + "_tpl": "5bfebc5e0db834001a6694e5", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 19, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a2a", + "_tpl": "57c5ac0824597754771e88a9", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 16, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a2e", + "_tpl": "5aa7d03ae5b5b00016327db5", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 20, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a2b", + "_tpl": "654a90aff4f81a421b0a7c86", + "parentId": "6613e1cf291a2e76b0026a2e", + "slotId": "helmet_top" + }, { + "_id": "6613e1cf291a2e76b0026a2c", + "_tpl": "654a91068e1ce698150fd1e2", + "parentId": "6613e1cf291a2e76b0026a2e", + "slotId": "helmet_back" + }, { + "_id": "6613e1cf291a2e76b0026a2d", + "_tpl": "654a9189bcc67a392b056c79", + "parentId": "6613e1cf291a2e76b0026a2e", + "slotId": "helmet_ears" + }, { + "_id": "6613e1cf291a2e76b0026a32", + "_tpl": "5aa7d03ae5b5b00016327db5", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 2, + "y": 20, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a2f", + "_tpl": "654a90aff4f81a421b0a7c86", + "parentId": "6613e1cf291a2e76b0026a32", + "slotId": "helmet_top" + }, { + "_id": "6613e1cf291a2e76b0026a30", + "_tpl": "654a91068e1ce698150fd1e2", + "parentId": "6613e1cf291a2e76b0026a32", + "slotId": "helmet_back" + }, { + "_id": "6613e1cf291a2e76b0026a31", + "_tpl": "654a9189bcc67a392b056c79", + "parentId": "6613e1cf291a2e76b0026a32", + "slotId": "helmet_ears" + }, { + "_id": "6613e1cf291a2e76b0026a33", + "_tpl": "544fb37f4bdc2dee738b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a34", + "_tpl": "544fb37f4bdc2dee738b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a35", + "_tpl": "58d3db5386f77426186285a0", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 19, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a36", + "_tpl": "58d3db5386f77426186285a0", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 4, + "y": 19, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a37", + "_tpl": "58d3db5386f77426186285a0", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 20, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a39", + "_tpl": "55d4887d4bdc2d962f8b4570", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 24, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a38", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026a39", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b0026a3a", + "_tpl": "5d1b371186f774253763a656", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 37, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a3b", + "_tpl": "5d1b36a186f7742523398433", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 37, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a3c", + "_tpl": "60098ad7c2240c0fe85c570a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 2, + "y": 37, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a3d", + "_tpl": "557ff21e4bdc2d89578b4586", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 23, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a3e", + "_tpl": "5448fee04bdc2dbc018b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 29, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a3f", + "_tpl": "5d02778e86f774203e7dedbe", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 32, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a40", + "_tpl": "5d5d940f86f7742797262046", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 27, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a41", + "_tpl": "57cd379a24597778e7682ecf", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 26, + "r": 1, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a47", + "_tpl": "544a5caa4bdc2d1a388b4568", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 22, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a42", + "_tpl": "656f9fa0498d1b7e3e071d98", + "parentId": "6613e1cf291a2e76b0026a47", + "slotId": "Front_plate" + }, { + "_id": "6613e1cf291a2e76b0026a43", + "_tpl": "656f9fa0498d1b7e3e071d98", + "parentId": "6613e1cf291a2e76b0026a47", + "slotId": "Back_plate" + }, { + "_id": "6613e1cf291a2e76b0026a44", + "_tpl": "6570e83223c1f638ef0b0ede", + "parentId": "6613e1cf291a2e76b0026a47", + "slotId": "Soft_armor_front" + }, { + "_id": "6613e1cf291a2e76b0026a45", + "_tpl": "6570e87c23c1f638ef0b0ee2", + "parentId": "6613e1cf291a2e76b0026a47", + "slotId": "Soft_armor_back" + }, { + "_id": "6613e1cf291a2e76b0026a46", + "_tpl": "6570e90b3a5689d85f08db97", + "parentId": "6613e1cf291a2e76b0026a47", + "slotId": "Groin" + }, { + "_id": "6613e1cf291a2e76b0026a48", + "_tpl": "5d5d85c586f774279a21cbdb", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 22, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a49", + "_tpl": "5e2af4a786f7746d3f3c3400", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a4a", + "_tpl": "570fd6c2d2720bc6458b457f", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 26, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a4b", + "_tpl": "5448be9a4bdc2dfd2f8b456a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 4, + "y": 20, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a4c", + "_tpl": "5448be9a4bdc2dfd2f8b456a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 21, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a4d", + "_tpl": "590c657e86f77412b013051d", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a50", + "_tpl": "5d5e9c74a4b9364855191c40", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 17, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a4e", + "_tpl": "657f8b94f92cd718b70154ff", + "parentId": "6613e1cf291a2e76b0026a50", + "slotId": "Helmet_top" + }, { + "_id": "6613e1cf291a2e76b0026a4f", + "_tpl": "657f8b43f92cd718b70154fb", + "parentId": "6613e1cf291a2e76b0026a50", + "slotId": "Helmet_back" + }, { + "_id": "6613e1cf291a2e76b0026a52", + "_tpl": "55d4887d4bdc2d962f8b4570", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 26, + "r": 1, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a51", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026a52", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b0026a53", + "_tpl": "590c678286f77426c9660122", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a54", + "_tpl": "590c678286f77426c9660122", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 4, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a55", + "_tpl": "590c678286f77426c9660122", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a57", + "_tpl": "55d4887d4bdc2d962f8b4570", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 24, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a56", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026a57", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b0026a58", + "_tpl": "5448fee04bdc2dbc018b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 29, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a59", + "_tpl": "5e8488fa988a8701445df1e4", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 36, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a5a", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 26, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 60 + } + }, { + "_id": "6613e1cf291a2e76b0026a5b", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 26, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b0026a5c", + "_tpl": "5c0e530286f7747fa1419862", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a5d", + "_tpl": "5c0e530286f7747fa1419862", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a5e", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 25, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b0026a5f", + "_tpl": "5696686a4bdc2da3298b456a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 2, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 500 + } + }, { + "_id": "6613e1cf291a2e76b0026a61", + "_tpl": "5bfeaa0f0db834001b734927", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 19, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a60", + "_tpl": "58dd3ad986f77403051cba8f", + "parentId": "6613e1cf291a2e76b0026a61", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 10 + } + }, { + "_id": "6613e1cf291a2e76b0026a63", + "_tpl": "5bfeaa0f0db834001b734927", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 19, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a62", + "_tpl": "58dd3ad986f77403051cba8f", + "parentId": "6613e1cf291a2e76b0026a63", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 10 + } + }, { + "_id": "6613e1cf291a2e76b0026a65", + "_tpl": "5bfeaa0f0db834001b734927", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 20, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a64", + "_tpl": "58dd3ad986f77403051cba8f", + "parentId": "6613e1cf291a2e76b0026a65", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 10 + } + }, { + "_id": "6613e1cf291a2e76b0026a66", + "_tpl": "58dd3ad986f77403051cba8f", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 19, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b0026a67", + "_tpl": "5448fee04bdc2dbc018b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 29, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a68", + "_tpl": "544fb3364bdc2d34748b456a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 34, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a6a", + "_tpl": "5d2f213448f0355009199284", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 7, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a69", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026a6a", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b0026a6c", + "_tpl": "5d2f213448f0355009199284", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 7, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a6b", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026a6c", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b0026a6e", + "_tpl": "5cadc2e0ae9215051e1c21e7", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 6, + "y": 6, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a6d", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026a6e", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 17 + } + }, { + "_id": "6613e1cf291a2e76b0026a6f", + "_tpl": "544fb3f34bdc2d03748b456a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 30, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a70", + "_tpl": "544fb3f34bdc2d03748b456a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 30, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a71", + "_tpl": "5e2af47786f7746d404f3aaa", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 38, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a72", + "_tpl": "5e2af4a786f7746d3f3c3400", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 37, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a73", + "_tpl": "5e2af47786f7746d404f3aaa", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 39, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a74", + "_tpl": "58dd3ad986f77403051cba8f", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 16, + "r": 0, + "isSearched": true + }, + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b0026a75", + "_tpl": "5448be9a4bdc2dfd2f8b456a", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 4, + "y": 21, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a76", + "_tpl": "5645bcc04bdc2d363b8b4572", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 23, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a77", + "_tpl": "57347da92459774491567cf5", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 8, + "y": 29, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a78", + "_tpl": "57347da92459774491567cf5", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 29, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a79", + "_tpl": "544fb25a4bdc2dfb738b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 9, + "y": 35, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a82", + "_tpl": "5cadc190ae921500103bb3b6", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 5, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a7b", + "_tpl": "5cadc1c6ae9215000f2775a4", + "parentId": "6613e1cf291a2e76b0026a82", + "slotId": "mod_barrel" + }, { + "_id": "6613e1cf291a2e76b0026a7a", + "_tpl": "5cadc390ae921500126a77f1", + "parentId": "6613e1cf291a2e76b0026a7b", + "slotId": "mod_muzzle" + }, { + "_id": "6613e1cf291a2e76b0026a7c", + "_tpl": "5cadc431ae921500113bb8d5", + "parentId": "6613e1cf291a2e76b0026a82", + "slotId": "mod_pistol_grip" + }, { + "_id": "6613e1cf291a2e76b0026a7f", + "_tpl": "5cadc55cae921500103bb3be", + "parentId": "6613e1cf291a2e76b0026a82", + "slotId": "mod_reciever" + }, { + "_id": "6613e1cf291a2e76b0026a7d", + "_tpl": "5cadd940ae9215051e1c2316", + "parentId": "6613e1cf291a2e76b0026a7f", + "slotId": "mod_sight_rear" + }, { + "_id": "6613e1cf291a2e76b0026a7e", + "_tpl": "5cadd919ae921500126a77f3", + "parentId": "6613e1cf291a2e76b0026a7f", + "slotId": "mod_sight_front" + }, { + "_id": "6613e1cf291a2e76b0026a81", + "_tpl": "5cadc2e0ae9215051e1c21e7", + "parentId": "6613e1cf291a2e76b0026a82", + "slotId": "mod_magazine" + }, { + "_id": "6613e1cf291a2e76b0026a80", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026a81", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 17 + } + }, { + "_id": "6613e1cf291a2e76b0026a8b", + "_tpl": "5cadc190ae921500103bb3b6", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 4, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a84", + "_tpl": "5cadc1c6ae9215000f2775a4", + "parentId": "6613e1cf291a2e76b0026a8b", + "slotId": "mod_barrel" + }, { + "_id": "6613e1cf291a2e76b0026a83", + "_tpl": "5cadc390ae921500126a77f1", + "parentId": "6613e1cf291a2e76b0026a84", + "slotId": "mod_muzzle" + }, { + "_id": "6613e1cf291a2e76b0026a85", + "_tpl": "5cadc431ae921500113bb8d5", + "parentId": "6613e1cf291a2e76b0026a8b", + "slotId": "mod_pistol_grip" + }, { + "_id": "6613e1cf291a2e76b0026a88", + "_tpl": "5cadc55cae921500103bb3be", + "parentId": "6613e1cf291a2e76b0026a8b", + "slotId": "mod_reciever" + }, { + "_id": "6613e1cf291a2e76b0026a86", + "_tpl": "5cadd940ae9215051e1c2316", + "parentId": "6613e1cf291a2e76b0026a88", + "slotId": "mod_sight_rear" + }, { + "_id": "6613e1cf291a2e76b0026a87", + "_tpl": "5cadd919ae921500126a77f3", + "parentId": "6613e1cf291a2e76b0026a88", + "slotId": "mod_sight_front" + }, { + "_id": "6613e1cf291a2e76b0026a8a", + "_tpl": "5cadc2e0ae9215051e1c21e7", + "parentId": "6613e1cf291a2e76b0026a8b", + "slotId": "mod_magazine" + }, { + "_id": "6613e1cf291a2e76b0026a89", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026a8a", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 17 + } + }, { + "_id": "6613e1cf291a2e76b0026a94", + "_tpl": "5926bb2186f7744b1c6c6e60", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 7, + "y": 6, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a8d", + "_tpl": "5d2f213448f0355009199284", + "parentId": "6613e1cf291a2e76b0026a94", + "slotId": "mod_magazine" + }, { + "_id": "6613e1cf291a2e76b0026a8c", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026a8d", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b0026a92", + "_tpl": "5926c0df86f77462f647f764", + "parentId": "6613e1cf291a2e76b0026a94", + "slotId": "mod_reciever" + }, { + "_id": "6613e1cf291a2e76b0026a8e", + "_tpl": "5926c36d86f77467a92a8629", + "parentId": "6613e1cf291a2e76b0026a92", + "slotId": "mod_handguard" + }, { + "_id": "6613e1cf291a2e76b0026a8f", + "_tpl": "5926d2be86f774134d668e4e", + "parentId": "6613e1cf291a2e76b0026a92", + "slotId": "mod_sight_rear" + }, { + "_id": "6613e1cf291a2e76b0026a90", + "_tpl": "5926d3c686f77410de68ebc8", + "parentId": "6613e1cf291a2e76b0026a92", + "slotId": "mod_stock" + }, { + "_id": "6613e1cf291a2e76b0026a91", + "_tpl": "5926e16e86f7742f5a0f7ecb", + "parentId": "6613e1cf291a2e76b0026a92", + "slotId": "mod_muzzle" + }, { + "_id": "6613e1cf291a2e76b0026a93", + "_tpl": "5926c32286f774616e42de99", + "parentId": "6613e1cf291a2e76b0026a94", + "slotId": "mod_charge" + }, { + "_id": "6613e1cf291a2e76b0026a9d", + "_tpl": "5926bb2186f7744b1c6c6e60", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 6, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a96", + "_tpl": "5d2f213448f0355009199284", + "parentId": "6613e1cf291a2e76b0026a9d", + "slotId": "mod_magazine" + }, { + "_id": "6613e1cf291a2e76b0026a95", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026a96", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 20 + } + }, { + "_id": "6613e1cf291a2e76b0026a9b", + "_tpl": "5926c0df86f77462f647f764", + "parentId": "6613e1cf291a2e76b0026a9d", + "slotId": "mod_reciever" + }, { + "_id": "6613e1cf291a2e76b0026a97", + "_tpl": "5926c36d86f77467a92a8629", + "parentId": "6613e1cf291a2e76b0026a9b", + "slotId": "mod_handguard" + }, { + "_id": "6613e1cf291a2e76b0026a98", + "_tpl": "5926d2be86f774134d668e4e", + "parentId": "6613e1cf291a2e76b0026a9b", + "slotId": "mod_sight_rear" + }, { + "_id": "6613e1cf291a2e76b0026a99", + "_tpl": "5926d3c686f77410de68ebc8", + "parentId": "6613e1cf291a2e76b0026a9b", + "slotId": "mod_stock" + }, { + "_id": "6613e1cf291a2e76b0026a9a", + "_tpl": "5926e16e86f7742f5a0f7ecb", + "parentId": "6613e1cf291a2e76b0026a9b", + "slotId": "mod_muzzle" + }, { + "_id": "6613e1cf291a2e76b0026a9c", + "_tpl": "5926c32286f774616e42de99", + "parentId": "6613e1cf291a2e76b0026a9d", + "slotId": "mod_charge" + }, { + "_id": "6613e1cf291a2e76b0026aa6", + "_tpl": "5cadc190ae921500103bb3b6", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 3, + "y": 3, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026a9f", + "_tpl": "5cadc1c6ae9215000f2775a4", + "parentId": "6613e1cf291a2e76b0026aa6", + "slotId": "mod_barrel" + }, { + "_id": "6613e1cf291a2e76b0026a9e", + "_tpl": "5cadc390ae921500126a77f1", + "parentId": "6613e1cf291a2e76b0026a9f", + "slotId": "mod_muzzle" + }, { + "_id": "6613e1cf291a2e76b0026aa0", + "_tpl": "5cadc431ae921500113bb8d5", + "parentId": "6613e1cf291a2e76b0026aa6", + "slotId": "mod_pistol_grip" + }, { + "_id": "6613e1cf291a2e76b0026aa3", + "_tpl": "5cadc55cae921500103bb3be", + "parentId": "6613e1cf291a2e76b0026aa6", + "slotId": "mod_reciever" + }, { + "_id": "6613e1cf291a2e76b0026aa1", + "_tpl": "5cadd940ae9215051e1c2316", + "parentId": "6613e1cf291a2e76b0026aa3", + "slotId": "mod_sight_rear" + }, { + "_id": "6613e1cf291a2e76b0026aa2", + "_tpl": "5cadd919ae921500126a77f3", + "parentId": "6613e1cf291a2e76b0026aa3", + "slotId": "mod_sight_front" + }, { + "_id": "6613e1cf291a2e76b0026aa5", + "_tpl": "5cadc2e0ae9215051e1c21e7", + "parentId": "6613e1cf291a2e76b0026aa6", + "slotId": "mod_magazine" + }, { + "_id": "6613e1cf291a2e76b0026aa4", + "_tpl": "64b7bbb74b75259c590fa897", + "parentId": "6613e1cf291a2e76b0026aa5", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 17 + } + }, { + "_id": "6613e1cf291a2e76b0026aaf", + "_tpl": "5e870397991fd70db46995c8", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 16, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026aa8", + "_tpl": "5e87071478f43e51ca2de5e1", + "parentId": "6613e1cf291a2e76b0026aaf", + "slotId": "mod_barrel" + }, { + "_id": "6613e1cf291a2e76b0026aa7", + "_tpl": "5e8708d4ae379e67d22e0102", + "parentId": "6613e1cf291a2e76b0026aa8", + "slotId": "mod_sight_front" + }, { + "_id": "6613e1cf291a2e76b0026aa9", + "_tpl": "5e87076ce2db31558c75a11d", + "parentId": "6613e1cf291a2e76b0026aaf", + "slotId": "mod_handguard" + }, { + "_id": "6613e1cf291a2e76b0026aab", + "_tpl": "5e87080c81c4ed43e83cefda", + "parentId": "6613e1cf291a2e76b0026aaf", + "slotId": "mod_magazine" + }, { + "_id": "6613e1cf291a2e76b0026aaa", + "_tpl": "560d5e524bdc2d25448b4571", + "parentId": "6613e1cf291a2e76b0026aab", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 8 + } + }, { + "_id": "6613e1cf291a2e76b0026aac", + "_tpl": "5e87116b81c4ed43e83cefdd", + "parentId": "6613e1cf291a2e76b0026aaf", + "slotId": "mod_stock" + }, { + "_id": "6613e1cf291a2e76b0026aad", + "_tpl": "5e87114fe2db31558c75a120", + "parentId": "6613e1cf291a2e76b0026aaf", + "slotId": "mod_mount" + }, { + "_id": "6613e1cf291a2e76b0026aae", + "_tpl": "560d5e524bdc2d25448b4571", + "parentId": "6613e1cf291a2e76b0026aaf", + "slotId": "patron_in_weapon" + }, { + "_id": "6613e1cf291a2e76b0026ab4", + "_tpl": "5bfea6e90db834001b7347f3", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 18, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026ab1", + "_tpl": "5bfeaa0f0db834001b734927", + "parentId": "6613e1cf291a2e76b0026ab4", + "slotId": "mod_magazine" + }, { + "_id": "6613e1cf291a2e76b0026ab0", + "_tpl": "58dd3ad986f77403051cba8f", + "parentId": "6613e1cf291a2e76b0026ab1", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 10 + } + }, { + "_id": "6613e1cf291a2e76b0026ab2", + "_tpl": "5bfeb32b0db834001a6694d9", + "parentId": "6613e1cf291a2e76b0026ab4", + "slotId": "mod_stock" + }, { + "_id": "6613e1cf291a2e76b0026ab3", + "_tpl": "5bfebc320db8340019668d79", + "parentId": "6613e1cf291a2e76b0026ab4", + "slotId": "mod_barrel" + }, { + "_id": "6613e1cf291a2e76b0026abd", + "_tpl": "5c488a752e221602b412af63", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 5, + "y": 27, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026ab5", + "_tpl": "5c48a2c22e221602b313fb6c", + "parentId": "6613e1cf291a2e76b0026abd", + "slotId": "mod_pistol_grip" + }, { + "_id": "6613e1cf291a2e76b0026ab7", + "_tpl": "55d4887d4bdc2d962f8b4570", + "parentId": "6613e1cf291a2e76b0026abd", + "slotId": "mod_magazine" + }, { + "_id": "6613e1cf291a2e76b0026ab6", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026ab7", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b0026ab9", + "_tpl": "5c48a14f2e2216152006edd7", + "parentId": "6613e1cf291a2e76b0026abd", + "slotId": "mod_handguard" + }, { + "_id": "6613e1cf291a2e76b0026ab8", + "_tpl": "5c18b90d2e2216152142466b", + "parentId": "6613e1cf291a2e76b0026ab9", + "slotId": "mod_sight_front" + }, { + "_id": "6613e1cf291a2e76b0026abb", + "_tpl": "5c48a2852e221602b21d5923", + "parentId": "6613e1cf291a2e76b0026abd", + "slotId": "mod_barrel" + }, { + "_id": "6613e1cf291a2e76b0026aba", + "_tpl": "5c48a2a42e221602b66d1e07", + "parentId": "6613e1cf291a2e76b0026abb", + "slotId": "mod_muzzle" + }, { + "_id": "6613e1cf291a2e76b0026abc", + "_tpl": "5c18b9192e2216398b5a8104", + "parentId": "6613e1cf291a2e76b0026abd", + "slotId": "mod_sight_rear" + }, { + "_id": "6613e1cf291a2e76b0026acb", + "_tpl": "5447a9cd4bdc2dbd208b4567", + "parentId": "6613e1cf291a2e76b0026acc", + "slotId": "hideout", + "location": { + "x": 0, + "y": 14, + "r": 0, + "isSearched": true + } + }, { + "_id": "6613e1cf291a2e76b0026abe", + "_tpl": "55d4b9964bdc2d1d4e8b456e", + "parentId": "6613e1cf291a2e76b0026acb", + "slotId": "mod_pistol_grip" + }, { + "_id": "6613e1cf291a2e76b0026ac0", + "_tpl": "55d4887d4bdc2d962f8b4570", + "parentId": "6613e1cf291a2e76b0026acb", + "slotId": "mod_magazine" + }, { + "_id": "6613e1cf291a2e76b0026abf", + "_tpl": "54527a984bdc2d4e668b4567", + "parentId": "6613e1cf291a2e76b0026ac0", + "slotId": "cartridges", + "upd": { + "StackObjectsCount": 30 + } + }, { + "_id": "6613e1cf291a2e76b0026ac7", + "_tpl": "55d355e64bdc2d962f8b4569", + "parentId": "6613e1cf291a2e76b0026acb", + "slotId": "mod_reciever" + }, { + "_id": "6613e1cf291a2e76b0026ac3", + "_tpl": "55d3632e4bdc2d972f8b4569", + "parentId": "6613e1cf291a2e76b0026ac7", + "slotId": "mod_barrel" + }, { + "_id": "6613e1cf291a2e76b0026ac1", + "_tpl": "544a38634bdc2d58388b4568", + "parentId": "6613e1cf291a2e76b0026ac3", + "slotId": "mod_muzzle" + }, { + "_id": "6613e1cf291a2e76b0026ac2", + "_tpl": "5ae30e795acfc408fb139a0b", + "parentId": "6613e1cf291a2e76b0026ac3", + "slotId": "mod_gas_block" + }, { + "_id": "6613e1cf291a2e76b0026ac5", + "_tpl": "5ae30db85acfc408fb139a05", + "parentId": "6613e1cf291a2e76b0026ac7", + "slotId": "mod_handguard" + }, { + "_id": "6613e1cf291a2e76b0026ac4", + "_tpl": "637f57a68d137b27f70c4968", + "parentId": "6613e1cf291a2e76b0026ac5", + "slotId": "mod_handguard" + }, { + "_id": "6613e1cf291a2e76b0026ac6", + "_tpl": "5ae30bad5acfc400185c2dc4", + "parentId": "6613e1cf291a2e76b0026ac7", + "slotId": "mod_sight_rear" + }, { + "_id": "6613e1cf291a2e76b0026ac9", + "_tpl": "5649be884bdc2d79388b4577", + "parentId": "6613e1cf291a2e76b0026acb", + "slotId": "mod_stock" + }, { + "_id": "6613e1cf291a2e76b0026ac8", + "_tpl": "55d4ae6c4bdc2d8b2f8b456e", + "parentId": "6613e1cf291a2e76b0026ac9", + "slotId": "mod_stock_000" + }, { + "_id": "6613e1cf291a2e76b0026aca", + "_tpl": "55d44fd14bdc2d962f8b456e", + "parentId": "6613e1cf291a2e76b0026acb", + "slotId": "mod_charge" + }, { + "_id": "6613e1cf291a2e76b0026acf", + "_tpl": "602543c13fee350cd564d032" + }, { + "_id": "6613e1cf291a2e76b0026ace", + "_tpl": "5963866b86f7747bfa1c4462" + }, { + "_id": "6613e1cf291a2e76b0026acd", + "_tpl": "5963866286f7747bf429b572" + } + ], + "questRaidItems": "6613e1cf291a2e76b0026acd", + "questStashItems": "6613e1cf291a2e76b0026ace", + "sortingTable": "6613e1cf291a2e76b0026acf", + "stash": "6613e1cf291a2e76b0026acc" }, "Notes": { "Notes": [] diff --git a/project/package.json b/project/package.json index eaeae684..30963880 100644 --- a/project/package.json +++ b/project/package.json @@ -33,6 +33,7 @@ "dependencies": { "atomically": "~1.7", "buffer-crc32": "^1.0.0", + "closest-match": "~1.3", "date-fns": "~2.30", "date-fns-tz": "~2.0", "i18n": "~0.15", diff --git a/project/src/callbacks/BotCallbacks.ts b/project/src/callbacks/BotCallbacks.ts index 3867921a..966104ac 100644 --- a/project/src/callbacks/BotCallbacks.ts +++ b/project/src/callbacks/BotCallbacks.ts @@ -4,6 +4,7 @@ import { BotController } from "@spt-aki/controllers/BotController"; import { IGenerateBotsRequestData } from "@spt-aki/models/eft/bot/IGenerateBotsRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IBotBase } from "@spt-aki/models/eft/common/tables/IBotBase"; +import { Difficulties } from "@spt-aki/models/eft/common/tables/IBotType"; import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData"; import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil"; @@ -44,6 +45,15 @@ export class BotCallbacks return this.httpResponse.noBody(this.botController.getBotDifficulty(type, difficulty)); } + /** + * Handle singleplayer/settings/bot/difficulties + * @returns dictionary of every bot and its diffiulty settings + */ + public getAllBotDifficulties(url: string, info: IEmptyRequestData, sessionID: string): Record + { + return this.httpResponse.noBody(this.botController.getAllBotDifficulties()); + } + /** * Handle client/game/bot/generate * @returns IGetBodyResponseData diff --git a/project/src/callbacks/InraidCallbacks.ts b/project/src/callbacks/InraidCallbacks.ts index 005284c5..87a5dec2 100644 --- a/project/src/callbacks/InraidCallbacks.ts +++ b/project/src/callbacks/InraidCallbacks.ts @@ -65,15 +65,6 @@ export class InraidCallbacks return this.httpResponse.noBody(this.inraidController.getInraidConfig().raidMenuSettings); } - /** - * Handle singleplayer/settings/weapon/durability - * @returns - */ - public getWeaponDurability(): string - { - return this.httpResponse.noBody(this.inraidController.getInraidConfig().save.durability); - } - /** * Handle singleplayer/airdrop/config * @returns JSON as string diff --git a/project/src/controllers/BotController.ts b/project/src/controllers/BotController.ts index 42f740d0..908333a5 100644 --- a/project/src/controllers/BotController.ts +++ b/project/src/controllers/BotController.ts @@ -83,7 +83,7 @@ export class BotController /** * Get bot difficulty settings - * adjust PMC settings to ensure they engage the correct bot types + * Adjust PMC settings to ensure they engage the correct bot types * @param type what bot the server is requesting settings for * @param diffLevel difficulty level server requested settings for * @returns Difficulty object @@ -104,7 +104,7 @@ export class BotController // Check value chosen in pre-raid difficulty dropdown // If value is not 'asonline', change requested difficulty to be what was chosen in dropdown - const botDifficultyDropDownValue = raidConfig.wavesSettings.botDifficulty.toLowerCase(); + const botDifficultyDropDownValue = raidConfig?.wavesSettings.botDifficulty.toLowerCase() ?? "asonline"; if (botDifficultyDropDownValue !== "asonline") { difficulty = this.botDifficultyHelper.convertBotDifficultyDropdownToBotDifficulty( @@ -140,6 +140,31 @@ export class BotController return difficultySettings; } + public getAllBotDifficulties(): Record + { + const result = {}; + + const botDb = this.databaseServer.getTables().bots.types; + const botTypes = Object.keys(botDb); + for (const botType of botTypes) + { + const botDetails = botDb[botType]; + if (!botDetails.difficulty) + { + continue; + } + const botDifficulties = Object.keys(botDetails.difficulty); + + result[botType] = {}; + for (const difficulty of botDifficulties) + { + result[botType][difficulty] = this.getBotDifficulty(botType, difficulty); + } + } + + return result; + } + /** * Generate bot profiles and store in cache * @param sessionId Session id diff --git a/project/src/controllers/BuildController.ts b/project/src/controllers/BuildController.ts index a337b9f5..b43ec7cb 100644 --- a/project/src/controllers/BuildController.ts +++ b/project/src/controllers/BuildController.ts @@ -147,7 +147,7 @@ export class BuildController this.removePlayerBuild(request.id, sessionID); } - protected removePlayerBuild(id: string, sessionID: string): void + protected removePlayerBuild(idToRemove: string, sessionID: string): void { const profile = this.saveServer.getProfile(sessionID); const weaponBuilds = profile.userbuilds.weaponBuilds; @@ -155,7 +155,7 @@ export class BuildController const magazineBuilds = profile.userbuilds.magazineBuilds; // Check for id in weapon array first - const matchingWeaponBuild = weaponBuilds.find((x) => x.Id === id); + const matchingWeaponBuild = weaponBuilds.find((weaponBuild) => weaponBuild.Id === idToRemove); if (matchingWeaponBuild) { weaponBuilds.splice(weaponBuilds.indexOf(matchingWeaponBuild), 1); @@ -164,7 +164,7 @@ export class BuildController } // Id not found in weapons, try equipment - const matchingEquipmentBuild = equipmentBuilds.find((x) => x.Id === id); + const matchingEquipmentBuild = equipmentBuilds.find((equipmentBuild) => equipmentBuild.Id === idToRemove); if (matchingEquipmentBuild) { equipmentBuilds.splice(equipmentBuilds.indexOf(matchingEquipmentBuild), 1); @@ -173,7 +173,7 @@ export class BuildController } // Id not found in weapons/equipment, try mags - const matchingMagazineBuild = magazineBuilds.find((x) => x.Id === id); + const matchingMagazineBuild = magazineBuilds.find((magBuild) => magBuild.Id === idToRemove); if (matchingMagazineBuild) { magazineBuilds.splice(magazineBuilds.indexOf(matchingMagazineBuild), 1); @@ -182,7 +182,9 @@ export class BuildController } // Not found in weapons,equipment or magazines, not good - this.logger.error(`Unable to delete preset, cannot find ${id} in weapon, equipment or magazine presets`); + this.logger.error( + `Unable to delete preset, cannot find ${idToRemove} in weapon, equipment or magazine presets`, + ); } /** diff --git a/project/src/controllers/GameController.ts b/project/src/controllers/GameController.ts index 1cede6dc..f8be4796 100644 --- a/project/src/controllers/GameController.ts +++ b/project/src/controllers/GameController.ts @@ -39,6 +39,7 @@ import { GiftService } from "@spt-aki/services/GiftService"; import { ItemBaseClassService } from "@spt-aki/services/ItemBaseClassService"; import { LocalisationService } from "@spt-aki/services/LocalisationService"; import { OpenZoneService } from "@spt-aki/services/OpenZoneService"; +import { ProfileActivityService } from "@spt-aki/services/ProfileActivityService"; import { ProfileFixerService } from "@spt-aki/services/ProfileFixerService"; import { RaidTimeAdjustmentService } from "@spt-aki/services/RaidTimeAdjustmentService"; import { SeasonalEventService } from "@spt-aki/services/SeasonalEventService"; @@ -78,6 +79,7 @@ export class GameController @inject("ItemBaseClassService") protected itemBaseClassService: ItemBaseClassService, @inject("GiftService") protected giftService: GiftService, @inject("RaidTimeAdjustmentService") protected raidTimeAdjustmentService: RaidTimeAdjustmentService, + @inject("ProfileActivityService") protected profileActivityService: ProfileActivityService, @inject("ApplicationContext") protected applicationContext: ApplicationContext, @inject("ConfigServer") protected configServer: ConfigServer, ) @@ -109,6 +111,8 @@ export class GameController // Store client start time in app context this.applicationContext.addValue(ContextVariableType.CLIENT_START_TIMESTAMP, startTimeStampMS); + this.profileActivityService.setActivityTimestamp(sessionID); + if (this.coreConfig.fixes.fixShotgunDispersion) { this.fixShotgunDispersions(); @@ -203,12 +207,16 @@ export class GameController this.hideoutHelper.setHideoutImprovementsToCompleted(pmcProfile); this.hideoutHelper.unlockHideoutWallInProfile(pmcProfile); this.profileFixerService.addMissingIdsToBonuses(pmcProfile); + this.profileFixerService.fixBitcoinProductionTime(pmcProfile); } this.logProfileDetails(fullProfile); this.adjustLabsRaiderSpawnRate(); + this.adjustHideoutCraftTimes(); + this.adjustHideoutBuildTimes(); + this.removePraporTestMessage(); this.saveActiveModsToProfile(fullProfile); @@ -240,6 +248,46 @@ export class GameController } } + protected adjustHideoutCraftTimes(): void + { + const craftTimeOverrideSeconds = this.hideoutConfig.overrideCraftTimeSeconds; + if (craftTimeOverrideSeconds === -1) + { + return; + } + + for (const craft of this.databaseServer.getTables().hideout.production) + { + // Only adjust crafts ABOVE the override + if (craft.productionTime > craftTimeOverrideSeconds) + { + craft.productionTime = craftTimeOverrideSeconds; + } + } + } + + protected adjustHideoutBuildTimes(): void + { + const craftTimeOverrideSeconds = this.hideoutConfig.overrideBuildTimeSeconds; + if (craftTimeOverrideSeconds === -1) + { + return; + } + + for (const area of this.databaseServer.getTables().hideout.areas) + { + for (const stageKey of Object.keys(area.stages)) + { + const stage = area.stages[stageKey]; + // Only adjust crafts ABOVE the override + if (stage.constructionTime > craftTimeOverrideSeconds) + { + stage.constructionTime = craftTimeOverrideSeconds; + } + } + } + } + protected adjustLocationBotValues(): void { const mapsDb = this.databaseServer.getTables().locations; @@ -460,6 +508,7 @@ export class GameController */ public getKeepAlive(sessionId: string): IGameKeepAliveResponse { + this.profileActivityService.setActivityTimestamp(sessionId); return { msg: "OK", utc_time: new Date().getTime() / 1000 }; } diff --git a/project/src/controllers/HideoutController.ts b/project/src/controllers/HideoutController.ts index 64a42525..d6d27841 100644 --- a/project/src/controllers/HideoutController.ts +++ b/project/src/controllers/HideoutController.ts @@ -48,6 +48,7 @@ import { SaveServer } from "@spt-aki/servers/SaveServer"; import { FenceService } from "@spt-aki/services/FenceService"; import { LocalisationService } from "@spt-aki/services/LocalisationService"; import { PlayerService } from "@spt-aki/services/PlayerService"; +import { ProfileActivityService } from "@spt-aki/services/ProfileActivityService"; import { HashUtil } from "@spt-aki/utils/HashUtil"; import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil"; import { JsonUtil } from "@spt-aki/utils/JsonUtil"; @@ -79,6 +80,7 @@ export class HideoutController @inject("HideoutHelper") protected hideoutHelper: HideoutHelper, @inject("ScavCaseRewardGenerator") protected scavCaseRewardGenerator: ScavCaseRewardGenerator, @inject("LocalisationService") protected localisationService: LocalisationService, + @inject("ProfileActivityService") protected profileActivityService: ProfileActivityService, @inject("ConfigServer") protected configServer: ConfigServer, @inject("JsonUtil") protected jsonUtil: JsonUtil, @inject("FenceService") protected fenceService: FenceService, @@ -1323,7 +1325,13 @@ export class HideoutController { for (const sessionID in this.saveServer.getProfiles()) { - if ("Hideout" in this.saveServer.getProfile(sessionID).characters.pmc) + if ( + "Hideout" in this.saveServer.getProfile(sessionID).characters.pmc + && this.profileActivityService.activeWithinLastMinutes( + sessionID, + this.hideoutConfig.updateProfileHideoutWhenActiveWithinMinutes, + ) + ) { this.hideoutHelper.updatePlayerHideout(sessionID); } diff --git a/project/src/controllers/InsuranceController.ts b/project/src/controllers/InsuranceController.ts index 6e903a5c..b07b7292 100644 --- a/project/src/controllers/InsuranceController.ts +++ b/project/src/controllers/InsuranceController.ts @@ -196,7 +196,7 @@ export class InsuranceController !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. if (hasRegularItems) { this.processRegularItems(insured, toDelete, parentAttachmentsMap); diff --git a/project/src/controllers/LauncherController.ts b/project/src/controllers/LauncherController.ts index e3a1b441..0e280622 100644 --- a/project/src/controllers/LauncherController.ts +++ b/project/src/controllers/LauncherController.ts @@ -172,8 +172,18 @@ export class LauncherController return sessionID; } + /** + * Handle launcher requesting profile be wiped + * @param info IRegisterData + * @returns Session id + */ public wipe(info: IRegisterData): string { + if (!this.coreConfig.allowProfileWipe) + { + return; + } + const sessionID = this.login(info); if (sessionID) diff --git a/project/src/di/Container.ts b/project/src/di/Container.ts index 30ab1fb1..2fdfde9d 100644 --- a/project/src/di/Container.ts +++ b/project/src/di/Container.ts @@ -213,6 +213,7 @@ import { OpenZoneService } from "@spt-aki/services/OpenZoneService"; import { PaymentService } from "@spt-aki/services/PaymentService"; import { PlayerService } from "@spt-aki/services/PlayerService"; import { PmcChatResponseService } from "@spt-aki/services/PmcChatResponseService"; +import { ProfileActivityService } from "@spt-aki/services/ProfileActivityService"; import { ProfileFixerService } from "@spt-aki/services/ProfileFixerService"; import { ProfileSnapshotService } from "@spt-aki/services/ProfileSnapshotService"; import { RagfairCategoriesService } from "@spt-aki/services/RagfairCategoriesService"; @@ -596,7 +597,7 @@ export class Container lifecycle: Lifecycle.Singleton, }); // SptCommands - depContainer.register("GiveSptCommand", GiveSptCommand); + depContainer.register("GiveSptCommand", GiveSptCommand, { lifecycle: Lifecycle.Singleton }); } private static registerLoaders(depContainer: DependencyContainer): void @@ -747,6 +748,10 @@ export class Container depContainer.register("GiftService", GiftService); depContainer.register("MailSendService", MailSendService); depContainer.register("RaidTimeAdjustmentService", RaidTimeAdjustmentService); + + depContainer.register("ProfileActivityService", ProfileActivityService, { + lifecycle: Lifecycle.Singleton, + }); } private static registerServers(depContainer: DependencyContainer): void diff --git a/project/src/generators/BotGenerator.ts b/project/src/generators/BotGenerator.ts index 0a9c5f93..dc572a86 100644 --- a/project/src/generators/BotGenerator.ts +++ b/project/src/generators/BotGenerator.ts @@ -258,13 +258,15 @@ export class BotGenerator * @param botJsonTemplate x.json from database * @param botGenerationDetails * @param botRole role of bot e.g. assault + * @param sessionId profile session id * @returns Nickname for bot */ + // TODO: Remove sessionId parameter from this function in v3.9.0 protected generateBotNickname( botJsonTemplate: IBotType, botGenerationDetails: BotGenerationDetails, botRole: string, - sessionId: string, + sessionId?: string, // @deprecated as of v3.8.1 ): string { const isPlayerScav = botGenerationDetails.isPlayerScav; @@ -273,9 +275,9 @@ export class BotGenerator this.randomUtil.getArrayValue(botJsonTemplate.lastName) || "" }`; name = name.trim(); - const playerProfile = this.profileHelper.getPmcProfile(sessionId); - // Simulate bot looking like a Player scav with the pmc name in brackets + // Simulate bot looking like a player scav with the PMC name in brackets. + // E.g. "ScavName (PMCName)" if (botRole === "assault" && this.randomUtil.getChance100(this.botConfig.chanceAssaultScavHasPlayerScavName)) { if (isPlayerScav) @@ -300,7 +302,7 @@ export class BotGenerator if (botGenerationDetails.isPmc && botGenerationDetails.allPmcsHaveSameNameAsPlayer) { const prefix = this.localisationService.getRandomTextThatMatchesPartialKey("pmc-name_prefix_"); - name = `${prefix} ${botGenerationDetails.playerName}`; + name = `${prefix} ${name}`; } return name; diff --git a/project/src/generators/BotLootGenerator.ts b/project/src/generators/BotLootGenerator.ts index e1c88ad9..08ae3c6d 100644 --- a/project/src/generators/BotLootGenerator.ts +++ b/project/src/generators/BotLootGenerator.ts @@ -98,6 +98,10 @@ export class BotLootGenerator ); const healingItemCount = Number(this.weightedRandomHelper.getWeightedValue(itemCounts.healing.weights)); const drugItemCount = Number(this.weightedRandomHelper.getWeightedValue(itemCounts.drugs.weights)); + + const foodItemCount = Number(this.weightedRandomHelper.getWeightedValue(itemCounts.food.weights)); + const drinkItemCount = Number(this.weightedRandomHelper.getWeightedValue(itemCounts.drink.weights)); + const stimItemCount = Number(this.weightedRandomHelper.getWeightedValue(itemCounts.stims.weights)); const grenadeCount = Number(this.weightedRandomHelper.getWeightedValue(itemCounts.grenades.weights)); @@ -145,6 +149,30 @@ export class BotLootGenerator isPmc, ); + // Food + this.addLootFromPool( + this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.FOOD_ITEMS, botJsonTemplate), + containersBotHasAvailable, + foodItemCount, + botInventory, + botRole, + null, + 0, + isPmc, + ); + + // Drink + this.addLootFromPool( + this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.DRINK_ITEMS, botJsonTemplate), + containersBotHasAvailable, + drinkItemCount, + botInventory, + botRole, + null, + 0, + isPmc, + ); + // Stims this.addLootFromPool( this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.STIM_ITEMS, botJsonTemplate), @@ -282,19 +310,6 @@ export class BotLootGenerator true, ); - // eTG regen stim - this.addLootFromPool( - // eslint-disable-next-line @typescript-eslint/naming-convention - { "5c0e534186f7747fa1419867": 1 }, - [EquipmentSlots.SECURED_CONTAINER], - 2, - botInventory, - botRole, - null, - 0, - true, - ); - // AFAK this.addLootFromPool( // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/project/src/generators/FenceBaseAssortGenerator.ts b/project/src/generators/FenceBaseAssortGenerator.ts index 1ad5fb76..be6ac7a2 100644 --- a/project/src/generators/FenceBaseAssortGenerator.ts +++ b/project/src/generators/FenceBaseAssortGenerator.ts @@ -74,7 +74,7 @@ export class FenceBaseAssortGenerator } } - // Only allow rigs with no slots (carrier rigs) + // Only allow rigs with no slots (carrier rigs) if (this.itemHelper.isOfBaseclass(rootItemDb._id, BaseClasses.VEST) && rootItemDb._props.Slots.length > 0) { continue; @@ -95,6 +95,15 @@ export class FenceBaseAssortGenerator upd: { StackObjectsCount: 9999999 }, }]; + // Ensure ammo is not above penetration limit value + if (this.itemHelper.isOfBaseclasses(rootItemDb._id, [BaseClasses.AMMO_BOX, BaseClasses.AMMO])) + { + if (this.isAmmoAbovePenetrationLimit(rootItemDb)) + { + continue; + } + } + if (this.itemHelper.isOfBaseclass(rootItemDb._id, BaseClasses.AMMO_BOX)) { this.itemHelper.addCartridgesToAmmoBox(itemWithChildrenToAdd, rootItemDb); @@ -175,6 +184,53 @@ export class FenceBaseAssortGenerator } } + /** + * Check ammo in boxes + loose ammos has a penetration value above the configured value in trader.json / ammoMaxPenLimit + * @param rootItemDb Ammo box or ammo item from items.db + * @returns True if penetration value is above limit set in config + */ + protected isAmmoAbovePenetrationLimit(rootItemDb: ITemplateItem): boolean + { + const ammoPenetrationPower = this.getAmmoPenetrationPower(rootItemDb); + if (ammoPenetrationPower === null) + { + this.logger.warning(`Ammo: ${rootItemDb._id} has no penetration value, skipping`); + return false; + } + + return ammoPenetrationPower > this.traderConfig.fence.ammoMaxPenLimit; + } + + /** + * Get the penetration power value of an ammo, works with ammo boxes and raw ammos + * @param rootItemDb Ammo box or ammo item from items.db + * @returns Penetration power of passed in item, null if it doesnt have a power + */ + protected getAmmoPenetrationPower(rootItemDb: ITemplateItem): number + { + if (this.itemHelper.isOfBaseclass(rootItemDb._id, BaseClasses.AMMO_BOX)) + { + const ammoTplInBox = rootItemDb._props.StackSlots[0]._props.filters[0].Filter[0]; + const ammoItemDb = this.itemHelper.getItem(ammoTplInBox); + if (!ammoItemDb[0]) + { + this.logger.warning(`Ammo: ${ammoTplInBox} not an item, skipping`); + return null; + } + + return ammoItemDb[1]._props.PenetrationPower; + } + + // Plain old ammo, get its pen property + if (this.itemHelper.isOfBaseclass(rootItemDb._id, BaseClasses.AMMO)) + { + return rootItemDb._props.PenetrationPower; + } + + // Not an ammobox or ammo + return null; + } + protected getItemPrice(itemTpl: string, items: Item[]): number { return this.itemHelper.isOfBaseclass(itemTpl, BaseClasses.AMMO_BOX) diff --git a/project/src/generators/LocationGenerator.ts b/project/src/generators/LocationGenerator.ts index cf523064..b185c74b 100644 --- a/project/src/generators/LocationGenerator.ts +++ b/project/src/generators/LocationGenerator.ts @@ -871,7 +871,7 @@ export class LocationGenerator // Create array with just magazine const magazineItem: Item[] = [{ _id: this.objectId.generate(), _tpl: chosenTpl }]; - if (this.randomUtil.getChance100(this.locationConfig.magazineLootHasAmmoChancePercent)) + if (this.randomUtil.getChance100(this.locationConfig.staticMagazineLootHasAmmoChancePercent)) { // Add randomised amount of cartridges this.itemHelper.fillMagazineWithRandomCartridge( diff --git a/project/src/generators/LootGenerator.ts b/project/src/generators/LootGenerator.ts index a73a0094..5d5df833 100644 --- a/project/src/generators/LootGenerator.ts +++ b/project/src/generators/LootGenerator.ts @@ -99,12 +99,15 @@ export class LootGenerator && options.itemTypeWhitelist.includes(x[1]._parent) ); - const randomisedItemCount = this.randomUtil.getInt(options.itemCount.min, options.itemCount.max); - for (let index = 0; index < randomisedItemCount; index++) + if (items.length > 0) { - if (!this.findAndAddRandomItemToLoot(items, itemTypeCounts, options, result)) + const randomisedItemCount = this.randomUtil.getInt(options.itemCount.min, options.itemCount.max); + for (let index = 0; index < randomisedItemCount; index++) { - index--; + if (!this.findAndAddRandomItemToLoot(items, itemTypeCounts, options, result)) + { + index--; + } } } @@ -122,13 +125,21 @@ export class LootGenerator this.itemHelper.isOfBaseclass(preset._encyclopedia, BaseClasses.WEAPON) ); - for (let index = 0; index < randomisedWeaponPresetCount; index++) + if (weaponDefaultPresets.length > 0) { - if ( - !this.findAndAddRandomPresetToLoot(weaponDefaultPresets, itemTypeCounts, itemBlacklistArray, result) - ) + for (let index = 0; index < randomisedWeaponPresetCount; index++) { - index--; + if ( + !this.findAndAddRandomPresetToLoot( + weaponDefaultPresets, + itemTypeCounts, + itemBlacklistArray, + result, + ) + ) + { + index--; + } } } } @@ -146,18 +157,22 @@ export class LootGenerator const levelFilteredArmorPresets = armorDefaultPresets.filter((armor) => this.armorIsDesiredProtectionLevel(armor, options) ); - for (let index = 0; index < randomisedArmorPresetCount; index++) + + if (levelFilteredArmorPresets.length > 0) { - if ( - !this.findAndAddRandomPresetToLoot( - levelFilteredArmorPresets, - itemTypeCounts, - itemBlacklistArray, - result, - ) - ) + for (let index = 0; index < randomisedArmorPresetCount; index++) { - index--; + if ( + !this.findAndAddRandomPresetToLoot( + levelFilteredArmorPresets, + itemTypeCounts, + itemBlacklistArray, + result, + ) + ) + { + index--; + } } } } @@ -307,7 +322,7 @@ export class LootGenerator const randomPreset = this.randomUtil.getArrayValue(globalDefaultPresets); if (!randomPreset?._encyclopedia) { - this.logger.debug(`Airdrop - preset with id: ${randomPreset._id} lacks encyclopedia property, skipping`); + this.logger.debug(`Airdrop - preset with id: ${randomPreset?._id} lacks encyclopedia property, skipping`); return false; } diff --git a/project/src/generators/PMCLootGenerator.ts b/project/src/generators/PMCLootGenerator.ts index ff7d4f93..f7abc809 100644 --- a/project/src/generators/PMCLootGenerator.ts +++ b/project/src/generators/PMCLootGenerator.ts @@ -192,7 +192,7 @@ export class PMCLootGenerator for (const itemToAdd of itemsToAdd) { - // If pmc has override, use that. Otherwise use flea price + // If pmc has price override, use that. Otherwise use flea price if (pmcPriceOverrides[itemToAdd._id]) { this.backpackLootPool[itemToAdd._id] = pmcPriceOverrides[itemToAdd._id]; diff --git a/project/src/helpers/BotGeneratorHelper.ts b/project/src/helpers/BotGeneratorHelper.ts index a8620512..99d729e4 100644 --- a/project/src/helpers/BotGeneratorHelper.ts +++ b/project/src/helpers/BotGeneratorHelper.ts @@ -688,19 +688,19 @@ export class BotGeneratorHelper const itemDetails = this.itemHelper.getItem(itemTpl)[1]; // if item to add is found in exclude filter, not allowed - if (excludedFilter.includes(itemDetails._parent)) + if (excludedFilter?.includes(itemDetails._parent)) { return false; } // If Filter array only contains 1 filter and its for basetype 'item', allow it - if (filter.length === 1 && filter.includes(BaseClasses.ITEM)) + if (filter?.length === 1 && filter.includes(BaseClasses.ITEM)) { return true; } // If allowed filter has something in it + filter doesnt have basetype 'item', not allowed - if (filter.length > 0 && !filter.includes(itemDetails._parent)) + if (filter?.length > 0 && !filter.includes(itemDetails._parent)) { return false; } diff --git a/project/src/helpers/Dialogue/AbstractDialogueChatBot.ts b/project/src/helpers/Dialogue/AbstractDialogueChatBot.ts new file mode 100644 index 00000000..ed387b97 --- /dev/null +++ b/project/src/helpers/Dialogue/AbstractDialogueChatBot.ts @@ -0,0 +1,75 @@ +import { IChatCommand, ICommandoCommand } from "@spt-aki/helpers/Dialogue/Commando/IChatCommand"; +import { IDialogueChatBot } from "@spt-aki/helpers/Dialogue/IDialogueChatBot"; +import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest"; +import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile"; +import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; +import { MailSendService } from "@spt-aki/services/MailSendService"; + +export abstract class AbstractDialogueChatBot implements IDialogueChatBot +{ + public constructor( + protected logger: ILogger, + protected mailSendService: MailSendService, + protected chatCommands: IChatCommand[] | ICommandoCommand[], + ) + { + } + + /** + * @deprecated As of v3.7.6. Use registerChatCommand. + */ + // TODO: v3.9.0 - Remove registerCommandoCommand method. + public registerCommandoCommand(chatCommand: IChatCommand | ICommandoCommand): void + { + this.registerChatCommand(chatCommand); + } + + public registerChatCommand(chatCommand: IChatCommand | ICommandoCommand): void + { + if (this.chatCommands.some((cc) => cc.getCommandPrefix() === chatCommand.getCommandPrefix())) + { + throw new Error( + `The command "${chatCommand.getCommandPrefix()}" attempting to be registered already exists.`, + ); + } + this.chatCommands.push(chatCommand); + } + + public abstract getChatBot(): IUserDialogInfo; + + protected abstract getUnrecognizedCommandMessage(): string; + + public handleMessage(sessionId: string, request: ISendMessageRequest): string + { + if ((request.text ?? "").length === 0) + { + this.logger.error("Command came in as empty text! Invalid data!"); + return request.dialogId; + } + + const splitCommand = request.text.split(" "); + + const commandos = this.chatCommands.filter((c) => c.getCommandPrefix() === splitCommand[0]); + if (commandos[0]?.getCommands().has(splitCommand[1])) + { + return commandos[0].handle(splitCommand[1], this.getChatBot(), sessionId, request); + } + + if (splitCommand[0].toLowerCase() === "help") + { + const helpMessage = this.chatCommands.map((c) => + `Available commands:\n\n${c.getCommandPrefix()}:\n\n${ + Array.from(c.getCommands()).map((command) => c.getCommandHelp(command)).join("\n") + }` + ).join("\n"); + this.mailSendService.sendUserMessageToPlayer(sessionId, this.getChatBot(), helpMessage); + return request.dialogId; + } + + this.mailSendService.sendUserMessageToPlayer( + sessionId, + this.getChatBot(), + this.getUnrecognizedCommandMessage(), + ); + } +} diff --git a/project/src/helpers/Dialogue/Commando/ICommandoCommand.ts b/project/src/helpers/Dialogue/Commando/IChatCommand.ts similarity index 66% rename from project/src/helpers/Dialogue/Commando/ICommandoCommand.ts rename to project/src/helpers/Dialogue/Commando/IChatCommand.ts index 03083f3b..93a63487 100644 --- a/project/src/helpers/Dialogue/Commando/ICommandoCommand.ts +++ b/project/src/helpers/Dialogue/Commando/IChatCommand.ts @@ -1,7 +1,12 @@ import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest"; import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile"; -export interface ICommandoCommand +/** + * @deprecated As of v3.7.6. Use IChatCommand. Will be removed in v3.9.0. + */ +// TODO: v3.9.0 - Remove ICommandoCommand. +export type ICommandoCommand = IChatCommand; +export interface IChatCommand { getCommandPrefix(): string; getCommandHelp(command: string): string; diff --git a/project/src/helpers/Dialogue/Commando/SptCommandoCommands.ts b/project/src/helpers/Dialogue/Commando/SptCommandoCommands.ts index 82017853..1c2a6f46 100644 --- a/project/src/helpers/Dialogue/Commando/SptCommandoCommands.ts +++ b/project/src/helpers/Dialogue/Commando/SptCommandoCommands.ts @@ -1,4 +1,4 @@ -import { ICommandoCommand } from "@spt-aki/helpers/Dialogue/Commando/ICommandoCommand"; +import { IChatCommand } from "@spt-aki/helpers/Dialogue/Commando/IChatCommand"; import { ISptCommand } from "@spt-aki/helpers/Dialogue/Commando/SptCommands/ISptCommand"; import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest"; import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile"; @@ -8,7 +8,7 @@ import { ConfigServer } from "@spt-aki/servers/ConfigServer"; import { inject, injectAll, injectable } from "tsyringe"; @injectable() -export class SptCommandoCommands implements ICommandoCommand +export class SptCommandoCommands implements IChatCommand { constructor( @inject("ConfigServer") protected configServer: ConfigServer, @@ -31,7 +31,7 @@ export class SptCommandoCommands implements ICommandoCommand { if (this.sptCommands.some((c) => c.getCommand() === command.getCommand())) { - throw new Error(`The command ${command.getCommand()} being registered for SPT Commands already exists!`); + throw new Error(`The command "${command.getCommand()}" attempting to be registered already exists.`); } this.sptCommands.push(command); } diff --git a/project/src/helpers/Dialogue/Commando/SptCommands/GiveSptCommand.ts b/project/src/helpers/Dialogue/Commando/SptCommands/GiveSptCommand.ts index 644c1835..ccab75e2 100644 --- a/project/src/helpers/Dialogue/Commando/SptCommands/GiveSptCommand.ts +++ b/project/src/helpers/Dialogue/Commando/SptCommands/GiveSptCommand.ts @@ -1,4 +1,5 @@ import { ISptCommand } from "@spt-aki/helpers/Dialogue/Commando/SptCommands/ISptCommand"; +import { SavedCommand } from "@spt-aki/helpers/Dialogue/Commando/SptCommands/SavedCommand"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { PresetHelper } from "@spt-aki/helpers/PresetHelper"; import { Item } from "@spt-aki/models/eft/common/tables/IItem"; @@ -6,14 +7,30 @@ import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequ import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile"; import { BaseClasses } from "@spt-aki/models/enums/BaseClasses"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; +import { DatabaseServer } from "@spt-aki/servers/DatabaseServer"; +import { LocaleService } from "@spt-aki/services/LocaleService"; import { MailSendService } from "@spt-aki/services/MailSendService"; import { HashUtil } from "@spt-aki/utils/HashUtil"; import { JsonUtil } from "@spt-aki/utils/JsonUtil"; +import { closestMatch, distance } from "closest-match"; import { inject, injectable } from "tsyringe"; @injectable() export class GiveSptCommand implements ISptCommand { + /** + * Regex to account for all these cases: + * spt give "item name" 5 + * spt give templateId 5 + * spt give en "item name in english" 5 + * spt give es "nombre en español" 5 + * spt give 5 <== this is the reply when the algo isn't sure about an item + */ + private static commandRegex = /^spt give (((([a-z]{2,5}) )?"(.+)"|\w+) )?([0-9]+)$/; + private static maxAllowedDistance = 1.5; + + protected savedCommand: SavedCommand; + public constructor( @inject("WinstonLogger") protected logger: ILogger, @inject("ItemHelper") protected itemHelper: ItemHelper, @@ -21,6 +38,8 @@ export class GiveSptCommand implements ISptCommand @inject("JsonUtil") protected jsonUtil: JsonUtil, @inject("PresetHelper") protected presetHelper: PresetHelper, @inject("MailSendService") protected mailSendService: MailSendService, + @inject("LocaleService") protected localeService: LocaleService, + @inject("DatabaseServer") protected databaseServer: DatabaseServer, ) { } @@ -32,49 +51,135 @@ export class GiveSptCommand implements ISptCommand public getCommandHelp(): string { - return "Usage: spt give tplId quantity"; + return "spt give\n========\nSends items to the player through the message system.\n\n\tspt give [template ID] [quantity]\n\t\tEx: spt give 544fb25a4bdc2dfb738b4567 2\n\n\tspt give [\"item name\"] [quantity]\n\t\tEx: spt give \"pack of sugar\" 10\n\n\tspt give [locale] [\"item name\"] [quantity]\n\t\tEx: spt give fr \"figurine de chat\" 3"; } public performAction(commandHandler: IUserDialogInfo, sessionId: string, request: ISendMessageRequest): string { - const giveCommand = request.text.split(" "); - if (giveCommand[1] !== "give") - { - this.logger.error("Invalid action received for give command!"); - return request.dialogId; - } - - if (!giveCommand[2]) + if (!GiveSptCommand.commandRegex.test(request.text)) { this.mailSendService.sendUserMessageToPlayer( sessionId, commandHandler, - "Invalid use of give command! Template ID is missing. Use \"Help\" for more info", + "Invalid use of give command. Use \"help\" for more information.", ); return request.dialogId; } - const tplId = giveCommand[2]; - if (!giveCommand[3]) - { - this.mailSendService.sendUserMessageToPlayer( - sessionId, - commandHandler, - "Invalid use of give command! Quantity is missing. Use \"Help\" for more info", - ); - return request.dialogId; - } - const quantity = giveCommand[3]; + const result = GiveSptCommand.commandRegex.exec(request.text); - if (Number.isNaN(+quantity)) + let item: string; + let quantity: number; + let isItemName: boolean; + let locale: string; + + // This is a reply to a give request previously made pending a reply + if (result[1] === undefined) { - this.mailSendService.sendUserMessageToPlayer( - sessionId, - commandHandler, - "Invalid use of give command! Quantity is not a valid integer. Use \"Help\" for more info", - ); - return request.dialogId; + if (this.savedCommand === undefined) + { + this.mailSendService.sendUserMessageToPlayer( + sessionId, + commandHandler, + "Invalid use of give command. Use \"help\" for more information.", + ); + return request.dialogId; + } + if (+result[6] > this.savedCommand.potentialItemNames.length) + { + this.mailSendService.sendUserMessageToPlayer( + sessionId, + commandHandler, + "Invalid selection. Outside of bounds! Use \"help\" for more information.", + ); + return request.dialogId; + } + item = this.savedCommand.potentialItemNames[+result[6] - 1]; + quantity = this.savedCommand.quantity; + locale = this.savedCommand.locale; + isItemName = true; + this.savedCommand = undefined; } + else + { + // A new give request was entered, we need to ignore the old saved command + this.savedCommand = undefined; + isItemName = result[5] !== undefined; + item = result[5] ? result[5] : result[2]; + quantity = +result[6]; + + if (isItemName) + { + locale = result[4] ? result[4] : this.localeService.getDesiredGameLocale(); + if (!this.localeService.getServerSupportedLocales().includes(locale)) + { + this.mailSendService.sendUserMessageToPlayer( + sessionId, + commandHandler, + `Unknown locale "${locale}". Use \"help\" for more information.`, + ); + return request.dialogId; + } + + const localizedGlobal = this.databaseServer.getTables().locales.global[locale]; + + const closestItemsMatchedByName = closestMatch( + item.toLowerCase(), + this.itemHelper.getItems().filter((i) => i._type !== "Node").map((i) => + localizedGlobal[`${i?._id} Name`]?.toLowerCase() + ).filter((i) => i !== undefined), + true, + ) as string[]; + + if (closestItemsMatchedByName === undefined || closestItemsMatchedByName.length === 0) + { + this.mailSendService.sendUserMessageToPlayer( + sessionId, + commandHandler, + "That item could not be found. Please refine your request and try again.", + ); + return request.dialogId; + } + + if (closestItemsMatchedByName.length > 1) + { + let i = 1; + const slicedItems = closestItemsMatchedByName.slice(0, 10); + // max 10 item names and map them + const itemList = slicedItems.map((itemName) => `${i++}. ${itemName}`).join("\n"); + this.savedCommand = new SavedCommand(quantity, slicedItems, locale); + this.mailSendService.sendUserMessageToPlayer( + sessionId, + commandHandler, + `Could not find exact match. Closest matches are:\n\n${itemList}\n\nUse "spt give [number]" to select one.`, + ); + return request.dialogId; + } + + const dist = distance(item, closestItemsMatchedByName[0]); + if (dist > GiveSptCommand.maxAllowedDistance) + { + this.mailSendService.sendUserMessageToPlayer( + sessionId, + commandHandler, + `Found a possible match for "${item}" but uncertain. Match: "${ + closestItemsMatchedByName[0] + }". Please refine your request and try again.`, + ); + return request.dialogId; + } + // Only one available so we get that entry and use it + item = closestItemsMatchedByName[0]; + } + } + + // If item is an item name, we need to search using that item name and the locale which one we want otherwise + // item is just the tplId. + const tplId = isItemName + ? this.itemHelper.getItems().find((i) => + this.databaseServer.getTables().locales.global[locale][`${i?._id} Name`]?.toLowerCase() === item + )._id + : item; const checkedItem = this.itemHelper.getItem(tplId); if (!checkedItem[0]) @@ -82,21 +187,25 @@ export class GiveSptCommand implements ISptCommand this.mailSendService.sendUserMessageToPlayer( sessionId, commandHandler, - "Invalid template ID requested for give command. The item doesn't exist in the DB.", + "That item could not be found. Please refine your request and try again.", ); return request.dialogId; } const itemsToSend: Item[] = []; - const preset = this.presetHelper.getDefaultPreset(checkedItem[1]._id); - if (preset) + if (this.itemHelper.isOfBaseclass(checkedItem[1]._id, BaseClasses.WEAPON)) { - for (let i = 0; i < +quantity; i++) + const preset = this.presetHelper.getDefaultPreset(checkedItem[1]._id); + if (!preset) { - // Make sure IDs are unique before adding to array - prevent collisions - const presetToSend = this.itemHelper.replaceIDs(preset._items); - itemsToSend.push(...presetToSend); + this.mailSendService.sendUserMessageToPlayer( + sessionId, + commandHandler, + "That weapon template ID could not be found. Please refine your request and try again.", + ); + return request.dialogId; } + itemsToSend.push(...this.jsonUtil.clone(preset._items)); } else if (this.itemHelper.isOfBaseclass(checkedItem[1]._id, BaseClasses.AMMO_BOX)) { @@ -115,13 +224,25 @@ export class GiveSptCommand implements ISptCommand _tpl: checkedItem[1]._id, upd: { StackObjectsCount: +quantity, SpawnedInSession: true }, }; - itemsToSend.push(...this.itemHelper.splitStack(item)); + try + { + itemsToSend.push(...this.itemHelper.splitStack(item)); + } + catch + { + this.mailSendService.sendUserMessageToPlayer( + sessionId, + commandHandler, + "Too many items requested. Please lower the amount and try again.", + ); + return request.dialogId; + } } // Flag the items as FiR this.itemHelper.setFoundInRaid(itemsToSend); - this.mailSendService.sendSystemMessageToPlayer(sessionId, "Give command!", itemsToSend); + this.mailSendService.sendSystemMessageToPlayer(sessionId, "SPT GIVE", itemsToSend); return request.dialogId; } } diff --git a/project/src/helpers/Dialogue/Commando/SptCommands/SavedCommand.ts b/project/src/helpers/Dialogue/Commando/SptCommands/SavedCommand.ts new file mode 100644 index 00000000..c51412a4 --- /dev/null +++ b/project/src/helpers/Dialogue/Commando/SptCommands/SavedCommand.ts @@ -0,0 +1,6 @@ +export class SavedCommand +{ + public constructor(public quantity: number, public potentialItemNames: string[], public locale: string) + { + } +} diff --git a/project/src/helpers/Dialogue/CommandoDialogueChatBot.ts b/project/src/helpers/Dialogue/CommandoDialogueChatBot.ts index c000d186..db8018dc 100644 --- a/project/src/helpers/Dialogue/CommandoDialogueChatBot.ts +++ b/project/src/helpers/Dialogue/CommandoDialogueChatBot.ts @@ -1,33 +1,22 @@ import { inject, injectAll, injectable } from "tsyringe"; -import { ICommandoCommand } from "@spt-aki/helpers/Dialogue/Commando/ICommandoCommand"; -import { IDialogueChatBot } from "@spt-aki/helpers/Dialogue/IDialogueChatBot"; -import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest"; +import { AbstractDialogueChatBot } from "@spt-aki/helpers/Dialogue/AbstractDialogueChatBot"; +import { IChatCommand } from "@spt-aki/helpers/Dialogue/Commando/IChatCommand"; import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile"; import { MemberCategory } from "@spt-aki/models/enums/MemberCategory"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { MailSendService } from "@spt-aki/services/MailSendService"; @injectable() -export class CommandoDialogueChatBot implements IDialogueChatBot +export class CommandoDialogueChatBot extends AbstractDialogueChatBot { public constructor( - @inject("WinstonLogger") protected logger: ILogger, - @inject("MailSendService") protected mailSendService: MailSendService, - @injectAll("CommandoCommand") protected commandoCommands: ICommandoCommand[], + @inject("WinstonLogger") logger: ILogger, + @inject("MailSendService") mailSendService: MailSendService, + @injectAll("CommandoCommand") chatCommands: IChatCommand[], ) { - } - - public registerCommandoCommand(commandoCommand: ICommandoCommand): void - { - if (this.commandoCommands.some((cc) => cc.getCommandPrefix() === commandoCommand.getCommandPrefix())) - { - throw new Error( - `The commando command ${commandoCommand.getCommandPrefix()} being registered already exists!`, - ); - } - this.commandoCommands.push(commandoCommand); + super(logger, mailSendService, chatCommands); } public getChatBot(): IUserDialogInfo @@ -39,37 +28,8 @@ export class CommandoDialogueChatBot implements IDialogueChatBot }; } - public handleMessage(sessionId: string, request: ISendMessageRequest): string + protected getUnrecognizedCommandMessage(): string { - if ((request.text ?? "").length === 0) - { - this.logger.error("Commando command came in as empty text! Invalid data!"); - return request.dialogId; - } - - const splitCommand = request.text.split(" "); - - const commandos = this.commandoCommands.filter((c) => c.getCommandPrefix() === splitCommand[0]); - if (commandos[0]?.getCommands().has(splitCommand[1])) - { - return commandos[0].handle(splitCommand[1], this.getChatBot(), sessionId, request); - } - - if (splitCommand[0].toLowerCase() === "help") - { - const helpMessage = this.commandoCommands.map((c) => - `Help for ${c.getCommandPrefix()}:\n${ - Array.from(c.getCommands()).map((command) => c.getCommandHelp(command)).join("\n") - }` - ).join("\n"); - this.mailSendService.sendUserMessageToPlayer(sessionId, this.getChatBot(), helpMessage); - return request.dialogId; - } - - this.mailSendService.sendUserMessageToPlayer( - sessionId, - this.getChatBot(), - `Im sorry soldier, I dont recognize the command you are trying to use! Type "help" to see available commands.`, - ); + return `I'm sorry soldier, I don't recognize the command you are trying to use! Type "help" to see available commands.`; } } diff --git a/project/src/helpers/HideoutHelper.ts b/project/src/helpers/HideoutHelper.ts index 7793db80..bbd98544 100644 --- a/project/src/helpers/HideoutHelper.ts +++ b/project/src/helpers/HideoutHelper.ts @@ -595,7 +595,7 @@ export class HideoutHelper * @param applyHideoutManagementBonus should the hideout mgmt bonus be appled to the calculation * @returns Items craft time with bonuses subtracted */ - protected getAdjustedCraftTimeWithSkills( + public getAdjustedCraftTimeWithSkills( pmcData: IPmcData, recipeId: string, applyHideoutManagementBonus = false, @@ -613,13 +613,19 @@ export class HideoutHelper return undefined; } - // Seconds to deduct from crafts total time - let timeReductionSeconds = this.getSkillProductionTimeReduction( - pmcData, - recipe.productionTime, - SkillTypes.CRAFTING, - globalSkillsDb.Crafting.ProductionTimeReductionPerLevel, - ); + let timeReductionSeconds = 0; + + // Bitcoin farm is excluded from crafting skill cooldown reduction + if (recipeId !== HideoutHelper.bitcoinFarm) + { + // Seconds to deduct from crafts total time + timeReductionSeconds += this.getSkillProductionTimeReduction( + pmcData, + recipe.productionTime, + SkillTypes.CRAFTING, + globalSkillsDb.Crafting.ProductionTimeReductionPerLevel, + ); + } // Some crafts take into account hideout management, e.g. fuel, water/air filters if (applyHideoutManagementBonus) diff --git a/project/src/helpers/HttpServerHelper.ts b/project/src/helpers/HttpServerHelper.ts index d647c047..e0f6cadc 100644 --- a/project/src/helpers/HttpServerHelper.ts +++ b/project/src/helpers/HttpServerHelper.ts @@ -32,12 +32,12 @@ export class HttpServerHelper } /** - * Combine ip and port into url + * Combine ip and port into address * @returns url */ public buildUrl(): string { - return `${this.httpConfig.ip}:${this.httpConfig.port}`; + return `${this.httpConfig.backendIp}:${this.httpConfig.backendPort}`; } /** diff --git a/project/src/helpers/ItemHelper.ts b/project/src/helpers/ItemHelper.ts index a5d16f6c..e39f69a6 100644 --- a/project/src/helpers/ItemHelper.ts +++ b/project/src/helpers/ItemHelper.ts @@ -429,19 +429,12 @@ export class ItemHelper if (repairable.Durability > repairable.MaxDurability) { this.logger.warning( - `Max durability: ${repairable.MaxDurability} for item id: ${item._id} was below Durability: ${repairable.Durability}, adjusting values to match`, + `Max durability: ${repairable.MaxDurability} for item id: ${item._id} was below durability: ${repairable.Durability}, adjusting values to match`, ); repairable.MaxDurability = repairable.Durability; } - // Armor - if (itemDetails._props.armorClass) - { - return repairable.MaxDurability / itemDetails._props.MaxDurability; - } - - // Weapon - // Get max dura from props, if it isnt there use repairable max dura value + // Attempt to get the max durability from _props. If not available, use Repairable max durability value instead. const maxDurability = (itemDetails._props.MaxDurability) ? itemDetails._props.MaxDurability : repairable.MaxDurability; diff --git a/project/src/helpers/PresetHelper.ts b/project/src/helpers/PresetHelper.ts index b7fc1eb4..d7149fc1 100644 --- a/project/src/helpers/PresetHelper.ts +++ b/project/src/helpers/PresetHelper.ts @@ -85,6 +85,17 @@ export class PresetHelper return id in this.databaseServer.getTables().globals.ItemPresets; } + /** + * Checks to see if the preset is of the given base class. + * @param id The id of the preset + * @param baseClass The BaseClasses enum to check against + * @returns True if the preset is of the given base class, false otherwise + */ + public isPresetBaseClass(id: string, baseClass: BaseClasses): boolean + { + return this.isPreset(id) && this.itemHelper.isOfBaseclass(this.getPreset(id)._encyclopedia, baseClass); + } + public hasPreset(templateId: string): boolean { return templateId in this.lookup; diff --git a/project/src/helpers/QuestHelper.ts b/project/src/helpers/QuestHelper.ts index aaeb5efe..0a09a68f 100644 --- a/project/src/helpers/QuestHelper.ts +++ b/project/src/helpers/QuestHelper.ts @@ -731,16 +731,20 @@ export class QuestHelper repeatableType.activeQuests ).find((activeQuest) => activeQuest._id === failRequest.qid); - if (matchingRepeatableQuest || quest) + // Quest found and no repeatable found + if (quest && !matchingRepeatableQuest) { - this.mailSendService.sendLocalisedNpcMessageToPlayer( - sessionID, - this.traderHelper.getTraderById(quest?.traderId ?? matchingRepeatableQuest?.traderId), // Can be null when repeatable quest has been moved to inactiveQuests - MessageType.QUEST_FAIL, - quest.failMessageText, - questRewards, - this.timeUtil.getHoursAsSeconds(this.questConfig.redeemTime), - ); + if (quest.failMessageText.trim().length > 0) + { + this.mailSendService.sendLocalisedNpcMessageToPlayer( + sessionID, + this.traderHelper.getTraderById(quest?.traderId ?? matchingRepeatableQuest?.traderId), // Can be null when repeatable quest has been moved to inactiveQuests + MessageType.QUEST_FAIL, + quest.failMessageText, + questRewards, + this.timeUtil.getHoursAsSeconds(this.questConfig.redeemTime), + ); + } } output.profileChanges[sessionID].quests.push(...this.failedUnlocked(failRequest.qid, sessionID)); diff --git a/project/src/helpers/TradeHelper.ts b/project/src/helpers/TradeHelper.ts index 59d9bd1c..358860e0 100644 --- a/project/src/helpers/TradeHelper.ts +++ b/project/src/helpers/TradeHelper.ts @@ -158,6 +158,14 @@ export class TradeHelper ); } + // Check if trader has enough stock + if (itemPurchased.upd.StackObjectsCount < buyCount) + { + throw new Error( + `Unable to purchase ${buyCount} items, this would exceed the remaining stock left ${itemPurchased.upd.StackObjectsCount} from the traders assort: ${buyRequestData.tid} this refresh`, + ); + } + // Decrement trader item count itemPurchased.upd.StackObjectsCount -= buyCount; diff --git a/project/src/models/eft/common/tables/IBotType.ts b/project/src/models/eft/common/tables/IBotType.ts index 0ca331da..1f168525 100644 --- a/project/src/models/eft/common/tables/IBotType.ts +++ b/project/src/models/eft/common/tables/IBotType.ts @@ -130,6 +130,8 @@ export interface GenerationWeightingItems grenades: GenerationData; healing: GenerationData; drugs: GenerationData; + food: GenerationData; + drink: GenerationData; stims: GenerationData; backpackLoot: GenerationData; pocketLoot: GenerationData; diff --git a/project/src/models/eft/common/tables/IQuest.ts b/project/src/models/eft/common/tables/IQuest.ts index 65fabb1b..f544cb9f 100644 --- a/project/src/models/eft/common/tables/IQuest.ts +++ b/project/src/models/eft/common/tables/IQuest.ts @@ -169,6 +169,7 @@ export interface IQuestReward target?: string; items?: Item[]; loyaltyLevel?: number; + /** Hideout area id */ traderId?: string; unknown?: boolean; findInRaid?: boolean; diff --git a/project/src/models/spt/bots/IBotLootCache.ts b/project/src/models/spt/bots/IBotLootCache.ts index c2683770..3dc5e192 100644 --- a/project/src/models/spt/bots/IBotLootCache.ts +++ b/project/src/models/spt/bots/IBotLootCache.ts @@ -1,5 +1,3 @@ -import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem"; - export interface IBotLootCache { backpackLoot: Record; @@ -11,6 +9,8 @@ export interface IBotLootCache specialItems: Record; healingItems: Record; drugItems: Record; + foodItems: Record; + drinkItems: Record; stimItems: Record; grenadeItems: Record; } @@ -27,4 +27,6 @@ export enum LootCacheType DRUG_ITEMS = "DrugItems", STIM_ITEMS = "StimItems", GRENADE_ITEMS = "GrenadeItems", + FOOD_ITEMS = "FoodItems", + DRINK_ITEMS = "DrinkItems", } diff --git a/project/src/models/spt/config/IBotConfig.ts b/project/src/models/spt/config/IBotConfig.ts index fd71175c..1ea1acc2 100644 --- a/project/src/models/spt/config/IBotConfig.ts +++ b/project/src/models/spt/config/IBotConfig.ts @@ -186,12 +186,9 @@ export interface IAdjustmentDetails edit: Record>; } -export interface IArmorPlateWeights +export interface IArmorPlateWeights extends Record { levelRange: MinMax; - frontPlateWeights: Record; - backPlateWeights: Record; - sidePlateWeights: Record; } export interface IRandomisedResourceDetails diff --git a/project/src/models/spt/config/ICoreConfig.ts b/project/src/models/spt/config/ICoreConfig.ts index de65c646..21f61368 100644 --- a/project/src/models/spt/config/ICoreConfig.ts +++ b/project/src/models/spt/config/ICoreConfig.ts @@ -9,6 +9,7 @@ export interface ICoreConfig extends IBaseConfig serverName: string; profileSaveIntervalSeconds: number; sptFriendNickname: string; + allowProfileWipe: boolean; bsgLogging: IBsgLogging; release: IRelease; fixes: IGameFixes; diff --git a/project/src/models/spt/config/IHideoutConfig.ts b/project/src/models/spt/config/IHideoutConfig.ts index 5d17a15b..0fc1caca 100644 --- a/project/src/models/spt/config/IHideoutConfig.ts +++ b/project/src/models/spt/config/IHideoutConfig.ts @@ -9,4 +9,8 @@ export interface IHideoutConfig extends IBaseConfig runIntervalValues: IRunIntervalValues; hoursForSkillCrafting: number; expCraftAmount: number; + overrideCraftTimeSeconds: number; + overrideBuildTimeSeconds: number; + /** Only process a profiles hideout crafts when it has been active in the last x minutes */ + updateProfileHideoutWhenActiveWithinMinutes: number; } diff --git a/project/src/models/spt/config/IHttpConfig.ts b/project/src/models/spt/config/IHttpConfig.ts index e1ddb9d5..f1130624 100644 --- a/project/src/models/spt/config/IHttpConfig.ts +++ b/project/src/models/spt/config/IHttpConfig.ts @@ -2,10 +2,14 @@ import { IBaseConfig } from "@spt-aki/models/spt/config/IBaseConfig"; export interface IHttpConfig extends IBaseConfig { - webSocketPingDelayMs: number; kind: "aki-http"; + /** Address used by webserver */ ip: string; port: number; + /** Address used by game client to connect to */ + backendIp: string; + backendPort: string; + webSocketPingDelayMs: number; logRequests: boolean; /** e.g. "Aki_Data/Server/images/traders/579dc571d53a0658a154fbec.png": "Aki_Data/Server/images/traders/NewTraderImage.png" */ serverImagePathOverride: Record; diff --git a/project/src/models/spt/config/IInRaidConfig.ts b/project/src/models/spt/config/IInRaidConfig.ts index 0f836fcb..f3dd433a 100644 --- a/project/src/models/spt/config/IInRaidConfig.ts +++ b/project/src/models/spt/config/IInRaidConfig.ts @@ -42,5 +42,4 @@ export interface Save { /** Should loot gained from raid be saved */ loot: boolean; - durability: boolean; } diff --git a/project/src/models/spt/config/ILocationConfig.ts b/project/src/models/spt/config/ILocationConfig.ts index fee9de50..e282ba0f 100644 --- a/project/src/models/spt/config/ILocationConfig.ts +++ b/project/src/models/spt/config/ILocationConfig.ts @@ -36,8 +36,10 @@ export interface ILocationConfig extends IBaseConfig /** How full must a random static magazine be %*/ minFillStaticMagazinePercent: number; allowDuplicateItemsInStaticContainers: boolean; - /** Chance loose/static magazines have ammo in them */ + /** Chance loose magazines have ammo in them TODO - rename to dynamicMagazineLootHasAmmoChancePercent */ magazineLootHasAmmoChancePercent: number; + /** Chance static magazines have ammo in them */ + staticMagazineLootHasAmmoChancePercent: number; /** Key: map, value: loose loot ids to ignore */ looseLootBlacklist: Record; /** Key: map, value: settings to control how long scav raids are*/ diff --git a/project/src/models/spt/config/ITraderConfig.ts b/project/src/models/spt/config/ITraderConfig.ts index 1e972fbe..a4e98cb2 100644 --- a/project/src/models/spt/config/ITraderConfig.ts +++ b/project/src/models/spt/config/ITraderConfig.ts @@ -46,6 +46,8 @@ export interface FenceConfig presetSlotsToRemoveChancePercent: Record; /** Block seasonal items from appearing when season is inactive */ blacklistSeasonalItems: boolean; + /** Max pen value allowed to be listed on flea - affects ammo + ammo boxes */ + ammoMaxPenLimit: number; blacklist: string[]; coopExtractGift: CoopExtractReward; btrDeliveryExpireHours: number; diff --git a/project/src/models/spt/fence/ICreateFenceAssortsResult.ts b/project/src/models/spt/fence/ICreateFenceAssortsResult.ts new file mode 100644 index 00000000..b81fd1cb --- /dev/null +++ b/project/src/models/spt/fence/ICreateFenceAssortsResult.ts @@ -0,0 +1,9 @@ +import { Item } from "@spt-aki/models/eft/common/tables/IItem"; +import { IBarterScheme } from "@spt-aki/models/eft/common/tables/ITrader"; + +export interface ICreateFenceAssortsResult +{ + sptItems: Item[][]; + barter_scheme: Record; + loyal_level_items: Record; +} diff --git a/project/src/routers/dynamic/BotDynamicRouter.ts b/project/src/routers/dynamic/BotDynamicRouter.ts index df65c79b..323912c4 100644 --- a/project/src/routers/dynamic/BotDynamicRouter.ts +++ b/project/src/routers/dynamic/BotDynamicRouter.ts @@ -23,6 +23,13 @@ export class BotDynamicRouter extends DynamicRouter return this.botCallbacks.getBotDifficulty(url, info, sessionID); }, ), + new RouteAction( + "/singleplayer/settings/bot/difficulties/", + (url: string, info: any, sessionID: string, output: string): any => + { + return this.botCallbacks.getAllBotDifficulties(url, info, sessionID); + }, + ), new RouteAction( "/singleplayer/settings/bot/maxCap", (url: string, info: any, sessionID: string, output: string): any => diff --git a/project/src/routers/static/InraidStaticRouter.ts b/project/src/routers/static/InraidStaticRouter.ts index f2835755..a0f77653 100644 --- a/project/src/routers/static/InraidStaticRouter.ts +++ b/project/src/routers/static/InraidStaticRouter.ts @@ -20,13 +20,6 @@ export class InraidStaticRouter extends StaticRouter return this.inraidCallbacks.getRaidEndState(); }, ), - new RouteAction( - "/singleplayer/settings/weapon/durability", - (url: string, info: any, sessionID: string, output: string): any => - { - return this.inraidCallbacks.getWeaponDurability(); - }, - ), new RouteAction( "/singleplayer/settings/raid/menu", (url: string, info: any, sessionID: string, output: string): any => diff --git a/project/src/servers/HttpServer.ts b/project/src/servers/HttpServer.ts index 421c7ae4..952ed451 100644 --- a/project/src/servers/HttpServer.ts +++ b/project/src/servers/HttpServer.ts @@ -45,9 +45,6 @@ export class HttpServer this.handleRequest(req, res); }); - this.databaseServer.getTables().server.ip = this.httpConfig.ip; - this.databaseServer.getTables().server.port = this.httpConfig.port; - /* Config server to listen on a port */ httpServer.listen(this.httpConfig.port, this.httpConfig.ip, () => { @@ -82,17 +79,20 @@ export class HttpServer if (this.httpConfig.logRequests) { // TODO: Extend to include 192.168 / 10.10 ranges or check subnet - const isLocalRequest = req.socket.remoteAddress.startsWith("127.0.0"); - if (isLocalRequest) + const isLocalRequest = req.socket.remoteAddress?.startsWith("127.0.0"); + if (typeof isLocalRequest !== "undefined") { - this.logger.info(this.localisationService.getText("client_request", req.url)); - } - else - { - this.logger.info(this.localisationService.getText("client_request_ip", { - ip: req.socket.remoteAddress, - url: req.url.replaceAll("/", "\\"), // Localisation service escapes `/` into hex code `/` - })); + if (isLocalRequest) + { + this.logger.info(this.localisationService.getText("client_request", req.url)); + } + else + { + this.logger.info(this.localisationService.getText("client_request_ip", { + ip: req.socket.remoteAddress, + url: req.url.replaceAll("/", "\\"), // Localisation service escapes `/` into hex code `/` + })); + } } } diff --git a/project/src/services/BotLootCacheService.ts b/project/src/services/BotLootCacheService.ts index e5904d4c..252846e8 100644 --- a/project/src/services/BotLootCacheService.ts +++ b/project/src/services/BotLootCacheService.ts @@ -89,6 +89,12 @@ export class BotLootCacheService case LootCacheType.DRUG_ITEMS: result = this.lootCache[botRole].drugItems; break; + case LootCacheType.FOOD_ITEMS: + result = this.lootCache[botRole].foodItems; + break; + case LootCacheType.DRINK_ITEMS: + result = this.lootCache[botRole].drinkItems; + break; case LootCacheType.STIM_ITEMS: result = this.lootCache[botRole].stimItems; break; @@ -219,7 +225,7 @@ export class BotLootCacheService ? botJsonTemplate.generation.items.drugs.whitelist : {}; - // no whitelist, find and assign from combined item pool + // no drugs whitelist, find and assign from combined item pool if (Object.keys(drugItems).length === 0) { for (const [tpl, weight] of Object.entries(combinedLootPool)) @@ -232,6 +238,44 @@ export class BotLootCacheService } } + // Assign whitelisted food to bot if any exist + const foodItems: Record = + (Object.keys(botJsonTemplate.generation.items.food.whitelist)?.length > 0) + ? botJsonTemplate.generation.items.food.whitelist + : {}; + + // No food whitelist, find and assign from combined item pool + if (Object.keys(foodItems).length === 0) + { + for (const [tpl, weight] of Object.entries(combinedLootPool)) + { + const itemTemplate = this.itemHelper.getItem(tpl)[1]; + if (this.itemHelper.isOfBaseclass(itemTemplate._id, BaseClasses.FOOD)) + { + foodItems[tpl] = weight; + } + } + } + + // Assign whitelisted drink to bot if any exist + const drinkItems: Record = + (Object.keys(botJsonTemplate.generation.items.food.whitelist)?.length > 0) + ? botJsonTemplate.generation.items.food.whitelist + : {}; + + // No drink whitelist, find and assign from combined item pool + if (Object.keys(drinkItems).length === 0) + { + for (const [tpl, weight] of Object.entries(combinedLootPool)) + { + const itemTemplate = this.itemHelper.getItem(tpl)[1]; + if (this.itemHelper.isOfBaseclass(itemTemplate._id, BaseClasses.DRINK)) + { + drinkItems[tpl] = weight; + } + } + } + // Assign whitelisted stims to bot if any exist const stimItems: Record = (Object.keys(botJsonTemplate.generation.items.stims.whitelist)?.length > 0) @@ -270,7 +314,7 @@ export class BotLootCacheService } } - // Get backpack loot (excluding magazines, bullets, grenades and healing items) + // Get backpack loot (excluding magazines, bullets, grenades, drink, food and healing/stim items) const filteredBackpackItems = {}; for (const itemKey of Object.keys(backpackLootPool)) { @@ -285,6 +329,8 @@ export class BotLootCacheService || this.isMagazine(itemTemplate._props) || this.isMedicalItem(itemTemplate._props) || this.isGrenade(itemTemplate._props) + || this.isFood(itemTemplate._id) + || this.isDrink(itemTemplate._id) ) { // Is type we dont want as backpack loot, skip @@ -294,7 +340,7 @@ export class BotLootCacheService filteredBackpackItems[itemKey] = backpackLootPool[itemKey]; } - // Get pocket loot (excluding magazines, bullets, grenades, medical and healing items) + // Get pocket loot (excluding magazines, bullets, grenades, drink, food medical and healing/stim items) const filteredPocketItems = {}; for (const itemKey of Object.keys(pocketLootPool)) { @@ -309,6 +355,8 @@ export class BotLootCacheService || this.isMagazine(itemTemplate._props) || this.isMedicalItem(itemTemplate._props) || this.isGrenade(itemTemplate._props) + || this.isFood(itemTemplate._id) + || this.isDrink(itemTemplate._id) || !("Height" in itemTemplate._props) // lacks height || !("Width" in itemTemplate._props) // lacks width ) @@ -319,7 +367,7 @@ export class BotLootCacheService filteredPocketItems[itemKey] = pocketLootPool[itemKey]; } - // Get vest loot (excluding magazines, bullets, grenades, medical and healing items) + // Get vest loot (excluding magazines, bullets, grenades, medical and healing/stim items) const filteredVestItems = {}; for (const itemKey of Object.keys(vestLootPool)) { @@ -334,6 +382,8 @@ export class BotLootCacheService || this.isMagazine(itemTemplate._props) || this.isMedicalItem(itemTemplate._props) || this.isGrenade(itemTemplate._props) + || this.isFood(itemTemplate._id) + || this.isDrink(itemTemplate._id) ) { continue; @@ -344,6 +394,8 @@ export class BotLootCacheService this.lootCache[botRole].healingItems = healingItems; this.lootCache[botRole].drugItems = drugItems; + this.lootCache[botRole].foodItems = foodItems; + this.lootCache[botRole].drinkItems = drinkItems; this.lootCache[botRole].stimItems = stimItems; this.lootCache[botRole].grenadeItems = grenadeItems; @@ -429,6 +481,16 @@ export class BotLootCacheService return ("ThrowType" in props); } + protected isFood(tpl: string): boolean + { + return this.itemHelper.isOfBaseclass(tpl, BaseClasses.FOOD); + } + + protected isDrink(tpl: string): boolean + { + return this.itemHelper.isOfBaseclass(tpl, BaseClasses.DRINK); + } + /** * Check if a bot type exists inside the loot cache * @param botRole role to check for @@ -455,6 +517,8 @@ export class BotLootCacheService specialItems: {}, grenadeItems: {}, drugItems: {}, + foodItems: {}, + drinkItems: {}, healingItems: {}, stimItems: {}, }; diff --git a/project/src/services/FenceService.ts b/project/src/services/FenceService.ts index db4f83b7..6d538d0d 100644 --- a/project/src/services/FenceService.ts +++ b/project/src/services/FenceService.ts @@ -3,16 +3,16 @@ import { inject, injectable } from "tsyringe"; import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { PresetHelper } from "@spt-aki/helpers/PresetHelper"; -import { MinMax } from "@spt-aki/models/common/MinMax"; import { IFenceLevel } from "@spt-aki/models/eft/common/IGlobals"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; -import { Item, Repairable, Upd } from "@spt-aki/models/eft/common/tables/IItem"; +import { Item, Repairable } from "@spt-aki/models/eft/common/tables/IItem"; import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem"; import { IBarterScheme, ITraderAssort } from "@spt-aki/models/eft/common/tables/ITrader"; import { BaseClasses } from "@spt-aki/models/enums/BaseClasses"; import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { Traders } from "@spt-aki/models/enums/Traders"; import { IItemDurabilityCurrentMax, ITraderConfig } from "@spt-aki/models/spt/config/ITraderConfig"; +import { ICreateFenceAssortsResult } from "@spt-aki/models/spt/fence/ICreateFenceAssortsResult"; import { IFenceAssortGenerationValues, IGenerationAssortValues, @@ -43,7 +43,7 @@ export class FenceService /** Assorts shown on a separate tab when you max out fence rep */ protected fenceDiscountAssort: ITraderAssort = undefined; - /** Hydrated on initial assort generation as part of generateFenceAssorts() */ + /** Desired baseline counts - Hydrated on initial assort generation as part of generateFenceAssorts() */ protected desiredAssortCounts: IFenceAssortGenerationValues; constructor( @@ -231,16 +231,23 @@ export class FenceService this.deleteRandomAssorts(itemCountToReplace, this.fenceAssort); this.deleteRandomAssorts(discountItemCountToReplace, this.fenceDiscountAssort); - // Get count of what item pools need new items (item/weapon/equipment) - const itemCountsToReplace = this.getCountOfItemsToGenerate(); + const normalItemCountsToGenerate = this.getItemCountsToGenerate( + this.fenceAssort.items, + this.desiredAssortCounts.normal, + ); + const newItems = this.createAssorts(normalItemCountsToGenerate, 1); - const newItems = this.createFenceAssortSkeleton(); - this.createAssorts(itemCountsToReplace.normal, newItems, 1); - this.fenceAssort.items.push(...newItems.items); + // Push newly generated assorts into existing data + this.updateFenceAssorts(newItems, this.fenceAssort); - const newDiscountItems = this.createFenceAssortSkeleton(); - this.createAssorts(itemCountsToReplace.discount, newDiscountItems, 2); - this.fenceDiscountAssort.items.push(...newDiscountItems.items); + const discountItemCountsToGenerate = this.getItemCountsToGenerate( + this.fenceDiscountAssort.items, + this.desiredAssortCounts.discount, + ); + const newDiscountItems = this.createAssorts(discountItemCountsToGenerate, 2); + + // Push newly generated discount assorts into existing data + this.updateFenceAssorts(newDiscountItems, this.fenceDiscountAssort); // Add new barter items to fence barter scheme for (const barterItemKey in newItems.barter_scheme) @@ -271,6 +278,46 @@ export class FenceService this.incrementPartialRefreshTime(); } + /** + * Handle the process of folding new assorts into existing assorts, when a new assort exists already, increment its StackObjectsCount instead + * @param newFenceAssorts Assorts to fold into existing fence assorts + * @param existingFenceAssorts Current fence assorts new assorts will be added to + */ + protected updateFenceAssorts(newFenceAssorts: ICreateFenceAssortsResult, existingFenceAssorts: ITraderAssort): void + { + for (const itemWithChildren of newFenceAssorts.sptItems) + { + // Find the root item + const newRootItem = itemWithChildren.find((item) => item.slotId === "hideout"); + + // Find a matching root item with same tpl in existing assort + const existingRootItem = existingFenceAssorts.items.find((item) => + item._tpl === newRootItem._tpl && item.slotId === "hideout" + ); + + // Check if same type of item exists + its on list of item types to always stack + if (existingRootItem && this.itemInPreventDupeCategoryList(newRootItem._tpl)) + { + // Guard against a missing stack count + if (!existingRootItem.upd.StackObjectsCount) + { + existingRootItem.upd.StackObjectsCount = 1; + } + + // Merge new items count into existing, dont add new loyalty/barter data as it already exists + existingRootItem.upd.StackObjectsCount += newRootItem.upd.StackObjectsCount; + + continue; + } + + // New assort to be added to existing assorts + existingFenceAssorts.items.push(...itemWithChildren); + existingFenceAssorts.barter_scheme[newRootItem._id] = newFenceAssorts.barter_scheme[newRootItem._id]; + existingFenceAssorts.loyal_level_items[newRootItem._id] = + newFenceAssorts.loyal_level_items[newRootItem._id]; + } + } + /** * Increment fence next refresh timestamp by current timestamp + partialRefreshTimeSeconds from config */ @@ -281,18 +328,18 @@ export class FenceService } /** - * Compare the current fence offer count to what the config wants it to be, - * If value is lower add extra count to value to generate more items to fill gap - * @param existingItemCountToReplace count of items to generate - * @returns number of items to generate + * Get values that will hydrate the passed in assorts back to the desired counts + * @param assortItems Current assorts after items have been removed + * @param generationValues Base counts assorts should be adjusted to + * @returns IGenerationAssortValues object with adjustments needed to reach desired state */ - protected getCountOfItemsToGenerate(): IFenceAssortGenerationValues + protected getItemCountsToGenerate( + assortItems: Item[], + generationValues: IGenerationAssortValues, + ): IGenerationAssortValues { - const currentItemAssortCount = Object.keys(this.fenceAssort.loyal_level_items).length; - - const rootPresetItems = this.fenceAssort.items.filter((item) => - item.slotId === "hideout" && item.upd.sptPresetId - ); + const allRootItems = assortItems.filter((item) => item.slotId === "hideout"); + const rootPresetItems = allRootItems.filter((item) => item.upd.sptPresetId); // Get count of weapons const currentWeaponPresetCount = rootPresetItems.reduce((count, item) => @@ -306,60 +353,19 @@ export class FenceService return this.itemHelper.armorItemCanHoldMods(item._tpl) ? count + 1 : count; }, 0); - const itemCountToGenerate = Math.max(this.desiredAssortCounts.normal.item - currentItemAssortCount, 0); - const weaponCountToGenerate = Math.max( - this.desiredAssortCounts.normal.weaponPreset - currentWeaponPresetCount, - 0, - ); - const equipmentCountToGenerate = Math.max( - this.desiredAssortCounts.normal.equipmentPreset - currentEquipmentPresetCount, - 0, - ); + // Normal item count is total count minus weapon + armor count + const nonPresetItemAssortCount = allRootItems.length - (currentWeaponPresetCount + currentEquipmentPresetCount); - const normalValues: IGenerationAssortValues = { + // Get counts of items to generate, never let values fall below 0 + const itemCountToGenerate = Math.max(generationValues.item - nonPresetItemAssortCount, 0); + const weaponCountToGenerate = Math.max(generationValues.weaponPreset - currentWeaponPresetCount, 0); + const equipmentCountToGenerate = Math.max(generationValues.equipmentPreset - currentEquipmentPresetCount, 0); + + return { item: itemCountToGenerate, weaponPreset: weaponCountToGenerate, equipmentPreset: equipmentCountToGenerate, }; - - // Discount tab handling - const currentDiscountItemAssortCount = Object.keys(this.fenceDiscountAssort.loyal_level_items).length; - const rootDiscountPresetItems = this.fenceDiscountAssort.items.filter((item) => - item.slotId === "hideout" && item.upd.sptPresetId - ); - - // Get count of weapons - const currentDiscountWeaponPresetCount = rootDiscountPresetItems.reduce((count, item) => - { - return this.itemHelper.isOfBaseclass(item._tpl, BaseClasses.WEAPON) ? count + 1 : count; - }, 0); - - // Get count of equipment - const currentDiscountEquipmentPresetCount = rootDiscountPresetItems.reduce((count, item) => - { - return this.itemHelper.armorItemCanHoldMods(item._tpl) ? count + 1 : count; - }, 0); - - const itemDiscountCountToGenerate = Math.max( - this.desiredAssortCounts.discount.item - currentDiscountItemAssortCount, - 0, - ); - const weaponDiscountCountToGenerate = Math.max( - this.desiredAssortCounts.discount.weaponPreset - currentDiscountWeaponPresetCount, - 0, - ); - const equipmentDiscountCountToGenerate = Math.max( - this.desiredAssortCounts.discount.equipmentPreset - currentDiscountEquipmentPresetCount, - 0, - ); - - const discountValues: IGenerationAssortValues = { - item: itemDiscountCountToGenerate, - weaponPreset: weaponDiscountCountToGenerate, - equipmentPreset: equipmentDiscountCountToGenerate, - }; - - return { normal: normalValues, discount: discountValues }; } /** @@ -386,18 +392,26 @@ export class FenceService */ protected removeRandomItemFromAssorts(assort: ITraderAssort, rootItems: Item[]): void { - const rootItemToRemove = this.randomUtil.getArrayValue(rootItems); - - // Clean up any mods if item had them - const itemWithChildren = this.itemHelper.findAndReturnChildrenAsItems(assort.items, rootItemToRemove._id); - for (const itemToDelete of itemWithChildren) - { - // Delete item from assort items array - assort.items.splice(assort.items.indexOf(itemToDelete), 1); + const rootItemToAdjust = this.randomUtil.getArrayValue(rootItems); + const itemCountToRemove = this.randomUtil.getInt(1, rootItemToAdjust.upd.StackObjectsCount); + if (itemCountToRemove > 1 && itemCountToRemove < rootItemToAdjust.upd.StackObjectsCount) + { // More than 1 + less then full stack + // Reduce stack size but keep stack + rootItemToAdjust.upd.StackObjectsCount -= itemCountToRemove; } + else + { + // Remove up item + any mods + const itemWithChildren = this.itemHelper.findAndReturnChildrenAsItems(assort.items, rootItemToAdjust._id); + for (const itemToDelete of itemWithChildren) + { + // Delete item from assort items array + assort.items.splice(assort.items.indexOf(itemToDelete), 1); + } - delete assort.barter_scheme[rootItemToRemove._id]; - delete assort.loyal_level_items[rootItemToRemove._id]; + delete assort.barter_scheme[rootItemToAdjust._id]; + delete assort.loyal_level_items[rootItemToAdjust._id]; + } } /** @@ -437,16 +451,35 @@ export class FenceService this.createInitialFenceAssortGenerationValues(); // Create basic fence assort - const assorts = this.createFenceAssortSkeleton(); - this.createAssorts(this.desiredAssortCounts.normal, assorts, 1); + const assorts = this.createAssorts(this.desiredAssortCounts.normal, 1); + // Store in this.fenceAssort - this.setFenceAssort(assorts); + this.setFenceAssort(this.convertIntoFenceAssort(assorts)); // Create level 2 assorts accessible at rep level 6 - const discountAssorts = this.createFenceAssortSkeleton(); - this.createAssorts(this.desiredAssortCounts.discount, discountAssorts, 2); + const discountAssorts = this.createAssorts(this.desiredAssortCounts.discount, 2); + // Store in this.fenceDiscountAssort - this.setFenceDiscountAssort(discountAssorts); + this.setFenceDiscountAssort(this.convertIntoFenceAssort(discountAssorts)); + } + + /** + * Convert the intermediary assort data generated into format client can process + * @param intermediaryAssorts Generated assorts that will be converted + * @returns ITraderAssort + */ + protected convertIntoFenceAssort(intermediaryAssorts: ICreateFenceAssortsResult): ITraderAssort + { + const result = this.createFenceAssortSkeleton(); + for (const itemWithChilden of intermediaryAssorts.sptItems) + { + result.items.push(...itemWithChilden); + } + + result.barter_scheme = intermediaryAssorts.barter_scheme; + result.loyal_level_items = intermediaryAssorts.loyal_level_items; + + return result; } /** @@ -506,14 +539,22 @@ export class FenceService * @param assortCount Number of assorts to generate * @param assorts object to add created assorts to */ - protected createAssorts(itemCounts: IGenerationAssortValues, assorts: ITraderAssort, loyaltyLevel: number): void + protected createAssorts(itemCounts: IGenerationAssortValues, loyaltyLevel: number): ICreateFenceAssortsResult { + const result: ICreateFenceAssortsResult = { sptItems: [], barter_scheme: {}, loyal_level_items: {} }; + const baseFenceAssortClone = this.jsonUtil.clone(this.databaseServer.getTables().traders[Traders.FENCE].assort); const itemTypeLimitCounts = this.initItemLimitCounter(this.traderConfig.fence.itemTypeLimits); if (itemCounts.item > 0) { - this.addItemAssorts(itemCounts.item, assorts, baseFenceAssortClone, itemTypeLimitCounts, loyaltyLevel); + const itemResult = this.addItemAssorts( + itemCounts.item, + result, + baseFenceAssortClone, + itemTypeLimitCounts, + loyaltyLevel, + ); } if (itemCounts.weaponPreset > 0 || itemCounts.equipmentPreset > 0) @@ -522,11 +563,13 @@ export class FenceService this.addPresetsToAssort( itemCounts.weaponPreset, itemCounts.equipmentPreset, - assorts, + result, baseFenceAssortClone, loyaltyLevel, ); } + + return result; } /** @@ -539,15 +582,15 @@ export class FenceService */ protected addItemAssorts( assortCount: number, - assorts: ITraderAssort, + assorts: ICreateFenceAssortsResult, baseFenceAssortClone: ITraderAssort, itemTypeLimits: Record, loyaltyLevel: number, ): void { const priceLimits = this.traderConfig.fence.itemCategoryRoublePriceLimit; - const assortRootItems = baseFenceAssortClone.items.filter((x) => - x.parentId === "hideout" && !x.upd?.sptPresetId + const assortRootItems = baseFenceAssortClone.items.filter((item) => + item.parentId === "hideout" && !item.upd?.sptPresetId ); for (let i = 0; i < assortCount; i++) @@ -614,7 +657,7 @@ export class FenceService } // Skip items already in the assort if it exists in the prevent duplicate list - const existingItemThatMatches = this.getMatchingItem(rootItemBeingAdded, itemDbDetails, assorts.items); + const existingItemThatMatches = this.getMatchingItem(rootItemBeingAdded, itemDbDetails, assorts.sptItems); const shouldBeStacked = this.itemShouldBeForceStacked(existingItemThatMatches, itemDbDetails); if (shouldBeStacked && existingItemThatMatches) { // Decrement loop counter so another items gets added @@ -630,7 +673,7 @@ export class FenceService this.randomiseArmorModDurability(desiredAssortItemAndChildrenClone, itemDbDetails); } - assorts.items.push(...desiredAssortItemAndChildrenClone); + assorts.sptItems.push(desiredAssortItemAndChildrenClone); assorts.barter_scheme[rootItemBeingAdded._id] = this.jsonUtil.clone( baseFenceAssortClone.barter_scheme[chosenBaseAssortRoot._id], @@ -651,15 +694,15 @@ export class FenceService * e.g. salewa hp resource units left * @param rootItemBeingAdded item to look for a match against * @param itemDbDetails Db details of matching item - * @param fenceItemAssorts Items to search through + * @param itemsWithChildren Items to search through * @returns Matching assort item */ - protected getMatchingItem(rootItemBeingAdded: Item, itemDbDetails: ITemplateItem, fenceItemAssorts: Item[]): Item + protected getMatchingItem(rootItemBeingAdded: Item, itemDbDetails: ITemplateItem, itemsWithChildren: Item[][]): Item { // Get matching root items - const matchingItems = fenceItemAssorts.filter((item) => - item._tpl === rootItemBeingAdded._tpl && item.parentId === "hideout" - ); + const matchingItems = itemsWithChildren.filter((itemWithChildren) => + itemWithChildren.find((item) => item._tpl === rootItemBeingAdded._tpl && item.parentId === "hideout") + ).flatMap((x) => x); if (matchingItems.length === 0) { // Nothing matches by tpl and is root item, exit early @@ -726,11 +769,13 @@ export class FenceService return false; } + return this.itemInPreventDupeCategoryList(itemDbDetails._id); + } + + protected itemInPreventDupeCategoryList(tpl: string): boolean + { // Item type in config list - return this.itemHelper.isOfBaseclasses( - itemDbDetails._id, - this.traderConfig.fence.preventDuplicateOffersOfCategory, - ); + return this.itemHelper.isOfBaseclasses(tpl, this.traderConfig.fence.preventDuplicateOffersOfCategory); } /** @@ -799,7 +844,7 @@ export class FenceService protected addPresetsToAssort( desiredWeaponPresetsCount: number, desiredEquipmentPresetsCount: number, - assorts: ITraderAssort, + assorts: ICreateFenceAssortsResult, baseFenceAssort: ITraderAssort, loyaltyLevel: number, ): void @@ -848,7 +893,7 @@ export class FenceService // Remapping IDs causes parentid to be altered presetWithChildrenClone[0].parentId = "hideout"; - assorts.items.push(...presetWithChildrenClone); + assorts.sptItems.push(presetWithChildrenClone); // Set assort price // Must be careful to use correct id as the item has had its IDs regenerated @@ -908,7 +953,7 @@ export class FenceService // Remapping IDs causes parentid to be altered presetWithChildrenClone[0].parentId = "hideout"; - assorts.items.push(...presetWithChildrenClone); + assorts.sptItems.push(presetWithChildrenClone); // Set assort price // Must be careful to use correct id as the item has had its IDs regenerated diff --git a/project/src/services/ItemBaseClassService.ts b/project/src/services/ItemBaseClassService.ts index e9ed0493..94259cea 100644 --- a/project/src/services/ItemBaseClassService.ts +++ b/project/src/services/ItemBaseClassService.ts @@ -13,6 +13,7 @@ import { LocalisationService } from "@spt-aki/services/LocalisationService"; export class ItemBaseClassService { protected itemBaseClassesCache: Record = {}; + protected items: Record; protected cacheGenerated = false; constructor( @@ -31,15 +32,15 @@ export class ItemBaseClassService // Clear existing cache this.itemBaseClassesCache = {}; - const allDbItems = this.databaseServer.getTables().templates.items; - if (!allDbItems) + this.items = this.databaseServer.getTables().templates.items; + if (!this.items) { this.logger.warning(this.localisationService.getText("baseclass-missing_db_no_cache")); return; } - const filteredDbItems = Object.values(allDbItems).filter((x) => x._type === "Item"); + const filteredDbItems = Object.values(this.items).filter((x) => x._type === "Item"); for (const item of filteredDbItems) { const itemIdToUpdate = item._id; @@ -48,7 +49,7 @@ export class ItemBaseClassService this.itemBaseClassesCache[item._id] = []; } - this.addBaseItems(itemIdToUpdate, item, allDbItems); + this.addBaseItems(itemIdToUpdate, item); } this.cacheGenerated = true; @@ -58,16 +59,15 @@ export class ItemBaseClassService * Helper method, recursivly iterate through items parent items, finding and adding ids to dictionary * @param itemIdToUpdate item tpl to store base ids against in dictionary * @param item item being checked - * @param allDbItems all items in db */ - protected addBaseItems(itemIdToUpdate: string, item: ITemplateItem, allDbItems: Record): void + protected addBaseItems(itemIdToUpdate: string, item: ITemplateItem): void { this.itemBaseClassesCache[itemIdToUpdate].push(item._parent); - const parent = allDbItems[item._parent]; + const parent = this.items[item._parent]; if (parent._parent !== "") { - this.addBaseItems(itemIdToUpdate, parent, allDbItems); + this.addBaseItems(itemIdToUpdate, parent); } } @@ -91,8 +91,9 @@ export class ItemBaseClassService return false; } - // Edge case - this is the 'root' item that all other items inherit from - if (itemTpl === BaseClasses.ITEM) + // The cache is only generated for item templates with `_type === "Item"`, so return false for any other type, + // including item templates that simply don't exist. + if (!this.cachedItemIsOfItemType(itemTpl)) { return false; } @@ -114,6 +115,16 @@ export class ItemBaseClassService return this.itemBaseClassesCache[itemTpl].some((x) => baseClasses.includes(x)); } + /** + * Check if cached item template is of type Item + * @param itemTemplateId item to check + * @returns true if item is of type Item + */ + private cachedItemIsOfItemType(itemTemplateId: string): boolean + { + return this.items[itemTemplateId]?._type === "Item"; + } + /** * Get base classes item inherits from * @param itemTpl item to get base classes for diff --git a/project/src/services/ModCompilerService.ts b/project/src/services/ModCompilerService.ts index 159588b9..7968dea0 100644 --- a/project/src/services/ModCompilerService.ts +++ b/project/src/services/ModCompilerService.ts @@ -114,8 +114,8 @@ export class ModCompilerService if (output.sourceMapText) { output.outputText = output.outputText.replace( - "//# sourceMappingURL=module.js.map", - `//# sourceMappingURL=${parsedDestPath.base}.map`, + "//# sourceMappingURL\=module.js.map", + `//# sourceMappingURL\=${parsedDestPath.base}.map`, ); const sourceMap = JSON.parse(output.sourceMapText); diff --git a/project/src/services/PaymentService.ts b/project/src/services/PaymentService.ts index 4ef6bfac..c4658a74 100644 --- a/project/src/services/PaymentService.ts +++ b/project/src/services/PaymentService.ts @@ -315,7 +315,7 @@ export class PaymentService } /** - * Get all money stacks in inventory and prioritse items in stash + * Get all money stacks in inventory and prioritise items in stash * @param pmcData * @param currencyTpl * @param playerStashId Players stash id diff --git a/project/src/services/ProfileActivityService.ts b/project/src/services/ProfileActivityService.ts new file mode 100644 index 00000000..b9f7619e --- /dev/null +++ b/project/src/services/ProfileActivityService.ts @@ -0,0 +1,64 @@ +import { injectable } from "tsyringe"; + +@injectable() +export class ProfileActivityService +{ + protected profileActivityTimestamps: Record = {}; + + /** + * Was the requested profile active in the last requested minutes + * @param sessionId Profile to check + * @param minutes Minutes to check for activity in + * @returns True when profile was active within past x minutes + */ + public activeWithinLastMinutes(sessionId: string, minutes: number): boolean + { + const currentTimestamp = new Date().getTime() / 1000; + const storedActivityTimestamp = this.profileActivityTimestamps[sessionId]; + if (!storedActivityTimestamp) + { + // No value, no assumed activity (server offline?) + return false; + } + + // True if difference since last timestamp to now is below desired amount + return (currentTimestamp - storedActivityTimestamp) < (minutes * 60); // convert minutes to seconds to compare + } + + /** + * Get an array of profile ids that were active in the last x minutes + * @param minutes How many minutes from now to search for profiles + * @returns String array of profile ids + */ + public getActiveProfileIdsWithinMinutes(minutes: number): string[] + { + const currentTimestamp = new Date().getTime() / 1000; + const result: string[] = []; + + for (const id of Object.keys(this.profileActivityTimestamps ?? {})) + { + const lastActiveTimestamp = this.profileActivityTimestamps[id]; + if (!lastActiveTimestamp) + { + continue; + } + + // Profile was active in last x minutes, add to return list + if ((currentTimestamp - lastActiveTimestamp) < (minutes * 60)) + { + result.push(id); + } + } + + return result; + } + + /** + * Update the timestamp a profile was last observed active + * @param sessionId Profile to update + */ + public setActivityTimestamp(sessionId: string): void + { + this.profileActivityTimestamps[sessionId] = new Date().getTime() / 1000; + } +} diff --git a/project/src/services/ProfileFixerService.ts b/project/src/services/ProfileFixerService.ts index 23a09b25..015a0514 100644 --- a/project/src/services/ProfileFixerService.ts +++ b/project/src/services/ProfileFixerService.ts @@ -9,9 +9,9 @@ import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { Bonus, HideoutSlot, IQuestStatus } from "@spt-aki/models/eft/common/tables/IBotBase"; import { IHideoutImprovement } from "@spt-aki/models/eft/common/tables/IBotBase"; import { IPmcDataRepeatableQuest, IRepeatableQuest } from "@spt-aki/models/eft/common/tables/IRepeatableQuests"; +import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem"; import { StageBonus } from "@spt-aki/models/eft/hideout/IHideoutArea"; -import { IAkiProfile } from "@spt-aki/models/eft/profile/IAkiProfile"; -import { AccountTypes } from "@spt-aki/models/enums/AccountTypes"; +import { IAkiProfile, IEquipmentBuild, IMagazineBuild, IWeaponBuild } from "@spt-aki/models/eft/profile/IAkiProfile"; import { BonusType } from "@spt-aki/models/enums/BonusType"; import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { HideoutAreas } from "@spt-aki/models/enums/HideoutAreas"; @@ -282,7 +282,11 @@ export class ProfileFixerService } const db = this.databaseServer.getTables(); - const placeOfFameAreaDb = db.hideout.areas.find((x) => x.type === HideoutAreas.PLACE_OF_FAME); + const placeOfFameAreaDb = db.hideout.areas.find((area) => area.type === HideoutAreas.PLACE_OF_FAME); + if (!placeOfFameAreaDb) + { + return; + } const stageCurrentlyAt = placeOfFameAreaDb.stages[placeOfFameArea.level]; const placeOfFameStashId = pmcProfile.Inventory.hideoutAreaStashes[HideoutAreas.PLACE_OF_FAME]; @@ -870,53 +874,47 @@ export class ProfileFixerService const inventoryItemsToCheck = pmcProfile.Inventory.items.filter((item) => ["hideout", "main"].includes(item.slotId) ); - if (!inventoryItemsToCheck) + if (inventoryItemsToCheck) { - return; - } - - // Check each item in inventory to ensure item exists in itemdb - for (const item of inventoryItemsToCheck) - { - if (!itemsDb[item._tpl]) + // Check each item in inventory to ensure item exists in itemdb + for (const item of inventoryItemsToCheck) { - this.logger.error(this.localisationService.getText("fixer-mod_item_found", item._tpl)); - - if (this.coreConfig.fixes.removeModItemsFromProfile) - { - this.logger.success( - `Deleting item from inventory and insurance with id: ${item._id} tpl: ${item._tpl}`, - ); - - // Also deletes from insured array - this.inventoryHelper.removeItem(pmcProfile, item._id, sessionId); - } - } - } - - // Iterate over player-made weapon builds, look for missing items and remove weapon preset if found - for (const buildId in fullProfile.userbuilds?.weaponBuilds) - { - for (const item of fullProfile.userbuilds.weaponBuilds[buildId].Items) - { - // Check item exists in itemsDb if (!itemsDb[item._tpl]) { this.logger.error(this.localisationService.getText("fixer-mod_item_found", item._tpl)); if (this.coreConfig.fixes.removeModItemsFromProfile) { - delete fullProfile.userbuilds.weaponBuilds[buildId]; - this.logger.warning( - `Item: ${item._tpl} has resulted in the deletion of weapon build: ${buildId}`, + this.logger.success( + `Deleting item from inventory and insurance with id: ${item._id} tpl: ${item._tpl}`, ); - } - break; + // Also deletes from insured array + this.inventoryHelper.removeItem(pmcProfile, item._id, sessionId); + } } } } + // Remove invalid builds from weapon, equipment and magazine build lists + const weaponBuilds = fullProfile.userbuilds?.weaponBuilds || []; + fullProfile.userbuilds.weaponBuilds = weaponBuilds.filter((weaponBuild) => + { + return !this.shouldRemoveWeaponEquipmentBuild("weapon", weaponBuild, itemsDb); + }); + + const equipmentBuilds = fullProfile.userbuilds?.equipmentBuilds || []; + fullProfile.userbuilds.equipmentBuilds = equipmentBuilds.filter((equipmentBuild) => + { + return !this.shouldRemoveWeaponEquipmentBuild("equipment", equipmentBuild, itemsDb); + }); + + const magazineBuilds = fullProfile.userbuilds?.magazineBuilds || []; + fullProfile.userbuilds.magazineBuilds = magazineBuilds.filter((magazineBuild) => + { + return !this.shouldRemoveMagazineBuild(magazineBuild, itemsDb); + }); + // Iterate over dialogs, looking for messages with items not found in item db, remove message if item found for (const dialogId in fullProfile.dialogues) { @@ -927,7 +925,7 @@ export class ProfileFixerService } // Iterate over all messages in dialog - for (const message of dialog.messages) + for (const [_, message] of Object.entries(dialog.messages)) { if (!message.items?.data) { @@ -965,7 +963,7 @@ export class ProfileFixerService } const clothing = this.databaseServer.getTables().templates.customization; - for (const suitId of fullProfile.suits) + for (const [_, suitId] of Object.entries(fullProfile.suits)) { if (!clothing[suitId]) { @@ -980,7 +978,7 @@ export class ProfileFixerService for (const repeatable of fullProfile.characters.pmc.RepeatableQuests ?? []) { - for (const activeQuest of repeatable.activeQuests ?? []) + for (const [_, activeQuest] of Object.entries(repeatable.activeQuests ?? [])) { if (!this.traderHelper.traderEnumHasValue(activeQuest.traderId)) { @@ -1041,6 +1039,77 @@ export class ProfileFixerService } } + /** + * @param buildType The type of build, used for logging only + * @param build The build to check for invalid items + * @param itemsDb The items database to use for item lookup + * @returns True if the build should be removed from the build list, false otherwise + */ + protected shouldRemoveWeaponEquipmentBuild( + buildType: string, + build: IWeaponBuild | IEquipmentBuild, + itemsDb: Record, + ): boolean + { + for (const item of build.Items) + { + // Check item exists in itemsDb + if (!itemsDb[item._tpl]) + { + this.logger.error(this.localisationService.getText("fixer-mod_item_found", item._tpl)); + + if (this.coreConfig.fixes.removeModItemsFromProfile) + { + this.logger.warning( + `Item: ${item._tpl} has resulted in the deletion of ${buildType} build: ${build.Name}`, + ); + + return true; + } + + break; + } + } + + return false; + } + + /** + * @param magazineBuild The magazine build to check for validity + * @param itemsDb The items database to use for item lookup + * @returns True if the build should be removed from the build list, false otherwise + */ + protected shouldRemoveMagazineBuild(magazineBuild: IMagazineBuild, itemsDb: Record): boolean + { + for (const item of magazineBuild.Items) + { + // Magazine builds can have null items in them, skip those + if (!item) + { + continue; + } + + // Check item exists in itemsDb + if (!itemsDb[item.TemplateId]) + { + this.logger.error(this.localisationService.getText("fixer-mod_item_found", item.TemplateId)); + + if (this.coreConfig.fixes.removeModItemsFromProfile) + { + this.logger.warning( + `Item: ${item.TemplateId} has resulted in the deletion of magazine build: ${magazineBuild.Name}`, + ); + + return true; + } + + break; + } + } + + return false; + } + /** * Attempt to fix common item issues that corrupt profiles * @param pmcProfile Profile to check items of @@ -1307,6 +1376,21 @@ export class ProfileFixerService } } + /** + * 3.8.0 utilized the wrong ProductionTime for bitcoin, fix it if it's found + */ + public fixBitcoinProductionTime(pmcProfile: IPmcData): void + { + const btcProd = pmcProfile.Hideout?.Production[HideoutHelper.bitcoinFarm]; + if (btcProd) + { + btcProd.ProductionTime = this.hideoutHelper.getAdjustedCraftTimeWithSkills( + pmcProfile, + HideoutHelper.bitcoinProductionId, + ); + } + } + /** * At some point the property name was changed,migrate data across to new name * @param pmcProfile Profile to migrate improvements in @@ -1337,7 +1421,7 @@ export class ProfileFixerService repeatableQuests.push(...repeatableQuestType.activeQuests); } - for (let i = 0; i < profileQuests.length; i++) + for (let i = profileQuests.length - 1; i >= 0; i--) { if (!(quests[profileQuests[i].qid] || repeatableQuests.find((x) => x._id === profileQuests[i].qid))) { diff --git a/project/src/services/RagfairPriceService.ts b/project/src/services/RagfairPriceService.ts index 6762bcec..2c7288ea 100644 --- a/project/src/services/RagfairPriceService.ts +++ b/project/src/services/RagfairPriceService.ts @@ -223,109 +223,129 @@ export class RagfairPriceService implements OnLoad */ public getDynamicOfferPriceForOffer(offerItems: Item[], desiredCurrency: string, isPackOffer: boolean): number { - const rootItem = offerItems[0]; - - // Price to return + // Price to return. let price = 0; - let endLoop = false; - let isPreset = false; - let manuallyAdjusted = false; + // Iterate over each item in the offer. for (const item of offerItems) { - // Armor insert, skip - we dont factor these into an items price + // Skip over armour inserts as those are not factored into item prices. if (this.itemHelper.isOfBaseclass(item._tpl, BaseClasses.BUILT_IN_INSERTS)) { continue; } - // Get dynamic price, fallback to handbook price if value of 1 found - let itemPrice = this.getFleaPriceForItem(item._tpl); + price += this.getDynamicItemPrice(item._tpl, desiredCurrency, item, offerItems, isPackOffer); - if (this.ragfairConfig.dynamic.offerAdjustment.adjustPriceWhenBelowHandbookPrice) - { - itemPrice = this.adjustPriceIfBelowHandbook(itemPrice, item._tpl); - } - - if (this.ragfairConfig.dynamic.useTraderPriceForOffersIfHigher) - { - // Get highest trader price for item, if greater than value found so far, use it - const traderPrice = this.traderHelper.getHighestSellToTraderPrice(item._tpl); - if (traderPrice > itemPrice) - { - itemPrice = traderPrice; - } - } - - // Check if item type is weapon preset, handle differently - const itemDetails = this.itemHelper.getItem(item._tpl); - if (this.presetHelper.isPreset(item.upd?.sptPresetId) && itemDetails[1]._props.weapFireType) - { - itemPrice = this.getWeaponPresetPrice(item, offerItems, itemPrice); - endLoop = true; - isPreset = true; - } - - // Check for existance of manual price adjustment multiplier - const manualPriceMultipler = this.ragfairConfig.dynamic.itemPriceMultiplier[item._tpl]; - if (manualPriceMultipler) - { - manuallyAdjusted = true; - itemPrice *= manualPriceMultipler; - } - - // Multiply dynamic price by quality modifier - const itemQualityModifier = this.itemHelper.getItemQualityModifier(item); - price += itemPrice * itemQualityModifier; - - // Stop loop if weapon preset price function has been run - if (endLoop) + // Check if the item is a weapon preset. + if (item?.upd?.sptPresetId && this.presetHelper.isPresetBaseClass(item.upd.sptPresetId, BaseClasses.WEAPON)) { + // This is a weapon preset, which has it's own price calculation that takes into account the mods in the + // preset. Since we've already calculated the price for the preset entire preset in + // `getDynamicItemPrice`, we can skip the rest of the items in the offer. break; } } - // Check for unreasonable price on singular items - if (offerItems.length === 1 && !manuallyAdjusted) - { - const rootItemDb = this.itemHelper.getItem(rootItem._tpl)[1]; - let unreasonableItemPriceChange: IUnreasonableModPrices; - for (const key of Object.keys(this.ragfairConfig.dynamic.unreasonableModPrices)) - { - if (this.itemHelper.isOfBaseclass(rootItemDb._id, key)) - { - unreasonableItemPriceChange = this.ragfairConfig.dynamic.unreasonableModPrices[key]; + return Math.round(price); + } - break; - } - } - if (unreasonableItemPriceChange?.enabled) + /** + * @param itemTemplateId + * @param desiredCurrency + * @param item + * @param offerItems + * @param isPackOffer + * @returns + */ + public getDynamicItemPrice( + itemTemplateId: string, + desiredCurrency: string, + item?: Item, + offerItems?: Item[], + isPackOffer?: boolean, + ): number + { + let isPreset = false; + let price = this.getFleaPriceForItem(itemTemplateId); + + // Adjust price if below handbook price, based on config. + if (this.ragfairConfig.dynamic.offerAdjustment.adjustPriceWhenBelowHandbookPrice) + { + price = this.adjustPriceIfBelowHandbook(price, itemTemplateId); + } + + // Use trader price if higher, based on config. + if (this.ragfairConfig.dynamic.useTraderPriceForOffersIfHigher) + { + const traderPrice = this.traderHelper.getHighestSellToTraderPrice(itemTemplateId); + if (traderPrice > price) { - price = this.adjustUnreasonablePrice( - this.databaseServer.getTables().templates.handbook.Items, - unreasonableItemPriceChange, - rootItem._tpl, - price, - ); + price = traderPrice; } } - // Get price multiplier min/max to vary price - const rangeValues = this.getOfferTypeRangeValues(isPreset, isPackOffer); - price = this.randomiseOfferPrice(price, rangeValues); + // Prices for weapon presets are handled differently. + if ( + item?.upd?.sptPresetId + && offerItems + && this.presetHelper.isPresetBaseClass(item.upd.sptPresetId, BaseClasses.WEAPON) + ) + { + price = this.getWeaponPresetPrice(item, offerItems, price); + isPreset = true; + } - // Convert to different currency if desiredCurrency param is not roubles - if (desiredCurrency !== Money.ROUBLES) + // Check for existence of manual price adjustment multiplier + const multiplier = this.ragfairConfig.dynamic.itemPriceMultiplier[itemTemplateId]; + if (multiplier) + { + price *= multiplier; + } + + // The quality of the item affects the price. + if (item) + { + const qualityModifier = this.itemHelper.getItemQualityModifier(item); + price *= qualityModifier; + } + + // Make adjustments for unreasonably priced items. + for (const baseClassTemplateId of Object.keys(this.ragfairConfig.dynamic.unreasonableModPrices)) + { + if (this.itemHelper.isOfBaseclass(itemTemplateId, baseClassTemplateId)) + { + // Found an unreasonable price type. + const unreasonableModifier: IUnreasonableModPrices = + this.ragfairConfig.dynamic.unreasonableModPrices[baseClassTemplateId]; + + if (unreasonableModifier.enabled) + { + price = this.adjustUnreasonablePrice( + this.databaseServer.getTables().templates.handbook.Items, + unreasonableModifier, + itemTemplateId, + price, + ); + } + } + } + + // Vary the price based on the type of offer. + const range = this.getOfferTypeRangeValues(isPreset, isPackOffer); + price = this.randomiseOfferPrice(price, range); + + // Convert to different currency if required. + const roublesId = Money.ROUBLES; + if (desiredCurrency !== roublesId) { price = this.handbookHelper.fromRUB(price, desiredCurrency); } - // Guard against weird prices if (price < 1) { - price = 1; + return 1; } - return price; } @@ -400,7 +420,7 @@ export class RagfairPriceService implements OnLoad const itemHandbookPrice = this.getStaticPriceForItem(itemTpl); const priceDifferencePercent = this.getPriceDifference(itemHandbookPrice, itemPrice); - // Only adjust price if difference is > a percent AND item price passes threshhold set in config + // Only adjust price if difference is > a percent AND item price passes threshold set in config if ( priceDifferencePercent > this.ragfairConfig.dynamic.offerAdjustment.maxPriceDifferenceBelowHandbookPercent && itemPrice >= this.ragfairConfig.dynamic.offerAdjustment.priceThreshholdRub diff --git a/project/src/utils/logging/AbstractWinstonLogger.ts b/project/src/utils/logging/AbstractWinstonLogger.ts index 19071d6e..86a6975b 100644 --- a/project/src/utils/logging/AbstractWinstonLogger.ts +++ b/project/src/utils/logging/AbstractWinstonLogger.ts @@ -70,6 +70,7 @@ export abstract class AbstractWinstonLogger implements ILogger filename: this.filePath, datePattern: "YYYY-MM-DD", zippedArchive: true, + frequency: this.getLogFrequency(), maxSize: this.getLogMaxSize(), maxFiles: this.getLogMaxFiles(), format: format.combine( @@ -108,6 +109,11 @@ export abstract class AbstractWinstonLogger implements ILogger protected abstract getFileName(): string; + protected getLogFrequency(): string + { + return "3h"; + } + protected getLogMaxSize(): string { return "5m"; diff --git a/project/tests/__factories__/ProfileInsurance.factory.ts b/project/tests/__factories__/ProfileInsurance.factory.ts index 83ea5629..66679c11 100644 --- a/project/tests/__factories__/ProfileInsurance.factory.ts +++ b/project/tests/__factories__/ProfileInsurance.factory.ts @@ -24,7 +24,7 @@ export class ProfileInsuranceFactory } /** - * Adjusts the scheduledTime and messageContent.systemData.date and messageContent.systemData.time, otherwise the + * Adjusts the scheduledTime, messageContent.systemData.date, and messageContent.systemData.time, otherwise the * dates in the original fixture will likely be expired. */ public adjustPackageDates(dateInput?: DateInput): this @@ -45,8 +45,8 @@ export class ProfileInsuranceFactory } insurance.scheduledTime = date; - insurance.messageContent.systemData.date = format(date, "MM.dd.yyyy"); - insurance.messageContent.systemData.time = format(date, "HH:mm"); + insurance.systemData.date = format(date, "MM.dd.yyyy"); + insurance.systemData.time = format(date, "HH:mm"); return insurance; }); diff --git a/project/tests/__fixture__/profileInsurance.fixture.ts b/project/tests/__fixture__/profileInsurance.fixture.ts index dd26a560..348194e0 100644 --- a/project/tests/__fixture__/profileInsurance.fixture.ts +++ b/project/tests/__fixture__/profileInsurance.fixture.ts @@ -1,747 +1,1388 @@ import { Insurance } from "@spt-aki/models/eft/profile/IAkiProfile"; export const profileInsuranceFixture: Insurance[] = [{ - scheduledTime: 1698945140, - traderId: "54cb50c76803fa8b248b4571", // Prapor - messageContent: { - templateId: "58fe0e4586f774728248ca13 4", - type: 8, - maxStorageTime: 345600, - text: "", - profileChangeEvents: [], - systemData: { date: "01.11.2023", time: "10:51", location: "factory4_day" }, - }, + scheduledTime: 1712950044.4, + traderId: "54cb50c76803fa8b248b4571", + maxStorageTime: 345600, + systemData: { date: "11.04.2024", time: "18:59", location: "factory4_day" }, + messageType: 8, + messageTemplateId: "58fe0e4586f774728248ca13 0", items: [{ - _id: "3679078e05f5b14466d6a730", - _tpl: "5d6d3716a4b9361bc8618872", - parentId: "5fe49444ae6628187a2e77b8", + _id: "35111c9b72a87b6b7d95ad35", + _tpl: "58948c8e86f77409493f7266", + parentId: "d2b3b859f667d4fd8b35bc96", slotId: "hideout", - upd: { StackObjectsCount: 1, Repairable: { Durability: 55, MaxDurability: 55 } }, + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, }, { - _id: "911a0f04d5d9c7e239807ae0", - _tpl: "5644bd2b4bdc2d3b4c8b4572", - parentId: "5fe49444ae6628187a2e77b8", + _id: "d45436a159654f43ca3aa52f", + _tpl: "5580223e4bdc2d1c128b457f", + parentId: "d2b3b859f667d4fd8b35bc96", slotId: "hideout", - upd: { StackObjectsCount: 1, Repairable: { Durability: 97.7862549, MaxDurability: 100 } }, + upd: { + FireMode: { FireMode: "single" }, + StackObjectsCount: 1, + Repairable: { Durability: 100, MaxDurability: 100 }, + }, }, { - _id: "695b13896108f765e8985698", - _tpl: "5648a69d4bdc2ded0b8b457b", - parentId: "5fe49444ae6628187a2e77b8", + _id: "2c60ad9b6051f059ab796aa6", + _tpl: "5a7ae0c351dfba0017554310", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + }, { + _id: "a5c86cef7d25f57bf0fb593c", + _tpl: "5b432f3d5acfc4704b4a1dfb", + parentId: "d2b3b859f667d4fd8b35bc96", slotId: "hideout", upd: { StackObjectsCount: 1 }, }, { - _id: "bb49d6ceb3e87d8563a06455", - _tpl: "5df8a4d786f77412672a1e3b", - parentId: "5fe49444ae6628187a2e77b8", + _id: "8ac63abcbaf95d09a4d50c02", + _tpl: "5ea17ca01412a1425304d1c0", + parentId: "d2b3b859f667d4fd8b35bc96", slotId: "hideout", upd: { StackObjectsCount: 1 }, }, { - _id: "631f8492de748dec852f7ddf", - _tpl: "64abd93857958b4249003418", - parentId: "5fe49444ae6628187a2e77b8", + _id: "33c99e86f72af509da01dc9a", + _tpl: "657f9a55c6679fefb3051e19", + parentId: "8ac63abcbaf95d09a4d50c02", + slotId: "Helmet_top", + upd: { Repairable: { Durability: 24, MaxDurability: 24 } }, + }, { + _id: "426902ae3d7efa5f8c78acf7", + _tpl: "657f9a94ada5fadd1f07a589", + parentId: "8ac63abcbaf95d09a4d50c02", + slotId: "Helmet_back", + upd: { Repairable: { Durability: 24, MaxDurability: 24 } }, + }, { + _id: "5d2be23efb34d0d1da9d3701", + _tpl: "603648ff5a45383c122086ac", + parentId: "d2b3b859f667d4fd8b35bc96", slotId: "hideout", - upd: { StackObjectsCount: 1, Repairable: { Durability: 49.2865, MaxDurability: 60 } }, - }, { - _id: "a2b0c716162c5e31ec28c55a", - _tpl: "5a16b8a9fcdbcb00165aa6ca", - parentId: "3679078e05f5b14466d6a730", - slotId: "mod_nvg", upd: { StackObjectsCount: 1 }, }, { - _id: "dc565f750342cb2d19eeda06", - _tpl: "5d6d3be5a4b9361bc73bc763", - parentId: "3679078e05f5b14466d6a730", - slotId: "mod_equipment_001", - upd: { StackObjectsCount: 1, Repairable: { Durability: 29.33, MaxDurability: 29.33 } }, - }, { - _id: "e9ff62601669d9e2ea9c2fbb", - _tpl: "5d6d3943a4b9360dbc46d0cc", - parentId: "3679078e05f5b14466d6a730", - slotId: "mod_equipment_002", + _id: "9f601faab37dcc58190898ac", + _tpl: "618bb76513f5097c8d5aa2d5", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", upd: { StackObjectsCount: 1 }, }, { - _id: "ac134d7cf6c9d8e25edd0015", - _tpl: "5c11046cd174af02a012e42b", - parentId: "a2b0c716162c5e31ec28c55a", - slotId: "mod_nvg", + _id: "f74d377063e65d350e0099be", + _tpl: "5c0e5bab86f77461f55ed1f3", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", upd: { StackObjectsCount: 1 }, }, { - _id: "22274b895ecc80d51c3cba1c", - _tpl: "5c110624d174af029e69734c", - parentId: "ac134d7cf6c9d8e25edd0015", - slotId: "mod_nvg", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 }, Togglable: { On: true } }, + _id: "0ab2a81fc507ac846f43b15f", + _tpl: "6571b27a6d84a2b8b6007f92", + parentId: "f74d377063e65d350e0099be", + slotId: "Soft_armor_front", + upd: { Repairable: { Durability: 50.88512, MaxDurability: 52 } }, }, { - _id: "c9278dd8251e99578bf7a274", - _tpl: "59c6633186f7740cf0493bb9", - parentId: "911a0f04d5d9c7e239807ae0", - slotId: "mod_gas_block", + _id: "2ca1b6606d918483ed6b70a5", + _tpl: "6571baa74cb80d995d0a1490", + parentId: "f74d377063e65d350e0099be", + slotId: "Soft_armor_back", + upd: { Repairable: { Durability: 49, MaxDurability: 52 } }, + }, { + _id: "5658a9d10f9d44112a991561", + _tpl: "6571baac6d84a2b8b6007fa3", + parentId: "f74d377063e65d350e0099be", + slotId: "Soft_armor_left", + upd: { Repairable: { Durability: 8, MaxDurability: 8 } }, + }, { + _id: "8d0ba4d12fa601312b71d3d7", + _tpl: "6571bab0f41985531a038091", + parentId: "f74d377063e65d350e0099be", + slotId: "soft_armor_right", + upd: { Repairable: { Durability: 8, MaxDurability: 8 } }, + }, { + _id: "45d19bbff6d42c8f781abb38", + _tpl: "6571babb4076795e5e07383f", + parentId: "f74d377063e65d350e0099be", + slotId: "Collar", + upd: { Repairable: { Durability: 14, MaxDurability: 14 } }, + }, { + _id: "cf2ba30bab4d8e80393a8ffe", + _tpl: "6571bac34076795e5e073843", + parentId: "f74d377063e65d350e0099be", + slotId: "Groin", + upd: { Repairable: { Durability: 10, MaxDurability: 10 } }, + }, { + _id: "a3f866e60ccd9c29e77eb5ef", + _tpl: "6571babf4cb80d995d0a1494", + parentId: "f74d377063e65d350e0099be", + slotId: "Groin_back", + upd: { Repairable: { Durability: 12, MaxDurability: 12 } }, + }, { + _id: "a3287a706e1b77b44db82fa1", + _tpl: "5aa2ba71e5b5b000137b758f", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", upd: { StackObjectsCount: 1 }, }, { - _id: "677c209ebb45445ebb42c405", - _tpl: "5649ab884bdc2ded0b8b457f", - parentId: "911a0f04d5d9c7e239807ae0", - slotId: "mod_muzzle", + _id: "c6ad1be7e8401755de69d6a0", + _tpl: "5d6d2ef3a4b93618084f58bd", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", upd: { StackObjectsCount: 1 }, }, { - _id: "8ada5c9cc26585281577c6eb", - _tpl: "5649ae4a4bdc2d1b2b8b4588", - parentId: "911a0f04d5d9c7e239807ae0", + _id: "7c42d3dce0ddbc4806bce48b", + _tpl: "5894a51286f77426d13baf02", + parentId: "35111c9b72a87b6b7d95ad35", slotId: "mod_pistol_grip", - upd: { StackObjectsCount: 1 }, + upd: {}, }, { - _id: "4bd10f89836fd9f86aedcac1", - _tpl: "5649af094bdc2df8348b4586", - parentId: "911a0f04d5d9c7e239807ae0", + _id: "10b97872c5f4e0e1949a0369", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "35111c9b72a87b6b7d95ad35", + slotId: "mod_magazine", + }, { + _id: "a6cd9986dde4cabddcd2dce2", + _tpl: "5894a5b586f77426d2590767", + parentId: "35111c9b72a87b6b7d95ad35", slotId: "mod_reciever", - upd: { StackObjectsCount: 1 }, + upd: {}, }, { - _id: "8b1327270791b142ac341b03", - _tpl: "5649d9a14bdc2d79388b4580", - parentId: "911a0f04d5d9c7e239807ae0", + _id: "b65635b515712f990fdcc201", + _tpl: "58ac1bf086f77420ed183f9f", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "35111c9b72a87b6b7d95ad35", + slotId: "mod_stock", + }, { + _id: "0e11045873efe3625695c1ae", + _tpl: "5c5db6b32e221600102611a0", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "35111c9b72a87b6b7d95ad35", + slotId: "mod_charge", + }, { + _id: "94c4161abe8bf654fb986063", + _tpl: "57adff4f24597737f373b6e6", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "a6cd9986dde4cabddcd2dce2", + slotId: "mod_scope", + }, { + _id: "9b284ccfd0d535acec1ff58b", + _tpl: "5c5db5c62e22160012542255", + parentId: "a6cd9986dde4cabddcd2dce2", + slotId: "mod_barrel", + upd: {}, + }, { + _id: "d730caa83a11fd01250a7261", + _tpl: "5c5db63a2e2216000f1b284a", + parentId: "a6cd9986dde4cabddcd2dce2", + slotId: "mod_handguard", + upd: {}, + }, { + _id: "24291c7bcf91e362adb6d68b", + _tpl: "5fb6564947ce63734e3fa1da", + parentId: "a6cd9986dde4cabddcd2dce2", slotId: "mod_sight_rear", upd: { StackObjectsCount: 1 }, }, { - _id: "566335b3df586f34b47f5e35", - _tpl: "5649b2314bdc2d79388b4576", - parentId: "911a0f04d5d9c7e239807ae0", - slotId: "mod_stock", - upd: { StackObjectsCount: 1 }, - }, { - _id: "da8cde1b3024c336f6e06152", - _tpl: "55d482194bdc2d1d4e8b456b", - parentId: "911a0f04d5d9c7e239807ae0", - slotId: "mod_magazine", + _id: "0d98fd0769cce8e473bbe540", + _tpl: "58d2664f86f7747fec5834f6", upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "94c4161abe8bf654fb986063", + slotId: "mod_scope", }, { - _id: "1e0b177df108c0c117028812", - _tpl: "57cffddc24597763133760c6", - parentId: "c9278dd8251e99578bf7a274", - slotId: "mod_handguard", + _id: "11b174510f039e8217fbd202", + _tpl: "58d268fc86f774111273f8c2", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "0d98fd0769cce8e473bbe540", + slotId: "mod_scope", + }, { + _id: "c435230e530574b1d7c32300", + _tpl: "5c7e8fab2e22165df16b889b", + parentId: "9b284ccfd0d535acec1ff58b", + slotId: "mod_muzzle", + upd: {}, + }, { + _id: "15666fe6fd2d95206612e418", + _tpl: "6269220d70b6c02e665f2635", + parentId: "d730caa83a11fd01250a7261", + slotId: "mod_mount_000", upd: { StackObjectsCount: 1 }, }, { - _id: "bc041c0011d76f714b898400", - _tpl: "57cffcd624597763133760c5", - parentId: "1e0b177df108c0c117028812", + _id: "a54de8b9014eee71fdf1d01d", + _tpl: "6269220d70b6c02e665f2635", + parentId: "d730caa83a11fd01250a7261", + slotId: "mod_mount_001", + upd: { StackObjectsCount: 1 }, + }, { + _id: "c34555bc95a9a7a23150a36f", + _tpl: "6269220d70b6c02e665f2635", + parentId: "d730caa83a11fd01250a7261", + slotId: "mod_mount_002", + upd: { StackObjectsCount: 1 }, + }, { + _id: "91cae4ae30d1366b87158238", + _tpl: "6269220d70b6c02e665f2635", + parentId: "d730caa83a11fd01250a7261", slotId: "mod_mount_003", upd: { StackObjectsCount: 1 }, }, { - _id: "9f8d7880a6e0a47a211ec5d3", - _tpl: "58491f3324597764bc48fa02", - parentId: "8b1327270791b142ac341b03", - slotId: "mod_scope", + _id: "48f23df4509164cf397b9ab5", + _tpl: "6269220d70b6c02e665f2635", + parentId: "d730caa83a11fd01250a7261", + slotId: "mod_mount_004", upd: { StackObjectsCount: 1 }, }, { - _id: "402b4086535a50ef7d9cef88", - _tpl: "5649be884bdc2d79388b4577", - parentId: "566335b3df586f34b47f5e35", - slotId: "mod_stock", + _id: "a55f05f689978ac65c7da654", + _tpl: "5b7be4895acfc400170e2dd5", + parentId: "d730caa83a11fd01250a7261", + slotId: "mod_foregrip", + upd: {}, + }, { + _id: "8ae4ea81a2d6074162d87a9c", + _tpl: "5b7be47f5acfc400170e2dd2", + parentId: "d730caa83a11fd01250a7261", + slotId: "mod_mount_005", + upd: {}, + }, { + _id: "312cc0f6687963305457235e", + _tpl: "5b7be47f5acfc400170e2dd2", + parentId: "d730caa83a11fd01250a7261", + slotId: "mod_mount_006", + upd: {}, + }, { + _id: "e1e5aaf474b7282a52ac9a14", + _tpl: "5fb6567747ce63734e3fa1dc", + parentId: "d730caa83a11fd01250a7261", + slotId: "mod_sight_front", upd: { StackObjectsCount: 1 }, }, { - _id: "db2ef9442178910eba985b51", - _tpl: "58d2946386f774496974c37e", - parentId: "402b4086535a50ef7d9cef88", - slotId: "mod_stock_000", - upd: { StackObjectsCount: 1 }, - }, { - _id: "3c32b7d47ad80e83749fa906", - _tpl: "58d2912286f7744e27117493", - parentId: "db2ef9442178910eba985b51", - slotId: "mod_stock", - upd: { StackObjectsCount: 1 }, - }, { - _id: "574a9b5535585255cde19570", - _tpl: "55d482194bdc2d1d4e8b456b", - parentId: "695b13896108f765e8985698", - slotId: "1", - location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + _id: "bb9a34648e08f005db5d7484", + _tpl: "5cc9c20cd7f00c001336c65d", upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "15666fe6fd2d95206612e418", + slotId: "mod_tactical", }, { - _id: "696835b2badfb96623ea887c", - _tpl: "55d482194bdc2d1d4e8b456b", - parentId: "695b13896108f765e8985698", + _id: "dd9ac99d3ea4c9656221bcc9", + _tpl: "5cc9c20cd7f00c001336c65d", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "a54de8b9014eee71fdf1d01d", + slotId: "mod_tactical", + }, { + _id: "b22748de8da5f3c1362dd8e0", + _tpl: "5cc9c20cd7f00c001336c65d", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "c34555bc95a9a7a23150a36f", + slotId: "mod_tactical", + }, { + _id: "e3cc1be8954c4889f94b435a", + _tpl: "5cc9c20cd7f00c001336c65d", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "91cae4ae30d1366b87158238", + slotId: "mod_tactical", + }, { + _id: "e73f05be5a306168e847da82", + _tpl: "5cc9c20cd7f00c001336c65d", + parentId: "48f23df4509164cf397b9ab5", + slotId: "mod_tactical", + upd: { StackObjectsCount: 1 }, + }, { + _id: "847cf35ec92d8af8e4814ea8", + _tpl: "5c1cd46f2e22164bef5cfedb", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "a55f05f689978ac65c7da654", + slotId: "mod_foregrip", + }, { + _id: "bb4b7a4475fea0f0135305f6", + _tpl: "5cc9c20cd7f00c001336c65d", + parentId: "8ae4ea81a2d6074162d87a9c", + slotId: "mod_tactical", + upd: { StackObjectsCount: 1 }, + }, { + _id: "d0ac8e688a0bb17668589909", + _tpl: "5cc9c20cd7f00c001336c65d", + parentId: "312cc0f6687963305457235e", + slotId: "mod_tactical", + upd: { StackObjectsCount: 1 }, + }, { + _id: "5dbcf8cbbb3f8ef669836320", + _tpl: "5c793fc42e221600114ca25d", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "b65635b515712f990fdcc201", + slotId: "mod_stock", + }, { + _id: "f996645c809968f8033593a6", + _tpl: "5fc2369685fd526b824a5713", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5dbcf8cbbb3f8ef669836320", + slotId: "mod_stock_000", + }, { + _id: "7d959c20811fdc440387f0a4", + _tpl: "55d447bb4bdc2d892f8b456f", + parentId: "d45436a159654f43ca3aa52f", + slotId: "mod_barrel", + upd: {}, + }, { + _id: "16969c588bd20e223d93e65a", + _tpl: "611a31ce5b7ffe001b4649d1", + parentId: "d45436a159654f43ca3aa52f", + slotId: "mod_stock", + upd: {}, + }, { + _id: "d3a31aa632d852bfe57d7aca", + _tpl: "5a6b5f868dc32e000a311389", + parentId: "2c60ad9b6051f059ab796aa6", + slotId: "mod_barrel", + upd: {}, + }, { + _id: "fdba343644672594e7c73f47", + _tpl: "5a7b4960e899ef197b331a2d", + parentId: "2c60ad9b6051f059ab796aa6", + slotId: "mod_pistol_grip", + upd: {}, + }, { + _id: "5f47943e00d184b3c8f9c2b5", + _tpl: "5a6f5e048dc32e00094b97da", + parentId: "2c60ad9b6051f059ab796aa6", + slotId: "mod_reciever", + upd: {}, + }, { + _id: "f616853cb3b860d670252e66", + _tpl: "5a718b548dc32e000d46d262", + parentId: "2c60ad9b6051f059ab796aa6", + slotId: "mod_magazine", + upd: {}, + }, { + _id: "5153ee12f6d4abc4856dd4ae", + _tpl: "5a7ad74e51dfba0015068f45", + parentId: "2c60ad9b6051f059ab796aa6", + slotId: "mod_tactical", + upd: {}, + }, { + _id: "aa5dc438d849a311e335667b", + _tpl: "5a7d9122159bd4001438dbf4", + parentId: "5f47943e00d184b3c8f9c2b5", + slotId: "mod_sight_rear", + upd: {}, + }, { + _id: "79a1dfa8bff1b7ca118d6b0f", + _tpl: "5a7d90eb159bd400165484f1", + parentId: "5f47943e00d184b3c8f9c2b5", + slotId: "mod_sight_front", + upd: {}, + }, { + _id: "e784a6d774f9a885bf5ed847", + _tpl: "5a7b483fe899ef0016170d15", + parentId: "5153ee12f6d4abc4856dd4ae", + slotId: "mod_tactical", + upd: {}, + }, { + _id: "fd79789b0e394e2cc1299ab1", + _tpl: "5c5db6742e2216000f1b2852", + parentId: "5d2be23efb34d0d1da9d3701", + slotId: "1", + upd: { StackObjectsCount: 1 }, + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "a19f5e338bfd32f1c1f3fb73", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5d2be23efb34d0d1da9d3701", slotId: "2", location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, }, { - _id: "c2d5e23c7886e8ff02010731", - _tpl: "55d482194bdc2d1d4e8b456b", - parentId: "695b13896108f765e8985698", + _id: "9e709808929c226f7bdbf57a", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5d2be23efb34d0d1da9d3701", slotId: "3", location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, }, { - _id: "306de2f475a559610a4f6f1d", - _tpl: "55d482194bdc2d1d4e8b456b", - parentId: "695b13896108f765e8985698", + _id: "9fe70bf25a2db7f8c1b23502", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5d2be23efb34d0d1da9d3701", slotId: "4", location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, }, { - _id: "eb0445b49a97e84e27d47f3c", - _tpl: "5aa2ba71e5b5b000137b758f", - parentId: "695b13896108f765e8985698", + _id: "4519dc962deebb2dbfc9e70c", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5d2be23efb34d0d1da9d3701", + slotId: "5", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "a94275912f1cbcd483563916", + _tpl: "5c5db6742e2216000f1b2852", + parentId: "5d2be23efb34d0d1da9d3701", + slotId: "6", + upd: { StackObjectsCount: 1 }, + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "7f2ae8c0685bf3a2195185dd", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5d2be23efb34d0d1da9d3701", + slotId: "7", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "53a9f3dc5c08cbd02ff31b12", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5d2be23efb34d0d1da9d3701", + slotId: "8", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "e0ab45585b1a874dbaa68fb3", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5d2be23efb34d0d1da9d3701", + slotId: "9", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "3f66f7abde039a848f8b4cf0", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5d2be23efb34d0d1da9d3701", + slotId: "10", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "04a202a45f8a39b61a58a05a", + _tpl: "544a5caa4bdc2d1a388b4568", + parentId: "9f601faab37dcc58190898ac", + slotId: "main", + upd: { StackObjectsCount: 1 }, + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "d5f6e03c07ede944e89fb407", + _tpl: "6570e83223c1f638ef0b0ede", + parentId: "04a202a45f8a39b61a58a05a", + slotId: "Soft_armor_front", + upd: { Repairable: { Durability: 42, MaxDurability: 42 } }, + }, { + _id: "5433cbf0f07a68651e888c74", + _tpl: "6570e87c23c1f638ef0b0ee2", + parentId: "04a202a45f8a39b61a58a05a", + slotId: "Soft_armor_back", + upd: { Repairable: { Durability: 42, MaxDurability: 42 } }, + }, { + _id: "da91bed43f688a80b627ad4d", + _tpl: "6570e90b3a5689d85f08db97", + parentId: "04a202a45f8a39b61a58a05a", + slotId: "Groin", + upd: { Repairable: { Durability: 28, MaxDurability: 28 } }, + }, { + _id: "ad7f524f3de9ad544df8c0b8", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "9f601faab37dcc58190898ac", + slotId: "main", + location: { x: 3, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "0844cf6b7a89c13454b6e3db", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "9f601faab37dcc58190898ac", + slotId: "main", + location: { x: 4, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "c3f58f44366d0a06d29d66ba", + _tpl: "5a38e6bac4a2826c6e06d79b", + parentId: "9f601faab37dcc58190898ac", + slotId: "main", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + location: { x: 0, y: 4, r: "Horizontal", isSearched: true }, + }, { + _id: "d46e16faba780c68e0600532", + _tpl: "656fa0fb498d1b7e3e071d9c", + parentId: "9f601faab37dcc58190898ac", + slotId: "main", + upd: { StackObjectsCount: 1, Repairable: { Durability: 45, MaxDurability: 45 } }, + location: { x: 3, y: 2, r: "Horizontal", isSearched: true }, + }, { + _id: "26598f88d49198c4a0a9391c", + _tpl: "571a12c42459771f627b58a0", + parentId: "9f601faab37dcc58190898ac", + slotId: "main", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + location: { x: 3, y: 4, r: "Horizontal", isSearched: true }, + }, { + _id: "5ee8e16837809adc34caae00", + _tpl: "656f9fa0498d1b7e3e071d98", + parentId: "04a202a45f8a39b61a58a05a", + slotId: "Front_plate", + upd: { Repairable: { Durability: 50, MaxDurability: 50 } }, + }, { + _id: "de042f9ebf0fd9ad451033d4", + _tpl: "656f9fa0498d1b7e3e071d98", + parentId: "04a202a45f8a39b61a58a05a", + slotId: "Back_plate", + upd: { Repairable: { Durability: 50, MaxDurability: 50 } }, + }, { + _id: "03de471c2a3faa359aca7486", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "04a202a45f8a39b61a58a05a", + slotId: "1", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "091c85804613176da9478edd", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "04a202a45f8a39b61a58a05a", + slotId: "2", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "5482888e242a98ff154c0ee8", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "04a202a45f8a39b61a58a05a", + slotId: "3", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "3c8e206a2c2e9b0fee45b56b", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "04a202a45f8a39b61a58a05a", + slotId: "4", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "b2405216e5730f3511884a10", + _tpl: "5ea17ca01412a1425304d1c0", + parentId: "04a202a45f8a39b61a58a05a", slotId: "5", upd: { StackObjectsCount: 1 }, location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, }, { - _id: "fad89a5bdfd23e3248123346", - _tpl: "5fc5396e900b1d5091531e72", - parentId: "695b13896108f765e8985698", + _id: "7a0675280dbbad69ce592d74", + _tpl: "657f9a55c6679fefb3051e19", + parentId: "b2405216e5730f3511884a10", + slotId: "Helmet_top", + upd: { Repairable: { Durability: 24, MaxDurability: 24 } }, + }, { + _id: "c0c182942f54d3c183f0e179", + _tpl: "657f9a94ada5fadd1f07a589", + parentId: "b2405216e5730f3511884a10", + slotId: "Helmet_back", + upd: { Repairable: { Durability: 24, MaxDurability: 24 } }, + }, { + _id: "8ec4534a4fe96f89ea88c107", + _tpl: "5c165d832e2216398b5a7e36", + parentId: "04a202a45f8a39b61a58a05a", slotId: "6", - location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, upd: { StackObjectsCount: 1 }, - }, { - _id: "b16c2a938954cd69c687c51a", - _tpl: "5b4736b986f77405cb415c10", - parentId: "695b13896108f765e8985698", - slotId: "7", location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, }, { - _id: "a2b3019ac8d340eeb068d429", + _id: "0d91ed3d44881d33b1fd94ec", + _tpl: "5c5db6742e2216000f1b2852", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "04a202a45f8a39b61a58a05a", + slotId: "11", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "f7066fdfeefb29eca1d2dbeb", _tpl: "5ea18c84ecf1982c7712d9a2", - parentId: "695b13896108f765e8985698", - slotId: "10", - location: { x: 0, y: 0, r: "Vertical", isSearched: true }, - upd: { StackObjectsCount: 1, Repairable: { Durability: 29, MaxDurability: 33 } }, + upd: { StackObjectsCount: 1, Repairable: { Durability: 22, MaxDurability: 25 } }, + parentId: "b2405216e5730f3511884a10", + slotId: "mod_nvg", }, { - _id: "0b3c5d183e8b506d655f85c4", - _tpl: "644a3df63b0b6f03e101e065", - parentId: "fad89a5bdfd23e3248123346", - slotId: "mod_tactical", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, - }, { - _id: "757211a0b648fe27b0475ded", - _tpl: "59f8a37386f7747af3328f06", - parentId: "b16c2a938954cd69c687c51a", - slotId: "mod_foregrip", + _id: "ee0ec86e9608abe773175e3a", + _tpl: "5c0558060db834001b735271", + parentId: "f7066fdfeefb29eca1d2dbeb", + slotId: "mod_nvg", upd: { StackObjectsCount: 1 }, }, { - _id: "870a887c63ca30fb15736b3d", - _tpl: "62a1b7fbc30cfa1d366af586", - parentId: "bb49d6ceb3e87d8563a06455", - slotId: "main", - upd: { StackObjectsCount: 1 }, - location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, - }, { - _id: "f3de631a1bb2b74bd0160d9a", - _tpl: "5d6d3be5a4b9361bc73bc763", - parentId: "bb49d6ceb3e87d8563a06455", - slotId: "main", - location: { x: 5, y: 0, r: "Vertical", isSearched: true }, - upd: { StackObjectsCount: 1, Repairable: { Durability: 22.41, MaxDurability: 22.41 } }, - }, { - _id: "351180f3248d45c71cb2ebdc", - _tpl: "57c44b372459772d2b39b8ce", - parentId: "870a887c63ca30fb15736b3d", - slotId: "main", - location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, - }, { - _id: "7237f722106866f2df8dc8d1", - _tpl: "56e33680d2720be2748b4576", - parentId: "870a887c63ca30fb15736b3d", - slotId: "main", - location: { x: 0, y: 3, r: "Horizontal", isSearched: true }, - upd: { StackObjectsCount: 1 }, - }, { - _id: "d0cf00aff56ea520cdd94330", - _tpl: "57c44dd02459772d2e0ae249", - parentId: "351180f3248d45c71cb2ebdc", - slotId: "mod_muzzle", - upd: { StackObjectsCount: 1 }, - }, { - _id: "5119653b2c66d57ee219e26f", - _tpl: "57c44f4f2459772d2c627113", - parentId: "351180f3248d45c71cb2ebdc", - slotId: "mod_reciever", - upd: { StackObjectsCount: 1 }, - }, { - _id: "ed1ac0183a8af587110aa74e", - _tpl: "5a9e81fba2750c00164f6b11", - parentId: "351180f3248d45c71cb2ebdc", + _id: "0515d1e589fd626b504e59cd", + _tpl: "5a38ee51c4a282000c5a955c", + parentId: "c3f58f44366d0a06d29d66ba", slotId: "mod_magazine", - upd: { StackObjectsCount: 1 }, + upd: {}, }, { - _id: "310a7d1bb07ae0e522f3f8e3", - _tpl: "5a69a2ed8dc32e000d46d1f1", - parentId: "351180f3248d45c71cb2ebdc", - slotId: "mod_pistol_grip", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, - }, { - _id: "8a7e3489197b3b98126447fd", - _tpl: "6130ca3fd92c473c77020dbd", - parentId: "351180f3248d45c71cb2ebdc", - slotId: "mod_charge", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, - }, { - _id: "e818616e11ae07aa05388759", - _tpl: "5dff8db859400025ea5150d4", - parentId: "351180f3248d45c71cb2ebdc", - slotId: "mod_mount_000", - upd: { StackObjectsCount: 1 }, - }, { - _id: "768812984debf2756bece089", - _tpl: "57c44e7b2459772d28133248", - parentId: "d0cf00aff56ea520cdd94330", - slotId: "mod_sight_rear", - upd: { StackObjectsCount: 1 }, - }, { - _id: "67c610585ed668baf4604931", - _tpl: "59eb7ebe86f7740b373438ce", - parentId: "d0cf00aff56ea520cdd94330", - slotId: "mod_mount_000", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, - }, { - _id: "80e9dffa49bfe263ab0128c7", - _tpl: "6267c6396b642f77f56f5c1c", - parentId: "67c610585ed668baf4604931", - slotId: "mod_tactical_000", - upd: { StackObjectsCount: 1 }, - }, { - _id: "dee323443ce23ba8c54b9f1c", - _tpl: "5cc9c20cd7f00c001336c65d", - parentId: "67c610585ed668baf4604931", - slotId: "mod_tactical_001", - upd: { StackObjectsCount: 1 }, - }, { - _id: "3008088022dd55f1c99e5a32", - _tpl: "5c1cd46f2e22164bef5cfedb", - parentId: "67c610585ed668baf4604931", - slotId: "mod_foregrip", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, - }, { - _id: "71e9f8d005c72940d857fe64", - _tpl: "59d790f486f77403cb06aec6", - parentId: "80e9dffa49bfe263ab0128c7", - slotId: "mod_flashlight", - upd: { StackObjectsCount: 1 }, - }, { - _id: "8c610c6cc67115a5fc1662ff", - _tpl: "56eabf3bd2720b75698b4569", - parentId: "310a7d1bb07ae0e522f3f8e3", - slotId: "mod_stock_000", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, - }, { - _id: "9bf01177f0c1e346b2d65373", - _tpl: "58d2912286f7744e27117493", - parentId: "8c610c6cc67115a5fc1662ff", + _id: "cb30ae6f997a2e6d119f2186", + _tpl: "5a38ef1fc4a282000b1521f6", + parentId: "c3f58f44366d0a06d29d66ba", slotId: "mod_stock", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + upd: { Foldable: { Folded: true } }, }, { - _id: "7dd43ffa6e03c2da6cddc56e", - _tpl: "6171407e50224f204c1da3c5", - parentId: "e818616e11ae07aa05388759", - slotId: "mod_scope", - upd: { StackObjectsCount: 1 }, + _id: "be57a04835a8c1ae85811949", + _tpl: "5a38eecdc4a282329a73b512", + parentId: "cb30ae6f997a2e6d119f2186", + slotId: "mod_pistol_grip", + upd: {}, }, { - _id: "fa9da4ccf3630cb173c293f9", - _tpl: "5b3b99475acfc432ff4dcbee", - parentId: "7dd43ffa6e03c2da6cddc56e", - slotId: "mod_scope_000", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + _id: "fd6ef6e377e6280ca9386dbc", + _tpl: "571a26d524597720680fbe8a", + parentId: "26598f88d49198c4a0a9391c", + slotId: "mod_barrel", + upd: {}, }, { - _id: "6e2727806fb12e12123e9a57", - _tpl: "616554fe50224f204c1da2aa", - parentId: "7dd43ffa6e03c2da6cddc56e", - slotId: "mod_scope_001", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + _id: "5c40aff0d1c5d4f206123b83", + _tpl: "571a282c2459771fb2755a69", + parentId: "26598f88d49198c4a0a9391c", + slotId: "mod_pistol_grip", + upd: {}, }, { - _id: "2c868d4676adc934f897e9a7", - _tpl: "61605d88ffa6e502ac5e7eeb", - parentId: "7dd43ffa6e03c2da6cddc56e", - slotId: "mod_scope_002", - upd: { StackObjectsCount: 1 }, + _id: "34b2c7cf0f6b8f484411cebf", + _tpl: "571a29dc2459771fb2755a6a", + parentId: "26598f88d49198c4a0a9391c", + slotId: "mod_magazine", + upd: {}, }, { - _id: "1b159fdc14c350f8a4a7e19e", - _tpl: "58d39b0386f77443380bf13c", - parentId: "6e2727806fb12e12123e9a57", - slotId: "mod_scope", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + _id: "9932dd0e1339053e27d54a41", + _tpl: "654a4dea7c17dec2f50cc86a", + parentId: "f74d377063e65d350e0099be", + slotId: "Front_plate", + upd: { Repairable: { Durability: 50, MaxDurability: 50 } }, }, { - _id: "7691790ffc5290da292cab99", - _tpl: "61657230d92c473c770213d7", - parentId: "1b159fdc14c350f8a4a7e19e", - slotId: "mod_scope", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, - }, { - _id: "012a11e7dcb1280a1ab9d2f6", - _tpl: "618168b350224f204c1da4d8", - parentId: "7237f722106866f2df8dc8d1", - slotId: "main", - location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, - upd: { StackObjectsCount: 1 }, - }, { - _id: "38ca7415a458c4d22ba2f3c3", - _tpl: "6130c43c67085e45ef1405a1", - parentId: "012a11e7dcb1280a1ab9d2f6", - slotId: "mod_muzzle", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, - }, { - _id: "c5a0621ebf856ce1b0945efc", - _tpl: "61816fcad92c473c770215cc", - parentId: "012a11e7dcb1280a1ab9d2f6", - slotId: "mod_sight_front", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, - }, { - _id: "a74677b17c1c49edc002df9b", - _tpl: "5dfa3d2b0dee1b22f862eade", - parentId: "38ca7415a458c4d22ba2f3c3", - slotId: "mod_muzzle", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + _id: "0f69c261881206320d8f583d", + _tpl: "657b22485f444d6dff0c6c2f", + parentId: "f74d377063e65d350e0099be", + slotId: "Back_plate", + upd: { StackObjectsCount: 1, Repairable: { Durability: 4.681114, MaxDurability: 40 } }, }], }, { - scheduledTime: 1698945140, - traderId: "54cb57776803fa99248b456e", // Therapist - messageContent: { - templateId: "58fe0e3486f77471f772c3f2 2", - type: 8, - maxStorageTime: 518400, - text: "", - profileChangeEvents: [], - systemData: { date: "01.11.2023", time: "11:18", location: "factory4_day" }, - }, + scheduledTime: 1712896726, + traderId: "54cb57776803fa99248b456e", + maxStorageTime: 518400, + systemData: { date: "11.04.2024", time: "19:19", location: "factory4_day" }, + messageType: 8, + messageTemplateId: "58fe0e3486f77471f772c3f2 3", items: [{ - _id: "5ae1c2b99a0a339adc620148", - _tpl: "5cebec38d7f00c00110a652a", - parentId: "ad018df9da0cbf2726394ef1", - slotId: "mod_mount_000", - upd: { StackObjectsCount: 1 }, - }, { - _id: "30f4bcb87bcc4604e27c02c1", - _tpl: "5cc70146e4a949000d73bf6b", - parentId: "ad018df9da0cbf2726394ef1", - slotId: "mod_mount_001", - upd: { StackObjectsCount: 1 }, - }, { - _id: "ad018df9da0cbf2726394ef1", - _tpl: "5cc70102e4a949035e43ba74", - parentId: "3bc4ff5bd99f165dc75cbd25", - slotId: "main", - upd: { StackObjectsCount: 1 }, - location: { x: 3, y: 0, r: "Horizontal", isSearched: true }, - }, { - _id: "12c243bd6b3e486e61325f81", - _tpl: "5cc82d76e24e8d00134b4b83", - parentId: "5fe49444ae6628187a2e77b8", + _id: "5cfe91bfe022641c19bc8c60", + _tpl: "5aafa857e5b5b00018480968", + upd: { + StackObjectsCount: 1, + sptPresetId: "5ac4ad3686f774181345c3da", + Repairable: { Durability: 98.33, MaxDurability: 98.33 }, + }, + parentId: "d2b3b859f667d4fd8b35bc96", slotId: "hideout", - upd: { StackObjectsCount: 1, Repairable: { Durability: 99.93771, MaxDurability: 100 } }, }, { - _id: "760652d86ee78eed513e0ad7", - _tpl: "5ab8f39486f7745cd93a1cca", - parentId: "5fe49444ae6628187a2e77b8", + _id: "a5063619e7f4db123ca07fcc", + _tpl: "60db29ce99594040e04c4a27", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: { + FireMode: { FireMode: "single" }, + StackObjectsCount: 1, + Repairable: { Durability: 100, MaxDurability: 100 }, + }, + }, { + _id: "3702c30b6333e28d6a15d62c", + _tpl: "56e0598dd2720bb5668b45a6", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + }, { + _id: "387c9f2b44d2da266f856b31", + _tpl: "6571bde39837cc51b800c212", + parentId: "d2b3b859f667d4fd8b35bc96", slotId: "hideout", upd: { StackObjectsCount: 1 }, }, { - _id: "61ab4afefac354dfc64c7874", - _tpl: "5b432d215acfc4771e1c6624", - parentId: "5fe49444ae6628187a2e77b8", - slotId: "hideout", - upd: { StackObjectsCount: 1, Repairable: { Durability: 30, MaxDurability: 30 } }, - }, { - _id: "285e9d9ae196ae4e336cd04f", - _tpl: "5d5d87f786f77427997cfaef", - parentId: "5fe49444ae6628187a2e77b8", - slotId: "hideout", - upd: { StackObjectsCount: 1, Repairable: { Durability: 75, MaxDurability: 80 } }, - }, { - _id: "3bc4ff5bd99f165dc75cbd25", - _tpl: "5f5e467b0bc58666c37e7821", - parentId: "5fe49444ae6628187a2e77b8", + _id: "275f046ea1a7b40046cd54fa", + _tpl: "5b40e4035acfc47a87740943", + parentId: "d2b3b859f667d4fd8b35bc96", slotId: "hideout", upd: { StackObjectsCount: 1 }, }, { - _id: "6bf5d8ee81a3c9aec21bbbad", - _tpl: "5d5fca1ea4b93635fd598c07", - parentId: "5fe49444ae6628187a2e77b8", + _id: "f30858ff9924b1fe211dd1f7", + _tpl: "657f95bff92cd718b701550c", + parentId: "275f046ea1a7b40046cd54fa", + slotId: "Helmet_top", + upd: { Repairable: { Durability: 10.3212032, MaxDurability: 18 } }, + }, { + _id: "eec1072ac0cc44984e1ed43b", + _tpl: "657f9605f4c82973640b2358", + parentId: "275f046ea1a7b40046cd54fa", + slotId: "Helmet_back", + upd: { Repairable: { Durability: 13.3160009, MaxDurability: 18 } }, + }, { + _id: "b82495b01ad0bfe5dd7e864d", + _tpl: "5c0e746986f7741453628fe5", + parentId: "d2b3b859f667d4fd8b35bc96", slotId: "hideout", upd: { StackObjectsCount: 1 }, }, { - _id: "2371438cf809b5e483bf5d85", - _tpl: "5cc70093e4a949033c734312", - parentId: "12c243bd6b3e486e61325f81", + _id: "31531773990cd1aefa751db7", + _tpl: "6570df294cc0d2ab1e05ed74", + parentId: "b82495b01ad0bfe5dd7e864d", + slotId: "Soft_armor_front", + upd: { Repairable: { Durability: 31.0571022, MaxDurability: 35 } }, + }, { + _id: "eb8c6c7c671d2a2490454e7c", + _tpl: "6570df9c615f54368b04fca9", + parentId: "b82495b01ad0bfe5dd7e864d", + slotId: "Soft_armor_back", + upd: { Repairable: { Durability: 30.8, MaxDurability: 35 } }, + }, { + _id: "f9cc99048aa37c5a4a837ef9", + _tpl: "5ca20d5986f774331e7c9602", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: { StackObjectsCount: 1 }, + }, { + _id: "bd8a4a3783d80b81cc8655ee", + _tpl: "5aa2ba71e5b5b000137b758f", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: { StackObjectsCount: 1 }, + }, { + _id: "025748ec34dcd1bfb2529537", + _tpl: "5c0d32fcd174af02a1659c75", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: { StackObjectsCount: 1 }, + }, { + _id: "9c552e79f1ae38350afb3723", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5cfe91bfe022641c19bc8c60", slotId: "mod_magazine", - upd: { StackObjectsCount: 1 }, }, { - _id: "7f890346ea5b2cbc68c3170f", - _tpl: "5cc700b9e4a949000f0f0f25", - parentId: "12c243bd6b3e486e61325f81", + _id: "14cb5b7c9789876325670163", + _tpl: "5aaf8e43e5b5b00015693246", + parentId: "5cfe91bfe022641c19bc8c60", slotId: "mod_stock", - upd: { StackObjectsCount: 1 }, + upd: {}, }, { - _id: "12fb79a9c4929009ff8d89e1", - _tpl: "5cc700ede4a949033c734315", - parentId: "12c243bd6b3e486e61325f81", - slotId: "mod_reciever", - upd: { StackObjectsCount: 1 }, - }, { - _id: "d4c5274082ed716e19447f46", - _tpl: "5cc701d7e4a94900100ac4e7", - parentId: "12c243bd6b3e486e61325f81", + _id: "0e4c9e11000589751523a62c", + _tpl: "5addbac75acfc400194dbc56", + parentId: "5cfe91bfe022641c19bc8c60", slotId: "mod_barrel", upd: { StackObjectsCount: 1 }, }, { - _id: "d819dd4d2b13de10e9d6d805", - _tpl: "5cc6ea85e4a949000e1ea3c3", - parentId: "12c243bd6b3e486e61325f81", - slotId: "mod_charge", - upd: { StackObjectsCount: 1 }, - }, { - _id: "fc9a664cacc477c4e725a81a", - _tpl: "5cc700d4e4a949000f0f0f28", - parentId: "7f890346ea5b2cbc68c3170f", - slotId: "mod_stock_000", - upd: { StackObjectsCount: 1 }, - }, { - _id: "372891c593cf14e176b93ce2", - _tpl: "5cc7012ae4a949001252b43e", - parentId: "12fb79a9c4929009ff8d89e1", - slotId: "mod_mount_000", - upd: { StackObjectsCount: 1 }, - }, { - _id: "bd196435a57bdc433df1e49d", - _tpl: "5cc7012ae4a949001252b43e", - parentId: "12fb79a9c4929009ff8d89e1", - slotId: "mod_mount_001", - upd: { StackObjectsCount: 1 }, - }, { - _id: "ea3349d29797354d835c2192", - _tpl: "58491f3324597764bc48fa02", - parentId: "12fb79a9c4929009ff8d89e1", - slotId: "mod_scope", + _id: "a63cf65e9646a04944d18106", + _tpl: "5abcbb20d8ce87001773e258", upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5cfe91bfe022641c19bc8c60", + slotId: "mod_sight_rear", }, { - _id: "4ccf7c74ca7d2167deb0ae5c", - _tpl: "626becf9582c3e319310b837", - parentId: "372891c593cf14e176b93ce2", - slotId: "mod_tactical", - upd: { StackObjectsCount: 1 }, - }, { - _id: "adfd3640fc93daf21c721ca6", - _tpl: "5cc9c20cd7f00c001336c65d", - parentId: "bd196435a57bdc433df1e49d", - slotId: "mod_tactical", - upd: { StackObjectsCount: 1 }, - }, { - _id: "deeb36b1812790b0145d2532", - _tpl: "5a16badafcdbcb001865f72d", - parentId: "61ab4afefac354dfc64c7874", - slotId: "mod_equipment_000", - upd: { StackObjectsCount: 1, Repairable: { Durability: 12, MaxDurability: 25 } }, - }, { - _id: "4c0e0548df904c384569190c", - _tpl: "5ea058e01dbce517f324b3e2", - parentId: "61ab4afefac354dfc64c7874", - slotId: "mod_nvg", - upd: { StackObjectsCount: 1, Repairable: { Durability: 3, MaxDurability: 39 } }, - }, { - _id: "da82c293cabc705b30fef93a", - _tpl: "5a398ab9c4a282000c5a9842", - parentId: "61ab4afefac354dfc64c7874", + _id: "f67388e02546cd97c976d479", + _tpl: "5addbfe15acfc4001a5fc58b", + parentId: "5cfe91bfe022641c19bc8c60", slotId: "mod_mount", + upd: { StackObjectsCount: 1 }, + }, { + _id: "bed3b1a2f866e18743db2a63", + _tpl: "5addbfbb5acfc400194dbcf7", upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "14cb5b7c9789876325670163", + slotId: "mod_mount", }, { - _id: "b8fc94611def6e9ba534a8b3", - _tpl: "5a16b8a9fcdbcb00165aa6ca", - parentId: "4c0e0548df904c384569190c", - slotId: "mod_nvg", + _id: "821a4953b87f562b3f435fd7", + _tpl: "5649a2464bdc2d91118b45a8", upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "bed3b1a2f866e18743db2a63", + slotId: "mod_scope", }, { - _id: "20d6193c1f399e6326ebbc10", - _tpl: "5a16b93dfcdbcbcae6687261", - parentId: "b8fc94611def6e9ba534a8b3", - slotId: "mod_nvg", + _id: "24813deb9b9a6ec3ca8376ef", + _tpl: "5d10b49bd7ad1a1a560708b0", upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, - }, { - _id: "065c4f13b2bd8be266e1e809", - _tpl: "57235b6f24597759bf5a30f1", - parentId: "20d6193c1f399e6326ebbc10", - slotId: "mod_nvg", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 }, Togglable: { On: true } }, - }, { - _id: "1883b955ab202fa099809278", - _tpl: "57d17c5e2459775a5c57d17d", - parentId: "da82c293cabc705b30fef93a", - slotId: "mod_flashlight", - upd: { StackObjectsCount: 1 }, - }, { - _id: "e3c9e50ce31900c950b4ff6f", - _tpl: "5cc70093e4a949033c734312", - parentId: "285e9d9ae196ae4e336cd04f", - slotId: "1", - location: { x: 0, y: 0, r: "Vertical", isSearched: true }, - upd: { StackObjectsCount: 1 }, - }, { - _id: "193259b5eb848af4d036bee5", - _tpl: "5cc70093e4a949033c734312", - parentId: "285e9d9ae196ae4e336cd04f", - slotId: "2", - location: { x: 0, y: 0, r: "Vertical", isSearched: true }, - upd: { StackObjectsCount: 1 }, - }, { - _id: "f97ce69443f63bbe8f8097a7", - _tpl: "5cc70093e4a949033c734312", - parentId: "285e9d9ae196ae4e336cd04f", - slotId: "3", - location: { x: 0, y: 0, r: "Vertical", isSearched: true }, - upd: { StackObjectsCount: 1 }, - }, { - _id: "5d1c154a8abcfa934e477ac4", - _tpl: "5cc70093e4a949033c734312", - parentId: "285e9d9ae196ae4e336cd04f", - slotId: "4", - location: { x: 0, y: 0, r: "Vertical", isSearched: true }, - upd: { StackObjectsCount: 1 }, - }, { - _id: "289f7af841690c5388095477", - _tpl: "5cc70093e4a949033c734312", - parentId: "285e9d9ae196ae4e336cd04f", - slotId: "5", - location: { x: 0, y: 0, r: "Vertical", isSearched: true }, - upd: { StackObjectsCount: 1 }, - }, { - _id: "3e6d578165b61aef9865f677", - _tpl: "5cc70093e4a949033c734312", - parentId: "285e9d9ae196ae4e336cd04f", - slotId: "6", - location: { x: 0, y: 0, r: "Vertical", isSearched: true }, - upd: { StackObjectsCount: 1 }, - }, { - _id: "338682523f8504f97f84f3ab", - _tpl: "5cc70093e4a949033c734312", - parentId: "285e9d9ae196ae4e336cd04f", - slotId: "7", - location: { x: 0, y: 0, r: "Vertical", isSearched: true }, - upd: { StackObjectsCount: 1 }, - }, { - _id: "6d18ac01aa04b16e4f0d5d2f", - _tpl: "5cc70093e4a949033c734312", - parentId: "285e9d9ae196ae4e336cd04f", - slotId: "8", - location: { x: 0, y: 0, r: "Vertical", isSearched: true }, - upd: { StackObjectsCount: 1 }, - }, { - _id: "ac4ed54d61daa0c5219f8522", - _tpl: "5cc70093e4a949033c734312", - parentId: "285e9d9ae196ae4e336cd04f", - slotId: "9", - location: { x: 0, y: 0, r: "Vertical", isSearched: true }, - upd: { StackObjectsCount: 1 }, - }, { - _id: "2460460ef3d3df5c1ce07edb", - _tpl: "5cc70093e4a949033c734312", - parentId: "285e9d9ae196ae4e336cd04f", - slotId: "10", - location: { x: 0, y: 0, r: "Vertical", isSearched: true }, - upd: { StackObjectsCount: 1 }, - }, { - _id: "3aeb18aac0b532f34255f162", - _tpl: "5cc70146e4a949000d73bf6b", - parentId: "285e9d9ae196ae4e336cd04f", - slotId: "11", - upd: { StackObjectsCount: 1 }, - location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, - }, { - _id: "bdb46107abbf1d92edaaf14e", - _tpl: "6272379924e29f06af4d5ecb", - parentId: "3aeb18aac0b532f34255f162", + parentId: "bed3b1a2f866e18743db2a63", slotId: "mod_tactical", - upd: { StackObjectsCount: 1 }, }, { - _id: "0caadd8507a36d9ea871e88e", - _tpl: "5ab8f04f86f774585f4237d8", - parentId: "3bc4ff5bd99f165dc75cbd25", - slotId: "main", - location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, - upd: { StackObjectsCount: 1 }, + _id: "4194116ceb7e9e623cba4e89", + _tpl: "609bab8b455afd752b2e6138", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "821a4953b87f562b3f435fd7", + slotId: "mod_scope", }, { - _id: "240046eebc9040c1d7e58611", - _tpl: "5ac66d015acfc400180ae6e4", - parentId: "0caadd8507a36d9ea871e88e", - slotId: "main", - location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, - upd: { - StackObjectsCount: 1, - sptPresetId: "5acf7dfc86f774401e19c390", - Repairable: { Durability: 32, MaxDurability: 59 }, - Foldable: { Folded: true }, - }, - }, { - _id: "70b23c628fa17699d9a71e94", - _tpl: "59c6633186f7740cf0493bb9", - parentId: "240046eebc9040c1d7e58611", - slotId: "mod_gas_block", - upd: { - StackObjectsCount: 1, - sptPresetId: "5acf7dfc86f774401e19c390", - Repairable: { Durability: 32, MaxDurability: 59 }, - }, - }, { - _id: "7cc2e24dc6bc0716bdddc472", - _tpl: "5943ee5a86f77413872d25ec", - parentId: "240046eebc9040c1d7e58611", + _id: "3bd8b76ba1ff8f1cf954af91", + _tpl: "59bffc1f86f77435b128b872", + parentId: "0e4c9e11000589751523a62c", slotId: "mod_muzzle", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, - }, { - _id: "7a51ebbad703082660d59d27", - _tpl: "5649ade84bdc2d1b2b8b4587", - parentId: "240046eebc9040c1d7e58611", - slotId: "mod_pistol_grip", - upd: { - StackObjectsCount: 1, - sptPresetId: "5acf7dfc86f774401e19c390", - Repairable: { Durability: 32, MaxDurability: 59 }, - }, - }, { - _id: "b481bc57436ed9a0c3abe7f3", - _tpl: "5d2c76ed48f03532f2136169", - parentId: "240046eebc9040c1d7e58611", - slotId: "mod_reciever", upd: { StackObjectsCount: 1 }, }, { - _id: "5774ef80597c7f91bff40dbb", - _tpl: "5ac50c185acfc400163398d4", - parentId: "240046eebc9040c1d7e58611", - slotId: "mod_stock", - upd: { - StackObjectsCount: 1, - sptPresetId: "5acf7dfc86f774401e19c390", - Repairable: { Durability: 32, MaxDurability: 59 }, - }, + _id: "3d953b4a4283363d0494d614", + _tpl: "59bffbb386f77435b379b9c2", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "3bd8b76ba1ff8f1cf954af91", + slotId: "mod_muzzle", }, { - _id: "8b7c8e6ba172ac390c99a2ae", - _tpl: "5ac66c5d5acfc4001718d314", - parentId: "240046eebc9040c1d7e58611", + _id: "4b2c9fb752a7c3458e07a35d", + _tpl: "626bb8532c923541184624b4", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "f67388e02546cd97c976d479", + slotId: "mod_scope", + }, { + _id: "ce39864f056a3ad649d77243", + _tpl: "60dc519adf4c47305f6d410d", + parentId: "a5063619e7f4db123ca07fcc", slotId: "mod_magazine", - upd: { StackObjectsCount: 1 }, + upd: {}, }, { - _id: "1ed3a416b1fc7adbed1160df", - _tpl: "6130ca3fd92c473c77020dbd", - parentId: "240046eebc9040c1d7e58611", - slotId: "mod_charge", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + _id: "4ffc8f4e80708f6b9336c224", + _tpl: "612368f58b401f4f51239b33", + parentId: "a5063619e7f4db123ca07fcc", + slotId: "mod_barrel", + upd: {}, }, { - _id: "bbe087661947c0d9c1cde146", - _tpl: "5648b1504bdc2d9d488b4584", - parentId: "70b23c628fa17699d9a71e94", + _id: "b401a4ce551dfcb0602e4073", + _tpl: "612781056f3d944a17348d60", + parentId: "a5063619e7f4db123ca07fcc", + slotId: "mod_stock", + upd: {}, + }, { + _id: "b206761507a97037d05f0268", + _tpl: "6123649463849f3d843da7c4", + parentId: "a5063619e7f4db123ca07fcc", slotId: "mod_handguard", + upd: {}, + }, { + _id: "25af8615f5c902fd5920965f", + _tpl: "619d36da53b4d42ee724fae4", + parentId: "4ffc8f4e80708f6b9336c224", + slotId: "mod_muzzle", + upd: {}, + }, { + _id: "38c5e9751e1d69d4d0804a49", + _tpl: "5448c12b4bdc2d02308b456f", + parentId: "3702c30b6333e28d6a15d62c", + slotId: "mod_magazine", + upd: {}, + }, { + _id: "54da5dc9656bb9477eb16c88", + _tpl: "56e05b06d2720bb2668b4586", + parentId: "3702c30b6333e28d6a15d62c", + slotId: "mod_muzzle", + upd: {}, + }, { + _id: "ad690f7145984b942288457f", + _tpl: "56e05a6ed2720bd0748b4567", + parentId: "3702c30b6333e28d6a15d62c", + slotId: "mod_pistolgrip", + upd: {}, + }, { + _id: "c4ffff33f0a5f48c9500699a", + _tpl: "656fa0fb498d1b7e3e071d9c", + parentId: "b82495b01ad0bfe5dd7e864d", + slotId: "Front_plate", + upd: { Repairable: { Durability: 31.1713047, MaxDurability: 45 } }, + }, { + _id: "8453961a28b572039197e140", + _tpl: "656fa0fb498d1b7e3e071d9c", + parentId: "b82495b01ad0bfe5dd7e864d", + slotId: "Back_plate", + upd: { Repairable: { Durability: 32.4, MaxDurability: 45 } }, + }, { + _id: "43e7482d78b276a5db4f4fef", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "b82495b01ad0bfe5dd7e864d", + slotId: "1", + location: { x: 0, y: 1, r: "Horizontal", isSearched: true }, + }, { + _id: "7372a194a2de632f5941b701", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "b82495b01ad0bfe5dd7e864d", + slotId: "2", + location: { x: 0, y: 1, r: "Horizontal", isSearched: true }, + }, { + _id: "624555830937dfa5190a11bf", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "b82495b01ad0bfe5dd7e864d", + slotId: "3", + location: { x: 0, y: 1, r: "Horizontal", isSearched: true }, + }, { + _id: "05aedd00b683ce0d00ac5c74", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "b82495b01ad0bfe5dd7e864d", + slotId: "4", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "8c3eccca9f25989d68d90e59", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "b82495b01ad0bfe5dd7e864d", + slotId: "5", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "b8b2e1651d7dbb891053b514", + _tpl: "5aa7e454e5b5b0214e506fa2", + parentId: "b82495b01ad0bfe5dd7e864d", + slotId: "8", + upd: { StackObjectsCount: 1 }, + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "f9b891b8a5cf948b858a7b1b", + _tpl: "657f925dada5fadd1f07a57a", + parentId: "b8b2e1651d7dbb891053b514", + slotId: "Helmet_top", + upd: { Repairable: { Durability: 21, MaxDurability: 21 } }, + }, { + _id: "8b66bc46287219eb0e7c190d", + _tpl: "657f92acada5fadd1f07a57e", + parentId: "b8b2e1651d7dbb891053b514", + slotId: "Helmet_back", + upd: { Repairable: { Durability: 21, MaxDurability: 21 } }, + }, { + _id: "24cd31ecc0fdac526c8bd21d", + _tpl: "657f92e7f4c82973640b2354", + parentId: "b8b2e1651d7dbb891053b514", + slotId: "Helmet_ears", + upd: { Repairable: { Durability: 21, MaxDurability: 21 } }, + }, { + _id: "c6125558f051cd10cfaf77e0", + _tpl: "5d6d3716a4b9361bc8618872", + parentId: "b82495b01ad0bfe5dd7e864d", + slotId: "9", + upd: { StackObjectsCount: 1 }, + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "ee92a87a762b35b45f9d7fa7", + _tpl: "657fa009d4caf976440afe3a", + parentId: "c6125558f051cd10cfaf77e0", + slotId: "Helmet_top", + upd: { Repairable: { Durability: 33, MaxDurability: 33 } }, + }, { + _id: "be9a15c5ab850ae0437315bb", + _tpl: "657fa04ac6679fefb3051e24", + parentId: "c6125558f051cd10cfaf77e0", + slotId: "Helmet_back", + upd: { Repairable: { Durability: 33, MaxDurability: 33 } }, + }, { + _id: "65c9ceccbebe5f2813a8c70e", + _tpl: "657fa07387e11c61f70bface", + parentId: "c6125558f051cd10cfaf77e0", + slotId: "Helmet_ears", + upd: { Repairable: { Durability: 33, MaxDurability: 33 } }, + }, { + _id: "769eab07773ecfaa6e12e4c4", + _tpl: "5aa7e3abe5b5b000171d064d", + upd: { StackObjectsCount: 1, Repairable: { Durability: 50, MaxDurability: 50 }, Togglable: { On: true } }, + parentId: "b8b2e1651d7dbb891053b514", + slotId: "mod_equipment", + }, { + _id: "82aa530739c59be8dd5a0911", + _tpl: "5d6d3829a4b9361bc8618943", + upd: { StackObjectsCount: 1, Repairable: { Durability: 50, MaxDurability: 50 }, Togglable: { On: true } }, + parentId: "c6125558f051cd10cfaf77e0", + slotId: "mod_equipment_000", + }, { + _id: "996a6f0f8e90cb31f758c801", + _tpl: "5d6d3be5a4b9361bc73bc763", + upd: { StackObjectsCount: 1, Repairable: { Durability: 10, MaxDurability: 24 } }, + parentId: "c6125558f051cd10cfaf77e0", + slotId: "mod_equipment_001", + }, { + _id: "8c43cca672e16a931590945f", + _tpl: "5d6d3943a4b9360dbc46d0cc", + upd: { StackObjectsCount: 1, Repairable: { Durability: 1, MaxDurability: 1 } }, + parentId: "c6125558f051cd10cfaf77e0", + slotId: "mod_equipment_002", + }, { + _id: "5858b72da0ca732b2fb5ed95", + _tpl: "544a5caa4bdc2d1a388b4568", + parentId: "f9cc99048aa37c5a4a837ef9", + slotId: "main", + upd: { StackObjectsCount: 1 }, + location: { x: 0, y: 0, r: "Vertical", isSearched: true }, + }, { + _id: "43ef5a5e1c93ba3ab032811f", + _tpl: "6570e83223c1f638ef0b0ede", + parentId: "5858b72da0ca732b2fb5ed95", + slotId: "Soft_armor_front", + upd: { Repairable: { Durability: 42, MaxDurability: 42 } }, + }, { + _id: "e1f16c6d9e853f2735948665", + _tpl: "6570e87c23c1f638ef0b0ee2", + parentId: "5858b72da0ca732b2fb5ed95", + slotId: "Soft_armor_back", + upd: { Repairable: { Durability: 42, MaxDurability: 42 } }, + }, { + _id: "d9bdf684a8264ac1fb3208bf", + _tpl: "6570e90b3a5689d85f08db97", + parentId: "5858b72da0ca732b2fb5ed95", + slotId: "Groin", + upd: { Repairable: { Durability: 28, MaxDurability: 28 } }, + }, { + _id: "e4b484ba7209d770482732c8", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "f9cc99048aa37c5a4a837ef9", + slotId: "main", + location: { x: 0, y: 3, r: "Horizontal", isSearched: true }, + }, { + _id: "ddc3945694d52dcdae9cba4d", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "f9cc99048aa37c5a4a837ef9", + slotId: "main", + location: { x: 1, y: 3, r: "Horizontal", isSearched: true }, + }, { + _id: "59923cfba8be35031e5d95e6", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "f9cc99048aa37c5a4a837ef9", + slotId: "main", + location: { x: 2, y: 3, r: "Horizontal", isSearched: true }, + }, { + _id: "95cf47373df5c4f07f458a93", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "f9cc99048aa37c5a4a837ef9", + slotId: "main", + location: { x: 3, y: 3, r: "Horizontal", isSearched: true }, + }, { + _id: "98661f27ea826095d0cdd609", + _tpl: "656f9fa0498d1b7e3e071d98", + parentId: "5858b72da0ca732b2fb5ed95", + slotId: "Front_plate", + upd: { Repairable: { Durability: 50, MaxDurability: 50 } }, + }, { + _id: "525179b06d14baaddb2b04fb", + _tpl: "656f9fa0498d1b7e3e071d98", + parentId: "5858b72da0ca732b2fb5ed95", + slotId: "Back_plate", + upd: { Repairable: { Durability: 50, MaxDurability: 50 } }, + }, { + _id: "353638d16450339e40f5b5eb", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5858b72da0ca732b2fb5ed95", + slotId: "1", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "fa4a5c3e4e3c2f017e35eb1a", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5858b72da0ca732b2fb5ed95", + slotId: "2", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "7554a8ddb30e0306de7b7d80", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5858b72da0ca732b2fb5ed95", + slotId: "3", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "4c73b93f4d9f17a05a5782fa", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5858b72da0ca732b2fb5ed95", + slotId: "4", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "8ce190fcd2ffe5f1f9ad345a", + _tpl: "5aa7e4a4e5b5b000137b76f2", + parentId: "5858b72da0ca732b2fb5ed95", + slotId: "5", + upd: { StackObjectsCount: 1 }, + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "6607b1b9d73f83e559304208", + _tpl: "657f925dada5fadd1f07a57a", + parentId: "8ce190fcd2ffe5f1f9ad345a", + slotId: "Helmet_top", + upd: { Repairable: { Durability: 21, MaxDurability: 21 } }, + }, { + _id: "41912d06dac91585499c05a2", + _tpl: "657f92acada5fadd1f07a57e", + parentId: "8ce190fcd2ffe5f1f9ad345a", + slotId: "Helmet_back", + upd: { Repairable: { Durability: 21, MaxDurability: 21 } }, + }, { + _id: "db24f69de28bddd7f09b9c3e", + _tpl: "657f92e7f4c82973640b2354", + parentId: "8ce190fcd2ffe5f1f9ad345a", + slotId: "Helmet_ears", + upd: { Repairable: { Durability: 21, MaxDurability: 21 } }, + }, { + _id: "6c578731bc0c3f91c8089116", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5858b72da0ca732b2fb5ed95", + slotId: "6", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "aa7b1ce4897aa7e64309ce86", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5858b72da0ca732b2fb5ed95", + slotId: "6", + location: { x: 1, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "7e5e5dbe18de6aea779d904d", + _tpl: "5addccf45acfc400185c2989", + upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + parentId: "5858b72da0ca732b2fb5ed95", + slotId: "11", + location: { x: 0, y: 0, r: "Horizontal", isSearched: true }, + }, { + _id: "b50b5052892729841e26934f", + _tpl: "5aa7e3abe5b5b000171d064d", + upd: { StackObjectsCount: 1, Repairable: { Durability: 47, MaxDurability: 47 }, Togglable: { On: true } }, + parentId: "8ce190fcd2ffe5f1f9ad345a", + slotId: "mod_equipment", + }], +}, { + scheduledTime: 1712960777.6, + traderId: "54cb50c76803fa8b248b4571", + maxStorageTime: 345600, + systemData: { date: "11.04.2024", time: "19:30", location: "factory4_day" }, + messageType: 8, + messageTemplateId: "58fe0e4586f774728248ca13 4", + items: [{ + _id: "b29c463afe52421ba72b1816", + _tpl: "5aa7e3abe5b5b000171d064d", + upd: { StackObjectsCount: 1, Repairable: { Durability: 50, MaxDurability: 50 } }, + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + }, { + _id: "1813e676a1bceefd5424b4bb", + _tpl: "5ac7655e5acfc40016339a19", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: {}, + }, { + _id: "a58746a7e98ac16ba9105fc9", + _tpl: "5cf50850d7f00c056e24104c", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: {}, + }, { + _id: "70acf65d9944b19d17d92b19", + _tpl: "55d480c04bdc2d1d4e8b456a", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: {}, + }, { + _id: "e3a54ae66a2970372eee1888", + _tpl: "602e63fb6335467b0c5ac94d", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: {}, + }, { + _id: "a4b1cb12dc5ece274d348e2b", + _tpl: "6033749e88382f4fab3fd2c5", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: {}, + }, { + _id: "e3c2162f4001a0d6ed2a199d", + _tpl: "602f85fd9b513876d4338d9c", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: {}, + }, { + _id: "548a111c4e48fb058e7a5c09", + _tpl: "603372b4da11d6478d5a07ff", + parentId: "e3a54ae66a2970372eee1888", + slotId: "mod_barrel", + upd: {}, + }, { + _id: "d58db125fdd3f3b15a9798ca", + _tpl: "602e620f9b513876d4338d9a", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: {}, + }, { + _id: "f85ba56791757174e3447c55", + _tpl: "630764fea987397c0816d219", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: {}, + }, { + _id: "e3c409642a067f980ca168b7", + _tpl: "63075cc5962d0247b029dc2a", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: {}, + }, { + _id: "5ff60d8b2b61c9f20ee8e91b", + _tpl: "63076701a987397c0816d21b", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: {}, + }, { + _id: "b212acf3c8f09f48b4beaa0d", + _tpl: "5648a69d4bdc2ded0b8b457b", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: { StackObjectsCount: 1 }, + }], +}, { + scheduledTime: 1712920104.8, + traderId: "54cb57776803fa99248b456e", + maxStorageTime: 518400, + systemData: { date: "11.04.2024", time: "19:30", location: "factory4_day" }, + messageType: 8, + messageTemplateId: "58fe0e3486f77471f772c3f2 0", + items: [{ + _id: "203161dde59c5a2fdd362da9", + _tpl: "5aa7e4a4e5b5b000137b76f2", + upd: { StackObjectsCount: 1, sptPresetId: "657fa87fc6679fefb3051e32" }, + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + }, { + _id: "37c9968cfc4372c968f57c42", + _tpl: "657f925dada5fadd1f07a57a", + parentId: "203161dde59c5a2fdd362da9", + slotId: "Helmet_top", + upd: { Repairable: { Durability: 21, MaxDurability: 21 } }, + }, { + _id: "5517446f3cd41cf75d3a9cd2", + _tpl: "657f92acada5fadd1f07a57e", + parentId: "203161dde59c5a2fdd362da9", + slotId: "Helmet_back", + upd: { Repairable: { Durability: 21, MaxDurability: 21 } }, + }, { + _id: "0fdc8f25f7dfc61678cdef01", + _tpl: "657f92e7f4c82973640b2354", + parentId: "203161dde59c5a2fdd362da9", + slotId: "Helmet_ears", + upd: { Repairable: { Durability: 21, MaxDurability: 21 } }, + }, { + _id: "e2cba41b10edfc595e2bb574", + _tpl: "628b916469015a4e1711ed8d", + parentId: "6c5ef8a5fb3b88641420e9a0", + slotId: "mod_handguard", + upd: {}, + }, { + _id: "dd3aa187f853187198860933", + _tpl: "628b9be6cff66b70c002b14c", + parentId: "e2cba41b10edfc595e2bb574", + slotId: "mod_reciever", + upd: {}, + }, { + _id: "13d29ea647b01f0ecb774a54", + _tpl: "628b9471078f94059a4b9bfb", + parentId: "dd3aa187f853187198860933", + slotId: "mod_sight_rear", + upd: {}, + }, { + _id: "6c5ef8a5fb3b88641420e9a0", + _tpl: "628b8d83717774443b15e248", + parentId: "afcef56bf4fa36d0ec1f4166", + slotId: "mod_gas_block", + upd: {}, + }, { + _id: "7980e04a92db0858cb7f4bfa", + _tpl: "55d4ae6c4bdc2d8b2f8b456e", + parentId: "929c1577ba7390558c59d8a5", + slotId: "mod_stock", + upd: {}, + }, { + _id: "929c1577ba7390558c59d8a5", + _tpl: "628b9a40717774443b15e9f2", + parentId: "afcef56bf4fa36d0ec1f4166", + slotId: "mod_stock_000", + upd: {}, + }, { + _id: "afcef56bf4fa36d0ec1f4166", + _tpl: "628b5638ad252a16da6dd245", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", upd: { + FireMode: { FireMode: "single" }, StackObjectsCount: 1, - sptPresetId: "5acf7dfc86f774401e19c390", - Repairable: { Durability: 32, MaxDurability: 59 }, + Repairable: { Durability: 100, MaxDurability: 100 }, }, }, { - _id: "724388f8110434efccd79b3a", - _tpl: "544a3a774bdc2d3a388b4567", - parentId: "b481bc57436ed9a0c3abe7f3", - slotId: "mod_scope", + _id: "a94905f708670fca5de11e7e", + _tpl: "60339954d62c9b14ed777c06", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: { + FireMode: { FireMode: "single" }, + StackObjectsCount: 1, + Repairable: { Durability: 100, MaxDurability: 100 }, + }, + }, { + _id: "8f5ce6d3c7730240c3ae78ad", + _tpl: "602e71bd53a60014f9705bfa", + parentId: "a94905f708670fca5de11e7e", + slotId: "mod_pistol_grip", + upd: {}, + }, { + _id: "c320122de049da2880d0a235", + _tpl: "5a7ad2e851dfba0016153692", + parentId: "a94905f708670fca5de11e7e", + slotId: "mod_magazine", + upd: {}, + }, { + _id: "d2923c8984f26f68f01d20d7", + _tpl: "602e3f1254072b51b239f713", + parentId: "a94905f708670fca5de11e7e", + slotId: "mod_stock_001", + upd: {}, + }, { + _id: "ecd363cddbb5361670d531b0", + _tpl: "60337f5dce399e10262255d1", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: {}, + }, { + _id: "704c139d092f1bd3e3d18df2", + _tpl: "6034e3cb0ddce744014cb870", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: {}, + }, { + _id: "72bd97cb21996a2282ff7bcd", + _tpl: "630765cb962d0247b029dc45", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: {}, + }, { + _id: "44e3df51e01d5b23445fb95f", + _tpl: "630765777d50ff5e8a1ea718", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: {}, + }, { + _id: "1cb0900a4bd068b04ca05db1", + _tpl: "63088377b5cd696784087147", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, }, { - _id: "8581038b0f795618a3d26c94", - _tpl: "58d268fc86f774111273f8c2", - parentId: "724388f8110434efccd79b3a", - slotId: "mod_scope", - upd: { StackObjectsCount: 1, Repairable: { Durability: 100, MaxDurability: 100 } }, + _id: "379ca7cd56ebb1434bd89d62", + _tpl: "656f9d5900d62bcd2e02407c", + parentId: "eb3bbc6cb084a53ff48b672d", + slotId: "Front_plate", + upd: { Repairable: { Durability: 32.4841042, MaxDurability: 45 } }, + }, { + _id: "d700aaa1d7a15644f6b91dc7", + _tpl: "656f9d5900d62bcd2e02407c", + parentId: "eb3bbc6cb084a53ff48b672d", + slotId: "Back_plate", + upd: { Repairable: { Durability: 45, MaxDurability: 45 } }, + }, { + _id: "eb3bbc6cb084a53ff48b672d", + _tpl: "5b44d22286f774172b0c9de8", + parentId: "d2b3b859f667d4fd8b35bc96", + slotId: "hideout", + upd: { StackObjectsCount: 1 }, + }, { + _id: "6a3d83c5230d1779060e17a9", + _tpl: "65704de13e7bba58ea0285c8", + parentId: "eb3bbc6cb084a53ff48b672d", + slotId: "Soft_armor_front", + upd: { Repairable: { Durability: 37.4214172, MaxDurability: 56 } }, + }, { + _id: "9fba54de64b37902dd14b6e5", + _tpl: "65705c3c14f2ed6d7d0b7738", + parentId: "eb3bbc6cb084a53ff48b672d", + slotId: "Soft_armor_back", + upd: { Repairable: { Durability: 49.93156, MaxDurability: 56 } }, + }, { + _id: "2b534b3af5f240c625a77424", + _tpl: "65705c777260e1139e091408", + parentId: "eb3bbc6cb084a53ff48b672d", + slotId: "Soft_armor_left", + upd: { Repairable: { Durability: 12, MaxDurability: 12 } }, + }, { + _id: "e046688c9167ceaced5af3a7", + _tpl: "65705cb314f2ed6d7d0b773c", + parentId: "eb3bbc6cb084a53ff48b672d", + slotId: "soft_armor_right", + upd: { Repairable: { Durability: 12, MaxDurability: 12 } }, + }, { + _id: "6c612d370959e61b6c10b7bf", + _tpl: "65705cea4916448ae1050897", + parentId: "eb3bbc6cb084a53ff48b672d", + slotId: "Collar", + upd: { Repairable: { Durability: 14, MaxDurability: 14 } }, }], }]; diff --git a/project/tests/controllers/InsuranceController.test.ts b/project/tests/controllers/InsuranceController.test.ts index ba0cbed5..205d9160 100644 --- a/project/tests/controllers/InsuranceController.test.ts +++ b/project/tests/controllers/InsuranceController.test.ts @@ -122,9 +122,7 @@ describe("InsuranceController", () => // Verify that the correct methods were called. expect(mockGetProfile).toBeCalledTimes(1); - expect(mockLoggerDebug).toBeCalledWith( - `Found ${insuranceFixture.length} insurance packages in profile ${sessionID}`, - ); + expect(mockLoggerDebug).toBeCalledTimes(1); expect(insuredFiltered.length).toBe(insuranceFixture.length); }); @@ -147,9 +145,7 @@ describe("InsuranceController", () => // Verify that the correct methods were called. expect(mockGetProfile).toBeCalledTimes(1); - expect(mockLoggerDebug).toBeCalledWith( - `Found ${insuranceFixture.length} insurance packages in profile ${sessionID}`, - ); + expect(mockLoggerDebug).toBeCalledTimes(1); expect(insuredFiltered.length).toBe(insuranceFixture.length - 1); // Should be 1 less than the original fixture. }); @@ -173,9 +169,7 @@ describe("InsuranceController", () => // Verify that the correct methods were called. expect(mockGetProfile).toBeCalledTimes(1); - expect(mockLoggerDebug).toBeCalledWith( - `Found ${insuranceFixture.length} insurance packages in profile ${sessionID}`, - ); + expect(mockLoggerDebug).toBeCalledTimes(1); // Verify that the returned array is empty. expect(insuredFiltered.length).toBe(0); @@ -187,12 +181,14 @@ describe("InsuranceController", () => it("should log information about the insurance package", () => { const sessionId = "session-id"; + const numberOfItems = 666; // Spy on the logger.debug method. const mockLoggerDebug = vi.spyOn(insuranceController.logger, "debug"); + vi.spyOn(insuranceController, "countAllInsuranceItems").mockReturnValue(numberOfItems); vi.spyOn(insuranceController, "findItemsToDelete").mockImplementation(vi.fn()); vi.spyOn(insuranceController, "removeItemsFromInsurance").mockImplementation(vi.fn()); - vi.spyOn(insuranceController, "adoptOrphanedItems").mockImplementation(vi.fn()); + vi.spyOn(insuranceController.itemHelper, "adoptOrphanedItems").mockImplementation(vi.fn()); vi.spyOn(insuranceController, "sendMail").mockImplementation(vi.fn()); vi.spyOn(insuranceController, "removeInsurancePackageFromProfile").mockImplementation(vi.fn()); @@ -201,9 +197,7 @@ describe("InsuranceController", () => // Verify that the log was written. expect(mockLoggerDebug).toBeCalledWith( - `Processing ${insuranceFixture.length} insurance packages, which includes a total of ${ - insuranceController.countAllInsuranceItems(insuranceFixture) - } items, in profile ${sessionId}`, + `Processing ${insuranceFixture.length} insurance packages, which includes a total of ${numberOfItems} items, in profile ${sessionId}`, ); }); @@ -218,9 +212,8 @@ describe("InsuranceController", () => ); const mockRemoveItemsFromInsurance = vi.spyOn(insuranceController, "removeItemsFromInsurance") .mockImplementation(vi.fn()); - const mockAdoptOrphanedItems = vi.spyOn(insuranceController, "adoptOrphanedItems").mockImplementation( - vi.fn(), - ); + const mockAdoptOrphanedItems = vi.spyOn(insuranceController.itemHelper, "adoptOrphanedItems") + .mockImplementation(vi.fn()); const mockSendMail = vi.spyOn(insuranceController, "sendMail").mockImplementation(vi.fn()); const mockRemoveInsurancePackageFromProfile = vi.spyOn( insuranceController, @@ -295,12 +288,17 @@ describe("InsuranceController", () => it("should remove the specified insurance package from the profile", () => { const sessionID = "session-id"; - const packageToRemove = { date: "01.11.2023", time: "10:51", location: "factory4_day" }; + const packageToRemove = { + traderId: "54cb50c76803fa8b248b4571", + systemData: { date: "01.11.2023", time: "11:18", location: "factory4_day" }, + }; const profile = { insurance: [{ - messageContent: { systemData: { date: "01.11.2023", time: "11:18", location: "factory4_day" } }, - }, { // This one should be removed - messageContent: { systemData: { date: "01.11.2023", time: "10:51", location: "factory4_day" } }, + traderId: "54cb50c76803fa8b248b4571", + systemData: { date: "01.11.2023", time: "11:18", location: "factory4_day" }, + }, { + traderId: "54cb57776803fa99248b456e", + systemData: { date: "01.11.2023", time: "10:51", location: "factory4_day" }, }], }; @@ -312,20 +310,23 @@ describe("InsuranceController", () => // Verify that the specified insurance package was removed. expect(profile.insurance.length).toBe(1); - expect(profile.insurance[0].messageContent.systemData).toStrictEqual({ - date: "01.11.2023", - time: "11:18", - location: "factory4_day", - }); + expect(profile.insurance).toStrictEqual([{ + traderId: "54cb57776803fa99248b456e", + systemData: { date: "01.11.2023", time: "10:51", location: "factory4_day" }, + }]); }); it("should log a message indicating that the package was removed", () => { const sessionID = "session-id"; - const packageToRemove = { date: "01.11.2023", time: "10:51", location: "factory4_day" }; + const packageToRemove = { + traderId: "54cb50c76803fa8b248b4571", + systemData: { date: "01.11.2023", time: "11:18", location: "factory4_day" }, + }; const profile = { insurance: [{ - messageContent: { systemData: { date: "01.11.2023", time: "10:51", location: "factory4_day" } }, + traderId: "54cb50c76803fa8b248b4571", + systemData: { date: "01.11.2023", time: "11:18", location: "factory4_day" }, }], }; @@ -340,17 +341,24 @@ describe("InsuranceController", () => // Verify that the log was written. expect(mockLoggerDebug).toBeCalledWith( - `Removed insurance package with date: ${packageToRemove.date}, time: ${packageToRemove.time}, and location: ${packageToRemove.location} from profile ${sessionID}. Remaining packages: ${profile.insurance.length}`, + `Removed processed insurance package. Remaining packages: ${profile.insurance.length}`, ); }); it("should not remove any packages if the specified package is not found", () => { const sessionID = "session-id"; - const packageToRemove = { date: "01.11.2023", time: "10:51", location: "factory4_day" }; + const packageToRemove = { + traderId: "54cb50c76803fa8b248b4571", + systemData: { date: "01.11.2023", time: "11:25", location: "factory4_day" }, + }; const profile = { insurance: [{ - messageContent: { systemData: { date: "02.11.2023", time: "10:50", location: "factory4_night" } }, + traderId: "54cb50c76803fa8b248b4571", + systemData: { date: "01.11.2023", time: "11:18", location: "factory4_day" }, + }, { + traderId: "54cb57776803fa99248b456e", + systemData: { date: "01.11.2023", time: "10:51", location: "factory4_day" }, }], }; @@ -360,8 +368,8 @@ describe("InsuranceController", () => // Execute the method. insuranceController.removeInsurancePackageFromProfile(sessionID, packageToRemove); - // Verify that no packages were removed. - expect(profile.insurance.length).toBe(1); + // Verify that the specified insurance package was removed. + expect(profile.insurance.length).toBe(2); }); }); @@ -373,7 +381,10 @@ describe("InsuranceController", () => insurancePackage.items = []; // Execute the method. - const result = insuranceController.findItemsToDelete(insurancePackage); + const result = insuranceController.findItemsToDelete( + insuranceController.hashUtil.generate(), + insurancePackage, + ); // Verify that the result is correct. expect(result.size).toBe(0); @@ -387,7 +398,6 @@ describe("InsuranceController", () => const numberOfItems = insured.items.length; // Mock helper methods. - const mockPopulateItemsMap = vi.spyOn(insuranceController, "populateItemsMap"); const mockPopulateParentAttachmentsMap = vi.spyOn(insuranceController, "populateParentAttachmentsMap"); const mockIsAttachmentAttached = vi.spyOn(insuranceController.itemHelper, "isAttachmentAttached"); const mockProcessAttachments = vi.spyOn(insuranceController, "processAttachments").mockImplementation( @@ -405,12 +415,11 @@ describe("InsuranceController", () => vi.spyOn(insuranceController, "processRegularItems").mockImplementation(mockProcessRegularItems); // Execute the method. - const result = insuranceController.findItemsToDelete(insured); + const result = insuranceController.findItemsToDelete(insuranceController.hashUtil.generate(), insured); // Verify that the correct methods were called. - expect(mockPopulateItemsMap).toHaveBeenCalledTimes(1); expect(mockPopulateParentAttachmentsMap).toHaveBeenCalledTimes(1); - expect(mockIsAttachmentAttached).toHaveBeenCalledTimes(numberOfItems + 1); // Once for each item, plus once more + expect(mockIsAttachmentAttached).toHaveBeenCalled(); expect(mockProcessRegularItems).toHaveBeenCalledTimes(1); expect(mockProcessAttachments).not.toHaveBeenCalled(); @@ -426,7 +435,6 @@ describe("InsuranceController", () => const insured = insuranceFixture[0]; // Mock helper methods. - const mockPopulateItemsMap = vi.spyOn(insuranceController, "populateItemsMap"); const mockProcessRegularItems = vi.spyOn(insuranceController, "processRegularItems"); const mockProcessAttachments = vi.spyOn(insuranceController, "processAttachments"); @@ -440,10 +448,9 @@ describe("InsuranceController", () => ); // Execute the method. - const result = insuranceController.findItemsToDelete(insured); + const result = insuranceController.findItemsToDelete(insuranceController.hashUtil.generate(), insured); // Verify that the correct methods were called. - expect(mockPopulateItemsMap).toHaveBeenCalled(); expect(mockPopulateParentAttachmentsMap).toHaveBeenCalled(); expect(mockProcessRegularItems).not.toHaveBeenCalled(); expect(mockProcessAttachments).not.toHaveBeenCalled(); @@ -459,7 +466,6 @@ describe("InsuranceController", () => const numberOfItems = insured.items.length; // Mock helper methods. - const mockPopulateItemsMap = vi.spyOn(insuranceController, "populateItemsMap"); const mockPopulateParentAttachmentsMap = vi.spyOn(insuranceController, "populateParentAttachmentsMap"); // Add all items to the toDelete set. Not realistic, but it's fine for this test. @@ -481,10 +487,9 @@ describe("InsuranceController", () => vi.spyOn(insuranceController, "processAttachments").mockImplementation(mockProcessAttachments); // Execute the method. - const result = insuranceController.findItemsToDelete(insured); + const result = insuranceController.findItemsToDelete(insuranceController.hashUtil.generate(), insured); // Verify that the correct methods were called. - expect(mockPopulateItemsMap).toHaveBeenCalled(); expect(mockPopulateParentAttachmentsMap).toHaveBeenCalled(); expect(mockProcessRegularItems).toHaveBeenCalled(); expect(mockProcessAttachments).toHaveBeenCalled(); @@ -499,7 +504,6 @@ describe("InsuranceController", () => const insured = insuranceFixture[0]; // Mock helper methods. - const mockPopulateItemsMap = vi.spyOn(insuranceController, "populateItemsMap"); const mockPopulateParentAttachmentsMap = vi.spyOn(insuranceController, "populateParentAttachmentsMap"); // Don't add any items to the toDelete set. @@ -511,10 +515,9 @@ describe("InsuranceController", () => ); // Execute the method. - const result = insuranceController.findItemsToDelete(insured); + const result = insuranceController.findItemsToDelete(insuranceController.hashUtil.generate(), insured); // Verify that the correct methods were called. - expect(mockPopulateItemsMap).toHaveBeenCalled(); expect(mockPopulateParentAttachmentsMap).toHaveBeenCalled(); expect(mockProcessRegularItems).toHaveBeenCalled(); expect(mockProcessAttachments).toHaveBeenCalled(); @@ -551,7 +554,7 @@ describe("InsuranceController", () => vi.spyOn(insuranceController, "processAttachments").mockImplementation(mockProcessAttachments); // Execute the method. - const result = insuranceController.findItemsToDelete(insured); + const result = insuranceController.findItemsToDelete(insuranceController.hashUtil.generate(), insured); // Verify that the result is the correct size, and the size is logged. expect(result.size).toBe(numberOfItems); @@ -566,26 +569,54 @@ describe("InsuranceController", () => const insured = insuranceFixture[0]; // Generate the items map. - const itemsMap = insuranceController.populateItemsMap(insured); + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); // Execute the method. - const result = insuranceController.populateParentAttachmentsMap(insured, itemsMap); + const result = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); // Verify that the map is populated correctly. - expect(result.size).toBe(6); // There are 6 base-level items in this insurance package. + expect(result.size).toBe(9); // There are 9 base-level items in this insurance package. - const gun = result.get("911a0f04d5d9c7e239807ae0"); - expect(gun.length).toBe(7); // This AK has 7 attachments. + const gun = result.get("35111c9b72a87b6b7d95ad35"); + expect(gun.length).toBe(31); // This gun has 31 attachments. - // The attachments should be mapped to the AK properly... + // The attachments should be mapped to the gun properly... const validAttachmentTemplates = [ - "677c209ebb45445ebb42c405", - "4bd10f89836fd9f86aedcac1", - "8b1327270791b142ac341b03", - "da8cde1b3024c336f6e06152", - "bc041c0011d76f714b898400", - "9f8d7880a6e0a47a211ec5d3", - "db2ef9442178910eba985b51", + "7c42d3dce0ddbc4806bce48b", + "10b97872c5f4e0e1949a0369", + "a6cd9986dde4cabddcd2dce2", + "b65635b515712f990fdcc201", + "0e11045873efe3625695c1ae", + "94c4161abe8bf654fb986063", + "9b284ccfd0d535acec1ff58b", + "d730caa83a11fd01250a7261", + "24291c7bcf91e362adb6d68b", + "0d98fd0769cce8e473bbe540", + "11b174510f039e8217fbd202", + "c435230e530574b1d7c32300", + "15666fe6fd2d95206612e418", + "a54de8b9014eee71fdf1d01d", + "c34555bc95a9a7a23150a36f", + "91cae4ae30d1366b87158238", + "48f23df4509164cf397b9ab5", + "a55f05f689978ac65c7da654", + "8ae4ea81a2d6074162d87a9c", + "312cc0f6687963305457235e", + "e1e5aaf474b7282a52ac9a14", + "bb9a34648e08f005db5d7484", + "dd9ac99d3ea4c9656221bcc9", + "b22748de8da5f3c1362dd8e0", + "e3cc1be8954c4889f94b435a", + "e73f05be5a306168e847da82", + "847cf35ec92d8af8e4814ea8", + "bb4b7a4475fea0f0135305f6", + "d0ac8e688a0bb17668589909", + "5dbcf8cbbb3f8ef669836320", + "f996645c809968f8033593a6", ]; for (const value of validAttachmentTemplates) { @@ -594,64 +625,37 @@ describe("InsuranceController", () => } }); - it("should ignore gun accessories that cannot be modified in-raid", () => - { - const insured = insuranceFixture[0]; - - // Generate the items map. - const itemsMap = insuranceController.populateItemsMap(insured); - - // Execute the method. - const result = insuranceController.populateParentAttachmentsMap(insured, itemsMap); - - // Verify that the map is populated correctly. - expect(result.size).toBe(6); // There are 6 base-level items in this insurance package. - - const gun = result.get("911a0f04d5d9c7e239807ae0"); - expect(gun.length).toBe(7); // This AK has 7 valid attachments. - - // These are attachments for the AK, but they are not raid moddable, so they should not be mapped. - const invalidAttachmentTemplates = [ - "1e0b177df108c0c117028812", - "c9278dd8251e99578bf7a274", - "402b4086535a50ef7d9cef88", - "566335b3df586f34b47f5e35", - ]; - for (const value of invalidAttachmentTemplates) - { - // Verify that each template is not present in the array of attachments. - expect(gun.every((item) => item._id !== value)).toBe(true); - } - }); - it("should correctly map helmet to all of its attachments", () => { const insured = insuranceFixture[0]; // Generate the items map. - const itemsMap = insuranceController.populateItemsMap(insured); + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); // Execute the method. - const result = insuranceController.populateParentAttachmentsMap(insured, itemsMap); + const result = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); // Verify that the map is populated correctly. - expect(result.size).toBe(6); // There are 6 base-level items in this insurance package. + expect(result.size).toBe(9); // There are 9 base-level items in this insurance package. - const gun = result.get("3679078e05f5b14466d6a730"); - expect(gun.length).toBe(5); // This LShZ-2DTM has 5 valid attachments. + const helmet = result.get("b2405216e5730f3511884a10"); + expect(helmet.length).toBe(4); // This helmet has 2 valid attachments. - // The attachments should be mapped to the AK properly... + // The attachments should be mapped to the helmet properly... const validAttachmentTemplates = [ - "a2b0c716162c5e31ec28c55a", - "dc565f750342cb2d19eeda06", - "e9ff62601669d9e2ea9c2fbb", - "ac134d7cf6c9d8e25edd0015", - "22274b895ecc80d51c3cba1c", + "7a0675280dbbad69ce592d74", + "c0c182942f54d3c183f0e179", + "f7066fdfeefb29eca1d2dbeb", + "ee0ec86e9608abe773175e3a", ]; for (const value of validAttachmentTemplates) { // Verify that each template is present in the array of attachments. - expect(gun.some((item) => item._id === value)).toBe(true); + expect(helmet.some((item) => item._id === value)).toBe(true); } }); @@ -660,29 +664,41 @@ describe("InsuranceController", () => const insured = insuranceFixture[0]; // Generate the items map. - const itemsMap = insuranceController.populateItemsMap(insured); + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); // Execute the method. - const result = insuranceController.populateParentAttachmentsMap(insured, itemsMap); + const result = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); // Verify that the map is populated correctly. - expect(result.size).toBe(6); // There are 6 base-level items in this insurance package. + expect(result.size).toBe(9); // There are 9 base-level items in this insurance package. - const gun = result.get("351180f3248d45c71cb2ebdc"); - expect(insured.items.find((item) => item._id === "351180f3248d45c71cb2ebdc").slotId).toBe("main"); - expect(gun.length).toBe(14); // This AS VAL has 14 valid attachments. + const gun = result.get("26598f88d49198c4a0a9391c"); + expect(insured.items.find((item) => item._id === "26598f88d49198c4a0a9391c").slotId).toBe("main"); + expect(gun.length).toBe(3); }); it("should not map items that do not have a main-parent", () => { + // Remove regular items from the fixture. insuranceFixture = new ProfileInsuranceFactory().adjustPackageDates().removeRegularItems().get(); const insured = insuranceFixture[0]; // Generate the items map. - const itemsMap = insuranceController.populateItemsMap(insured); + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + + // Suppress warnings. + const mockLoggerWarning = vi.spyOn(insuranceController.logger, "warning").mockImplementation(vi.fn()); // Execute the method. - const result = insuranceController.populateParentAttachmentsMap(insured, itemsMap); + const result = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); // Verify that the map is populated correctly. expect(result.size).toBe(0); @@ -690,31 +706,92 @@ describe("InsuranceController", () => it("should log a warning when an item does not have a main-parent", () => { + // Remove regular items from the fixture. insuranceFixture = new ProfileInsuranceFactory().adjustPackageDates().removeRegularItems().get(); const insured = insuranceFixture[0]; // Generate the items map. - const itemsMap = insuranceController.populateItemsMap(insured); + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); // Suppress warnings. const mockLoggerWarning = vi.spyOn(insuranceController.logger, "warning").mockImplementation(vi.fn()); // Execute the method. - insuranceController.populateParentAttachmentsMap(insured, itemsMap); + insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); // Verify that the warning was logged. expect(mockLoggerWarning).toHaveBeenCalled(); }); }); + describe("removeNonModdableAttachments", () => + { + it("should return a Map where each parent item ID is mapped to only moddable attachments", () => + { + const insured = insuranceFixture[0]; + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); + + // Execute the method. + const result = insuranceController.removeNonModdableAttachments(parentAttachmentsMap, itemsMap); + + // Verify that the map is populated correctly. + for (const [parentId, attachments] of result) + { + for (const attachment of attachments) + { + // Verify that each attachment is moddable. + const attachmentParentItem = itemsMap.get(parentId); + expect(insuranceController.itemHelper.isRaidModdable(attachment, attachmentParentItem)).toBe(true); + } + } + }); + + it("should remove parents that do not have any moddable attachments", () => + { + const insured = insuranceFixture[0]; + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); + + // Mock isRaidModdable to return false for all attachments. + vi.spyOn(insuranceController.itemHelper, "isRaidModdable").mockReturnValue(false); + + // Execute the method. + const result = insuranceController.removeNonModdableAttachments(parentAttachmentsMap, itemsMap); + + // Verify that the map is now empty. + expect(result.size).toBe(0); + }); + }); + describe("processRegularItems", () => { it("should process regular items and their non-attachment children", () => { + // Remove attachment items from the fixture. insuranceFixture = new ProfileInsuranceFactory().adjustPackageDates().removeAttachmentItems().get(); + const insured = insuranceFixture[0]; const numberOfItems = insured.items.length; const toDelete = new Set(); + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); // Mock helper methods. const mockIsAttachmentAttached = vi.spyOn(insuranceController.itemHelper, "isAttachmentAttached"); @@ -727,11 +804,11 @@ describe("InsuranceController", () => const mockRollForDelete = vi.spyOn(insuranceController, "rollForDelete").mockReturnValue(true); // Execute the method. - insuranceController.processRegularItems(insured, toDelete); + insuranceController.processRegularItems(insured, toDelete, parentAttachmentsMap); // Verify that the correct methods were called. - expect(mockIsAttachmentAttached).toHaveBeenCalled(); - expect(mockFindAndReturnChildrenAsItems).toHaveBeenCalled(); + expect(mockIsAttachmentAttached).toHaveBeenCalledTimes(numberOfItems); + expect(mockFindAndReturnChildrenAsItems).not.toHaveBeenCalled(); expect(mockRollForDelete).toHaveBeenCalledTimes(numberOfItems); // Verify that all items were added to the toDelete set. @@ -742,6 +819,12 @@ describe("InsuranceController", () => { const insured = insuranceFixture[0]; const toDelete = new Set(); + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); // Mock isAttachmentAttached to return true for all items. vi.spyOn(insuranceController.itemHelper, "isAttachmentAttached").mockReturnValue(true); @@ -750,7 +833,7 @@ describe("InsuranceController", () => const mockRollForDelete = vi.spyOn(insuranceController, "rollForDelete").mockReturnValue(true); // Execute the method. - insuranceController.processRegularItems(insured, toDelete); + insuranceController.processRegularItems(insured, toDelete, parentAttachmentsMap); // Verify that a roll was not made for any items. expect(mockRollForDelete).not.toHaveBeenCalled(); @@ -761,20 +844,24 @@ describe("InsuranceController", () => it("should mark attachments for deletion when parent is marked for deletion", () => { - const itemHelper = container.resolve("ItemHelper"); - const insured = insuranceFixture[0]; const toDelete = new Set(); + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); // Mock rollForDelete to return true for all base-parent items. const mockRollForDelete = vi.fn((traderId, insuredItem) => { - return !itemHelper.isAttachmentAttached(insuredItem); + return !insuranceController.itemHelper.isAttachmentAttached(insuredItem); }); vi.spyOn(insuranceController, "rollForDelete").mockImplementation(mockRollForDelete); // Execute the method. - insuranceController.processRegularItems(insured, toDelete); + insuranceController.processRegularItems(insured, toDelete, parentAttachmentsMap); // Verify that all items were added to the toDelete set. expect(toDelete).toEqual(new Set(insured.items.map((item) => item._id))); @@ -786,44 +873,53 @@ describe("InsuranceController", () => it("should iterate over each parent item", () => { const insured = insuranceFixture[0]; - const itemsMap = insuranceController.populateItemsMap(insured); - const parentToAttachmentMap = insuranceController.populateParentAttachmentsMap(insured, itemsMap); const toDelete = new Set(); + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); // Mock helper methods. const mockProcessAttachmentByParent = vi.spyOn(insuranceController, "processAttachmentByParent"); // Execute the method. - insuranceController.processAttachments(parentToAttachmentMap, itemsMap, insured.traderId, toDelete); + insuranceController.processAttachments(parentAttachmentsMap, itemsMap, insured.traderId, toDelete); // Verify - expect(mockProcessAttachmentByParent).toHaveBeenCalledTimes(parentToAttachmentMap.size); + expect(mockProcessAttachmentByParent).toHaveBeenCalledTimes(parentAttachmentsMap.size); }); it("should log the name of each parent item", () => { - const itemHelper = container.resolve("ItemHelper"); - const insured = insuranceFixture[0]; - const itemsMap = insuranceController.populateItemsMap(insured); - const parentToAttachmentMap = insuranceController.populateParentAttachmentsMap(insured, itemsMap); const toDelete = new Set(); + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); // Mock helper methods. - const mockLoggerDebug = vi.spyOn(insuranceController.logger, "debug"); + const mockLoggerDebug = vi.spyOn(insuranceController.logger, "debug").mockImplementation(vi.fn()); + + // Mock processAttachmentByParent to prevent it from being called. + vi.spyOn(insuranceController, "processAttachmentByParent").mockImplementation(vi.fn()); // Execute the method. - insuranceController.processAttachments(parentToAttachmentMap, itemsMap, insured.traderId, toDelete); + insuranceController.processAttachments(parentAttachmentsMap, itemsMap, insured.traderId, toDelete); // Verify that the name of each parent item is logged. - for (const [parentId] of parentToAttachmentMap) + for (const [parentId] of parentAttachmentsMap) { const parentItem = itemsMap.get(parentId); if (parentItem) { - const expectedMessage = `Processing attachments for parent item: ${ - itemHelper.getItemName(parentItem._tpl) - }`; + const expectedMessage = `Processing attachments of parent "${ + insuranceController.itemHelper.getItemName(parentItem._tpl) + }":`; expect(mockLoggerDebug).toHaveBeenCalledWith(expectedMessage); } } @@ -835,9 +931,13 @@ describe("InsuranceController", () => it("should handle sorting, rolling, and deleting attachments by calling helper methods", () => { const insured = insuranceFixture[0]; - const itemsMap = insuranceController.populateItemsMap(insured); - const parentToAttachmentMap = insuranceController.populateParentAttachmentsMap(insured, itemsMap); - const attachments = parentToAttachmentMap.entries().next().value; + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); + const attachments = parentAttachmentsMap.entries().next().value; const toDelete = new Set(); // Mock helper methods. @@ -854,12 +954,16 @@ describe("InsuranceController", () => expect(mockAttachmentDeletionByValue).toHaveBeenCalled(); }); - it("should log attachment details and number of successful rolls", () => + it("should log attachment details and number of attachments to be deleted", () => { const insured = insuranceFixture[0]; - const itemsMap = insuranceController.populateItemsMap(insured); - const parentToAttachmentMap = insuranceController.populateParentAttachmentsMap(insured, itemsMap); - const attachments = parentToAttachmentMap.values().next().value; + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); + const attachments = parentAttachmentsMap.entries().next().value; const toDelete = new Set(); const successfulRolls = 4; @@ -873,7 +977,7 @@ describe("InsuranceController", () => // Verify that the logs were called/written. expect(mockLogAttachmentsDetails).toBeCalled(); - expect(mockLoggerDebug).toHaveBeenCalledWith(`Number of successful rolls: ${successfulRolls}`); + expect(mockLoggerDebug).toHaveBeenCalledWith(`Number of attachments to be deleted: ${successfulRolls}`); }); }); @@ -882,15 +986,20 @@ describe("InsuranceController", () => it("should sort the attachments array by maxPrice in descending order", () => { const insured = insuranceFixture[0]; - const itemsMap = insuranceController.populateItemsMap(insured); - const parentToAttachmentMap = insuranceController.populateParentAttachmentsMap(insured, itemsMap); - const attachments = parentToAttachmentMap.values().next().value; + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); + const attachments = parentAttachmentsMap.entries().next().value; + const attachmentCount = attachments.length; // Execute the method. const sortedAttachments = insuranceController.sortAttachmentsByPrice(attachments); - // Verify the length of the sorted attachments array - expect(sortedAttachments.length).toBe(5); + // Verify the length of the sorted attachments array is unchanged + expect(sortedAttachments.length).toBe(attachmentCount); // Verify that the attachments are sorted by maxPrice in descending order for (let i = 1; i < sortedAttachments.length; i++) @@ -902,20 +1011,22 @@ describe("InsuranceController", () => it("should place attachments with null maxPrice at the bottom of the sorted list", () => { const insured = insuranceFixture[0]; - const itemsMap = insuranceController.populateItemsMap(insured); - const parentToAttachmentMap = insuranceController.populateParentAttachmentsMap(insured, itemsMap); - const attachments = parentToAttachmentMap.values().next().value; - - // Set the maxPrice of the first two attachments to null. - vi.spyOn(insuranceController.itemHelper, "getItemMaxPrice").mockReturnValueOnce(null).mockReturnValueOnce( - null, + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, ); + const attachments = parentAttachmentsMap.entries().next().value; + + // Set the maxPrice of the first attachment to null. + vi.spyOn(insuranceController.itemHelper, "getItemMaxPrice").mockReturnValue(666).mockReturnValueOnce(null); // Execute the method. const sortedAttachments = insuranceController.sortAttachmentsByPrice(attachments); // Verify that the attachments with null maxPrice are at the bottom of the list - const nullPriceAttachments = sortedAttachments.slice(-2); + const nullPriceAttachments = sortedAttachments.slice(-1); for (const attachment of nullPriceAttachments) { expect(attachment.maxPrice).toBeNull(); @@ -947,8 +1058,8 @@ describe("InsuranceController", () => // Verify that logger.debug was called correctly. expect(loggerDebugSpy).toHaveBeenCalledTimes(2); - expect(loggerDebugSpy).toHaveBeenNthCalledWith(1, "Child Item - Name: Item 1, Max Price: 100"); - expect(loggerDebugSpy).toHaveBeenNthCalledWith(2, "Child Item - Name: Item 2, Max Price: 200"); + expect(loggerDebugSpy).toHaveBeenNthCalledWith(1, "Attachment 1: \"Item 1\" - Price: 100"); + expect(loggerDebugSpy).toHaveBeenNthCalledWith(2, "Attachment 2: \"Item 2\" - Price: 200"); }); it("should not log anything when there are no attachments", () => @@ -968,12 +1079,16 @@ describe("InsuranceController", () => describe("countSuccessfulRolls", () => { - it("should count the number of successful rolls based on the rollForDelete method", () => + it("should count the number of successful rolls made in the rollForDelete method", () => { const insured = insuranceFixture[0]; - const itemsMap = insuranceController.populateItemsMap(insured); - const parentToAttachmentMap = insuranceController.populateParentAttachmentsMap(insured, itemsMap); - const attachments = parentToAttachmentMap.values().next().value; + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); + const attachments = parentAttachmentsMap.values().next().value; // Mock rollForDelete to return true for the first two attachments. const mockRollForDelete = vi.spyOn(insuranceController, "rollForDelete").mockReturnValue(false) @@ -987,12 +1102,16 @@ describe("InsuranceController", () => expect(result).toBe(2); }); - it("should count the number of successful rolls based on the rollForDelete method", () => + it("should return zero if no successful rolls were made in the rollForDelete method", () => { const insured = insuranceFixture[0]; - const itemsMap = insuranceController.populateItemsMap(insured); - const parentToAttachmentMap = insuranceController.populateParentAttachmentsMap(insured, itemsMap); - const attachments = parentToAttachmentMap.values().next().value; + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); + const attachments = parentAttachmentsMap.values().next().value; // Mock rollForDelete to return false. const mockRollForDelete = vi.spyOn(insuranceController, "rollForDelete").mockReturnValue(false); @@ -1027,9 +1146,13 @@ describe("InsuranceController", () => it("should add the correct number of attachments to the toDelete set", () => { const insured = insuranceFixture[0]; - const itemsMap = insuranceController.populateItemsMap(insured); - const parentToAttachmentMap = insuranceController.populateParentAttachmentsMap(insured, itemsMap); - const attachments = parentToAttachmentMap.values().next().value; + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); + const attachments = parentAttachmentsMap.values().next().value; const successfulRolls = 2; const toDelete = new Set(); @@ -1044,9 +1167,13 @@ describe("InsuranceController", () => it("should not add any attachments to toDelete if successfulRolls is zero", () => { const insured = insuranceFixture[0]; - const itemsMap = insuranceController.populateItemsMap(insured); - const parentToAttachmentMap = insuranceController.populateParentAttachmentsMap(insured, itemsMap); - const attachments = parentToAttachmentMap.values().next().value; + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); + const attachments = parentAttachmentsMap.values().next().value; const successfulRolls = 0; const toDelete = new Set(); @@ -1061,9 +1188,13 @@ describe("InsuranceController", () => it("should add all attachments to toDelete if successfulRolls is greater than the number of attachments", () => { const insured = insuranceFixture[0]; - const itemsMap = insuranceController.populateItemsMap(insured); - const parentToAttachmentMap = insuranceController.populateParentAttachmentsMap(insured, itemsMap); - const attachments = parentToAttachmentMap.values().next().value; + const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items); + const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap( + insuranceController.hashUtil.generate(), + insured, + itemsMap, + ); + const attachments = parentAttachmentsMap.values().next().value; const successfulRolls = 999; const toDelete = new Set(); @@ -1134,125 +1265,10 @@ describe("InsuranceController", () => }); }); - describe("adoptOrphanedItems", () => - { - it("should adopt orphaned items by resetting them as base-level items", () => - { - // Get all of the items, so that we can dynamically find the hideout item. - const insured = insuranceFixture[0]; - const hideoutParentId = insuranceController.fetchHideoutItemParent(insured.items); - - // Manually set one of the items to be orphaned. - insured.items[0].parentId = "9999"; // Should not exist in the items array. - insured.items[0].slotId = "main"; // Should not be "hideout". - - // Iterate over the items and find an individual orphaned item. - const orphanedItem = insured.items.find((item) => - !insured.items.some((parent) => parent._id === item.parentId) - ); - - // Setup tests to verify that the orphaned item we added is in fact orphaned. - expect(orphanedItem.parentId).toBe(insured.items[0].parentId); - expect(orphanedItem.slotId).toBe(insured.items[0].slotId); - - // Execute the method. - insuranceController.adoptOrphanedItems(insured); - - // Verify that the orphaned items have been adopted. - expect(orphanedItem.parentId).toBe(hideoutParentId); - expect(orphanedItem.slotId).toBe("hideout"); - }); - - it("should not adopt items that are not orphaned", () => - { - const unmodified = insuranceFixture[0]; - - // Create a deep copy of the insured items array. - const insured = JSON.parse(JSON.stringify(insuranceFixture[0])); - - // Execute the method. - insuranceController.adoptOrphanedItems(insured); - - // Verify that the orphaned items have been adopted. - expect(insured).toStrictEqual(unmodified); - }); - - it("should remove location data from adopted items", () => - { - const insured = insuranceFixture[0]; - - // Manually set one of the items to be orphaned. - insured.items[0].parentId = "9999"; // Should not exist in the items array. - insured.items[0].slotId = "main"; // Should not be "hideout". - insured.items[0].location = { x: 1, y: 2, r: 3, isSearched: true }; // Should be removed. - - // Iterate over the items and find an individual orphaned item. - const orphanedItem = insured.items.find((item) => - !insured.items.some((parent) => parent._id === item.parentId) - ); - - // Setup tests to verify that the orphaned item we added is in fact orphaned. - expect(orphanedItem.parentId).toBe(insured.items[0].parentId); - expect(orphanedItem.slotId).toBe(insured.items[0].slotId); - - // Execute the method. - insuranceController.adoptOrphanedItems(insured); - - // Verify that the orphaned items have been adopted. - expect(orphanedItem).not.toHaveProperty("location"); - }); - }); - - describe("fetchHideoutItemParent", () => - { - it("should return the parentId value of an item that has a slotId of 'hideout'", () => - { - const insured = insuranceFixture[0]; - const hideoutParentId = insuranceController.fetchHideoutItemParent(insured.items); - - // Execute the method. - const result = insuranceController.fetchHideoutItemParent(insured.items); - - // Verify that the hideout item parentId is returned. - expect(result).toBe(hideoutParentId); - }); - - it("should return an empty string if no item with a slotId of 'hideout' could be found", () => - { - // Fetch a bunch of orphaned items that don't have a hideout parent. - const insuranceFixture = new ProfileInsuranceFactory().adjustPackageDates().removeRegularItems().get(); - const insured = insuranceFixture[0]; - - // Execute the method. - const result = insuranceController.fetchHideoutItemParent(insured.items); - - // Verify that the hideout item parentId is returned. - expect(result).toBe(""); - }); - - it("should log a warning if the base-level item does not exist", () => - { - // Fetch a bunch of orphaned items that don't have a hideout parent. - const insuranceFixture = new ProfileInsuranceFactory().adjustPackageDates().removeRegularItems().get(); - const insured = insuranceFixture[0]; - - // Spy on the logger. - const loggerWarningSpy = vi.spyOn(insuranceController.logger, "warning"); - - // Execute the method. - insuranceController.fetchHideoutItemParent(insured.items); - - // Verify that the hideout item parentId is returned. - expect(loggerWarningSpy).toHaveBeenCalled(); - }); - }); - describe("sendMail", () => { it("should send insurance failed message when no items are present", () => { - const traderHelper = container.resolve("TraderHelper"); - const insurance = insuranceFixture[0]; insurance.items = []; // Empty the items array const sessionID = "session-id"; @@ -1276,19 +1292,17 @@ describe("InsuranceController", () => // Verify that the insurance failed message was sent. expect(sendMessageSpy).toHaveBeenCalledWith( sessionID, - traderHelper.getTraderById(insurance.traderId), + insuranceController.traderHelper.getTraderById(insurance.traderId), MessageType.INSURANCE_RETURN, insuranceFailedTpl, insurance.items, - insurance.messageContent.maxStorageTime, - insurance.messageContent.systemData, + insurance.maxStorageTime, + insurance.systemData, ); }); it("should not send insurance failed message when items are present", () => { - const traderHelper = container.resolve("TraderHelper"); - const insurance = insuranceFixture[0]; const sessionID = "session-id"; const insuranceFailedTpl = "failed-message-template"; @@ -1311,12 +1325,12 @@ describe("InsuranceController", () => // Verify that the insurance failed message was not sent. expect(sendMessageSpy).toHaveBeenCalledWith( sessionID, - traderHelper.getTraderById(insurance.traderId), + insuranceController.traderHelper.getTraderById(insurance.traderId), MessageType.INSURANCE_RETURN, - insurance.messageContent.templateId, + insurance.messageTemplateId, insurance.items, - insurance.messageContent.maxStorageTime, - insurance.messageContent.systemData, + insurance.maxStorageTime, + insurance.systemData, ); }); }); @@ -1519,14 +1533,17 @@ describe("InsuranceController", () => expect(pmcData.InsuredItems.length).toBe(body.items.length); }); - it("should return the output with warnings if payment fails", () => + it("should update output with warnings if payment fails", () => { // Override the payMoney mock to simulate a payment failure with a warning. const expectedPayMoneyReturn = { - warnings: [{ index: 0, errmsg: "Not enough money to complete transaction", code: 500 }], + warnings: [{ index: 0, errmsg: "You broke.", code: 500 }], otherProperty: "property-value", }; - mockPayMoney.mockReturnValue(expectedPayMoneyReturn); + mockPayMoney.mockImplementation((pmcData, request, sessionID, output) => + { + output.warnings = expectedPayMoneyReturn.warnings; + }); // Execute the method. const response = insuranceController.insure(pmcData, body, sessionId); @@ -1542,10 +1559,13 @@ describe("InsuranceController", () => { // Override the payMoney mock to simulate a payment failure with a warning. const expectedPayMoneyReturn = { - warnings: [{ index: 0, errmsg: "Not enough money to complete transaction", code: 500 }], + warnings: [{ index: 0, errmsg: "You broke.", code: 500 }], otherProperty: "property-value", }; - mockPayMoney.mockReturnValue(expectedPayMoneyReturn); + mockPayMoney.mockImplementation((pmcData, request, sessionID, output) => + { + output.warnings = expectedPayMoneyReturn.warnings; + }); // Execute the method. insuranceController.insure(pmcData, body, sessionId); diff --git a/project/tests/generators/BotGenerator.test.ts b/project/tests/generators/BotGenerator.test.ts index 05d9f402..6562bcae 100644 --- a/project/tests/generators/BotGenerator.test.ts +++ b/project/tests/generators/BotGenerator.test.ts @@ -55,94 +55,157 @@ describe("BotGenerator", () => describe("generateBotNickname", () => { - it("should return single name `test` for non pscav assault bot name ", () => + it("should choose random firstname for non player scav assault bot", () => { + const botJsonTemplate = { firstName: ["one", "two"], lastName: [] }; + const botGenerationDetails = { isPlayerScav: false, isPmc: true, allPmcsHaveSameNameAsPlayer: false }; + const botRole = "assault"; + botGenerator.botConfig.chanceAssaultScavHasPlayerScavName = 0; const mockPlayerProfile = { Info: { Nickname: "Player Nickname", Level: 1 } }; - vi.spyOn(botGenerator.profileHelper, "getPmcProfile").mockReturnValue(mockPlayerProfile); - const botJsonTemplate = { firstName: ["test"], lastName: [] }; + const result = botGenerator.generateBotNickname(botJsonTemplate, botGenerationDetails, botRole); - const sessionId = "sessionId"; - const isPlayerScav = false; - const botRole = "assault"; - - const result = botGenerator.generateBotNickname(botJsonTemplate, isPlayerScav, botRole, sessionId); - expect(result).toBe("test"); + expect(result).toMatch(/(one|two)/); }); - it("should return `test assault` for non pscav assault bot with `showTypeInNickname` enabled ", () => + it("should choose random lastname for non player scav assault bot", () => { + const botJsonTemplate = { firstName: [], lastName: [["one", "two"]] }; + const botGenerationDetails = { isPlayerScav: false, isPmc: true, allPmcsHaveSameNameAsPlayer: false }; + const botRole = "assault"; + + botGenerator.botConfig.chanceAssaultScavHasPlayerScavName = 0; + + const mockPlayerProfile = { Info: { Nickname: "Player Nickname", Level: 1 } }; + vi.spyOn(botGenerator.profileHelper, "getPmcProfile").mockReturnValue(mockPlayerProfile); + + const result = botGenerator.generateBotNickname(botJsonTemplate, botGenerationDetails, botRole); + + expect(result).toMatch(/(one|two)/); + }); + + it("should choose random firstname and lastname for non player scav assault bot", () => + { + const botJsonTemplate = { firstName: ["first-one", "first-two"], lastName: [["last-one", "last-two"]] }; + const botGenerationDetails = { isPlayerScav: false, isPmc: true, allPmcsHaveSameNameAsPlayer: false }; + const botRole = "assault"; + + botGenerator.botConfig.chanceAssaultScavHasPlayerScavName = 0; + + const mockPlayerProfile = { Info: { Nickname: "Player Nickname", Level: 1 } }; + vi.spyOn(botGenerator.profileHelper, "getPmcProfile").mockReturnValue(mockPlayerProfile); + + const result = botGenerator.generateBotNickname(botJsonTemplate, botGenerationDetails, botRole); + + expect(result).toMatch(/first-(one|two) last-(one|two)/); + }); + + it("should choose random firstname for player scav assault bot", () => + { + const botJsonTemplate = { firstName: ["one", "two"], lastName: [] }; + const botGenerationDetails = { isPlayerScav: true, isPmc: false, allPmcsHaveSameNameAsPlayer: false }; + const botRole = "assault"; + + botGenerator.botConfig.chanceAssaultScavHasPlayerScavName = 0; + + const mockPlayerProfile = { Info: { Nickname: "Player Nickname", Level: 1 } }; + vi.spyOn(botGenerator.profileHelper, "getPmcProfile").mockReturnValue(mockPlayerProfile); + + const result = botGenerator.generateBotNickname(botJsonTemplate, botGenerationDetails, botRole); + + expect(result).toMatch(/(one|two)/); + }); + + it("should choose random lastname for player scav assault bot", () => + { + const botJsonTemplate = { firstName: [], lastName: [["one", "two"]] }; + const botGenerationDetails = { isPlayerScav: true, isPmc: false, allPmcsHaveSameNameAsPlayer: false }; + const botRole = "assault"; + + botGenerator.botConfig.chanceAssaultScavHasPlayerScavName = 0; + + const mockPlayerProfile = { Info: { Nickname: "Player Nickname", Level: 1 } }; + vi.spyOn(botGenerator.profileHelper, "getPmcProfile").mockReturnValue(mockPlayerProfile); + + const result = botGenerator.generateBotNickname(botJsonTemplate, botGenerationDetails, botRole); + + expect(result).toMatch(/(one|two)/); + }); + + it("should choose random firstname and lastname for player scav assault bot", () => + { + const botJsonTemplate = { firstName: ["first-one", "first-two"], lastName: [["last-one", "last-two"]] }; + const botGenerationDetails = { isPlayerScav: true, isPmc: false, allPmcsHaveSameNameAsPlayer: false }; + const botRole = "assault"; + + botGenerator.botConfig.chanceAssaultScavHasPlayerScavName = 0; + + const mockPlayerProfile = { Info: { Nickname: "Player Nickname", Level: 1 } }; + vi.spyOn(botGenerator.profileHelper, "getPmcProfile").mockReturnValue(mockPlayerProfile); + + const result = botGenerator.generateBotNickname(botJsonTemplate, botGenerationDetails, botRole); + + expect(result).toMatch(/first-(one|two) last-(one|two)/); + }); + + it("should append bot type to end of name when showTypeInNickname option is enabled ", () => + { + const botJsonTemplate = { firstName: ["firstname"], lastName: ["lastname"] }; + const botGenerationDetails = { isPlayerScav: false, isPmc: true, allPmcsHaveSameNameAsPlayer: false }; + const botRole = "assault"; + + botGenerator.botConfig.chanceAssaultScavHasPlayerScavName = 0; botGenerator.botConfig.showTypeInNickname = true; const mockPlayerProfile = { Info: { Nickname: "Player Nickname", Level: 1 } }; vi.spyOn(botGenerator.profileHelper, "getPmcProfile").mockReturnValue(mockPlayerProfile); - const botJsonTemplate = { firstName: ["test"], lastName: [] }; + const result = botGenerator.generateBotNickname(botJsonTemplate, botGenerationDetails, botRole); - const sessionId = "sessionId"; - const isPlayerScav = false; - const botRole = "assault"; - - const result = botGenerator.generateBotNickname(botJsonTemplate, isPlayerScav, botRole, sessionId); - expect(result).toBe("test assault"); + expect(result).toBe("firstname lastname assault"); }); - it("should return name `test Player` for bot with same name as player and `addPrefixToSameNamePMCAsPlayerChance` 100%", () => + it("should return name prefix for PMC bot with same name as player if allPmcsHaveSameNameAsPlayer is enabled", () => { + const botJsonTemplate = { firstName: ["player"], lastName: [] }; + const botGenerationDetails = { isPlayerScav: false, isPmc: true, allPmcsHaveSameNameAsPlayer: true }; + const botRole = "assault"; + botGenerator.botConfig.showTypeInNickname = false; botGenerator.pmcConfig.addPrefixToSameNamePMCAsPlayerChance = 100; - const mockPlayerProfile = { Info: { Nickname: "Player", Level: 1 } }; - vi.spyOn(botGenerator.profileHelper, "getPmcProfile").mockReturnValue(mockPlayerProfile); - vi.spyOn(botGenerator.localisationService, "getRandomTextThatMatchesPartialKey").mockReturnValue("test"); - - const botJsonTemplate = { firstName: ["Player"], lastName: [] }; - - const sessionId = "sessionId"; - const isPlayerScav = false; - const botRole = "assault"; - - const result = botGenerator.generateBotNickname(botJsonTemplate, isPlayerScav, botRole, sessionId); - expect(result).toBe("test Player"); - }); - - it("should return name `test` for player scav bot", () => - { - botGenerator.botConfig.chanceAssaultScavHasPlayerScavName = 100; - - const mockPlayerProfile = { Info: { Nickname: "Player", Level: 1 } }; + const mockPlayerProfile = { Info: { Nickname: "player", Level: 1 } }; vi.spyOn(botGenerator.profileHelper, "getPmcProfile").mockReturnValue(mockPlayerProfile); - const botJsonTemplate = { firstName: ["test"], lastName: [] }; + const getRandomTextThatMatchesPartialKeySpy = vi.spyOn( + (botGenerator as any).localisationService, + "getRandomTextThatMatchesPartialKey", + ).mockReturnValue("test"); - const sessionId = "sessionId"; - const isPlayerScav = true; - const botRole = "assault"; + const result = botGenerator.generateBotNickname(botJsonTemplate, botGenerationDetails, botRole); - const result = botGenerator.generateBotNickname(botJsonTemplate, isPlayerScav, botRole, sessionId); - expect(result).toBe("test"); + expect(getRandomTextThatMatchesPartialKeySpy).toHaveBeenCalled(); + expect(result).toBe("test player"); }); - it("should return name `test (usec)` for player scav bot", () => + it("should generate PMC name in brackets behind scav name when chanceAssaultScavHasPlayerScavName is enabled", () => { + const botJsonTemplate = { firstName: ["scav"], lastName: [] }; + const botGenerationDetails = { isPlayerScav: false, isPmc: true, allPmcsHaveSameNameAsPlayer: false }; + const botRole = "assault"; + botGenerator.botConfig.chanceAssaultScavHasPlayerScavName = 100; - botGenerator.databaseServer.getTables().bots.types.usec.firstName = ["usec"]; + botGenerator.databaseServer.getTables().bots.types.usec.firstName = ["player"]; botGenerator.databaseServer.getTables().bots.types.bear.firstName = []; const mockPlayerProfile = { Info: { Nickname: "Player", Level: 1 } }; vi.spyOn(botGenerator.profileHelper, "getPmcProfile").mockReturnValue(mockPlayerProfile); - const botJsonTemplate = { firstName: ["test"], lastName: [] }; - - const sessionId = "sessionId"; - const isPlayerScav = false; - const botRole = "assault"; - - const result = botGenerator.generateBotNickname(botJsonTemplate, isPlayerScav, botRole, sessionId); - expect(result).toBe("test (usec)"); + const result = botGenerator.generateBotNickname(botJsonTemplate, botGenerationDetails, botRole); + expect(result).toBe("scav (player)"); }); }); }); diff --git a/project/tests/generators/BotLevelGenerator.test.ts b/project/tests/generators/BotLevelGenerator.test.ts index 8d8815a6..1def6ee4 100644 --- a/project/tests/generators/BotLevelGenerator.test.ts +++ b/project/tests/generators/BotLevelGenerator.test.ts @@ -35,6 +35,7 @@ describe("BotLevelGenerator", () => side: "", playerLevel: 5, botRelativeLevelDeltaMax: 0, + botRelativeLevelDeltaMin: 0, botCountToGenerate: 0, botDifficulty: "", isPlayerScav: false, diff --git a/project/tests/helpers/HandbookHelper.test.ts b/project/tests/helpers/HandbookHelper.test.ts index 0747f1a7..9509a02f 100644 --- a/project/tests/helpers/HandbookHelper.test.ts +++ b/project/tests/helpers/HandbookHelper.test.ts @@ -88,10 +88,26 @@ describe("HandbookHelper", () => expect(result).toBe(0); }); - it("should return roughly 1380 roubles when given 10 euros ", () => + it("should lookup currency value and multiply the input by the value", () => { - const result = handbookHelper.inRUB(10, Money.EUROS); - expect(result).closeTo(1379, 10); + // Mock the getTemplatePrice method to return a value of 100 roubles + const getTemplatePriceSpy = vi.spyOn(handbookHelper, "getTemplatePrice").mockReturnValue(100); + + const result = handbookHelper.inRUB(5, Money.EUROS); + + expect(getTemplatePriceSpy).toHaveBeenCalled(); + expect(result).toBe(500); + }); + + it("should always return a whole number", () => + { + // Mock the getTemplatePrice method to return a value of 100 roubles + const getTemplatePriceSpy = vi.spyOn(handbookHelper, "getTemplatePrice").mockReturnValue(123.321); + + const result = handbookHelper.inRUB(12.21, Money.EUROS); + + expect(getTemplatePriceSpy).toHaveBeenCalled(); + expect(result).toBe(1506); }); }); diff --git a/project/tests/helpers/InRaidHelper.test.ts b/project/tests/helpers/InRaidHelper.test.ts index d13f2e91..b9bf02ad 100644 --- a/project/tests/helpers/InRaidHelper.test.ts +++ b/project/tests/helpers/InRaidHelper.test.ts @@ -3,7 +3,8 @@ import { container } from "tsyringe"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { InRaidHelper } from "@spt-aki/helpers/InRaidHelper"; -import { DatabaseServer } from "@spt-aki/servers/DatabaseServer"; + +import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; describe("InRaidHelper", () => { @@ -19,67 +20,32 @@ describe("InRaidHelper", () => vi.restoreAllMocks(); }); - describe("calculateFenceStandingChangeFromKills", () => + describe("resetSkillPointsEarnedDuringRaid", () => { - it("should return negative value when player kills 2 scavs as scav", () => + it("should reset PointsEarnedDuringSession for each skill in profile", () => { - const fenceStanding = 0; - const postRaidPlayerVictims = [{ Side: "Savage", Role: "assault" }, { Side: "Savage", Role: "assault" }]; // Kills + const mockProfile = { + Skills: { + Common: [ + { Id: "BotReload", Progress: 160.543, PointsEarnedDuringSession: 42, LastAccess: 1712633904 }, + { Id: "BotSound", Progress: 145.6547, PointsEarnedDuringSession: 42, LastAccess: 1712633904 }, + { + Id: "Endurance", + Progress: 223.951157, + PointsEarnedDuringSession: 42, + LastAccess: 1712633904, + }, + { Id: "Strength", Progress: 141.2618, PointsEarnedDuringSession: 42, LastAccess: 1712633904 }, + ], + }, + }; - const databaseServer = container.resolve("DatabaseServer"); - const scavStandingChangeOnKill = databaseServer.getTables().bots.types.assault.experience.standingForKill; + (inraidHelper as any).resetSkillPointsEarnedDuringRaid(mockProfile); - const result = inraidHelper.calculateFenceStandingChangeFromKills(fenceStanding, postRaidPlayerVictims); - expect(result).toBe(scavStandingChangeOnKill * postRaidPlayerVictims.length); // Scav rep loss times number of scav kills - expect(result).lessThan(0); - }); - - it("should return positive value when player kills 2 PMCs of different sides as scav", () => - { - const fenceStanding = 0; - const postRaidPlayerVictims = [{ Side: "Usec", Role: "sptUsec" }, { Side: "Bear", Role: "sptBear" }]; // Kills - - const databaseServer = container.resolve("DatabaseServer"); - const bearStandingChangeOnKill = databaseServer.getTables().bots.types.bear.experience.standingForKill; - const usecStandingChangeOnKill = databaseServer.getTables().bots.types.bear.experience.standingForKill; - - const result = inraidHelper.calculateFenceStandingChangeFromKills(fenceStanding, postRaidPlayerVictims); - expect(result).toBe(bearStandingChangeOnKill + usecStandingChangeOnKill); - expect(result).greaterThan(0); - }); - - it("should return negative value when player kills 1 PMC, 1 boss and 2 scavs as scav", () => - { - const fenceStanding = 0; - const postRaidPlayerVictims = [{ Side: "Usec", Role: "sptUsec" }, { Side: "savage", Role: "assault" }, { - Side: "savage", - Role: "bossBoar", - }, { Side: "savage", Role: "assault" }]; // Kills - - const databaseServer = container.resolve("DatabaseServer"); - const usecStandingChangeOnKill = databaseServer.getTables().bots.types.bear.experience.standingForKill; - const scavStandingChangeOnKill = databaseServer.getTables().bots.types.assault.experience.standingForKill; - const bossBoarStandingChangeOnKill = - databaseServer.getTables().bots.types.bossboar.experience.standingForKill; - - const result = inraidHelper.calculateFenceStandingChangeFromKills(fenceStanding, postRaidPlayerVictims); - expect(result).toBe( - usecStandingChangeOnKill + (scavStandingChangeOnKill * 2) + bossBoarStandingChangeOnKill, - ); - expect(result).lessThan(0); - }); - - it("should return 0 when player kills bot with undefined standing as scav", () => - { - const fenceStanding = 0; - const postRaidPlayerVictims = [{ Side: "savage", Role: "testRole" }]; // Kills - - // Fake getFenceStandingChangeForKillAsScav() returning null - vi.spyOn(inraidHelper, "getFenceStandingChangeForKillAsScav").mockReturnValueOnce(null).mockReturnValueOnce( - null, - ); - const result = inraidHelper.calculateFenceStandingChangeFromKills(fenceStanding, postRaidPlayerVictims); - expect(result).toBe(0); + for (const skill of mockProfile.Skills.Common) + { + expect(skill.PointsEarnedDuringSession).toBe(0); + } }); }); }); diff --git a/project/tests/helpers/ItemHelper.test.ts b/project/tests/helpers/ItemHelper.test.ts index 8e875727..a732ffe1 100644 --- a/project/tests/helpers/ItemHelper.test.ts +++ b/project/tests/helpers/ItemHelper.test.ts @@ -275,44 +275,6 @@ describe("ItemHelper", () => }); }); - describe("generateItemsFromStackSlot", () => - { - it("should generate valid StackSlot item for an AmmoBox", () => - { - const ammoBox = itemHelper.getItem("57372c89245977685d4159b1"); // "5.45x39mm BT gs ammo pack (30 pcs)" - const parentId = container.resolve("HashUtil").generate(); - - const result = itemHelper.generateItemsFromStackSlot(ammoBox[1], parentId); - - expect(result.length).toBe(1); - expect(result[0]._id).toBeDefined(); - expect(result[0]._tpl).toBe(ammoBox[1]._props.StackSlots[0]._props.filters[0].Filter[0]); - expect(result[0].parentId).toBe(parentId); - expect(result[0].slotId).toBe("cartridges"); - expect(result[0].location).toBe(0); - expect(result[0].upd.StackObjectsCount).toBe(ammoBox[1]._props.StackSlots[0]._max_count); - }); - - it("should log a warning if no IDs are found in Filter", () => - { - const ammoBox = itemHelper.getItem("57372c89245977685d4159b1"); // "5.45x39mm BT gs ammo pack (30 pcs)" - ammoBox[1]._props.StackSlots[0]._props.filters[0].Filter = []; // Empty the Filter array. - - const parentId = container.resolve("HashUtil").generate(); - - // Spy on the logger's warning method and mock its implementation to prevent it from being actually called. - const loggerWarningSpy = vi.spyOn((itemHelper as any).logger, "warning").mockImplementation(() => - {}); - - itemHelper.generateItemsFromStackSlot(ammoBox[1], parentId); - - expect(loggerWarningSpy).toHaveBeenCalled(); - - // Restore the original behavior - loggerWarningSpy.mockRestore(); - }); - }); - describe("getItems", () => { it("should call databaseServer.getTables() and jsonUtil.clone() methods", () => @@ -451,12 +413,16 @@ describe("ItemHelper", () => const itemId = container.resolve("HashUtil").generate(); const item: Item = { _id: itemId, - _tpl: "5b40e1525acfc4771e1c6611", // "HighCom Striker ULACH IIIA helmet (Black)" + _tpl: "5b40e1525acfc4771e1c6611", upd: { Repairable: { Durability: 19, MaxDurability: 38 } }, }; + const getRepairableItemQualityValueSpt = vi.spyOn(itemHelper as any, "getRepairableItemQualityValue") + .mockReturnValue(0.5); + const result = itemHelper.getItemQualityModifier(item); + expect(getRepairableItemQualityValueSpt).toHaveBeenCalled(); expect(result).toBe(0.5); }); @@ -556,40 +522,7 @@ describe("ItemHelper", () => describe("getRepairableItemQualityValue", () => { - it("should return the correct quality value for armor items", () => - { - const armor = itemHelper.getItem("5648a7494bdc2d9d488b4583")[1]; // "PACA Soft Armor" - const repairable: Repairable = { Durability: 25, MaxDurability: 50 }; - const item: Item = { // Not used for armor, but required for the method. - _id: "", - _tpl: "", - }; - - // Cast the method to any to allow access to private/protected method. - const result = (itemHelper as any).getRepairableItemQualityValue(armor, repairable, item); - - expect(result).toBe(0.5); - }); - - it("should not use the Repairable MaxDurability property for armor", () => - { - const armor = itemHelper.getItem("5648a7494bdc2d9d488b4583")[1]; // "PACA Soft Armor" - const repairable: Repairable = { - Durability: 25, - MaxDurability: 1000, // This should be ignored. - }; - const item: Item = { // Not used for armor, but required for the method. - _id: "", - _tpl: "", - }; - - // Cast the method to any to allow access to private/protected method. - const result = (itemHelper as any).getRepairableItemQualityValue(armor, repairable, item); - - expect(result).toBe(0.5); - }); - - it("should return the correct quality value for weapon items", () => + it("should return the correct quality value", () => { const weapon = itemHelper.getItem("5a38e6bac4a2826c6e06d79b")[1]; // "TOZ-106 20ga bolt-action shotgun" const repairable: Repairable = { Durability: 50, MaxDurability: 100 }; @@ -601,7 +534,7 @@ describe("ItemHelper", () => expect(result).toBe(Math.sqrt(0.5)); }); - it("should fall back to using Repairable MaxDurability for weapon items", () => + it("should fall back to using Repairable MaxDurability", () => { const weapon = itemHelper.getItem("5a38e6bac4a2826c6e06d79b")[1]; // "TOZ-106 20ga bolt-action shotgun" weapon._props.MaxDurability = undefined; // Remove the MaxDurability property. @@ -941,6 +874,74 @@ describe("ItemHelper", () => }); }); + describe("adoptOrphanedItems", () => + { + it("should adopt orphaned items by resetting them as base-level items", () => + { + const rootId = "root-id"; + const items = [ + { _id: "first-id", _tpl: "anything1", parentId: "does-not-exist", slotId: "main" }, + { _id: "second-id", _tpl: "anything2", parentId: "first-id", slotId: "slot-id" }, + { _id: "third-id", _tpl: "anything3", parentId: "second-id", slotId: "slot-id" }, + { _id: "forth-id", _tpl: "anything4", parentId: "third-id", slotId: "slot-id" }, + ]; + + // Iterate over the items and find the individual orphaned item. + const orphanedItem = items.find((item) => !items.some((parent) => parent._id === item.parentId)); + + // Setup tests to verify that the orphaned item is in fact orphaned. + expect(orphanedItem.parentId).toBe(items[0].parentId); + expect(orphanedItem.slotId).toBe(items[0].slotId); + + // Execute the method. + (itemHelper as any).adoptOrphanedItems(rootId, items); + + // Verify that the orphaned items have been adopted. + expect(orphanedItem.parentId).toBe(rootId); + expect(orphanedItem.slotId).toBe("hideout"); + }); + + it("should not adopt items that are not orphaned", () => + { + const rootId = "root-id"; + const items = [ + { _id: "first-id", _tpl: "anything1", parentId: rootId, slotId: "hideout" }, + { _id: "second-id", _tpl: "anything2", parentId: "first-id", slotId: "slot-id" }, + { _id: "third-id", _tpl: "anything3", parentId: "second-id", slotId: "slot-id" }, + { _id: "forth-id", _tpl: "anything4", parentId: "third-id", slotId: "slot-id" }, + ]; + + // Execute the method. + const adopted = (itemHelper as any).adoptOrphanedItems(rootId, items); + + // Verify that the orphaned items have been adopted. + expect(adopted).toStrictEqual(items); + }); + + it("should remove location data from adopted items", () => + { + const rootId = "root-id"; + const items = [ + { + _id: "first-id", + _tpl: "anything1", + parentId: "does-not-exist", + slotId: "main", + location: { x: 1, y: 2, r: 3, isSearched: true }, // Should be removed. + }, + { _id: "second-id", _tpl: "anything2", parentId: "first-id", slotId: "slot-id" }, + { _id: "third-id", _tpl: "anything3", parentId: "second-id", slotId: "slot-id" }, + { _id: "forth-id", _tpl: "anything4", parentId: "third-id", slotId: "slot-id" }, + ]; + + // Execute the method. + (itemHelper as any).adoptOrphanedItems(rootId, items); + + // Verify that the location property has been removed. + expect(items).not.toHaveProperty("location"); + }); + }); + describe("splitStack", () => { it("should return array of two items when provided item over its natural stack size limit", () => diff --git a/project/tests/services/ItemBaseClassService.test.ts b/project/tests/services/ItemBaseClassService.test.ts index eee0d619..1fedba8d 100644 --- a/project/tests/services/ItemBaseClassService.test.ts +++ b/project/tests/services/ItemBaseClassService.test.ts @@ -42,23 +42,23 @@ describe("ItemBaseClassService", () => it("should return false when the base item type is passed in", () => { // Remove item from base cache - const result = itemBaseClassService.itemHasBaseClass("54009119af1c881c07000029", []); // "Base item" + const result = itemBaseClassService.itemHasBaseClass("54009119af1c881c07000029", []); expect(result).toBe(false); }); - it("should return true when an item is passed in", () => + it("should return true when a med item is passed in with the meds base class", () => { const salewaTpl = "544fb45d4bdc2dee738b4568"; // Remove item from base cache delete itemBaseClassService.itemBaseClassesCache[salewaTpl]; - const result = itemBaseClassService.itemHasBaseClass(salewaTpl, ["543be5664bdc2dd4348b4569"]); // "Meds" type + const result = itemBaseClassService.itemHasBaseClass(salewaTpl, ["543be5664bdc2dd4348b4569"]); expect(result).toBe(true); }); - it("should return true when an item and 2 matching base classes are passed in", () => + it("should return true when an item and two matching base classes are passed in", () => { const salewaTpl = "544fb45d4bdc2dee738b4568"; @@ -67,7 +67,7 @@ describe("ItemBaseClassService", () => const result = itemBaseClassService.itemHasBaseClass(salewaTpl, [ "543be5664bdc2dd4348b4569", "54009119af1c881c07000029", - ]); // "Meds" and "Item" type + ]); // "Meds" and "Item" base classes expect(result).toBe(true); }); @@ -84,15 +84,28 @@ describe("ItemBaseClassService", () => delete itemBaseClassService.itemBaseClassesCache[salewaTpl]; // Perform check - const result = itemBaseClassService.itemHasBaseClass(salewaTpl, ["543be5664bdc2dd4348b4569"]); // "Meds" type + const result = itemBaseClassService.itemHasBaseClass(salewaTpl, ["543be5664bdc2dd4348b4569"]); expect(result).toBe(true); expect(hydrateItemBaseClassCacheSpy).toHaveBeenCalled(); }); - it("should throw an exception when an invalid item is passed in", () => + it("should return false for any item template ID that does not exist", () => { - expect(() => itemBaseClassService.itemHasBaseClass("fakeTpl", ["543be5664bdc2dd4348b4569"])).toThrowError(); + const result = itemBaseClassService.itemHasBaseClass("not-a-valid-template-id", [ + "543be5664bdc2dd4348b4569", + ]); + + expect(result).toBe(false); + }); + + it("should return false for any item template ID without the Item type ", () => + { + const result = itemBaseClassService.itemHasBaseClass("54009119af1c881c07000029", [ + "543be5664bdc2dd4348b4569", + ]); + + expect(result).toBe(false); }); }); diff --git a/project/tests/services/PaymentService.test.ts b/project/tests/services/PaymentService.test.ts index cea1dae3..9f97f17c 100644 --- a/project/tests/services/PaymentService.test.ts +++ b/project/tests/services/PaymentService.test.ts @@ -71,48 +71,50 @@ describe("PaymentService", () => const itemEventRouterResponse = { warnings: [], - profileChanges: { sessionID: { _id: sessionID, items: { new: [], change: [], del: [] } } }, + profileChanges: { [sessionID]: { _id: sessionID, items: { new: [], change: [], del: [] } } }, } as unknown as IItemEventRouterResponse; // Mock the logger debug method to return void. - vi.spyOn((paymentService as any).logger, "debug").mockImplementation(() => - {}); + vi.spyOn((paymentService as any).logger, "debug").mockResolvedValue(undefined); // Mock the trader helper to return a trader with the currency of Roubles. - const traderHelperGetTraderSpy = vi.spyOn((paymentService as any).traderHelper, "getTrader") - .mockReturnValue({ tid: traderId, currency: "RUB" } as unknown as ITraderBase); + const getTraderSpy = vi.spyOn((paymentService as any).traderHelper, "getTrader").mockReturnValue( + { tid: traderId, currency: "RUB" } as unknown as ITraderBase, + ); // Mock the addPaymentToOutput method to subtract the item cost from the money stack. - const addPaymentToOutputSpy = vi.spyOn(paymentService as any, "addPaymentToOutput").mockImplementation(() => - { - moneyItem.upd.StackObjectsCount -= costAmount; - return { warnings: [], profileChanges: { [sessionID]: { items: { change: [moneyItem] } } } }; - }); + const addPaymentToOutputSpy = vi.spyOn(paymentService as any, "addPaymentToOutput").mockImplementation( + ( + pmcData: IPmcData, + currencyTpl: string, + amountToPay: number, + sessionIdentifier: string, + output: IItemEventRouterResponse, + ) => + { + moneyItem.upd.StackObjectsCount -= costAmount; + output.profileChanges[sessionIdentifier].items.change.push(moneyItem); + }, + ); // Mock the traderHelper lvlUp method to return void. - const traderHelperLvlUpSpy = vi.spyOn((paymentService as any).traderHelper, "lvlUp").mockImplementation( - () => - {}, - ); + const lvlUpSpy = vi.spyOn((paymentService as any).traderHelper, "lvlUp").mockResolvedValue(undefined); - const output = paymentService.payMoney( - pmcData, - processBuyTradeRequestData, - sessionID, - itemEventRouterResponse, - ); + paymentService.payMoney(pmcData, processBuyTradeRequestData, sessionID, itemEventRouterResponse); // Check for absence of output warnings. - expect(output.warnings).toHaveLength(0); + expect(itemEventRouterResponse.warnings).toHaveLength(0); // Check that the currency change was correctly handled. - expect(output.profileChanges[sessionID].items.change).toHaveLength(1); - expect(output.profileChanges[sessionID].items.change[0]._id).toBe(costItemId); - expect(output.profileChanges[sessionID].items.change[0]._tpl).toBe(costItemTpl); - expect(output.profileChanges[sessionID].items.change[0].upd.StackObjectsCount).toBe(costAmount * 3); + expect(itemEventRouterResponse.profileChanges[sessionID].items.change).toHaveLength(1); + expect(itemEventRouterResponse.profileChanges[sessionID].items.change[0]._id).toBe(costItemId); + expect(itemEventRouterResponse.profileChanges[sessionID].items.change[0]._tpl).toBe(costItemTpl); + expect(itemEventRouterResponse.profileChanges[sessionID].items.change[0].upd.StackObjectsCount).toBe( + costAmount * 3, + ); // Check if mocked methods were called as expected. - expect(traderHelperGetTraderSpy).toBeCalledTimes(1); + expect(getTraderSpy).toBeCalledTimes(1); expect(addPaymentToOutputSpy).toBeCalledWith( expect.anything(), costItemTpl, @@ -120,7 +122,7 @@ describe("PaymentService", () => sessionID, expect.anything(), ); - expect(traderHelperLvlUpSpy).toBeCalledTimes(1); + expect(lvlUpSpy).toBeCalledTimes(1); }); }); diff --git a/project/tests/services/PlayerService.test.ts b/project/tests/services/PlayerService.test.ts index 6c731861..fd03934c 100644 --- a/project/tests/services/PlayerService.test.ts +++ b/project/tests/services/PlayerService.test.ts @@ -61,11 +61,11 @@ describe("PlayerService", () => expect(result).toBe(25); }); - it("should return 79 when player xp is 68,206,066", () => + it("should return 79 when player xp is 81,126,895", () => { const playerProfile = { Info: { - Experience: 68206066, // Via wiki: https://escapefromtarkov.fandom.com/wiki/Character_skills#Levels + Experience: 81126895, // Via wiki: https://escapefromtarkov.fandom.com/wiki/Character_skills#Levels }, }; diff --git a/project/tests/services/RagfairPriceService.test.ts b/project/tests/services/RagfairPriceService.test.ts new file mode 100644 index 00000000..8ae6fee2 --- /dev/null +++ b/project/tests/services/RagfairPriceService.test.ts @@ -0,0 +1,501 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import "reflect-metadata"; +import { container } from "tsyringe"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +import { RagfairPriceService } from "@spt-aki/services/RagfairPriceService"; + +import { MinMax } from "@spt-aki/models/common/MinMax"; +import { Money } from "@spt-aki/models/enums/Money"; + +describe("RagfairPriceService", () => +{ + let ragfairPriceService: any; // Using "any" to access private/protected methods without type errors. + + beforeEach(() => + { + ragfairPriceService = container.resolve("RagfairPriceService"); + }); + + afterEach(() => + { + vi.restoreAllMocks(); + }); + + describe("getDynamicOfferPriceForOffer", () => + { + it("should return zero when empty offerItems array is passed", () => + { + const offerItems = []; + const desiredCurrency = Money.ROUBLES; + const isPackOffer = false; + + const price = ragfairPriceService.getDynamicOfferPriceForOffer(offerItems, desiredCurrency, isPackOffer); + + expect(price).toEqual(0); + }); + + it("should return non-zero number when valid item is passed", () => + { + const offerItems = [{ + _id: "d445ea263cdfc5f278334264", + _tpl: "57e3dba62459770f0c32322b", + parentId: "631abbff398cc0170cbd3089", + slotId: "mod_pistol_grip", + }]; + const desiredCurrency = Money.ROUBLES; + const isPackOffer = false; + const expectedPrice = 42069; + + // Mock the getDynamicItemPrice method to return a static price. + vi.spyOn(ragfairPriceService, "getDynamicItemPrice").mockReturnValue(expectedPrice); + + const price = ragfairPriceService.getDynamicOfferPriceForOffer(offerItems, desiredCurrency, isPackOffer); + + expect(price).toBe(expectedPrice); + }); + + it("should always return a whole number", () => + { + const offerItems = [{ + _id: "d445ea263cdfc5f278334264", + _tpl: "57e3dba62459770f0c32322b", + parentId: "631abbff398cc0170cbd3089", + slotId: "mod_pistol_grip", + }]; + const desiredCurrency = Money.ROUBLES; + const isPackOffer = false; + const originalPrice = 42069.999999999; + + // Mock the getDynamicItemPrice method to return a static price. + vi.spyOn(ragfairPriceService, "getDynamicItemPrice").mockReturnValue(originalPrice); + + const price = ragfairPriceService.getDynamicOfferPriceForOffer(offerItems, desiredCurrency, isPackOffer); + + expect(price).toBeGreaterThan(originalPrice); + expect(price).toBe(Math.round(originalPrice)); + }); + + it("should skip prices for soft armour inserts", () => + { + const offerItems = [{ + _id: "d445ea263cdfc5f278334264", + _tpl: "657080a212755ae0d907ad04", + parentId: "631abbff398cc0170cbd3089", + slotId: "Soft_armor_front", + }]; + const desiredCurrency = Money.ROUBLES; + const isPackOffer = false; + + // Mock the getDynamicItemPrice method. + const getDynamicItemPriceSpy = vi.spyOn(ragfairPriceService, "getDynamicItemPrice"); + + const price = ragfairPriceService.getDynamicOfferPriceForOffer(offerItems, desiredCurrency, isPackOffer); + + expect(price).toBe(0); + expect(getDynamicItemPriceSpy).not.toHaveBeenCalled(); + }); + + it("should not add value of mods to weapon preset", () => + { + const offerItems = [{ + _id: "344d02bbf2102ce4e145bf35", + _tpl: "579204f224597773d619e051", + upd: { + StackObjectsCount: 1, + UnlimitedCount: true, + sptPresetId: "5841499024597759f825ff3e", + Repairable: { Durability: 90, MaxDurability: 90 }, + }, + }, { + _id: "59c6897a59ed48f1ca02f659", + _tpl: "5448c12b4bdc2d02308b456f", + parentId: "344d02bbf2102ce4e145bf35", + slotId: "mod_magazine", + }, { + _id: "7e8062d4bc57b56927c2d117", + _tpl: "6374a822e629013b9c0645c8", + parentId: "344d02bbf2102ce4e145bf35", + slotId: "mod_reciever", + }, { + _id: "3b09149e8b7833dc5fdd32a4", + _tpl: "63c6adcfb4ba094317063742", + parentId: "7e8062d4bc57b56927c2d117", + slotId: "mod_sight_rear", + }, { + _id: "e833a5c26af29870df9cdd2e", + _tpl: "6374a7e7417239a7bf00f042", + parentId: "344d02bbf2102ce4e145bf35", + slotId: "mod_pistolgrip", + }]; + const desiredCurrency = Money.ROUBLES; + const isPackOffer = false; + const expectedPrice = 10000; + + // Mock the getDynamicItemPrice method to return a static price. + const getDynamicItemPriceSpy = vi.spyOn(ragfairPriceService, "getDynamicItemPrice").mockReturnValue( + expectedPrice, + ); + + const price = ragfairPriceService.getDynamicOfferPriceForOffer(offerItems, desiredCurrency, isPackOffer); + + expect(price).toBe(expectedPrice); + expect(getDynamicItemPriceSpy).toHaveBeenCalledTimes(1); + }); + + it("should sum value of all offer items", () => + { + const offerItems = [{ + _id: "59c6897a59ed48f1ca02f659", + _tpl: "5448c12b4bdc2d02308b456f", + parentId: "344d02bbf2102ce4e145bf35", + slotId: "mod_magazine", + }, { + _id: "7e8062d4bc57b56927c2d117", + _tpl: "6374a822e629013b9c0645c8", + parentId: "344d02bbf2102ce4e145bf35", + slotId: "mod_reciever", + }, { + _id: "3b09149e8b7833dc5fdd32a4", + _tpl: "63c6adcfb4ba094317063742", + parentId: "7e8062d4bc57b56927c2d117", + slotId: "mod_sight_rear", + }, { + _id: "e833a5c26af29870df9cdd2e", + _tpl: "6374a7e7417239a7bf00f042", + parentId: "344d02bbf2102ce4e145bf35", + slotId: "mod_pistolgrip", + }]; + const desiredCurrency = Money.ROUBLES; + const isPackOffer = false; + const expectedPrice = 10000; + + // Mock the getDynamicItemPrice method to return a static price. + const getDynamicItemPriceSpy = vi.spyOn(ragfairPriceService, "getDynamicItemPrice").mockReturnValue( + expectedPrice, + ); + + const price = ragfairPriceService.getDynamicOfferPriceForOffer(offerItems, desiredCurrency, isPackOffer); + + expect(price).toBe(expectedPrice * offerItems.length); + expect(getDynamicItemPriceSpy).toHaveBeenCalledTimes(offerItems.length); + }); + }); + + describe("getDynamicItemPrice", () => + { + it("should not return zero for a valid template ID", () => + { + const itemTemplateId = "5e54f6af86f7742199090bf3"; + const desiredCurrency = Money.ROUBLES; + + const price = ragfairPriceService.getDynamicItemPrice(itemTemplateId, desiredCurrency); + + expect(price).not.toBe(0); + }); + + it("should use trader price if it is higher than flea price and configuration allows it", () => + { + const itemTemplateId = "5e54f6af86f7742199090bf3"; + const desiredCurrency = Money.ROUBLES; + const mockTraderPrice = 20000; + const mockFleaPrice = 15000; + const getOfferTypeRangeValues = { max: 1, min: 1 }; + + // Mock the configs to allow using trader price if higher. Disable other adjustments for isolation. + ragfairPriceService.ragfairConfig.dynamic.offerAdjustment.adjustPriceWhenBelowHandbookPrice = false; + ragfairPriceService.ragfairConfig.dynamic.useTraderPriceForOffersIfHigher = true; + ragfairPriceService.ragfairConfig.dynamic.itemPriceMultiplier[itemTemplateId] = null; + + // Mock the getFleaPriceForItem method to return a static price. + vi.spyOn(ragfairPriceService, "getFleaPriceForItem").mockReturnValue(mockFleaPrice); + + // Mock the getHighestSellToTraderPrice method to return a higher static price. + vi.spyOn((ragfairPriceService as any).traderHelper, "getHighestSellToTraderPrice").mockReturnValue( + mockTraderPrice, + ); + + // Mock the getOfferTypeRangeValues method to return a static minMax. + vi.spyOn(ragfairPriceService, "getOfferTypeRangeValues").mockReturnValue(getOfferTypeRangeValues); + + // Call the method. + const price = ragfairPriceService.getDynamicItemPrice(itemTemplateId, desiredCurrency); + + expect(price).toBe(mockTraderPrice); + }); + + it("should adjust flea price when below handbook price and configuration allows it", () => + { + const itemTemplateId = "5e54f6af86f7742199090bf3"; + const desiredCurrency = Money.ROUBLES; + const mockFleaPrice = 1; + const handbookPrice = 10000; + const adjustedPrice = 9000; + const getOfferTypeRangeValues = { max: 1, min: 1 }; + + // Enable adjustment for prices below handbook price. Disable other adjustments for isolation. + ragfairPriceService.ragfairConfig.dynamic.offerAdjustment.adjustPriceWhenBelowHandbookPrice = true; + ragfairPriceService.ragfairConfig.dynamic.useTraderPriceForOffersIfHigher = false; + ragfairPriceService.ragfairConfig.dynamic.itemPriceMultiplier[itemTemplateId] = null; + + // Mock the getFleaPriceForItem method to return a static price below the handbook price. + vi.spyOn(ragfairPriceService, "getFleaPriceForItem").mockReturnValue(mockFleaPrice); + + // Mock the adjustPriceIfBelowHandbook method to simulate price adjustment. + vi.spyOn(ragfairPriceService, "adjustPriceIfBelowHandbook").mockImplementation( + (price: number, templateId) => + { + return price < handbookPrice ? adjustedPrice : price; + }, + ); + + // Mock the getOfferTypeRangeValues method to return a static minMax. + vi.spyOn(ragfairPriceService, "getOfferTypeRangeValues").mockReturnValue(getOfferTypeRangeValues); + + // Call the method. + const price = ragfairPriceService.getDynamicItemPrice(itemTemplateId, desiredCurrency); + + // Verify the price is adjusted correctly according to the mocked handbook price adjustment logic. + expect(price).toBe(adjustedPrice); + }); + + it("should handle weapon preset prices correctly", () => + { + const itemTemplateId = "579204f224597773d619e051"; + const desiredCurrency = Money.ROUBLES; + const mockPresetPrice = 25000; + const getOfferTypeRangeValues = { max: 1, min: 1 }; + const offerItems = [{ + _id: "344d02bbf2102ce4e145bf35", + _tpl: "579204f224597773d619e051", + upd: { + StackObjectsCount: 1, + UnlimitedCount: true, + sptPresetId: "5841499024597759f825ff3e", + Repairable: { Durability: 90, MaxDurability: 90 }, + }, + }, { + _id: "7e8062d4bc57b56927c2d117", + _tpl: "6374a822e629013b9c0645c8", + parentId: "344d02bbf2102ce4e145bf35", + slotId: "mod_reciever", + }]; + const item = offerItems[0]; + + // Disable other adjustments for isolation. + ragfairPriceService.ragfairConfig.dynamic.offerAdjustment.adjustPriceWhenBelowHandbookPrice = false; + ragfairPriceService.ragfairConfig.dynamic.useTraderPriceForOffersIfHigher = false; + ragfairPriceService.ragfairConfig.dynamic.itemPriceMultiplier[itemTemplateId] = null; + + // Mock getFleaPriceForItem to bypass initial flea price fetch + vi.spyOn(ragfairPriceService, "getFleaPriceForItem").mockReturnValue(0); + + // Mock the isPresetBaseClass method to return true for the item + vi.spyOn((ragfairPriceService as any).presetHelper, "isPresetBaseClass").mockReturnValue(true); + + // Mock the getWeaponPresetPrice method to return a specific preset price + const getWeaponPresetPriceSpy = vi.spyOn(ragfairPriceService, "getWeaponPresetPrice").mockReturnValue( + mockPresetPrice, + ); + + // Mock the getOfferTypeRangeValues method to return a static minMax. + vi.spyOn(ragfairPriceService, "getOfferTypeRangeValues").mockReturnValue(getOfferTypeRangeValues); + + // Mock the getItemQualityModifier method to return 1 (no change) + vi.spyOn((ragfairPriceService as any).itemHelper, "getItemQualityModifier").mockReturnValue(1); + + // Call the method with the mock item and offer items + const price = ragfairPriceService.getDynamicItemPrice(itemTemplateId, desiredCurrency, item, offerItems); + + // Call the method. + expect(price).toBe(mockPresetPrice); + + // Additionally, you can verify that getWeaponPresetPrice was called with the correct parameters + expect(getWeaponPresetPriceSpy).toHaveBeenCalledWith(item, offerItems, expect.any(Number)); + }); + + it("should update price based on the ragfair config item price multiplier values", () => + { + const itemTemplateId = "5e54f6af86f7742199090bf3"; + const desiredCurrency = Money.ROUBLES; + const mockFleaPrice = 20000; + const itemPriceMultiplier = 2; + const getOfferTypeRangeValues = { max: 1, min: 1 }; + + // Mock the ragfair config to have a price multiplier of 2. Disable other adjustments for isolation. + ragfairPriceService.ragfairConfig.dynamic.itemPriceMultiplier[itemTemplateId] = itemPriceMultiplier; + ragfairPriceService.ragfairConfig.dynamic.offerAdjustment.adjustPriceWhenBelowHandbookPrice = false; + ragfairPriceService.ragfairConfig.dynamic.useTraderPriceForOffersIfHigher = false; + + // Mock the getFleaPriceForItem method to return a static price. + vi.spyOn(ragfairPriceService, "getFleaPriceForItem").mockReturnValue(mockFleaPrice); + + // Mock the getOfferTypeRangeValues method to return a static minMax. + vi.spyOn(ragfairPriceService, "getOfferTypeRangeValues").mockReturnValue(getOfferTypeRangeValues); + + // Call the method. + const price = ragfairPriceService.getDynamicItemPrice(itemTemplateId, desiredCurrency); + + expect(price).toBe(mockFleaPrice * itemPriceMultiplier); + }); + + it("should adjust price when durability is not perfect", () => + { + const itemTemplateId = "579204f224597773d619e051"; + const desiredCurrency = Money.ROUBLES; + const mockPrice = 25000; + const mockDurabilityMulti = 0.5; + const getOfferTypeRangeValues = { max: 1, min: 1 }; + const offerItems = [{ + _id: "344d02bbf2102ce4e145bf35", + _tpl: "579204f224597773d619e051", + upd: { + StackObjectsCount: 1, + UnlimitedCount: true, + sptPresetId: "5841499024597759f825ff3e", + Repairable: { Durability: 40, MaxDurability: 90 }, + }, + }, { + _id: "7e8062d4bc57b56927c2d117", + _tpl: "6374a822e629013b9c0645c8", + parentId: "344d02bbf2102ce4e145bf35", + slotId: "mod_reciever", + }]; + const item = offerItems[0]; + + // Disable other adjustments for isolation. + ragfairPriceService.ragfairConfig.dynamic.offerAdjustment.adjustPriceWhenBelowHandbookPrice = false; + ragfairPriceService.ragfairConfig.dynamic.useTraderPriceForOffersIfHigher = false; + ragfairPriceService.ragfairConfig.dynamic.itemPriceMultiplier[itemTemplateId] = null; + + // Mock getFleaPriceForItem to bypass initial flea price fetch + vi.spyOn(ragfairPriceService, "getFleaPriceForItem").mockReturnValue(0); + + // Mock the isPresetBaseClass method to return true for the item + vi.spyOn((ragfairPriceService as any).presetHelper, "isPresetBaseClass").mockReturnValue(true); + + // Mock the getWeaponPresetPrice method to return a specific preset price + vi.spyOn(ragfairPriceService, "getWeaponPresetPrice").mockReturnValue(mockPrice); + + // Mock the getOfferTypeRangeValues method to return a static minMax. + vi.spyOn(ragfairPriceService, "getOfferTypeRangeValues").mockReturnValue(getOfferTypeRangeValues); + + // Mock the getItemQualityModifier method to return 1 (no change) + const getItemQualityModifierSpy = vi.spyOn( + (ragfairPriceService as any).itemHelper, + "getItemQualityModifier", + ).mockReturnValue(mockDurabilityMulti); + + // Call the method. + const price = ragfairPriceService.getDynamicItemPrice(itemTemplateId, desiredCurrency, item, offerItems); + + expect(getItemQualityModifierSpy).toHaveBeenCalled(); + expect(price).toBe(mockPrice * mockDurabilityMulti); + }); + + it("should adjust unreasonable prices based on ragfair config unreasonable price values", () => + { + const itemTemplateId = "5c052f6886f7746b1e3db148"; + const desiredCurrency = Money.ROUBLES; + const mockFleaPrice = 9999999; + const getOfferTypeRangeValues = { max: 1, min: 1 }; + const mockBaseClassTemplateId = "57864a66245977548f04a81f"; + const mockUnreasonableModPrices = { + itemType: "Electronics", + enabled: true, + handbookPriceOverMultiplier: 11, + newPriceHandbookMultiplier: 11, + }; + + // Mock the Disable unreasonableModPrices config. Disable other adjustments for isolation. + ragfairPriceService.ragfairConfig.dynamic.unreasonableModPrices[mockBaseClassTemplateId] = + mockUnreasonableModPrices; + ragfairPriceService.ragfairConfig.dynamic.offerAdjustment.adjustPriceWhenBelowHandbookPrice = false; + ragfairPriceService.ragfairConfig.dynamic.useTraderPriceForOffersIfHigher = false; + ragfairPriceService.ragfairConfig.dynamic.itemPriceMultiplier[itemTemplateId] = null; + + // Mock getFleaPriceForItem to bypass initial flea price fetch + vi.spyOn(ragfairPriceService, "getFleaPriceForItem").mockReturnValue(mockFleaPrice); + + // Mock isOfBaseclass to ensure that the item is always of the base class + const isOfBaseclassSpy = vi.spyOn((ragfairPriceService as any).itemHelper, "isOfBaseclass").mockReturnValue( + true, + ); + + // Mock the adjustUnreasonablePrice method to ensure it was called + const adjustUnreasonablePriceSpy = vi.spyOn(ragfairPriceService, "adjustUnreasonablePrice"); + + // Mock the getOfferTypeRangeValues method to return a static minMax + vi.spyOn(ragfairPriceService, "getOfferTypeRangeValues").mockReturnValue(getOfferTypeRangeValues); + + // Call the method. + const price = ragfairPriceService.getDynamicItemPrice(itemTemplateId, desiredCurrency); + + expect(isOfBaseclassSpy).toHaveBeenCalled(); + expect(adjustUnreasonablePriceSpy).toHaveBeenCalled(); + expect(price).toBeLessThan(mockFleaPrice); + }); + + it("should vary the price within a random range", () => + { + const itemTemplateId = "5e54f6af86f7742199090bf3"; + const desiredCurrency = Money.ROUBLES; + const mockFleaPrice = 10000; + const mockRandomiseOfferPrice = 9500; + + // Mock the configs to allow using trader price if higher. Disable other adjustments for isolation. + ragfairPriceService.ragfairConfig.dynamic.offerAdjustment.adjustPriceWhenBelowHandbookPrice = false; + ragfairPriceService.ragfairConfig.dynamic.useTraderPriceForOffersIfHigher = false; + ragfairPriceService.ragfairConfig.dynamic.itemPriceMultiplier[itemTemplateId] = null; + + // Mock the getFleaPriceForItem method to return a static price + vi.spyOn(ragfairPriceService, "getFleaPriceForItem").mockReturnValue(mockFleaPrice); + + // Mock the isPresetBaseClass method to return false + vi.spyOn((ragfairPriceService as any).presetHelper, "isPresetBaseClass").mockReturnValue(false); + + // Mock the randomiseOfferPrice method to have a simplified implementation + const randomiseOfferPriceSpy = vi.spyOn(ragfairPriceService, "randomiseOfferPrice").mockReturnValue( + mockRandomiseOfferPrice, + ); + + // Call the method. + const price = ragfairPriceService.getDynamicItemPrice(itemTemplateId, desiredCurrency); + + expect(randomiseOfferPriceSpy).toHaveBeenCalled(); + expect(price).toBe(mockRandomiseOfferPrice); + }); + + it("should convert currency", () => + { + const itemTemplateId = "5e54f6af86f7742199090bf3"; + const desiredCurrency = Money.DOLLARS; + const mockRoublePrice = 10000; + const mockDollarPrice = 500; + const getOfferTypeRangeValues = { max: 1, min: 1 }; + + // Mock the configs to allow using trader price if higher. Disable other adjustments for isolation. + ragfairPriceService.ragfairConfig.dynamic.offerAdjustment.adjustPriceWhenBelowHandbookPrice = false; + ragfairPriceService.ragfairConfig.dynamic.useTraderPriceForOffersIfHigher = false; + ragfairPriceService.ragfairConfig.dynamic.itemPriceMultiplier[itemTemplateId] = null; + + // Mock the getFleaPriceForItem method to return a static price. + vi.spyOn(ragfairPriceService, "getFleaPriceForItem").mockReturnValue(mockRoublePrice); + + // Mock the getOfferTypeRangeValues method to return a static minMax + vi.spyOn(ragfairPriceService, "getOfferTypeRangeValues").mockReturnValue(getOfferTypeRangeValues); + + // Mock the fromRUB method to convert the price to a different currency + const fromRUBSpy = vi.spyOn((ragfairPriceService as any).handbookHelper, "fromRUB").mockReturnValue( + mockDollarPrice, + ); + + // Call the method. + const price = ragfairPriceService.getDynamicItemPrice(itemTemplateId, desiredCurrency); + + expect(fromRUBSpy).toHaveBeenCalledWith(mockRoublePrice, desiredCurrency); + expect(price).not.toBe(mockRoublePrice); + expect(price).toBe(mockDollarPrice); + }); + }); +});