diff --git a/.gitea/workflows/run-lint.yaml b/.gitea/workflows/run-lint.yaml index 2891f190..4870b564 100644 --- a/.gitea/workflows/run-lint.yaml +++ b/.gitea/workflows/run-lint.yaml @@ -15,7 +15,7 @@ jobs: - 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 + git clone https://dev.sp-tarkov.com/${GITHUB_REPOSITORY}.git --branch master /workspace/SPT-AKI/Build/server cd /workspace/SPT-AKI/Build/server git checkout ${GITHUB_SHA} diff --git a/.gitea/workflows/run-style.yaml b/.gitea/workflows/run-style.yaml index 4a5a24ab..cdc20708 100644 --- a/.gitea/workflows/run-style.yaml +++ b/.gitea/workflows/run-style.yaml @@ -15,7 +15,7 @@ jobs: - 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 + git clone https://dev.sp-tarkov.com/${GITHUB_REPOSITORY}.git --branch master /workspace/SPT-AKI/Build/server cd /workspace/SPT-AKI/Build/server git checkout ${GITHUB_SHA} diff --git a/.gitea/workflows/run-test.yaml b/.gitea/workflows/run-test.yaml index 73a51cf7..e5f9adad 100644 --- a/.gitea/workflows/run-test.yaml +++ b/.gitea/workflows/run-test.yaml @@ -15,7 +15,7 @@ jobs: - 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 + git clone https://dev.sp-tarkov.com/${GITHUB_REPOSITORY}.git --branch master /workspace/SPT-AKI/Build/server cd /workspace/SPT-AKI/Build/server git checkout ${GITHUB_SHA} diff --git a/project/package.json b/project/package.json index 30963880..22c662fc 100644 --- a/project/package.json +++ b/project/package.json @@ -27,7 +27,7 @@ "run:build": "gulp run:build", "run:debug": "gulp run:debug", "run:profiler": "gulp run:profiler", - "gen:types": "tsc -p tsconfig.typedef.json", + "gen:types": "tsc -p tsconfig.typedef.json --resolveJsonModule", "gen:docs": "typedoc --options ./typedoc.json --entryPointStrategy expand ./src" }, "dependencies": { diff --git a/project/src/generators/BotEquipmentModGenerator.ts b/project/src/generators/BotEquipmentModGenerator.ts index 56bbcd2f..dc0612d5 100644 --- a/project/src/generators/BotEquipmentModGenerator.ts +++ b/project/src/generators/BotEquipmentModGenerator.ts @@ -1106,12 +1106,12 @@ export class BotEquipmentModGenerator } /** - * Log errors if mod is not compatible with slot - * @param modToAdd template of mod to check - * @param slotAddedToTemplate slot the item will be placed in - * @param modSlot slot the mod will fill - * @param parentTemplate template of the mods being added - * @param botRole + * Check if mod exists in db + is for a required slot + * @param modToAdd Db template of mod to check + * @param slotAddedToTemplate Slot object the item will be placed as child into + * @param modSlot Slot the mod will fill + * @param parentTemplate Db template of the mods being added + * @param botRole Bots wildspawntype (assault/pmcBot etc) * @returns true if valid */ protected isModValidForSlot( @@ -1122,31 +1122,31 @@ export class BotEquipmentModGenerator botRole: string, ): boolean { - const modBeingAddedTemplate = modToAdd[1]; + const modBeingAddedDbTemplate = modToAdd[1]; - // Mod lacks template item - if (!modBeingAddedTemplate) + // Mod lacks db template object + if (!modBeingAddedDbTemplate) { this.logger.error( this.localisationService.getText("bot-no_item_template_found_when_adding_mod", { - modId: modBeingAddedTemplate._id, + modId: modBeingAddedDbTemplate?._id ?? "UNKNOWN", modSlot: modSlot, }), ); - this.logger.debug(`Item -> ${parentTemplate._id}; Slot -> ${modSlot}`); + this.logger.debug(`Item -> ${parentTemplate?._id}; Slot -> ${modSlot}`); return false; } - // Mod isn't a valid item + // Mod has invalid db item if (!modToAdd[0]) { - // Slot must be filled, show warning + // Parent slot must be filled but db object is invalid, show warning and return false if (slotAddedToTemplate._required) { this.logger.warning( this.localisationService.getText("bot-unable_to_add_mod_item_invalid", { - itemName: modBeingAddedTemplate._name, + itemName: modBeingAddedDbTemplate?._name ?? "UNKNOWN", modSlot: modSlot, parentItemName: parentTemplate._name, botRole: botRole, @@ -1157,6 +1157,7 @@ export class BotEquipmentModGenerator return false; } + // Mod was found in db return true; } diff --git a/project/src/generators/PMCLootGenerator.ts b/project/src/generators/PMCLootGenerator.ts index f7abc809..b4f1b765 100644 --- a/project/src/generators/PMCLootGenerator.ts +++ b/project/src/generators/PMCLootGenerator.ts @@ -270,13 +270,14 @@ export class PMCLootGenerator protected gcd(a: number, b: number): number { - while (b !== 0) + let x = a; + let y = b; + while (y !== 0) { - const temp = b; - b = a % b; - a = temp; + const temp = y; + y = x % y; + x = temp; } - - return a; + return x; } } diff --git a/project/src/helpers/AssortHelper.ts b/project/src/helpers/AssortHelper.ts index 88ae86e3..6b0c2a29 100644 --- a/project/src/helpers/AssortHelper.ts +++ b/project/src/helpers/AssortHelper.ts @@ -37,6 +37,8 @@ export class AssortHelper flea = false, ): ITraderAssort { + let strippedTraderAssorts = traderAssorts; + // Trader assort does not always contain loyal_level_items if (!traderAssorts.loyal_level_items) { @@ -59,11 +61,11 @@ export class AssortHelper const questStatusInProfile = this.questHelper.getQuestStatus(pmcProfile, unlockValues.questId); if (!unlockValues.status.includes(questStatusInProfile)) { - traderAssorts = this.removeItemFromAssort(traderAssorts, assortId, flea); + strippedTraderAssorts = this.removeItemFromAssort(traderAssorts, assortId, flea); } } - return traderAssorts; + return strippedTraderAssorts; } /** @@ -108,12 +110,14 @@ export class AssortHelper */ public stripLockedLoyaltyAssort(pmcProfile: IPmcData, traderId: string, assort: ITraderAssort): ITraderAssort { + let strippedAssort = assort; + // Trader assort does not always contain loyal_level_items if (!assort.loyal_level_items) { this.logger.warning(this.localisationService.getText("assort-missing_loyalty_level_object", traderId)); - return assort; + return strippedAssort; } // Remove items restricted by loyalty levels above those reached by the player @@ -121,11 +125,11 @@ export class AssortHelper { if (assort.loyal_level_items[itemId] > pmcProfile.TradersInfo[traderId].loyaltyLevel) { - assort = this.removeItemFromAssort(assort, itemId); + strippedAssort = this.removeItemFromAssort(assort, itemId); } } - return assort; + return strippedAssort; } /** diff --git a/project/src/helpers/ItemHelper.ts b/project/src/helpers/ItemHelper.ts index e39f69a6..0a9ed753 100644 --- a/project/src/helpers/ItemHelper.ts +++ b/project/src/helpers/ItemHelper.ts @@ -1198,6 +1198,7 @@ export class ItemHelper const cartridgeTpl = this.drawAmmoTpl( chosenCaliber, staticAmmoDist, + weapon?._props.defAmmo, weapon?._props?.Chambers[0]?._props?.filters[0]?.Filter, ); this.fillMagazineWithCartridge(magazine, magTemplate, cartridgeTpl, minSizePercent); @@ -1306,12 +1307,14 @@ export class ItemHelper * Chose a randomly weighted cartridge that fits * @param caliber Desired caliber * @param staticAmmoDist Cartridges and thier weights + * @param fallbackCartridgeTpl If a cartridge cannot be found in the above staticAmmoDist param, use this instead * @param cartridgeWhitelist OPTIONAL whitelist for cartridges * @returns Tpl of cartridge */ protected drawAmmoTpl( caliber: string, staticAmmoDist: Record, + fallbackCartridgeTpl: string, cartridgeWhitelist: string[] = null, ): string { @@ -1319,14 +1322,20 @@ export class ItemHelper const ammos = staticAmmoDist[caliber]; if (!ammos) { - this.logger.error(`Missing caliber data for: ${caliber}`); + this.logger.error( + `Unable to pick a cartridge for caliber: ${caliber} as staticAmmoDist has no data. using fallback value of ${fallbackCartridgeTpl}`, + ); + + return fallbackCartridgeTpl; } if (!Array.isArray(ammos)) { this.logger.error( - `Unable to pick a cartridge for caliber ${caliber}, chosen staticAmmoDist data is not an array: ${ammos}`, + `Unable to pick a cartridge for caliber: ${caliber}, the chosen staticAmmoDist data is not an array. Using fallback value of ${fallbackCartridgeTpl}`, ); + + return fallbackCartridgeTpl; } for (const icd of ammos) @@ -1463,7 +1472,6 @@ export class ItemHelper const modItemDbDetails = this.getItem(modItemToAdd._tpl)[1]; // Include conflicting items of newly added mod in pool to be used for next mod choice - // biome-ignore lint/complexity/noForEach: modItemDbDetails._props.ConflictingItems.forEach(incompatibleModTpls.add, incompatibleModTpls); } @@ -1472,7 +1480,7 @@ export class ItemHelper /** * Get a compatible tpl from the array provided where it is not found in the provided incompatible mod tpls parameter - * @param possibleTpls Tpls to randomply choose from + * @param possibleTpls Tpls to randomly choose from * @param incompatibleModTpls Incompatible tpls to not allow * @returns Chosen tpl or null */ diff --git a/project/src/helpers/QuestHelper.ts b/project/src/helpers/QuestHelper.ts index 0a09a68f..d0aa9018 100644 --- a/project/src/helpers/QuestHelper.ts +++ b/project/src/helpers/QuestHelper.ts @@ -692,12 +692,12 @@ export class QuestHelper */ public getQuestWithOnlyLevelRequirementStartCondition(quest: IQuest): IQuest { - quest = this.jsonUtil.clone(quest); - quest.conditions.AvailableForStart = quest.conditions.AvailableForStart.filter((q) => + const updatedQuest = this.jsonUtil.clone(quest); + updatedQuest.conditions.AvailableForStart = updatedQuest.conditions.AvailableForStart.filter((q) => q.conditionType === "Level" ); - return quest; + return updatedQuest; } /** @@ -714,14 +714,22 @@ export class QuestHelper output: IItemEventRouterResponse = null, ): void { + let updatedOutput = output; + // Prepare response to send back to client - if (!output) + if (!updatedOutput) { - output = this.eventOutputHolder.getOutput(sessionID); + updatedOutput = this.eventOutputHolder.getOutput(sessionID); } this.updateQuestState(pmcData, QuestStatus.Fail, failRequest.qid); - const questRewards = this.applyQuestReward(pmcData, failRequest.qid, QuestStatus.Fail, sessionID, output); + const questRewards = this.applyQuestReward( + pmcData, + failRequest.qid, + QuestStatus.Fail, + sessionID, + updatedOutput, + ); // Create a dialog message for completing the quest. const quest = this.getQuestFromDb(failRequest.qid, pmcData); @@ -747,7 +755,7 @@ export class QuestHelper } } - output.profileChanges[sessionID].quests.push(...this.failedUnlocked(failRequest.qid, sessionID)); + updatedOutput.profileChanges[sessionID].quests.push(...this.failedUnlocked(failRequest.qid, sessionID)); } /** diff --git a/project/src/helpers/TradeHelper.ts b/project/src/helpers/TradeHelper.ts index 358860e0..05c71d56 100644 --- a/project/src/helpers/TradeHelper.ts +++ b/project/src/helpers/TradeHelper.ts @@ -72,7 +72,7 @@ export class TradeHelper ): void { let offerItems: Item[] = []; - let buyCallback: { (buyCount: number); }; + let buyCallback: (buyCount: number) => void; if (buyRequestData.tid.toLocaleLowerCase() === "ragfair") { buyCallback = (buyCount: number) => diff --git a/project/src/models/enums/WeaponTypes.ts b/project/src/models/enums/WeaponTypes.ts index c3f377dd..e0ea6430 100644 --- a/project/src/models/enums/WeaponTypes.ts +++ b/project/src/models/enums/WeaponTypes.ts @@ -15,7 +15,7 @@ export enum Weapons9x39 AS_VAL = "57c44b372459772d2b39b8ce", VSS_VINTOREZ = "57838ad32459774a17445cd2", KBP_9A_91 = "644674a13d52156624001fbc", - VSK_94 = "645e0c6b3b381ede770e1cc9", + VSK_94 = "645e0c6b3b381ede770e1cc9", } export enum Weapons762x54R @@ -26,9 +26,9 @@ export enum Weapons762x54R MOSIN_SNIPER = "5ae08f0a5acfc408fb1398a1", SV_98 = "55801eed4bdc2d89578b4588", AVT_40 = "6410733d5dd49d77bd07847e", - SVT_40 = "643ea5b23db6f9f57107d9fd", - PKM = "64637076203536ad5600c990", - PKP = "64ca3d3954fc657e230529cc", + SVT_40 = "643ea5b23db6f9f57107d9fd", + PKM = "64637076203536ad5600c990", + PKP = "64ca3d3954fc657e230529cc", } export enum Weapons762x51 @@ -68,7 +68,7 @@ export enum Weapons762x39 RD_704 = "628a60ae6b1d481ff772e9c8", VPO_136 = "59e6152586f77473dc057aa1", RPD = "6513ef33e06849f06c0957ca", - RPDN = "65268d8ecb944ff1e90ea385", + RPDN = "65268d8ecb944ff1e90ea385", } export enum Weapons762x35 @@ -89,7 +89,7 @@ export enum Weapons556x45 SCARL_FDE = "618428466ef05c2ce828f218", TX15_DML = "5d43021ca4b9362eab4b5e25", AUG_A1 = "62e7c4fba689e8c9c50dfc38", - AUG_A3 = "63171672192e68c5460cebc5", + AUG_A3 = "63171672192e68c5460cebc5", } export enum Weapons545x39 diff --git a/project/src/services/FenceService.ts b/project/src/services/FenceService.ts index 9cef446a..67cc6c8d 100644 --- a/project/src/services/FenceService.ts +++ b/project/src/services/FenceService.ts @@ -387,8 +387,8 @@ export class FenceService /** * Choose an item at random and remove it + mods from assorts - * @param assort Items to remove from - * @param rootItems Assort root items to pick from to remove + * @param assort Trader assort to remove item from + * @param rootItems Pool of root items to pick from to remove */ protected removeRandomItemFromAssorts(assort: ITraderAssort, rootItems: Item[]): void { @@ -399,24 +399,35 @@ export class FenceService // Get a random count of the chosen item to remove const itemCountToRemove = this.randomUtil.getInt(1, stackSize); - 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 + + const isEntireStackToBeRemoved = itemCountToRemove === stackSize; + + // Partial stack reduction + if (!isEntireStackToBeRemoved) { - // Remove up item + any mods - const itemWithChildren = this.itemHelper.findAndReturnChildrenAsItems(assort.items, rootItemToAdjust._id); - for (const itemToDelete of itemWithChildren) + if (!rootItemToAdjust.upd) { - // Delete item from assort items array - assort.items.splice(assort.items.indexOf(itemToDelete), 1); + this.logger.warning(`Fence Item: ${rootItemToAdjust._tpl} lacks a upd object, adding`); + rootItemToAdjust.upd = {}; } - delete assort.barter_scheme[rootItemToAdjust._id]; - delete assort.loyal_level_items[rootItemToAdjust._id]; + // Reduce stack to at smallest, 1 + rootItemToAdjust.upd.StackObjectsCount -= Math.max(1, itemCountToRemove); + + return; } + + // Remove item + child mods (if any) + 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); + } + + // Need to remove item from all areas of trader assort + delete assort.barter_scheme[rootItemToAdjust._id]; + delete assort.loyal_level_items[rootItemToAdjust._id]; } /** diff --git a/project/src/utils/DatabaseImporter.ts b/project/src/utils/DatabaseImporter.ts index 78a65150..699f04b9 100644 --- a/project/src/utils/DatabaseImporter.ts +++ b/project/src/utils/DatabaseImporter.ts @@ -134,7 +134,7 @@ export class DatabaseImporter implements OnLoad try { const finalPath = filePathAndName.replace(this.filepath, "").replace(".json", ""); - let tempObject; + let tempObject: any; for (const prop of finalPath.split("/")) { if (!tempObject) diff --git a/project/tests/controllers/InsuranceController.test.ts b/project/tests/controllers/InsuranceController.test.ts index dc278d74..7b1fc23b 100644 --- a/project/tests/controllers/InsuranceController.test.ts +++ b/project/tests/controllers/InsuranceController.test.ts @@ -1020,7 +1020,8 @@ describe("InsuranceController", () => const attachments = parentAttachmentsMap.entries().next().value; // Set the dynamicPrice of the first attachment to null. - vi.spyOn(insuranceController.ragfairPriceService, "getDynamicItemPrice").mockReturnValue(666).mockReturnValueOnce(null); + vi.spyOn(insuranceController.ragfairPriceService, "getDynamicItemPrice").mockReturnValue(666) + .mockReturnValueOnce(null); // Execute the method. const sortedAttachments = insuranceController.sortAttachmentsByPrice(attachments);