forked from OpenWF/SpaceNinjaServer
Compare commits
6 Commits
870ff2dd2c
...
45c0da6ed8
Author | SHA1 | Date | |
---|---|---|---|
45c0da6ed8 | |||
727f6837ba | |||
77a3b64f49 | |||
ce59086f7d | |||
9b0989f1df | |||
b01376f703 |
@ -32,6 +32,7 @@ ENV APP_NO_MASTERY_RANK_UP_COOLDOWN=false
|
|||||||
ENV APP_NO_VENDOR_PURCHASE_LIMITS=true
|
ENV APP_NO_VENDOR_PURCHASE_LIMITS=true
|
||||||
ENV APP_NO_DEATH_MARKS=false
|
ENV APP_NO_DEATH_MARKS=false
|
||||||
ENV APP_NO_KIM_COOLDOWNS=false
|
ENV APP_NO_KIM_COOLDOWNS=false
|
||||||
|
ENV APP_INSTANT_FINISH_RIVEN_CHALLENGE=false
|
||||||
ENV APP_INSTANT_RESOURCE_EXTRACTOR_DRONES=false
|
ENV APP_INSTANT_RESOURCE_EXTRACTOR_DRONES=false
|
||||||
ENV APP_NO_RESOURCE_EXTRACTOR_DRONES_DAMAGE=false
|
ENV APP_NO_RESOURCE_EXTRACTOR_DRONES_DAMAGE=false
|
||||||
ENV APP_SKIP_CLAN_KEY_CRAFTING=false
|
ENV APP_SKIP_CLAN_KEY_CRAFTING=false
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
"noVendorPurchaseLimits": true,
|
"noVendorPurchaseLimits": true,
|
||||||
"noDeathMarks": false,
|
"noDeathMarks": false,
|
||||||
"noKimCooldowns": false,
|
"noKimCooldowns": false,
|
||||||
|
"instantFinishRivenChallenge": false,
|
||||||
"instantResourceExtractorDrones": false,
|
"instantResourceExtractorDrones": false,
|
||||||
"noResourceExtractorDronesDamage": false,
|
"noResourceExtractorDronesDamage": false,
|
||||||
"skipClanKeyCrafting": false,
|
"skipClanKeyCrafting": false,
|
||||||
|
@ -39,6 +39,7 @@ services:
|
|||||||
# APP_NO_VENDOR_PURCHASE_LIMITS: true
|
# APP_NO_VENDOR_PURCHASE_LIMITS: true
|
||||||
# APP_NO_DEATH_MARKS: false
|
# APP_NO_DEATH_MARKS: false
|
||||||
# APP_NO_KIM_COOLDOWNS: false
|
# APP_NO_KIM_COOLDOWNS: false
|
||||||
|
# APP_INSTANT_FINISH_RIVEN_CHALLENGE: false
|
||||||
# APP_INSTANT_RESOURCE_EXTRACTOR_DRONES: false
|
# APP_INSTANT_RESOURCE_EXTRACTOR_DRONES: false
|
||||||
# APP_NO_RESOURCE_EXTRACTOR_DRONES_DAMAGE: false
|
# APP_NO_RESOURCE_EXTRACTOR_DRONES_DAMAGE: false
|
||||||
# APP_SKIP_CLAN_KEY_CRAFTING: false
|
# APP_SKIP_CLAN_KEY_CRAFTING: false
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
|
import { toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import { createVeiledRivenFingerprint, rivenRawToRealWeighted } from "@/src/helpers/rivenHelper";
|
import {
|
||||||
|
createVeiledRivenFingerprint,
|
||||||
|
createUnveiledRivenFingerprint,
|
||||||
|
rivenRawToRealWeighted
|
||||||
|
} from "@/src/helpers/rivenHelper";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { addMods, getInventory } from "@/src/services/inventoryService";
|
import { addMods, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getRandomElement } from "@/src/services/rngService";
|
import { getRandomElement } from "@/src/services/rngService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { ExportUpgrades } from "warframe-public-export-plus";
|
import { ExportUpgrades } from "warframe-public-export-plus";
|
||||||
|
import { config } from "@/src/services/configService";
|
||||||
|
|
||||||
export const activateRandomModController: RequestHandler = async (req, res) => {
|
export const activateRandomModController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -18,7 +23,9 @@ export const activateRandomModController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType])!;
|
const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType])!;
|
||||||
const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
|
const fingerprint = config.instantFinishRivenChallenge
|
||||||
|
? createUnveiledRivenFingerprint(ExportUpgrades[rivenType])
|
||||||
|
: createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
|
||||||
const upgradeIndex =
|
const upgradeIndex =
|
||||||
inventory.Upgrades.push({
|
inventory.Upgrades.push({
|
||||||
ItemType: rivenType,
|
ItemType: rivenType,
|
||||||
|
@ -75,7 +75,7 @@ export const addToAllianceController: RequestHandler = async (req, res) => {
|
|||||||
const invitedClanOwnerMember = (await GuildMember.findOne({ guildId: guilds[0]._id, rank: 0 }))!;
|
const invitedClanOwnerMember = (await GuildMember.findOne({ guildId: guilds[0]._id, rank: 0 }))!;
|
||||||
const senderInventory = await getInventory(account._id.toString(), "ActiveAvatarImageType");
|
const senderInventory = await getInventory(account._id.toString(), "ActiveAvatarImageType");
|
||||||
const senderGuild = (await Guild.findById(allianceMember.guildId, "Name"))!;
|
const senderGuild = (await Guild.findById(allianceMember.guildId, "Name"))!;
|
||||||
const alliance = (await Alliance.findById(req.query.allianceId, "Name"))!;
|
const alliance = (await Alliance.findById(req.query.allianceId as string, "Name"))!;
|
||||||
await createMessage(invitedClanOwnerMember.accountId, [
|
await createMessage(invitedClanOwnerMember.accountId, [
|
||||||
{
|
{
|
||||||
sndr: getSuffixedName(account),
|
sndr: getSuffixedName(account),
|
||||||
|
@ -24,7 +24,7 @@ import {
|
|||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { catBreadHash } from "@/src/helpers/stringHelpers";
|
import { catBreadHash } from "@/src/helpers/stringHelpers";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { isNemesisCompatibleWithVersion } from "@/src/helpers/nemesisHelpers";
|
import { getNemesisManifest } from "@/src/helpers/nemesisHelpers";
|
||||||
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
||||||
import { IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
|
import { IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
|
||||||
import { Ship } from "@/src/models/shipModel";
|
import { Ship } from "@/src/models/shipModel";
|
||||||
@ -308,7 +308,10 @@ export const getInventoryResponse = async (
|
|||||||
|
|
||||||
if (buildLabel) {
|
if (buildLabel) {
|
||||||
// Fix nemesis for older versions
|
// Fix nemesis for older versions
|
||||||
if (inventoryResponse.Nemesis && !isNemesisCompatibleWithVersion(inventoryResponse.Nemesis, buildLabel)) {
|
if (
|
||||||
|
inventoryResponse.Nemesis &&
|
||||||
|
version_compare(getNemesisManifest(inventoryResponse.Nemesis.manifest).minBuild, buildLabel) < 0
|
||||||
|
) {
|
||||||
inventoryResponse.Nemesis = undefined;
|
inventoryResponse.Nemesis = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,7 +343,7 @@ export const getInventoryResponse = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
const addString = (arr: string[], str: string): void => {
|
const addString = (arr: string[], str: string): void => {
|
||||||
if (!arr.find(x => x == str)) {
|
if (arr.indexOf(str) == -1) {
|
||||||
arr.push(str);
|
arr.push(str);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -26,7 +26,7 @@ export const loginRewardsSelectionController: RequestHandler = async (req, res)
|
|||||||
StoreItemType: body.ChosenReward
|
StoreItemType: body.ChosenReward
|
||||||
};
|
};
|
||||||
inventoryChanges = (await handleStoreItemAcquisition(body.ChosenReward, inventory)).InventoryChanges;
|
inventoryChanges = (await handleStoreItemAcquisition(body.ChosenReward, inventory)).InventoryChanges;
|
||||||
if (!evergreenRewards.find(x => x == body.ChosenReward)) {
|
if (evergreenRewards.indexOf(body.ChosenReward) == -1) {
|
||||||
inventory.LoginMilestoneRewards.push(body.ChosenReward);
|
inventory.LoginMilestoneRewards.push(body.ChosenReward);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
|
import { version_compare } from "@/src/helpers/inventoryHelpers";
|
||||||
import {
|
import {
|
||||||
consumeModCharge,
|
consumeModCharge,
|
||||||
encodeNemesisGuess,
|
encodeNemesisGuess,
|
||||||
getInfNodes,
|
getInfNodes,
|
||||||
getKnifeUpgrade,
|
getKnifeUpgrade,
|
||||||
|
getNemesisManifest,
|
||||||
getNemesisPasscode,
|
getNemesisPasscode,
|
||||||
getNemesisPasscodeModTypes,
|
getNemesisPasscodeModTypes,
|
||||||
getWeaponsForManifest,
|
IKnifeResponse
|
||||||
IKnifeResponse,
|
|
||||||
nemesisFactionInfos
|
|
||||||
} 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";
|
||||||
import { freeUpSlot, getInventory } from "@/src/services/inventoryService";
|
import { freeUpSlot, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountForRequest } from "@/src/services/loginService";
|
||||||
import { SRng } from "@/src/services/rngService";
|
import { SRng } from "@/src/services/rngService";
|
||||||
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
@ -31,10 +31,10 @@ import { logger } from "@/src/utils/logger";
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const nemesisController: RequestHandler = async (req, res) => {
|
export const nemesisController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const account = await getAccountForRequest(req);
|
||||||
if ((req.query.mode as string) == "f") {
|
if ((req.query.mode as string) == "f") {
|
||||||
const body = getJSONfromString<IValenceFusionRequest>(String(req.body));
|
const body = getJSONfromString<IValenceFusionRequest>(String(req.body));
|
||||||
const inventory = await getInventory(accountId, body.Category + " WeaponBin");
|
const inventory = await getInventory(account._id.toString(), body.Category + " WeaponBin");
|
||||||
const destWeapon = inventory[body.Category].id(body.DestWeapon.$oid)!;
|
const destWeapon = inventory[body.Category].id(body.DestWeapon.$oid)!;
|
||||||
const sourceWeapon = inventory[body.Category].id(body.SourceWeapon.$oid)!;
|
const sourceWeapon = inventory[body.Category].id(body.SourceWeapon.$oid)!;
|
||||||
const destFingerprint = JSON.parse(destWeapon.UpgradeFingerprint!) as IInnateDamageFingerprint;
|
const destFingerprint = JSON.parse(destWeapon.UpgradeFingerprint!) as IInnateDamageFingerprint;
|
||||||
@ -69,7 +69,7 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if ((req.query.mode as string) == "p") {
|
} else if ((req.query.mode as string) == "p") {
|
||||||
const inventory = await getInventory(accountId, "Nemesis");
|
const inventory = await getInventory(account._id.toString(), "Nemesis");
|
||||||
const body = getJSONfromString<INemesisPrespawnCheckRequest>(String(req.body));
|
const body = getJSONfromString<INemesisPrespawnCheckRequest>(String(req.body));
|
||||||
const passcode = getNemesisPasscode(inventory.Nemesis!);
|
const passcode = getNemesisPasscode(inventory.Nemesis!);
|
||||||
let guessResult = 0;
|
let guessResult = 0;
|
||||||
@ -90,7 +90,7 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
res.json({ GuessResult: guessResult });
|
res.json({ GuessResult: guessResult });
|
||||||
} else if (req.query.mode == "r") {
|
} else if (req.query.mode == "r") {
|
||||||
const inventory = await getInventory(
|
const inventory = await getInventory(
|
||||||
accountId,
|
account._id.toString(),
|
||||||
"Nemesis LoadOutPresets CurrentLoadOutIds DataKnives Upgrades RawUpgrades"
|
"Nemesis LoadOutPresets CurrentLoadOutIds DataKnives Upgrades RawUpgrades"
|
||||||
);
|
);
|
||||||
const body = getJSONfromString<INemesisRequiemRequest>(String(req.body));
|
const body = getJSONfromString<INemesisRequiemRequest>(String(req.body));
|
||||||
@ -144,7 +144,7 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
if (inventory.Nemesis!.HenchmenKilled >= 100) {
|
if (inventory.Nemesis!.HenchmenKilled >= 100) {
|
||||||
inventory.Nemesis!.HenchmenKilled = 100;
|
inventory.Nemesis!.HenchmenKilled = 100;
|
||||||
}
|
}
|
||||||
inventory.Nemesis!.InfNodes = getInfNodes("FC_INFESTATION", 0);
|
inventory.Nemesis!.InfNodes = getInfNodes(getNemesisManifest(inventory.Nemesis!.manifest), 0);
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json(response);
|
res.json(response);
|
||||||
@ -154,30 +154,40 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
res.end();
|
res.end();
|
||||||
} else {
|
} else {
|
||||||
inventory.Nemesis!.Rank += 1;
|
inventory.Nemesis!.Rank += 1;
|
||||||
inventory.Nemesis!.InfNodes = getInfNodes(inventory.Nemesis!.Faction, inventory.Nemesis!.Rank);
|
inventory.Nemesis!.InfNodes = getInfNodes(
|
||||||
|
getNemesisManifest(inventory.Nemesis!.manifest),
|
||||||
|
inventory.Nemesis!.Rank
|
||||||
|
);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({ RankIncrease: 1 });
|
res.json({ RankIncrease: 1 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ((req.query.mode as string) == "rs") {
|
} else if ((req.query.mode as string) == "rs") {
|
||||||
// report spawn; POST but no application data in body
|
// report spawn; POST but no application data in body
|
||||||
const inventory = await getInventory(accountId, "Nemesis");
|
const inventory = await getInventory(account._id.toString(), "Nemesis");
|
||||||
inventory.Nemesis!.LastEnc = inventory.Nemesis!.MissionCount;
|
inventory.Nemesis!.LastEnc = inventory.Nemesis!.MissionCount;
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({ LastEnc: inventory.Nemesis!.LastEnc });
|
res.json({ LastEnc: inventory.Nemesis!.LastEnc });
|
||||||
} else if ((req.query.mode as string) == "s") {
|
} else if ((req.query.mode as string) == "s") {
|
||||||
const inventory = await getInventory(accountId, "Nemesis");
|
const inventory = await getInventory(account._id.toString(), "Nemesis");
|
||||||
const body = getJSONfromString<INemesisStartRequest>(String(req.body));
|
const body = getJSONfromString<INemesisStartRequest>(String(req.body));
|
||||||
body.target.fp = BigInt(body.target.fp);
|
body.target.fp = BigInt(body.target.fp);
|
||||||
|
|
||||||
|
const manifest = getNemesisManifest(body.target.manifest);
|
||||||
|
if (account.BuildLabel && version_compare(manifest.minBuild, account.BuildLabel) < 0) {
|
||||||
|
logger.warn(
|
||||||
|
`client on version ${account.BuildLabel} provided nemesis manifest ${body.target.manifest} which was expected to require ${manifest.minBuild} or above. please file a bug report.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let weaponIdx = -1;
|
let weaponIdx = -1;
|
||||||
if (body.target.Faction != "FC_INFESTATION") {
|
if (body.target.Faction != "FC_INFESTATION") {
|
||||||
const weapons = getWeaponsForManifest(body.target.manifest);
|
const weapons: readonly string[] = manifest.weapons;
|
||||||
const initialWeaponIdx = new SRng(body.target.fp).randomInt(0, weapons.length - 1);
|
const initialWeaponIdx = new SRng(body.target.fp).randomInt(0, weapons.length - 1);
|
||||||
weaponIdx = initialWeaponIdx;
|
weaponIdx = initialWeaponIdx;
|
||||||
do {
|
do {
|
||||||
const weapon = weapons[weaponIdx];
|
const weapon = weapons[weaponIdx];
|
||||||
if (!body.target.DisallowedWeapons.find(x => x == weapon)) {
|
if (body.target.DisallowedWeapons.indexOf(weapon) == -1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
weaponIdx = (weaponIdx + 1) % weapons.length;
|
weaponIdx = (weaponIdx + 1) % weapons.length;
|
||||||
@ -198,7 +208,7 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
k: false,
|
k: false,
|
||||||
Traded: false,
|
Traded: false,
|
||||||
d: new Date(),
|
d: new Date(),
|
||||||
InfNodes: getInfNodes(body.target.Faction, 0),
|
InfNodes: getInfNodes(manifest, 0),
|
||||||
GuessHistory: [],
|
GuessHistory: [],
|
||||||
Hints: [],
|
Hints: [],
|
||||||
HintProgress: 0,
|
HintProgress: 0,
|
||||||
@ -216,14 +226,14 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
});
|
});
|
||||||
} else if ((req.query.mode as string) == "w") {
|
} else if ((req.query.mode as string) == "w") {
|
||||||
const inventory = await getInventory(
|
const inventory = await getInventory(
|
||||||
accountId,
|
account._id.toString(),
|
||||||
"Nemesis LoadOutPresets CurrentLoadOutIds DataKnives Upgrades RawUpgrades"
|
"Nemesis LoadOutPresets CurrentLoadOutIds DataKnives Upgrades RawUpgrades"
|
||||||
);
|
);
|
||||||
//const body = getJSONfromString<INemesisWeakenRequest>(String(req.body));
|
//const body = getJSONfromString<INemesisWeakenRequest>(String(req.body));
|
||||||
|
|
||||||
inventory.Nemesis!.InfNodes = [
|
inventory.Nemesis!.InfNodes = [
|
||||||
{
|
{
|
||||||
Node: nemesisFactionInfos[inventory.Nemesis!.Faction].showdownNode,
|
Node: getNemesisManifest(inventory.Nemesis!.manifest).showdownNode,
|
||||||
Influence: 1
|
Influence: 1
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -84,7 +84,10 @@ export const getProfileViewingDataGetController: RequestHandler = async (req, re
|
|||||||
res.status(409).send("Could not find requested account");
|
res.status(409).send("Could not find requested account");
|
||||||
}
|
}
|
||||||
} else if (req.query.guildId) {
|
} else if (req.query.guildId) {
|
||||||
const guild = await Guild.findById(req.query.guildId, "Name Tier XP Class Emblem TechProjects ClaimedXP");
|
const guild = await Guild.findById(
|
||||||
|
req.query.guildId as string,
|
||||||
|
"Name Tier XP Class Emblem TechProjects ClaimedXP"
|
||||||
|
);
|
||||||
if (!guild) {
|
if (!guild) {
|
||||||
res.status(409).send("Could not find guild");
|
res.status(409).send("Could not find guild");
|
||||||
return;
|
return;
|
||||||
|
@ -7,51 +7,197 @@ import { IOid } from "../types/commonTypes";
|
|||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { addMods, generateRewardSeed } from "../services/inventoryService";
|
import { addMods, generateRewardSeed } from "../services/inventoryService";
|
||||||
import { isArchwingMission } from "../services/worldStateService";
|
import { isArchwingMission } from "../services/worldStateService";
|
||||||
import { version_compare } from "./inventoryHelpers";
|
|
||||||
|
|
||||||
export interface INemesisFactionInfo {
|
type TInnateDamageTag =
|
||||||
systemIndexes: number[];
|
| "InnateElectricityDamage"
|
||||||
|
| "InnateHeatDamage"
|
||||||
|
| "InnateFreezeDamage"
|
||||||
|
| "InnateToxinDamage"
|
||||||
|
| "InnateMagDamage"
|
||||||
|
| "InnateRadDamage"
|
||||||
|
| "InnateImpactDamage";
|
||||||
|
|
||||||
|
export interface INemesisManifest {
|
||||||
|
weapons: readonly string[];
|
||||||
|
systemIndexes: readonly number[];
|
||||||
showdownNode: string;
|
showdownNode: string;
|
||||||
ephemeraChance: number;
|
ephemeraChance: number;
|
||||||
|
ephemeraTypes?: Record<TInnateDamageTag, string>;
|
||||||
firstKillReward: string;
|
firstKillReward: string;
|
||||||
firstConvertReward: string;
|
firstConvertReward: string;
|
||||||
messageTitle: string;
|
messageTitle: string;
|
||||||
messageBody: string;
|
messageBody: string;
|
||||||
|
minBuild: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const nemesisFactionInfos: Record<TNemesisFaction, INemesisFactionInfo> = {
|
class KuvaLichManifest implements INemesisManifest {
|
||||||
FC_GRINEER: {
|
weapons = [
|
||||||
systemIndexes: [2, 3, 9, 11, 18],
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Drakgoon/KuvaDrakgoon",
|
||||||
showdownNode: "CrewBattleNode557",
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Karak/KuvaKarak",
|
||||||
ephemeraChance: 0.05,
|
"/Lotus/Weapons/Grineer/Melee/GrnKuvaLichScythe/GrnKuvaLichScytheWeapon",
|
||||||
firstKillReward: "/Lotus/StoreItems/Upgrades/Skins/Clan/LichKillerBadgeItem",
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Kohm/KuvaKohm",
|
||||||
firstConvertReward: "/Lotus/StoreItems/Upgrades/Skins/Sigils/KuvaLichSigil",
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Ogris/KuvaOgris",
|
||||||
messageTitle: "/Lotus/Language/Inbox/VanquishKuvaMsgTitle",
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Quartakk/KuvaQuartakk",
|
||||||
messageBody: "/Lotus/Language/Inbox/VanquishLichMsgBody"
|
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Tonkor/KuvaTonkor",
|
||||||
},
|
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Brakk/KuvaBrakk",
|
||||||
FC_CORPUS: {
|
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Kraken/KuvaKraken",
|
||||||
systemIndexes: [1, 15, 4, 7, 8],
|
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Seer/KuvaSeer",
|
||||||
showdownNode: "CrewBattleNode558",
|
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Stubba/KuvaStubba",
|
||||||
ephemeraChance: 0.2,
|
"/Lotus/Weapons/Grineer/HeavyWeapons/GrnHeavyGrenadeLauncher",
|
||||||
firstKillReward: "/Lotus/StoreItems/Upgrades/Skins/Clan/CorpusLichBadgeItem",
|
"/Lotus/Weapons/Grineer/LongGuns/GrnKuvaLichRifle/GrnKuvaLichRifleWeapon"
|
||||||
firstConvertReward: "/Lotus/StoreItems/Upgrades/Skins/Sigils/CorpusLichSigil",
|
];
|
||||||
messageTitle: "/Lotus/Language/Inbox/VanquishLawyerMsgTitle",
|
systemIndexes = [2, 3, 9, 11, 18];
|
||||||
messageBody: "/Lotus/Language/Inbox/VanquishLichMsgBody"
|
showdownNode = "CrewBattleNode557";
|
||||||
},
|
ephemeraChance = 0.05;
|
||||||
FC_INFESTATION: {
|
ephemeraTypes = {
|
||||||
systemIndexes: [23],
|
InnateElectricityDamage: "/Lotus/Upgrades/Skins/Effects/Kuva/KuvaLightningEphemera",
|
||||||
showdownNode: "CrewBattleNode559",
|
InnateHeatDamage: "/Lotus/Upgrades/Skins/Effects/Kuva/KuvaFireEphemera",
|
||||||
ephemeraChance: 0,
|
InnateFreezeDamage: "/Lotus/Upgrades/Skins/Effects/Kuva/KuvaIceEphemera",
|
||||||
firstKillReward: "/Lotus/StoreItems/Upgrades/Skins/Sigils/InfLichVanquishedSigil",
|
InnateToxinDamage: "/Lotus/Upgrades/Skins/Effects/Kuva/KuvaToxinEphemera",
|
||||||
firstConvertReward: "/Lotus/StoreItems/Upgrades/Skins/Sigils/InfLichConvertedSigil",
|
InnateMagDamage: "/Lotus/Upgrades/Skins/Effects/Kuva/KuvaMagneticEphemera",
|
||||||
messageTitle: "/Lotus/Language/Inbox/VanquishBandMsgTitle",
|
InnateRadDamage: "/Lotus/Upgrades/Skins/Effects/Kuva/KuvaTricksterEphemera",
|
||||||
messageBody: "/Lotus/Language/Inbox/VanquishBandMsgBody"
|
InnateImpactDamage: "/Lotus/Upgrades/Skins/Effects/Kuva/KuvaImpactEphemera"
|
||||||
|
};
|
||||||
|
firstKillReward = "/Lotus/StoreItems/Upgrades/Skins/Clan/LichKillerBadgeItem";
|
||||||
|
firstConvertReward = "/Lotus/StoreItems/Upgrades/Skins/Sigils/KuvaLichSigil";
|
||||||
|
messageTitle = "/Lotus/Language/Inbox/VanquishKuvaMsgTitle";
|
||||||
|
messageBody = "/Lotus/Language/Inbox/VanquishLichMsgBody";
|
||||||
|
minBuild = "2019.10.31.22.42"; // 26.0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
class KuvaLichManifestVersionTwo extends KuvaLichManifest {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.ephemeraChance = 0.1;
|
||||||
|
this.minBuild = "2020.03.05.16.06"; // Unsure about this one, so using the same value as in version three.
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KuvaLichManifestVersionThree extends KuvaLichManifestVersionTwo {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.weapons.push("/Lotus/Weapons/Grineer/Bows/GrnBow/GrnBowWeapon");
|
||||||
|
this.weapons.push("/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hind/KuvaHind");
|
||||||
|
this.weapons.push("/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Nukor/KuvaNukor");
|
||||||
|
this.ephemeraChance = 0.2;
|
||||||
|
this.minBuild = "2020.03.05.16.06"; // This is 27.2.0, tho 27.1.0 should also recognise this.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KuvaLichManifestVersionFour extends KuvaLichManifestVersionThree {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.minBuild = "2021.07.05.17.03"; // Unsure about this one, so using the same value as in version five.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KuvaLichManifestVersionFive extends KuvaLichManifestVersionFour {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.weapons.push("/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hek/KuvaHekWeapon");
|
||||||
|
this.weapons.push("/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Zarr/KuvaZarr");
|
||||||
|
this.weapons.push("/Lotus/Weapons/Grineer/KuvaLich/HeavyWeapons/Grattler/KuvaGrattler");
|
||||||
|
this.minBuild = "2021.07.05.17.03"; // 30.5.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KuvaLichManifestVersionSix extends KuvaLichManifestVersionFive {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.weapons.push("/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Sobek/KuvaSobek");
|
||||||
|
this.minBuild = "2024.05.15.11.07"; // 35.6.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LawyerManifest implements INemesisManifest {
|
||||||
|
weapons = [
|
||||||
|
"/Lotus/Weapons/Corpus/LongGuns/CrpBriefcaseLauncher/CrpBriefcaseLauncher",
|
||||||
|
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEArcaPlasmor/CrpBEArcaPlasmor",
|
||||||
|
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEFluxRifle/CrpBEFluxRifle",
|
||||||
|
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBETetra/CrpBETetra",
|
||||||
|
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBECycron/CrpBECycron",
|
||||||
|
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEDetron/CrpBEDetron",
|
||||||
|
"/Lotus/Weapons/Corpus/Pistols/CrpIgniterPistol/CrpIgniterPistol",
|
||||||
|
"/Lotus/Weapons/Corpus/Pistols/CrpBriefcaseAkimbo/CrpBriefcaseAkimboPistol"
|
||||||
|
];
|
||||||
|
systemIndexes = [1, 15, 4, 7, 8];
|
||||||
|
showdownNode = "CrewBattleNode558";
|
||||||
|
ephemeraChance = 0.2;
|
||||||
|
ephemeraTypes = {
|
||||||
|
InnateElectricityDamage: "/Lotus/Upgrades/Skins/Effects/CorpusLichEphemeraA",
|
||||||
|
InnateHeatDamage: "/Lotus/Upgrades/Skins/Effects/CorpusLichEphemeraB",
|
||||||
|
InnateFreezeDamage: "/Lotus/Upgrades/Skins/Effects/CorpusLichEphemeraC",
|
||||||
|
InnateToxinDamage: "/Lotus/Upgrades/Skins/Effects/CorpusLichEphemeraD",
|
||||||
|
InnateMagDamage: "/Lotus/Upgrades/Skins/Effects/CorpusLichEphemeraE",
|
||||||
|
InnateRadDamage: "/Lotus/Upgrades/Skins/Effects/CorpusLichEphemeraF",
|
||||||
|
InnateImpactDamage: "/Lotus/Upgrades/Skins/Effects/CorpusLichEphemeraG"
|
||||||
|
};
|
||||||
|
firstKillReward = "/Lotus/StoreItems/Upgrades/Skins/Clan/CorpusLichBadgeItem";
|
||||||
|
firstConvertReward = "/Lotus/StoreItems/Upgrades/Skins/Sigils/CorpusLichSigil";
|
||||||
|
messageTitle = "/Lotus/Language/Inbox/VanquishLawyerMsgTitle";
|
||||||
|
messageBody = "/Lotus/Language/Inbox/VanquishLichMsgBody";
|
||||||
|
minBuild = "2021.07.05.17.03"; // 30.5.0
|
||||||
|
}
|
||||||
|
|
||||||
|
class LawyerManifestVersionTwo extends LawyerManifest {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.weapons.push("/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEPlinx/CrpBEPlinxWeapon");
|
||||||
|
this.minBuild = "2022.11.30.08.13"; // 32.2.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LawyerManifestVersionThree extends LawyerManifestVersionTwo {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.weapons.push("/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEGlaxion/CrpBEGlaxion");
|
||||||
|
this.minBuild = "2024.05.15.11.07"; // 35.6.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LawyerManifestVersionFour extends LawyerManifestVersionThree {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.minBuild = "2024.10.01.11.03"; // 37.0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class InfestedLichManfest implements INemesisManifest {
|
||||||
|
weapons = [];
|
||||||
|
systemIndexes = [23];
|
||||||
|
showdownNode = "CrewBattleNode559";
|
||||||
|
ephemeraChance = 0;
|
||||||
|
firstKillReward = "/Lotus/StoreItems/Upgrades/Skins/Sigils/InfLichVanquishedSigil";
|
||||||
|
firstConvertReward = "/Lotus/StoreItems/Upgrades/Skins/Sigils/InfLichConvertedSigil";
|
||||||
|
messageTitle = "/Lotus/Language/Inbox/VanquishBandMsgTitle";
|
||||||
|
messageBody = "/Lotus/Language/Inbox/VanquishBandMsgBody";
|
||||||
|
minBuild = "2025.03.18.09.51"; // 38.5.0
|
||||||
|
}
|
||||||
|
|
||||||
|
const nemesisManifests: Record<string, INemesisManifest> = {
|
||||||
|
"/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifest": new KuvaLichManifest(),
|
||||||
|
"/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionTwo": new KuvaLichManifestVersionTwo(),
|
||||||
|
"/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionThree": new KuvaLichManifestVersionThree(),
|
||||||
|
"/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionFour": new KuvaLichManifestVersionFour(),
|
||||||
|
"/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionFive": new KuvaLichManifestVersionFive(),
|
||||||
|
"/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionSix": new KuvaLichManifestVersionSix(),
|
||||||
|
"/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifest": new LawyerManifest(),
|
||||||
|
"/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionTwo": new LawyerManifestVersionTwo(),
|
||||||
|
"/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree": new LawyerManifestVersionThree(),
|
||||||
|
"/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour": new LawyerManifestVersionFour(),
|
||||||
|
"/Lotus/Types/Enemies/InfestedLich/InfestedLichManifest": new InfestedLichManfest()
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getInfNodes = (faction: TNemesisFaction, rank: number): IInfNode[] => {
|
export const getNemesisManifest = (manifest: string): INemesisManifest => {
|
||||||
|
if (manifest in nemesisManifests) {
|
||||||
|
return nemesisManifests[manifest];
|
||||||
|
}
|
||||||
|
throw new Error(`unknown nemesis manifest: ${manifest}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getInfNodes = (manifest: INemesisManifest, rank: number): IInfNode[] => {
|
||||||
const infNodes = [];
|
const infNodes = [];
|
||||||
const systemIndex = nemesisFactionInfos[faction].systemIndexes[rank];
|
const systemIndex = manifest.systemIndexes[rank];
|
||||||
for (const [key, value] of Object.entries(ExportRegions)) {
|
for (const [key, value] of Object.entries(ExportRegions)) {
|
||||||
if (
|
if (
|
||||||
value.systemIndex === systemIndex &&
|
value.systemIndex === systemIndex &&
|
||||||
@ -73,36 +219,6 @@ export const getInfNodes = (faction: TNemesisFaction, rank: number): IInfNode[]
|
|||||||
return infNodes;
|
return infNodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
type TInnateDamageTag =
|
|
||||||
| "InnateElectricityDamage"
|
|
||||||
| "InnateHeatDamage"
|
|
||||||
| "InnateFreezeDamage"
|
|
||||||
| "InnateToxinDamage"
|
|
||||||
| "InnateMagDamage"
|
|
||||||
| "InnateRadDamage"
|
|
||||||
| "InnateImpactDamage";
|
|
||||||
|
|
||||||
const ephmeraTypes: Record<"FC_GRINEER" | "FC_CORPUS", Record<TInnateDamageTag, string>> = {
|
|
||||||
FC_GRINEER: {
|
|
||||||
InnateElectricityDamage: "/Lotus/Upgrades/Skins/Effects/Kuva/KuvaLightningEphemera",
|
|
||||||
InnateHeatDamage: "/Lotus/Upgrades/Skins/Effects/Kuva/KuvaFireEphemera",
|
|
||||||
InnateFreezeDamage: "/Lotus/Upgrades/Skins/Effects/Kuva/KuvaIceEphemera",
|
|
||||||
InnateToxinDamage: "/Lotus/Upgrades/Skins/Effects/Kuva/KuvaToxinEphemera",
|
|
||||||
InnateMagDamage: "/Lotus/Upgrades/Skins/Effects/Kuva/KuvaMagneticEphemera",
|
|
||||||
InnateRadDamage: "/Lotus/Upgrades/Skins/Effects/Kuva/KuvaTricksterEphemera",
|
|
||||||
InnateImpactDamage: "/Lotus/Upgrades/Skins/Effects/Kuva/KuvaImpactEphemera"
|
|
||||||
},
|
|
||||||
FC_CORPUS: {
|
|
||||||
InnateElectricityDamage: "/Lotus/Upgrades/Skins/Effects/CorpusLichEphemeraA",
|
|
||||||
InnateHeatDamage: "/Lotus/Upgrades/Skins/Effects/CorpusLichEphemeraB",
|
|
||||||
InnateFreezeDamage: "/Lotus/Upgrades/Skins/Effects/CorpusLichEphemeraC",
|
|
||||||
InnateToxinDamage: "/Lotus/Upgrades/Skins/Effects/CorpusLichEphemeraD",
|
|
||||||
InnateMagDamage: "/Lotus/Upgrades/Skins/Effects/CorpusLichEphemeraE",
|
|
||||||
InnateRadDamage: "/Lotus/Upgrades/Skins/Effects/CorpusLichEphemeraF",
|
|
||||||
InnateImpactDamage: "/Lotus/Upgrades/Skins/Effects/CorpusLichEphemeraG"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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: TNemesisFaction }): number[] => {
|
export const getNemesisPasscode = (nemesis: { fp: bigint; Faction: TNemesisFaction }): number[] => {
|
||||||
const rng = new SRng(nemesis.fp);
|
const rng = new SRng(nemesis.fp);
|
||||||
@ -256,77 +372,6 @@ export const consumeModCharge = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const kuvaLichVersionSixWeapons = [
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Drakgoon/KuvaDrakgoon",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Karak/KuvaKarak",
|
|
||||||
"/Lotus/Weapons/Grineer/Melee/GrnKuvaLichScythe/GrnKuvaLichScytheWeapon",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Kohm/KuvaKohm",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Ogris/KuvaOgris",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Quartakk/KuvaQuartakk",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Tonkor/KuvaTonkor",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Brakk/KuvaBrakk",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Kraken/KuvaKraken",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Seer/KuvaSeer",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Stubba/KuvaStubba",
|
|
||||||
"/Lotus/Weapons/Grineer/HeavyWeapons/GrnHeavyGrenadeLauncher",
|
|
||||||
"/Lotus/Weapons/Grineer/LongGuns/GrnKuvaLichRifle/GrnKuvaLichRifleWeapon",
|
|
||||||
"/Lotus/Weapons/Grineer/Bows/GrnBow/GrnBowWeapon",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hind/KuvaHind",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Nukor/KuvaNukor",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hek/KuvaHekWeapon",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Zarr/KuvaZarr",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/HeavyWeapons/Grattler/KuvaGrattler",
|
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Sobek/KuvaSobek"
|
|
||||||
];
|
|
||||||
|
|
||||||
const corpusVersionThreeWeapons = [
|
|
||||||
"/Lotus/Weapons/Corpus/LongGuns/CrpBriefcaseLauncher/CrpBriefcaseLauncher",
|
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEArcaPlasmor/CrpBEArcaPlasmor",
|
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEFluxRifle/CrpBEFluxRifle",
|
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBETetra/CrpBETetra",
|
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBECycron/CrpBECycron",
|
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEDetron/CrpBEDetron",
|
|
||||||
"/Lotus/Weapons/Corpus/Pistols/CrpIgniterPistol/CrpIgniterPistol",
|
|
||||||
"/Lotus/Weapons/Corpus/Pistols/CrpBriefcaseAkimbo/CrpBriefcaseAkimboPistol",
|
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEPlinx/CrpBEPlinxWeapon",
|
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEGlaxion/CrpBEGlaxion"
|
|
||||||
];
|
|
||||||
|
|
||||||
export const getWeaponsForManifest = (manifest: string): readonly string[] => {
|
|
||||||
switch (manifest) {
|
|
||||||
case "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionSix": // >= 35.6.0
|
|
||||||
return kuvaLichVersionSixWeapons;
|
|
||||||
case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree": // >= 35.6.0
|
|
||||||
case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour": // >= 37.0.0
|
|
||||||
return corpusVersionThreeWeapons;
|
|
||||||
}
|
|
||||||
throw new Error(`unknown nemesis manifest: ${manifest}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isNemesisCompatibleWithVersion = (
|
|
||||||
nemesis: { manifest: string; Faction: TNemesisFaction },
|
|
||||||
buildLabel: string
|
|
||||||
): boolean => {
|
|
||||||
// Anything below 35.6.0 is not going to be okay given our set of supported manifests.
|
|
||||||
if (version_compare(buildLabel, "2024.05.15.11.07") < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nemesis.Faction == "FC_INFESTATION") {
|
|
||||||
// Anything below 38.5.0 isn't gonna like an infested lich.
|
|
||||||
if (version_compare(buildLabel, "2025.03.18.16.07") < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (nemesis.manifest == "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour") {
|
|
||||||
// Anything below 37.0.0 isn't gonna know version 4, but version 3 is identical in terms of weapon choices, so we can spoof it to that.
|
|
||||||
if (version_compare(buildLabel, "2024.10.01.11.03") < 0) {
|
|
||||||
nemesis.manifest = "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getInnateDamageTag = (KillingSuit: string): TInnateDamageTag => {
|
export const getInnateDamageTag = (KillingSuit: string): TInnateDamageTag => {
|
||||||
return ExportWarframes[KillingSuit].nemesisUpgradeTag!;
|
return ExportWarframes[KillingSuit].nemesisUpgradeTag!;
|
||||||
};
|
};
|
||||||
@ -349,7 +394,7 @@ export interface INemesisProfile {
|
|||||||
|
|
||||||
export const generateNemesisProfile = (
|
export const generateNemesisProfile = (
|
||||||
fp: bigint = generateRewardSeed(),
|
fp: bigint = generateRewardSeed(),
|
||||||
Faction: TNemesisFaction = "FC_CORPUS",
|
manifest: INemesisManifest = new LawyerManifest(),
|
||||||
killingSuit: string = "/Lotus/Powersuits/Ember/Ember"
|
killingSuit: string = "/Lotus/Powersuits/Ember/Ember"
|
||||||
): INemesisProfile => {
|
): INemesisProfile => {
|
||||||
const rng = new SRng(fp);
|
const rng = new SRng(fp);
|
||||||
@ -363,11 +408,11 @@ export const generateNemesisProfile = (
|
|||||||
innateDamageTag: getInnateDamageTag(killingSuit),
|
innateDamageTag: getInnateDamageTag(killingSuit),
|
||||||
innateDamageValue: Math.trunc(value * 0x40000000) // TODO: For -1399275245665749231n, the value should be 75306944, but we're off by 59 with 75307003.
|
innateDamageValue: Math.trunc(value * 0x40000000) // TODO: For -1399275245665749231n, the value should be 75306944, but we're off by 59 with 75307003.
|
||||||
};
|
};
|
||||||
if (rng.randomFloat() <= nemesisFactionInfos[Faction].ephemeraChance && Faction != "FC_INFESTATION") {
|
if (rng.randomFloat() <= manifest.ephemeraChance && manifest.ephemeraTypes) {
|
||||||
profile.ephemera = ephmeraTypes[Faction][profile.innateDamageTag];
|
profile.ephemera = manifest.ephemeraTypes[profile.innateDamageTag];
|
||||||
}
|
}
|
||||||
rng.randomFloat(); // something related to sentinel agent maybe
|
rng.randomFloat(); // something related to sentinel agent maybe
|
||||||
if (Faction == "FC_CORPUS") {
|
if (manifest instanceof LawyerManifest) {
|
||||||
profile.petHead = rng.randomElement(petHeads)!;
|
profile.petHead = rng.randomElement(petHeads)!;
|
||||||
profile.petBody = rng.randomElement([
|
profile.petBody = rng.randomElement([
|
||||||
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyA",
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyA",
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
export const rootDir = path.join(__dirname, "../..");
|
export const rootDir = path.join(__dirname, "../..");
|
||||||
export const repoDir = path.basename(rootDir) == "build" ? path.join(rootDir, "..") : rootDir;
|
export const isDev = path.basename(rootDir) != "build";
|
||||||
|
export const repoDir = isDev ? rootDir : path.join(rootDir, "..");
|
||||||
|
@ -44,6 +44,7 @@ interface IConfig {
|
|||||||
noVendorPurchaseLimits?: boolean;
|
noVendorPurchaseLimits?: boolean;
|
||||||
noDeathMarks?: boolean;
|
noDeathMarks?: boolean;
|
||||||
noKimCooldowns?: boolean;
|
noKimCooldowns?: boolean;
|
||||||
|
instantFinishRivenChallenge?: boolean;
|
||||||
instantResourceExtractorDrones?: boolean;
|
instantResourceExtractorDrones?: boolean;
|
||||||
noResourceExtractorDronesDamage?: boolean;
|
noResourceExtractorDronesDamage?: boolean;
|
||||||
skipClanKeyCrafting?: boolean;
|
skipClanKeyCrafting?: boolean;
|
||||||
|
@ -445,7 +445,7 @@ export const addGuildMemberShipDecoContribution = (guildMember: IGuildMemberData
|
|||||||
export const processDojoBuildMaterialsGathered = (guild: TGuildDatabaseDocument, build: IDojoBuild): void => {
|
export const processDojoBuildMaterialsGathered = (guild: TGuildDatabaseDocument, build: IDojoBuild): void => {
|
||||||
if (build.guildXpValue) {
|
if (build.guildXpValue) {
|
||||||
guild.ClaimedXP ??= [];
|
guild.ClaimedXP ??= [];
|
||||||
if (!guild.ClaimedXP.find(x => x == build.resultType)) {
|
if (guild.ClaimedXP.indexOf(build.resultType) == -1) {
|
||||||
guild.ClaimedXP.push(build.resultType);
|
guild.ClaimedXP.push(build.resultType);
|
||||||
guild.XP += build.guildXpValue;
|
guild.XP += build.guildXpValue;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ export const getAccountForRequest = async (req: Request): Promise<TAccountDocume
|
|||||||
throw new Error("Request is missing nonce parameter");
|
throw new Error("Request is missing nonce parameter");
|
||||||
}
|
}
|
||||||
|
|
||||||
const account = await Account.findById(req.query.accountId);
|
const account = await Account.findById(req.query.accountId as string);
|
||||||
if (!account || account.Nonce != nonce) {
|
if (!account || account.Nonce != nonce) {
|
||||||
throw new Error("Invalid accountId-nonce pair");
|
throw new Error("Invalid accountId-nonce pair");
|
||||||
}
|
}
|
||||||
@ -90,7 +90,7 @@ export const getAccountIdForRequest = async (req: Request): Promise<string> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const isAdministrator = (account: TAccountDocument): boolean => {
|
export const isAdministrator = (account: TAccountDocument): boolean => {
|
||||||
return !!config.administratorNames?.find(x => x == account.DisplayName);
|
return config.administratorNames?.indexOf(account.DisplayName) != -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
const platform_magics = [753, 639, 247, 37, 60];
|
const platform_magics = [753, 639, 247, 37, 60];
|
||||||
|
@ -61,9 +61,8 @@ import {
|
|||||||
getInfestedLichItemRewards,
|
getInfestedLichItemRewards,
|
||||||
getInfNodes,
|
getInfNodes,
|
||||||
getKillTokenRewardCount,
|
getKillTokenRewardCount,
|
||||||
getNemesisPasscode,
|
getNemesisManifest,
|
||||||
getWeaponsForManifest,
|
getNemesisPasscode
|
||||||
nemesisFactionInfos
|
|
||||||
} from "@/src/helpers/nemesisHelpers";
|
} from "@/src/helpers/nemesisHelpers";
|
||||||
import { Loadout } from "../models/inventoryModels/loadoutModel";
|
import { Loadout } from "../models/inventoryModels/loadoutModel";
|
||||||
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
|
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
|
||||||
@ -383,7 +382,7 @@ export const addMissionInventoryUpdates = async (
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
inventory.LibraryActiveDailyTaskInfo &&
|
inventory.LibraryActiveDailyTaskInfo &&
|
||||||
inventory.LibraryActiveDailyTaskInfo.EnemyTypes.find(x => x == scan.EnemyType)
|
inventory.LibraryActiveDailyTaskInfo.EnemyTypes.indexOf(scan.EnemyType) != -1
|
||||||
) {
|
) {
|
||||||
inventory.LibraryActiveDailyTaskInfo.Scans ??= 0;
|
inventory.LibraryActiveDailyTaskInfo.Scans ??= 0;
|
||||||
inventory.LibraryActiveDailyTaskInfo.Scans += scan.Count;
|
inventory.LibraryActiveDailyTaskInfo.Scans += scan.Count;
|
||||||
@ -662,12 +661,12 @@ export const addMissionInventoryUpdates = async (
|
|||||||
k: value.killed
|
k: value.killed
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const manifest = getNemesisManifest(inventory.Nemesis.manifest);
|
||||||
const profile = generateNemesisProfile(
|
const profile = generateNemesisProfile(
|
||||||
inventory.Nemesis.fp,
|
inventory.Nemesis.fp,
|
||||||
inventory.Nemesis.Faction,
|
manifest,
|
||||||
inventory.Nemesis.KillingSuit
|
inventory.Nemesis.KillingSuit
|
||||||
);
|
);
|
||||||
const nemesisFactionInfo = nemesisFactionInfos[inventory.Nemesis.Faction];
|
|
||||||
const att: string[] = [];
|
const att: string[] = [];
|
||||||
let countedAtt: ITypeCount[] | undefined;
|
let countedAtt: ITypeCount[] | undefined;
|
||||||
|
|
||||||
@ -676,9 +675,7 @@ export const addMissionInventoryUpdates = async (
|
|||||||
value.weaponLoc &&
|
value.weaponLoc &&
|
||||||
inventory.Nemesis.Faction != "FC_INFESTATION" // weaponLoc is "/Lotus/Language/Weapons/DerelictCernosName" for these for some reason
|
inventory.Nemesis.Faction != "FC_INFESTATION" // weaponLoc is "/Lotus/Language/Weapons/DerelictCernosName" for these for some reason
|
||||||
) {
|
) {
|
||||||
const weaponType = getWeaponsForManifest(inventory.Nemesis.manifest)[
|
const weaponType = manifest.weapons[inventory.Nemesis.WeaponIdx];
|
||||||
inventory.Nemesis.WeaponIdx
|
|
||||||
];
|
|
||||||
giveNemesisWeaponRecipe(inventory, weaponType, value.nemesisName, value.weaponLoc, profile);
|
giveNemesisWeaponRecipe(inventory, weaponType, value.nemesisName, value.weaponLoc, profile);
|
||||||
att.push(weaponType);
|
att.push(weaponType);
|
||||||
}
|
}
|
||||||
@ -704,9 +701,7 @@ export const addMissionInventoryUpdates = async (
|
|||||||
att.push(profile.ephemera);
|
att.push(profile.ephemera);
|
||||||
}
|
}
|
||||||
|
|
||||||
const skinRewardStoreItem = value.killed
|
const skinRewardStoreItem = value.killed ? manifest.firstKillReward : manifest.firstConvertReward;
|
||||||
? nemesisFactionInfo.firstKillReward
|
|
||||||
: nemesisFactionInfo.firstConvertReward;
|
|
||||||
if (Object.keys(addSkin(inventory, fromStoreItem(skinRewardStoreItem))).length != 0) {
|
if (Object.keys(addSkin(inventory, fromStoreItem(skinRewardStoreItem))).length != 0) {
|
||||||
att.push(skinRewardStoreItem);
|
att.push(skinRewardStoreItem);
|
||||||
}
|
}
|
||||||
@ -737,7 +732,7 @@ export const addMissionInventoryUpdates = async (
|
|||||||
await createMessage(inventory.accountOwnerId, [
|
await createMessage(inventory.accountOwnerId, [
|
||||||
{
|
{
|
||||||
sndr: "/Lotus/Language/Bosses/Ordis",
|
sndr: "/Lotus/Language/Bosses/Ordis",
|
||||||
msg: nemesisFactionInfo.messageBody,
|
msg: manifest.messageBody,
|
||||||
arg: [
|
arg: [
|
||||||
{
|
{
|
||||||
Key: "LICH_NAME",
|
Key: "LICH_NAME",
|
||||||
@ -747,7 +742,7 @@ export const addMissionInventoryUpdates = async (
|
|||||||
att: att,
|
att: att,
|
||||||
countedAtt: countedAtt,
|
countedAtt: countedAtt,
|
||||||
attVisualOnly: true,
|
attVisualOnly: true,
|
||||||
sub: nemesisFactionInfo.messageTitle,
|
sub: manifest.messageTitle,
|
||||||
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
|
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
|
||||||
highPriority: true
|
highPriority: true
|
||||||
}
|
}
|
||||||
@ -1187,7 +1182,10 @@ export const addMissionRewards = async (
|
|||||||
inventory.Nemesis.Rank = Math.min(inventory.Nemesis.Rank + 1, 4);
|
inventory.Nemesis.Rank = Math.min(inventory.Nemesis.Rank + 1, 4);
|
||||||
inventoryChanges.Nemesis.Rank = inventory.Nemesis.Rank;
|
inventoryChanges.Nemesis.Rank = inventory.Nemesis.Rank;
|
||||||
}
|
}
|
||||||
inventory.Nemesis.InfNodes = getInfNodes(inventory.Nemesis.Faction, inventory.Nemesis.Rank);
|
inventory.Nemesis.InfNodes = getInfNodes(
|
||||||
|
getNemesisManifest(inventory.Nemesis.manifest),
|
||||||
|
inventory.Nemesis.Rank
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inventory.Nemesis.Faction == "FC_INFESTATION") {
|
if (inventory.Nemesis.Faction == "FC_INFESTATION") {
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
||||||
|
import { isDev } from "@/src/helpers/pathHelper";
|
||||||
import { catBreadHash } from "@/src/helpers/stringHelpers";
|
import { catBreadHash } from "@/src/helpers/stringHelpers";
|
||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { mixSeeds, SRng } from "@/src/services/rngService";
|
import { mixSeeds, SRng } from "@/src/services/rngService";
|
||||||
import { IMongoDate } from "@/src/types/commonTypes";
|
import { IMongoDate } from "@/src/types/commonTypes";
|
||||||
import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes";
|
import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes";
|
||||||
|
import { logger } from "@/src/utils/logger";
|
||||||
import { ExportVendors, IRange, IVendor } from "warframe-public-export-plus";
|
import { ExportVendors, IRange, IVendor } from "warframe-public-export-plus";
|
||||||
|
|
||||||
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
|
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
|
||||||
@ -268,11 +270,22 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
|||||||
manifest.items.length != manifest.numItems.minValue) &&
|
manifest.items.length != manifest.numItems.minValue) &&
|
||||||
!manifest.isOneBinPerCycle
|
!manifest.isOneBinPerCycle
|
||||||
) {
|
) {
|
||||||
|
const remainingItemCapacity: Record<string, number> = {};
|
||||||
|
for (const item of manifest.items) {
|
||||||
|
remainingItemCapacity[item.storeItem] = 1 + item.duplicates;
|
||||||
|
}
|
||||||
|
for (const offer of info.ItemManifest) {
|
||||||
|
remainingItemCapacity[offer.StoreItem] -= 1;
|
||||||
|
}
|
||||||
const numItemsTarget = rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue);
|
const numItemsTarget = rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue);
|
||||||
while (info.ItemManifest.length + offersToAdd.length < numItemsTarget) {
|
while (info.ItemManifest.length + offersToAdd.length < numItemsTarget) {
|
||||||
// TODO: Consider per-bin item limits
|
// TODO: Consider per-bin item limits
|
||||||
// TODO: Consider item probability weightings
|
// TODO: Consider item probability weightings
|
||||||
offersToAdd.push(rng.randomElement(manifest.items)!);
|
const item = rng.randomElement(manifest.items)!;
|
||||||
|
if (remainingItemCapacity[item.storeItem] != 0) {
|
||||||
|
remainingItemCapacity[item.storeItem] -= 1;
|
||||||
|
offersToAdd.push(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let binThisCycle;
|
let binThisCycle;
|
||||||
@ -363,3 +376,18 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
|||||||
}
|
}
|
||||||
return cacheEntry;
|
return cacheEntry;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (isDev) {
|
||||||
|
const ads = getVendorManifestByTypeName("/Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest")!
|
||||||
|
.VendorInfo.ItemManifest;
|
||||||
|
if (
|
||||||
|
ads.length != 5 ||
|
||||||
|
ads[0].Bin != "BIN_4" ||
|
||||||
|
ads[1].Bin != "BIN_3" ||
|
||||||
|
ads[2].Bin != "BIN_2" ||
|
||||||
|
ads[3].Bin != "BIN_1" ||
|
||||||
|
ads[4].Bin != "BIN_0"
|
||||||
|
) {
|
||||||
|
logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -674,6 +674,10 @@
|
|||||||
<input class="form-check-input" type="checkbox" id="noKimCooldowns" />
|
<input class="form-check-input" type="checkbox" id="noKimCooldowns" />
|
||||||
<label class="form-check-label" for="noKimCooldowns" data-loc="cheats_noKimCooldowns"></label>
|
<label class="form-check-label" for="noKimCooldowns" data-loc="cheats_noKimCooldowns"></label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="instantFinishRivenChallenge" />
|
||||||
|
<label class="form-check-label" for="instantFinishRivenChallenge" data-loc="cheats_instantFinishRivenChallenge"></label>
|
||||||
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="instantResourceExtractorDrones" />
|
<input class="form-check-input" type="checkbox" id="instantResourceExtractorDrones" />
|
||||||
<label class="form-check-label" for="instantResourceExtractorDrones" data-loc="cheats_instantResourceExtractorDrones"></label>
|
<label class="form-check-label" for="instantResourceExtractorDrones" data-loc="cheats_instantResourceExtractorDrones"></label>
|
||||||
|
@ -151,6 +151,7 @@ dict = {
|
|||||||
cheats_noVendorPurchaseLimits: `Keine Kaufbeschränkungen bei Händlern`,
|
cheats_noVendorPurchaseLimits: `Keine Kaufbeschränkungen bei Händlern`,
|
||||||
cheats_noDeathMarks: `Keine Todesmarkierungen`,
|
cheats_noDeathMarks: `Keine Todesmarkierungen`,
|
||||||
cheats_noKimCooldowns: `Keine Wartezeit bei KIM`,
|
cheats_noKimCooldowns: `Keine Wartezeit bei KIM`,
|
||||||
|
cheats_instantFinishRivenChallenge: `Riven-Mod Herausforderung sofort abschließen`,
|
||||||
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
|
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
|
||||||
cheats_noResourceExtractorDronesDamage: `Kein Schaden für Ressourcen-Extraktor-Drohnen`,
|
cheats_noResourceExtractorDronesDamage: `Kein Schaden für Ressourcen-Extraktor-Drohnen`,
|
||||||
cheats_skipClanKeyCrafting: `Clan-Schlüsselherstellung überspringen`,
|
cheats_skipClanKeyCrafting: `Clan-Schlüsselherstellung überspringen`,
|
||||||
|
@ -150,6 +150,7 @@ dict = {
|
|||||||
cheats_noVendorPurchaseLimits: `No Vendor Purchase Limits`,
|
cheats_noVendorPurchaseLimits: `No Vendor Purchase Limits`,
|
||||||
cheats_noDeathMarks: `No Death Marks`,
|
cheats_noDeathMarks: `No Death Marks`,
|
||||||
cheats_noKimCooldowns: `No KIM Cooldowns`,
|
cheats_noKimCooldowns: `No KIM Cooldowns`,
|
||||||
|
cheats_instantFinishRivenChallenge: `Instant Finish Riven Challenge`,
|
||||||
cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`,
|
cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`,
|
||||||
cheats_noResourceExtractorDronesDamage: `No Resource Extractor Drones Damage`,
|
cheats_noResourceExtractorDronesDamage: `No Resource Extractor Drones Damage`,
|
||||||
cheats_skipClanKeyCrafting: `Skip Clan Key Crafting`,
|
cheats_skipClanKeyCrafting: `Skip Clan Key Crafting`,
|
||||||
|
@ -151,6 +151,7 @@ dict = {
|
|||||||
cheats_noVendorPurchaseLimits: `Sin límite de compras de vendedores`,
|
cheats_noVendorPurchaseLimits: `Sin límite de compras de vendedores`,
|
||||||
cheats_noDeathMarks: `Sin marcas de muerte`,
|
cheats_noDeathMarks: `Sin marcas de muerte`,
|
||||||
cheats_noKimCooldowns: `Sin tiempo de espera para conversaciones KIM`,
|
cheats_noKimCooldowns: `Sin tiempo de espera para conversaciones KIM`,
|
||||||
|
cheats_instantFinishRivenChallenge: `[UNTRANSLATED] Instant Finish Riven Challenge`,
|
||||||
cheats_instantResourceExtractorDrones: `Drones de extracción de recursos instantáneos`,
|
cheats_instantResourceExtractorDrones: `Drones de extracción de recursos instantáneos`,
|
||||||
cheats_noResourceExtractorDronesDamage: `Sin daño a los drones extractores de recursos`,
|
cheats_noResourceExtractorDronesDamage: `Sin daño a los drones extractores de recursos`,
|
||||||
cheats_skipClanKeyCrafting: `Saltar la fabricación de la llave de clan`,
|
cheats_skipClanKeyCrafting: `Saltar la fabricación de la llave de clan`,
|
||||||
|
@ -151,6 +151,7 @@ dict = {
|
|||||||
cheats_noVendorPurchaseLimits: `Aucune limite d'achat chez les PNJ`,
|
cheats_noVendorPurchaseLimits: `Aucune limite d'achat chez les PNJ`,
|
||||||
cheats_noDeathMarks: `Aucune marque d'assassin`,
|
cheats_noDeathMarks: `Aucune marque d'assassin`,
|
||||||
cheats_noKimCooldowns: `Aucun cooldown sur le KIM`,
|
cheats_noKimCooldowns: `Aucun cooldown sur le KIM`,
|
||||||
|
cheats_instantFinishRivenChallenge: `[UNTRANSLATED] Instant Finish Riven Challenge`,
|
||||||
cheats_instantResourceExtractorDrones: `Ressources de drones d'extraction instantannées`,
|
cheats_instantResourceExtractorDrones: `Ressources de drones d'extraction instantannées`,
|
||||||
cheats_noResourceExtractorDronesDamage: `Aucun dégâts aux drones d'extraction de resources`,
|
cheats_noResourceExtractorDronesDamage: `Aucun dégâts aux drones d'extraction de resources`,
|
||||||
cheats_skipClanKeyCrafting: `[UNTRANSLATED] Skip Clan Key Crafting`,
|
cheats_skipClanKeyCrafting: `[UNTRANSLATED] Skip Clan Key Crafting`,
|
||||||
|
@ -151,6 +151,7 @@ dict = {
|
|||||||
cheats_noVendorPurchaseLimits: `Отсутствие лимитов на покупки у вендоров`,
|
cheats_noVendorPurchaseLimits: `Отсутствие лимитов на покупки у вендоров`,
|
||||||
cheats_noDeathMarks: `Без меток сметри`,
|
cheats_noDeathMarks: `Без меток сметри`,
|
||||||
cheats_noKimCooldowns: `Чаты KIM без кулдауна`,
|
cheats_noKimCooldowns: `Чаты KIM без кулдауна`,
|
||||||
|
cheats_instantFinishRivenChallenge: `[UNTRANSLATED] Instant Finish Riven Challenge`,
|
||||||
cheats_instantResourceExtractorDrones: `Мгновенные Экстракторы Ресурсов`,
|
cheats_instantResourceExtractorDrones: `Мгновенные Экстракторы Ресурсов`,
|
||||||
cheats_noResourceExtractorDronesDamage: `Без урона по дронам-сборщикам`,
|
cheats_noResourceExtractorDronesDamage: `Без урона по дронам-сборщикам`,
|
||||||
cheats_skipClanKeyCrafting: `Пропустить крафт кланового ключа`,
|
cheats_skipClanKeyCrafting: `Пропустить крафт кланового ключа`,
|
||||||
|
@ -151,6 +151,7 @@ dict = {
|
|||||||
cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`,
|
cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`,
|
||||||
cheats_noDeathMarks: `[UNTRANSLATED] No Death Marks`,
|
cheats_noDeathMarks: `[UNTRANSLATED] No Death Marks`,
|
||||||
cheats_noKimCooldowns: `[UNTRANSLATED] No KIM Cooldowns`,
|
cheats_noKimCooldowns: `[UNTRANSLATED] No KIM Cooldowns`,
|
||||||
|
cheats_instantFinishRivenChallenge: `[UNTRANSLATED] Instant Finish Riven Challenge`,
|
||||||
cheats_instantResourceExtractorDrones: `即时资源采集无人机`,
|
cheats_instantResourceExtractorDrones: `即时资源采集无人机`,
|
||||||
cheats_noResourceExtractorDronesDamage: `[UNTRANSLATED] No Resource Extractor Drones Damage`,
|
cheats_noResourceExtractorDronesDamage: `[UNTRANSLATED] No Resource Extractor Drones Damage`,
|
||||||
cheats_skipClanKeyCrafting: `[UNTRANSLATED] Skip Clan Key Crafting`,
|
cheats_skipClanKeyCrafting: `[UNTRANSLATED] Skip Clan Key Crafting`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user