feat: weaken nemesis (#1893)
Closes #1885 Reviewed-on: #1893 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
This commit is contained in:
parent
1e8f2fc766
commit
88d00eaaa1
@ -2,9 +2,12 @@ import {
|
|||||||
consumeModCharge,
|
consumeModCharge,
|
||||||
encodeNemesisGuess,
|
encodeNemesisGuess,
|
||||||
getInfNodes,
|
getInfNodes,
|
||||||
|
getKnifeUpgrade,
|
||||||
getNemesisPasscode,
|
getNemesisPasscode,
|
||||||
|
getNemesisPasscodeModTypes,
|
||||||
getWeaponsForManifest,
|
getWeaponsForManifest,
|
||||||
IKnifeResponse
|
IKnifeResponse,
|
||||||
|
showdownNodes
|
||||||
} from "@/src/helpers/nemesisHelpers";
|
} from "@/src/helpers/nemesisHelpers";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
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 { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import {
|
import {
|
||||||
IInnateDamageFingerprint,
|
IInnateDamageFingerprint,
|
||||||
|
IInventoryClient,
|
||||||
|
INemesisClient,
|
||||||
InventorySlot,
|
InventorySlot,
|
||||||
IUpgradeClient,
|
IUpgradeClient,
|
||||||
IWeaponSkinClient,
|
IWeaponSkinClient,
|
||||||
@ -100,50 +105,45 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
encodeNemesisGuess(guess[0], result1, guess[1], result2, guess[2], result3)
|
encodeNemesisGuess(guess[0], result1, guess[1], result2, guess[2], result3)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Increase antivirus
|
// Increase antivirus if correct antivirus mod is installed
|
||||||
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!;
|
|
||||||
const response: IKnifeResponse = {};
|
const response: IKnifeResponse = {};
|
||||||
for (const upgrade of body.knife!.AttachedUpgrades) {
|
if (result1 == 0 || result2 == 0 || result3 == 0) {
|
||||||
switch (upgrade.ItemType) {
|
let antivirusGain = 5;
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod":
|
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
|
||||||
antivirusGain += 10;
|
const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0;
|
||||||
break;
|
const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!;
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod":
|
for (const upgrade of body.knife!.AttachedUpgrades) {
|
||||||
antivirusGain += 10;
|
switch (upgrade.ItemType) {
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod":
|
||||||
break;
|
antivirusGain += 10;
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod": // Instant Secure
|
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||||
antivirusGain += 15;
|
break;
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod":
|
||||||
break;
|
antivirusGain += 10;
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod": // Immuno Shield
|
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||||
antivirusGain += 15;
|
break;
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod": // Instant Secure
|
||||||
break;
|
antivirusGain += 15;
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod":
|
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||||
antivirusGain += 10;
|
break;
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod": // Immuno Shield
|
||||||
break;
|
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) {
|
if (inventory.Nemesis!.HenchmenKilled >= 100) {
|
||||||
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();
|
await inventory.save();
|
||||||
res.json(response);
|
res.json(response);
|
||||||
@ -213,6 +213,38 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
res.json({
|
res.json({
|
||||||
target: inventory.toJSON().Nemesis
|
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<INemesisWeakenRequest>(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<IInventoryClient>().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 {
|
} else {
|
||||||
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
||||||
throw new Error(`unknown nemesis mode: ${String(req.query.mode)}`);
|
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
|
guess: number; // grn/crp: 4 bits | coda: 3x 4 bits
|
||||||
position: number; // grn/crp: 0-2 | coda: 0
|
position: number; // grn/crp: 0-2 | coda: 0
|
||||||
// knife field provided for coda only
|
// knife field provided for coda only
|
||||||
knife?: {
|
knife?: IKnife;
|
||||||
Item: IEquipmentClient;
|
}
|
||||||
Skins: IWeaponSkinClient[];
|
|
||||||
ModSlot: number;
|
// interface INemesisWeakenRequest {
|
||||||
CustSlot: number;
|
// target: INemesisClient;
|
||||||
AttachedUpgrades: IUpgradeClient[];
|
// knife: IKnife;
|
||||||
HiddenWhenHolstered: boolean;
|
// }
|
||||||
};
|
|
||||||
|
interface IKnife {
|
||||||
|
Item: IEquipmentClient;
|
||||||
|
Skins: IWeaponSkinClient[];
|
||||||
|
ModSlot: number;
|
||||||
|
CustSlot: number;
|
||||||
|
AttachedUpgrades: IUpgradeClient[];
|
||||||
|
HiddenWhenHolstered: boolean;
|
||||||
}
|
}
|
||||||
|
@ -38,17 +38,59 @@ const systemIndexes: Record<string, number[]> = {
|
|||||||
FC_INFESTATION: [23]
|
FC_INFESTATION: [23]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const showdownNodes: Record<string, string> = {
|
||||||
|
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.
|
// 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[] => {
|
export const getNemesisPasscode = (nemesis: { fp: bigint; Faction: string }): number[] => {
|
||||||
const rng = new SRng(nemesis.fp);
|
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") {
|
if (nemesis.Faction != "FC_INFESTATION") {
|
||||||
passcode.push(rng.randomInt(0, 7));
|
choices.splice(choiceIndex, 1);
|
||||||
passcode.push(rng.randomInt(0, 7));
|
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;
|
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 = (
|
export const encodeNemesisGuess = (
|
||||||
symbol1: number,
|
symbol1: number,
|
||||||
result1: number,
|
result1: number,
|
||||||
@ -79,6 +121,31 @@ export interface IKnifeResponse {
|
|||||||
HasKnife?: boolean;
|
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 = (
|
export const consumeModCharge = (
|
||||||
response: IKnifeResponse,
|
response: IKnifeResponse,
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user