From 6937724c1fe7a16dbd436057321e15af8968b656 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Sun, 27 Apr 2025 23:14:27 +0200 Subject: [PATCH] feat: weaken nemesis --- src/controllers/api/nemesisController.ts | 133 +++++++++++++++-------- src/helpers/nemesisHelpers.ts | 73 ++++++++++++- 2 files changed, 156 insertions(+), 50 deletions(-) diff --git a/src/controllers/api/nemesisController.ts b/src/controllers/api/nemesisController.ts index 252092f5..60b02a17 100644 --- a/src/controllers/api/nemesisController.ts +++ b/src/controllers/api/nemesisController.ts @@ -2,9 +2,12 @@ import { consumeModCharge, encodeNemesisGuess, getInfNodes, + getKnifeUpgrade, getNemesisPasscode, + getNemesisPasscodeModTypes, getWeaponsForManifest, - IKnifeResponse + IKnifeResponse, + showdownNodes } from "@/src/helpers/nemesisHelpers"; import { getJSONfromString } from "@/src/helpers/stringHelpers"; import { Loadout } from "@/src/models/inventoryModels/loadoutModel"; @@ -15,6 +18,8 @@ import { IMongoDate, IOid } from "@/src/types/commonTypes"; import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes"; import { IInnateDamageFingerprint, + IInventoryClient, + INemesisClient, InventorySlot, IUpgradeClient, IWeaponSkinClient, @@ -100,50 +105,45 @@ export const nemesisController: RequestHandler = async (req, res) => { encodeNemesisGuess(guess[0], result1, guess[1], result2, guess[2], result3) ); - // Increase antivirus - let antivirusGain = 5; - const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!; - const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid); - const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0; - const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!; + // Increase antivirus if correct antivirus mod is installed const response: IKnifeResponse = {}; - for (const upgrade of body.knife!.AttachedUpgrades) { - switch (upgrade.ItemType) { - case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod": - antivirusGain += 10; - consumeModCharge(response, inventory, upgrade, dataknifeUpgrades); - break; - case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod": - antivirusGain += 10; - consumeModCharge(response, inventory, upgrade, dataknifeUpgrades); - break; - case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod": // Instant Secure - antivirusGain += 15; - consumeModCharge(response, inventory, upgrade, dataknifeUpgrades); - break; - case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod": // Immuno Shield - antivirusGain += 15; - consumeModCharge(response, inventory, upgrade, dataknifeUpgrades); - break; - case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod": - antivirusGain += 10; - consumeModCharge(response, inventory, upgrade, dataknifeUpgrades); - break; + if (result1 == 0 || result2 == 0 || result3 == 0) { + let antivirusGain = 5; + const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!; + const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid); + const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0; + const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!; + for (const upgrade of body.knife!.AttachedUpgrades) { + switch (upgrade.ItemType) { + case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod": + antivirusGain += 10; + consumeModCharge(response, inventory, upgrade, dataknifeUpgrades); + break; + case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod": + antivirusGain += 10; + consumeModCharge(response, inventory, upgrade, dataknifeUpgrades); + break; + case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod": // Instant Secure + antivirusGain += 15; + consumeModCharge(response, inventory, upgrade, dataknifeUpgrades); + break; + case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod": // Immuno Shield + antivirusGain += 15; + consumeModCharge(response, inventory, upgrade, dataknifeUpgrades); + break; + case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod": + antivirusGain += 10; + consumeModCharge(response, inventory, upgrade, dataknifeUpgrades); + break; + } } + inventory.Nemesis!.HenchmenKilled += antivirusGain; } - inventory.Nemesis!.HenchmenKilled += antivirusGain; + if (inventory.Nemesis!.HenchmenKilled >= 100) { inventory.Nemesis!.HenchmenKilled = 100; - inventory.Nemesis!.InfNodes = [ - { - Node: "CrewBattleNode559", - Influence: 1 - } - ]; - inventory.Nemesis!.Weakened = true; - } else { - inventory.Nemesis!.InfNodes = getInfNodes("FC_INFESTATION", 0); } + inventory.Nemesis!.InfNodes = getInfNodes("FC_INFESTATION", 0); await inventory.save(); res.json(response); @@ -213,6 +213,38 @@ export const nemesisController: RequestHandler = async (req, res) => { res.json({ target: inventory.toJSON().Nemesis }); + } else if ((req.query.mode as string) == "w") { + const inventory = await getInventory( + accountId, + "Nemesis LoadOutPresets CurrentLoadOutIds DataKnives Upgrades RawUpgrades" + ); + //const body = getJSONfromString(String(req.body)); + + inventory.Nemesis!.InfNodes = [ + { + Node: showdownNodes[inventory.Nemesis!.Faction], + Influence: 1 + } + ]; + inventory.Nemesis!.Weakened = true; + + const response: IKnifeResponse & { target: INemesisClient } = { + target: inventory.toJSON().Nemesis! + }; + + // Consume charge of the correct requiem mod(s) + const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!; + const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid); + const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0; + const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!; + const modTypes = getNemesisPasscodeModTypes(inventory.Nemesis!); + for (const modType of modTypes) { + const upgrade = getKnifeUpgrade(inventory, dataknifeUpgrades, modType); + consumeModCharge(response, inventory, upgrade, dataknifeUpgrades); + } + + await inventory.save(); + res.json(response); } else { logger.debug(`data provided to ${req.path}: ${String(req.body)}`); throw new Error(`unknown nemesis mode: ${String(req.query.mode)}`); @@ -264,12 +296,19 @@ interface INemesisRequiemRequest { guess: number; // grn/crp: 4 bits | coda: 3x 4 bits position: number; // grn/crp: 0-2 | coda: 0 // knife field provided for coda only - knife?: { - Item: IEquipmentClient; - Skins: IWeaponSkinClient[]; - ModSlot: number; - CustSlot: number; - AttachedUpgrades: IUpgradeClient[]; - HiddenWhenHolstered: boolean; - }; + knife?: IKnife; +} + +// interface INemesisWeakenRequest { +// target: INemesisClient; +// knife: IKnife; +// } + +interface IKnife { + Item: IEquipmentClient; + Skins: IWeaponSkinClient[]; + ModSlot: number; + CustSlot: number; + AttachedUpgrades: IUpgradeClient[]; + HiddenWhenHolstered: boolean; } diff --git a/src/helpers/nemesisHelpers.ts b/src/helpers/nemesisHelpers.ts index 6543813f..17a2d3f5 100644 --- a/src/helpers/nemesisHelpers.ts +++ b/src/helpers/nemesisHelpers.ts @@ -38,17 +38,59 @@ const systemIndexes: Record = { FC_INFESTATION: [23] }; +export const showdownNodes: Record = { + FC_GRINEER: "CrewBattleNode557", + FC_CORPUS: "CrewBattleNode558", + FC_INFESTATION: "CrewBattleNode559" +}; + // Get a parazon 'passcode' based on the nemesis fingerprint so it's always the same for the same nemesis. export const getNemesisPasscode = (nemesis: { fp: bigint; Faction: string }): number[] => { const rng = new SRng(nemesis.fp); - const passcode = [rng.randomInt(0, 7)]; + const choices = [0, 1, 2, 3, 5, 6, 7]; + let choiceIndex = rng.randomInt(0, choices.length - 1); + const passcode = [choices[choiceIndex]]; if (nemesis.Faction != "FC_INFESTATION") { - passcode.push(rng.randomInt(0, 7)); - passcode.push(rng.randomInt(0, 7)); + choices.splice(choiceIndex, 1); + choiceIndex = rng.randomInt(0, choices.length - 1); + passcode.push(choices[choiceIndex]); + + choices.splice(choiceIndex, 1); + choiceIndex = rng.randomInt(0, choices.length - 1); + passcode.push(choices[choiceIndex]); } return passcode; }; +const reqiuemMods: readonly string[] = [ + "/Lotus/Upgrades/Mods/Immortal/ImmortalOneMod", + "/Lotus/Upgrades/Mods/Immortal/ImmortalTwoMod", + "/Lotus/Upgrades/Mods/Immortal/ImmortalThreeMod", + "/Lotus/Upgrades/Mods/Immortal/ImmortalFourMod", + "/Lotus/Upgrades/Mods/Immortal/ImmortalFiveMod", + "/Lotus/Upgrades/Mods/Immortal/ImmortalSixMod", + "/Lotus/Upgrades/Mods/Immortal/ImmortalSevenMod", + "/Lotus/Upgrades/Mods/Immortal/ImmortalEightMod" +]; + +const antivirusMods: readonly string[] = [ + "/Lotus/Upgrades/Mods/Immortal/AntivirusOneMod", + "/Lotus/Upgrades/Mods/Immortal/AntivirusTwoMod", + "/Lotus/Upgrades/Mods/Immortal/AntivirusThreeMod", + "/Lotus/Upgrades/Mods/Immortal/AntivirusFourMod", + "/Lotus/Upgrades/Mods/Immortal/AntivirusFiveMod", + "/Lotus/Upgrades/Mods/Immortal/AntivirusSixMod", + "/Lotus/Upgrades/Mods/Immortal/AntivirusSevenMod", + "/Lotus/Upgrades/Mods/Immortal/AntivirusEightMod" +]; + +export const getNemesisPasscodeModTypes = (nemesis: { fp: bigint; Faction: string }): string[] => { + const passcode = getNemesisPasscode(nemesis); + return nemesis.Faction == "FC_INFESTATION" + ? passcode.map(i => antivirusMods[i]) + : passcode.map(i => reqiuemMods[i]); +}; + export const encodeNemesisGuess = ( symbol1: number, result1: number, @@ -79,6 +121,31 @@ export interface IKnifeResponse { HasKnife?: boolean; } +export const getKnifeUpgrade = ( + inventory: TInventoryDatabaseDocument, + dataknifeUpgrades: string[], + type: string +): { ItemId: IOid; ItemType: string } => { + if (dataknifeUpgrades.indexOf(type) != -1) { + return { + ItemId: { $oid: "000000000000000000000000" }, + ItemType: type + }; + } + for (const upgradeId of dataknifeUpgrades) { + if (upgradeId.length == 24) { + const upgrade = inventory.Upgrades.id(upgradeId); + if (upgrade && upgrade.ItemType == type) { + return { + ItemId: { $oid: upgradeId }, + ItemType: type + }; + } + } + } + throw new Error(`${type} does not seem to be installed on parazon?!`); +}; + export const consumeModCharge = ( response: IKnifeResponse, inventory: TInventoryDatabaseDocument, -- 2.47.2