Compare commits
15 Commits
6bfb25a4b2
...
4acb16e6d6
Author | SHA1 | Date | |
---|---|---|---|
4acb16e6d6 | |||
c6acab6c11 | |||
bb315eaafe | |||
327b834b07 | |||
39be095818 | |||
ef4973e694 | |||
7f69667171 | |||
dcdeb0cd34 | |||
8ce86ad4fd | |||
a2f1469779 | |||
dd32e082f3 | |||
74c7d86090 | |||
7fd4d50e07 | |||
7f805a1dcc | |||
919f12b8f9 |
@ -34,6 +34,7 @@
|
|||||||
"noVendorPurchaseLimits": true,
|
"noVendorPurchaseLimits": true,
|
||||||
"instantResourceExtractorDrones": false,
|
"instantResourceExtractorDrones": false,
|
||||||
"noDojoRoomBuildStage": false,
|
"noDojoRoomBuildStage": false,
|
||||||
|
"noDecoBuildStage": false,
|
||||||
"fastDojoRoomDestruction": false,
|
"fastDojoRoomDestruction": false,
|
||||||
"noDojoResearchCosts": false,
|
"noDojoResearchCosts": false,
|
||||||
"noDojoResearchTime": false,
|
"noDojoResearchTime": false,
|
||||||
|
@ -34,8 +34,8 @@ export const inboxController: RequestHandler = async (req, res) => {
|
|||||||
message.r = true;
|
message.r = true;
|
||||||
await message.save();
|
await message.save();
|
||||||
|
|
||||||
const attachmentItems = message.att;
|
const attachmentItems = message.attVisualOnly ? undefined : message.att;
|
||||||
const attachmentCountedItems = message.countedAtt;
|
const attachmentCountedItems = message.attVisualOnly ? undefined : message.countedAtt;
|
||||||
|
|
||||||
if (!attachmentItems && !attachmentCountedItems && !message.gifts) {
|
if (!attachmentItems && !attachmentCountedItems && !message.gifts) {
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
|
@ -13,6 +13,7 @@ import { GuildPermission } from "@/src/types/guildTypes";
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { ExportDojoRecipes, ExportResources } from "warframe-public-export-plus";
|
import { ExportDojoRecipes, ExportResources } from "warframe-public-export-plus";
|
||||||
|
import { config } from "@/src/services/configService";
|
||||||
|
|
||||||
export const placeDecoInComponentController: RequestHandler = async (req, res) => {
|
export const placeDecoInComponentController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -62,36 +63,38 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) =
|
|||||||
guild.VaultShipDecorations!.find(x => x.ItemType == itemType)!.ItemCount -= 1;
|
guild.VaultShipDecorations!.find(x => x.ItemType == itemType)!.ItemCount -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!meta || (meta.price == 0 && meta.ingredients.length == 0)) {
|
if (deco.Type != "/Lotus/Objects/Tenno/Props/TnoPaintBotDojoDeco") {
|
||||||
deco.CompletionTime = new Date();
|
if (!meta || (meta.price == 0 && meta.ingredients.length == 0) || config.noDecoBuildStage) {
|
||||||
} else if (guild.AutoContributeFromVault && guild.VaultRegularCredits && guild.VaultMiscItems) {
|
deco.CompletionTime = new Date();
|
||||||
if (guild.VaultRegularCredits >= scaleRequiredCount(guild.Tier, meta.price)) {
|
} else if (guild.AutoContributeFromVault && guild.VaultRegularCredits && guild.VaultMiscItems) {
|
||||||
let enoughMiscItems = true;
|
if (guild.VaultRegularCredits >= scaleRequiredCount(guild.Tier, meta.price)) {
|
||||||
for (const ingredient of meta.ingredients) {
|
let enoughMiscItems = true;
|
||||||
if (
|
|
||||||
getVaultMiscItemCount(guild, ingredient.ItemType) <
|
|
||||||
scaleRequiredCount(guild.Tier, ingredient.ItemCount)
|
|
||||||
) {
|
|
||||||
enoughMiscItems = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (enoughMiscItems) {
|
|
||||||
guild.VaultRegularCredits -= scaleRequiredCount(guild.Tier, meta.price);
|
|
||||||
deco.RegularCredits = scaleRequiredCount(guild.Tier, meta.price);
|
|
||||||
|
|
||||||
deco.MiscItems = [];
|
|
||||||
for (const ingredient of meta.ingredients) {
|
for (const ingredient of meta.ingredients) {
|
||||||
guild.VaultMiscItems.find(x => x.ItemType == ingredient.ItemType)!.ItemCount -=
|
if (
|
||||||
scaleRequiredCount(guild.Tier, ingredient.ItemCount);
|
getVaultMiscItemCount(guild, ingredient.ItemType) <
|
||||||
deco.MiscItems.push({
|
scaleRequiredCount(guild.Tier, ingredient.ItemCount)
|
||||||
ItemType: ingredient.ItemType,
|
) {
|
||||||
ItemCount: scaleRequiredCount(guild.Tier, ingredient.ItemCount)
|
enoughMiscItems = false;
|
||||||
});
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (enoughMiscItems) {
|
||||||
|
guild.VaultRegularCredits -= scaleRequiredCount(guild.Tier, meta.price);
|
||||||
|
deco.RegularCredits = scaleRequiredCount(guild.Tier, meta.price);
|
||||||
|
|
||||||
deco.CompletionTime = new Date(Date.now() + meta.time * 1000);
|
deco.MiscItems = [];
|
||||||
processDojoBuildMaterialsGathered(guild, meta);
|
for (const ingredient of meta.ingredients) {
|
||||||
|
guild.VaultMiscItems.find(x => x.ItemType == ingredient.ItemType)!.ItemCount -=
|
||||||
|
scaleRequiredCount(guild.Tier, ingredient.ItemCount);
|
||||||
|
deco.MiscItems.push({
|
||||||
|
ItemType: ingredient.ItemType,
|
||||||
|
ItemCount: scaleRequiredCount(guild.Tier, ingredient.ItemCount)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deco.CompletionTime = new Date(Date.now() + meta.time * 1000);
|
||||||
|
processDojoBuildMaterialsGathered(guild, meta);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
src/controllers/api/setDojoComponentColorsController.ts
Normal file
34
src/controllers/api/setDojoComponentColorsController.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
|
import { getDojoClient, getGuildForRequestEx, hasAccessToDojo, hasGuildPermission } from "@/src/services/guildService";
|
||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
export const setDojoComponentColorsController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId, "GuildId LevelKeys");
|
||||||
|
const guild = await getGuildForRequestEx(req, inventory);
|
||||||
|
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Decorator))) {
|
||||||
|
res.json({ DojoRequestStatus: -1 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data = getJSONfromString<ISetDojoComponentColorsRequest>(String(req.body));
|
||||||
|
const component = guild.DojoComponents.id(data.ComponentId)!;
|
||||||
|
//const deco = component.Decos!.find(x => x._id.equals(data.DecoId))!;
|
||||||
|
//deco.Pending = true;
|
||||||
|
//component.PaintBot = new Types.ObjectId(data.DecoId);
|
||||||
|
if ("lights" in req.query) {
|
||||||
|
component.PendingLights = data.Colours;
|
||||||
|
} else {
|
||||||
|
component.PendingColors = data.Colours;
|
||||||
|
}
|
||||||
|
await guild.save();
|
||||||
|
res.json(await getDojoClient(guild, 0, component._id));
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ISetDojoComponentColorsRequest {
|
||||||
|
ComponentId: string;
|
||||||
|
DecoId: string;
|
||||||
|
Colours: number[];
|
||||||
|
}
|
25
src/controllers/api/setDojoComponentSettingsController.ts
Normal file
25
src/controllers/api/setDojoComponentSettingsController.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
|
import { getDojoClient, getGuildForRequestEx, hasAccessToDojo, hasGuildPermission } from "@/src/services/guildService";
|
||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
export const setDojoComponentSettingsController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId, "GuildId LevelKeys");
|
||||||
|
const guild = await getGuildForRequestEx(req, inventory);
|
||||||
|
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Decorator))) {
|
||||||
|
res.json({ DojoRequestStatus: -1 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const component = guild.DojoComponents.id(req.query.componentId)!;
|
||||||
|
const data = getJSONfromString<ISetDojoComponentSettingsRequest>(String(req.body));
|
||||||
|
component.Settings = data.Settings;
|
||||||
|
await guild.save();
|
||||||
|
res.json(await getDojoClient(guild, 0, component._id));
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ISetDojoComponentSettingsRequest {
|
||||||
|
Settings: string;
|
||||||
|
}
|
@ -1,10 +1,8 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { addChallenges, addSeasonalChallengeHistory, getInventory } from "@/src/services/inventoryService";
|
import { addChallenges, getInventory } from "@/src/services/inventoryService";
|
||||||
import { IChallengeProgress, ISeasonChallenge } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IChallengeProgress, ISeasonChallenge } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { ExportNightwave } from "warframe-public-export-plus";
|
|
||||||
import { logger } from "@/src/utils/logger";
|
|
||||||
import { IAffiliationMods } from "@/src/types/purchaseTypes";
|
import { IAffiliationMods } from "@/src/types/purchaseTypes";
|
||||||
|
|
||||||
export const updateChallengeProgressController: RequestHandler = async (req, res) => {
|
export const updateChallengeProgressController: RequestHandler = async (req, res) => {
|
||||||
@ -12,41 +10,19 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
|
|||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|
||||||
const inventory = await getInventory(accountId, "ChallengeProgress SeasonChallengeHistory Affiliations");
|
const inventory = await getInventory(accountId, "ChallengeProgress SeasonChallengeHistory Affiliations");
|
||||||
|
let affiliationMods: IAffiliationMods[] = [];
|
||||||
if (challenges.ChallengeProgress) {
|
if (challenges.ChallengeProgress) {
|
||||||
addChallenges(inventory, challenges.ChallengeProgress);
|
affiliationMods = addChallenges(inventory, challenges.ChallengeProgress, challenges.SeasonChallengeCompletions);
|
||||||
}
|
}
|
||||||
if (challenges.SeasonChallengeHistory) {
|
if (challenges.SeasonChallengeHistory) {
|
||||||
addSeasonalChallengeHistory(inventory, challenges.SeasonChallengeHistory);
|
challenges.SeasonChallengeHistory.forEach(({ challenge, id }) => {
|
||||||
}
|
const itemIndex = inventory.SeasonChallengeHistory.findIndex(i => i.challenge === challenge);
|
||||||
const affiliationMods: IAffiliationMods[] = [];
|
if (itemIndex !== -1) {
|
||||||
if (challenges.ChallengeProgress && challenges.SeasonChallengeCompletions) {
|
inventory.SeasonChallengeHistory[itemIndex].id = id;
|
||||||
for (const challenge of challenges.SeasonChallengeCompletions) {
|
} else {
|
||||||
// Ignore challenges that weren't completed just now
|
inventory.SeasonChallengeHistory.push({ challenge, id });
|
||||||
if (!challenges.ChallengeProgress.find(x => challenge.challenge.indexOf(x.Name) != -1)) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
const meta = ExportNightwave.challenges[challenge.challenge];
|
|
||||||
logger.debug("Completed challenge", meta);
|
|
||||||
|
|
||||||
let affiliation = inventory.Affiliations.find(x => x.Tag == ExportNightwave.affiliationTag);
|
|
||||||
if (!affiliation) {
|
|
||||||
affiliation =
|
|
||||||
inventory.Affiliations[
|
|
||||||
inventory.Affiliations.push({
|
|
||||||
Tag: ExportNightwave.affiliationTag,
|
|
||||||
Standing: 0
|
|
||||||
}) - 1
|
|
||||||
];
|
|
||||||
}
|
|
||||||
affiliation.Standing += meta.standing;
|
|
||||||
|
|
||||||
if (affiliationMods.length == 0) {
|
|
||||||
affiliationMods.push({ Tag: ExportNightwave.affiliationTag });
|
|
||||||
}
|
|
||||||
affiliationMods[0].Standing ??= 0;
|
|
||||||
affiliationMods[0].Standing += meta.standing;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
|
@ -150,9 +150,11 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
if (!item.hidden) {
|
if (!item.hidden) {
|
||||||
const resultName = getItemName(item.resultType);
|
const resultName = getItemName(item.resultType);
|
||||||
if (resultName) {
|
if (resultName) {
|
||||||
|
let itemName = getString(resultName, lang);
|
||||||
|
if (item.num > 1) itemName = `${itemName} X ${item.num}`;
|
||||||
res.miscitems.push({
|
res.miscitems.push({
|
||||||
uniqueName: uniqueName,
|
uniqueName: uniqueName,
|
||||||
name: recipeNameTemplate.replace("|ITEM|", getString(resultName, lang))
|
name: recipeNameTemplate.replace("|ITEM|", itemName)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -218,6 +220,11 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
name: getString(key.name || "", lang),
|
name: getString(key.name || "", lang),
|
||||||
chainLength: key.chainStages.length
|
chainLength: key.chainStages.length
|
||||||
});
|
});
|
||||||
|
} else if (key.name) {
|
||||||
|
res.miscitems.push({
|
||||||
|
uniqueName,
|
||||||
|
name: getString(key.name, lang)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,8 +10,16 @@ import { unixTimesInMs } from "@/src/constants/timeConstants";
|
|||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
import { CRng } from "@/src/services/rngService";
|
import { CRng } from "@/src/services/rngService";
|
||||||
import { ExportNightwave, ExportRegions } from "warframe-public-export-plus";
|
import { ExportNightwave, ExportRegions } from "warframe-public-export-plus";
|
||||||
|
import {
|
||||||
const EPOCH = 1734307200 * 1000; // Monday, Dec 16, 2024 @ 00:00 UTC+0; should logically be winter in 1999 iteration 0
|
EPOCH,
|
||||||
|
getSortieTime,
|
||||||
|
missionTags,
|
||||||
|
sortieBosses,
|
||||||
|
sortieBossNode,
|
||||||
|
sortieBossToFaction,
|
||||||
|
sortieFactionToFactionIndexes,
|
||||||
|
sortieFactionToSystemIndexes
|
||||||
|
} from "@/src/helpers/worlstateHelper";
|
||||||
|
|
||||||
export const worldStateController: RequestHandler = (req, res) => {
|
export const worldStateController: RequestHandler = (req, res) => {
|
||||||
const day = Math.trunc((Date.now() - EPOCH) / 86400000);
|
const day = Math.trunc((Date.now() - EPOCH) / 86400000);
|
||||||
@ -27,6 +35,7 @@ export const worldStateController: RequestHandler = (req, res) => {
|
|||||||
Time: config.worldState?.lockTime || Math.round(Date.now() / 1000),
|
Time: config.worldState?.lockTime || Math.round(Date.now() / 1000),
|
||||||
Goals: [],
|
Goals: [],
|
||||||
GlobalUpgrades: [],
|
GlobalUpgrades: [],
|
||||||
|
Sorties: [],
|
||||||
LiteSorties: [],
|
LiteSorties: [],
|
||||||
EndlessXpChoices: [],
|
EndlessXpChoices: [],
|
||||||
SeasonInfo: {
|
SeasonInfo: {
|
||||||
@ -154,6 +163,142 @@ export const worldStateController: RequestHandler = (req, res) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sortie cycling every day
|
||||||
|
{
|
||||||
|
let genDay;
|
||||||
|
let dayStart;
|
||||||
|
let dayEnd;
|
||||||
|
const sortieRolloverToday = getSortieTime(day);
|
||||||
|
if (Date.now() < sortieRolloverToday) {
|
||||||
|
// Early in the day, generate sortie for `day - 1`, expiring at `sortieRolloverToday`.
|
||||||
|
genDay = day - 1;
|
||||||
|
dayStart = getSortieTime(genDay);
|
||||||
|
dayEnd = sortieRolloverToday;
|
||||||
|
} else {
|
||||||
|
// Late in the day, generate sortie for `day`, expiring at `getSortieTime(day + 1)`.
|
||||||
|
genDay = day;
|
||||||
|
dayStart = sortieRolloverToday;
|
||||||
|
dayEnd = getSortieTime(day + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const rng = new CRng(genDay);
|
||||||
|
|
||||||
|
const boss = rng.randomElement(sortieBosses);
|
||||||
|
|
||||||
|
const modifiers = [
|
||||||
|
"SORTIE_MODIFIER_LOW_ENERGY",
|
||||||
|
"SORTIE_MODIFIER_IMPACT",
|
||||||
|
"SORTIE_MODIFIER_SLASH",
|
||||||
|
"SORTIE_MODIFIER_PUNCTURE",
|
||||||
|
"SORTIE_MODIFIER_EXIMUS",
|
||||||
|
"SORTIE_MODIFIER_MAGNETIC",
|
||||||
|
"SORTIE_MODIFIER_CORROSIVE",
|
||||||
|
"SORTIE_MODIFIER_VIRAL",
|
||||||
|
"SORTIE_MODIFIER_ELECTRICITY",
|
||||||
|
"SORTIE_MODIFIER_RADIATION",
|
||||||
|
"SORTIE_MODIFIER_GAS",
|
||||||
|
"SORTIE_MODIFIER_FIRE",
|
||||||
|
"SORTIE_MODIFIER_EXPLOSION",
|
||||||
|
"SORTIE_MODIFIER_FREEZE",
|
||||||
|
"SORTIE_MODIFIER_TOXIN",
|
||||||
|
"SORTIE_MODIFIER_POISON",
|
||||||
|
"SORTIE_MODIFIER_HAZARD_RADIATION",
|
||||||
|
"SORTIE_MODIFIER_HAZARD_MAGNETIC",
|
||||||
|
"SORTIE_MODIFIER_HAZARD_FOG", // TODO: push this if the mission tileset is Grineer Forest
|
||||||
|
"SORTIE_MODIFIER_HAZARD_FIRE", // TODO: push this if the mission tileset is Corpus Ship or Grineer Galleon
|
||||||
|
"SORTIE_MODIFIER_HAZARD_ICE",
|
||||||
|
"SORTIE_MODIFIER_HAZARD_COLD",
|
||||||
|
"SORTIE_MODIFIER_SECONDARY_ONLY",
|
||||||
|
"SORTIE_MODIFIER_SHOTGUN_ONLY",
|
||||||
|
"SORTIE_MODIFIER_SNIPER_ONLY",
|
||||||
|
"SORTIE_MODIFIER_RIFLE_ONLY",
|
||||||
|
"SORTIE_MODIFIER_MELEE_ONLY",
|
||||||
|
"SORTIE_MODIFIER_BOW_ONLY"
|
||||||
|
];
|
||||||
|
|
||||||
|
if (sortieBossToFaction[boss] == "FC_CORPUS") modifiers.push("SORTIE_MODIFIER_SHIELDS");
|
||||||
|
if (sortieBossToFaction[boss] != "FC_CORPUS") modifiers.push("SORTIE_MODIFIER_ARMOR");
|
||||||
|
|
||||||
|
const nodes: string[] = [];
|
||||||
|
const availableMissionIndexes: number[] = [];
|
||||||
|
for (const [key, value] of Object.entries(ExportRegions)) {
|
||||||
|
if (
|
||||||
|
sortieFactionToSystemIndexes[sortieBossToFaction[boss]].includes(value.systemIndex) &&
|
||||||
|
sortieFactionToFactionIndexes[sortieBossToFaction[boss]].includes(value.factionIndex!) &&
|
||||||
|
value.name.indexOf("Archwing") == -1 &&
|
||||||
|
value.missionIndex != 0 && // Exclude MT_ASSASSINATION
|
||||||
|
value.missionIndex != 5 && // Exclude MT_CAPTURE
|
||||||
|
value.missionIndex != 21 && // Exclude MT_PURIFY
|
||||||
|
value.missionIndex != 23 && // Exclude MT_JUNCTION
|
||||||
|
value.missionIndex <= 28
|
||||||
|
) {
|
||||||
|
if (!availableMissionIndexes.includes(value.missionIndex)) {
|
||||||
|
availableMissionIndexes.push(value.missionIndex);
|
||||||
|
}
|
||||||
|
nodes.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedNodes: { missionType: string; modifierType: string; node: string }[] = [];
|
||||||
|
const missionTypes = new Set();
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
const randomIndex = rng.randomInt(0, nodes.length - 1);
|
||||||
|
const node = nodes[randomIndex];
|
||||||
|
let missionIndex = ExportRegions[node].missionIndex;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!["SolNode404", "SolNode411"].includes(node) && // for some reason the game doesn't like missionType changes for these missions
|
||||||
|
missionIndex != 28 &&
|
||||||
|
rng.randomInt(0, 2) == 2
|
||||||
|
) {
|
||||||
|
missionIndex = rng.randomElement(availableMissionIndexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 2 && rng.randomInt(0, 2) == 2) {
|
||||||
|
const filteredModifiers = modifiers.filter(mod => mod !== "SORTIE_MODIFIER_MELEE_ONLY");
|
||||||
|
const modifierType = rng.randomElement(filteredModifiers);
|
||||||
|
|
||||||
|
if (boss == "SORTIE_BOSS_PHORID") {
|
||||||
|
selectedNodes.push({ missionType: "MT_ASSASSINATION", modifierType, node });
|
||||||
|
nodes.splice(randomIndex, 1);
|
||||||
|
continue;
|
||||||
|
} else if (sortieBossNode[boss]) {
|
||||||
|
selectedNodes.push({ missionType: "MT_ASSASSINATION", modifierType, node: sortieBossNode[boss] });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const missionType = missionTags[missionIndex];
|
||||||
|
|
||||||
|
if (missionTypes.has(missionType)) {
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredModifiers =
|
||||||
|
missionType === "MT_TERRITORY"
|
||||||
|
? modifiers.filter(mod => mod != "SORTIE_MODIFIER_HAZARD_RADIATION")
|
||||||
|
: modifiers;
|
||||||
|
|
||||||
|
const modifierType = rng.randomElement(filteredModifiers);
|
||||||
|
|
||||||
|
selectedNodes.push({ missionType, modifierType, node });
|
||||||
|
nodes.splice(randomIndex, 1);
|
||||||
|
missionTypes.add(missionType);
|
||||||
|
}
|
||||||
|
|
||||||
|
worldState.Sorties.push({
|
||||||
|
_id: { $oid: Math.trunc(dayStart / 1000).toString(16) + "d4d932c97c0a3acd" },
|
||||||
|
Activation: { $date: { $numberLong: dayStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: dayEnd.toString() } },
|
||||||
|
Reward: "/Lotus/Types/Game/MissionDecks/SortieRewards",
|
||||||
|
Seed: genDay,
|
||||||
|
Boss: boss,
|
||||||
|
Variants: selectedNodes
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Archon Hunt cycling every week
|
// Archon Hunt cycling every week
|
||||||
{
|
{
|
||||||
const boss = ["SORTIE_BOSS_AMAR", "SORTIE_BOSS_NIRA", "SORTIE_BOSS_BOREAL"][week % 3];
|
const boss = ["SORTIE_BOSS_AMAR", "SORTIE_BOSS_NIRA", "SORTIE_BOSS_BOREAL"][week % 3];
|
||||||
@ -298,6 +443,7 @@ interface IWorldState {
|
|||||||
Goals: IGoal[];
|
Goals: IGoal[];
|
||||||
SyndicateMissions: ISyndicateMission[];
|
SyndicateMissions: ISyndicateMission[];
|
||||||
GlobalUpgrades: IGlobalUpgrade[];
|
GlobalUpgrades: IGlobalUpgrade[];
|
||||||
|
Sorties: ISortie[];
|
||||||
LiteSorties: ILiteSortie[];
|
LiteSorties: ILiteSortie[];
|
||||||
NodeOverrides: INodeOverride[];
|
NodeOverrides: INodeOverride[];
|
||||||
EndlessXpChoices: IEndlessXpChoice[];
|
EndlessXpChoices: IEndlessXpChoice[];
|
||||||
@ -361,6 +507,20 @@ interface INodeOverride {
|
|||||||
CustomNpcEncounters?: string;
|
CustomNpcEncounters?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ISortie {
|
||||||
|
_id: IOid;
|
||||||
|
Activation: IMongoDate;
|
||||||
|
Expiry: IMongoDate;
|
||||||
|
Reward: "/Lotus/Types/Game/MissionDecks/SortieRewards";
|
||||||
|
Seed: number;
|
||||||
|
Boss: string;
|
||||||
|
Variants: {
|
||||||
|
missionType: string;
|
||||||
|
modifierType: string;
|
||||||
|
node: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
interface ILiteSortie {
|
interface ILiteSortie {
|
||||||
_id: IOid;
|
_id: IOid;
|
||||||
Activation: IMongoDate;
|
Activation: IMongoDate;
|
||||||
|
130
src/helpers/worlstateHelper.ts
Normal file
130
src/helpers/worlstateHelper.ts
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
export const missionTags = [
|
||||||
|
"MT_ASSASSINATION",
|
||||||
|
"MT_EXTERMINATION",
|
||||||
|
"MT_SURVIVAL",
|
||||||
|
"MT_RESCUE",
|
||||||
|
"MT_SABOTAGE",
|
||||||
|
"MT_CAPTURE",
|
||||||
|
"MT_COUNTER_INTEL",
|
||||||
|
"MT_INTEL",
|
||||||
|
"MT_DEFENSE",
|
||||||
|
"MT_MOBILE_DEFENSE",
|
||||||
|
"MT_PVP",
|
||||||
|
"MT_MASTERY",
|
||||||
|
"MT_RECOVERY",
|
||||||
|
"MT_TERRITORY",
|
||||||
|
"MT_RETRIEVAL",
|
||||||
|
"MT_HIVE",
|
||||||
|
"MT_SALVAGE",
|
||||||
|
"MT_EXCAVATE",
|
||||||
|
"MT_RAID",
|
||||||
|
"MT_PURGE",
|
||||||
|
"MT_GENERIC",
|
||||||
|
"MT_PURIFY",
|
||||||
|
"MT_ARENA",
|
||||||
|
"MT_JUNCTION",
|
||||||
|
"MT_PURSUIT",
|
||||||
|
"MT_RACE",
|
||||||
|
"MT_ASSAULT",
|
||||||
|
"MT_EVACUATION",
|
||||||
|
"MT_LANDSCAPE",
|
||||||
|
"MT_RESOURCE_THEFT",
|
||||||
|
"MT_ENDLESS_EXTERMINATION",
|
||||||
|
"MT_ENDLESS_DUVIRI",
|
||||||
|
"MT_RAILJACK",
|
||||||
|
"MT_ARTIFACT",
|
||||||
|
"MT_CORRUPTION",
|
||||||
|
"MT_VOID_CASCADE",
|
||||||
|
"MT_ARMAGEDDON",
|
||||||
|
"MT_VAULTS",
|
||||||
|
"MT_ALCHEMY",
|
||||||
|
"MT_ASCENSION",
|
||||||
|
"MT_ENDLESS_CAPTURE",
|
||||||
|
"MT_OFFERING",
|
||||||
|
"MT_PVPVE"
|
||||||
|
];
|
||||||
|
|
||||||
|
export const sortieBosses = [
|
||||||
|
"SORTIE_BOSS_HYENA",
|
||||||
|
"SORTIE_BOSS_KELA",
|
||||||
|
"SORTIE_BOSS_VOR",
|
||||||
|
"SORTIE_BOSS_RUK",
|
||||||
|
"SORTIE_BOSS_HEK",
|
||||||
|
"SORTIE_BOSS_KRIL",
|
||||||
|
"SORTIE_BOSS_TYL",
|
||||||
|
"SORTIE_BOSS_JACKAL",
|
||||||
|
"SORTIE_BOSS_ALAD",
|
||||||
|
"SORTIE_BOSS_AMBULAS",
|
||||||
|
"SORTIE_BOSS_NEF",
|
||||||
|
"SORTIE_BOSS_RAPTOR",
|
||||||
|
"SORTIE_BOSS_PHORID",
|
||||||
|
"SORTIE_BOSS_LEPHANTIS",
|
||||||
|
"SORTIE_BOSS_INFALAD",
|
||||||
|
"SORTIE_BOSS_CORRUPTED_VOR"
|
||||||
|
];
|
||||||
|
|
||||||
|
export const sortieBossToFaction: Record<string, string> = {
|
||||||
|
SORTIE_BOSS_HYENA: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_KELA: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_VOR: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_RUK: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_HEK: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_KRIL: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_TYL: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_JACKAL: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_ALAD: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_AMBULAS: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_NEF: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_RAPTOR: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_PHORID: "FC_INFESTATION",
|
||||||
|
SORTIE_BOSS_LEPHANTIS: "FC_INFESTATION",
|
||||||
|
SORTIE_BOSS_INFALAD: "FC_INFESTATION",
|
||||||
|
SORTIE_BOSS_CORRUPTED_VOR: "FC_CORRUPTED"
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sortieFactionToSystemIndexes: Record<string, number[]> = {
|
||||||
|
FC_GRINEER: [0, 2, 3, 5, 6, 9, 11, 18],
|
||||||
|
FC_CORPUS: [1, 4, 7, 8, 12, 15],
|
||||||
|
FC_INFESTATION: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15],
|
||||||
|
FC_CORRUPTED: [14]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sortieFactionToFactionIndexes: Record<string, number[]> = {
|
||||||
|
FC_GRINEER: [0],
|
||||||
|
FC_CORPUS: [1],
|
||||||
|
FC_INFESTATION: [0, 1, 2],
|
||||||
|
FC_CORRUPTED: [3]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sortieBossNode: Record<string, string> = {
|
||||||
|
SORTIE_BOSS_HYENA: "SolNode127",
|
||||||
|
SORTIE_BOSS_KELA: "SolNode193",
|
||||||
|
SORTIE_BOSS_VOR: "SolNode108",
|
||||||
|
SORTIE_BOSS_RUK: "SolNode32",
|
||||||
|
SORTIE_BOSS_HEK: "SolNode24",
|
||||||
|
SORTIE_BOSS_KRIL: "SolNode99",
|
||||||
|
SORTIE_BOSS_TYL: "SolNode105",
|
||||||
|
SORTIE_BOSS_JACKAL: "SolNode104",
|
||||||
|
SORTIE_BOSS_ALAD: "SolNode53",
|
||||||
|
SORTIE_BOSS_AMBULAS: "SolNode51",
|
||||||
|
SORTIE_BOSS_NEF: "SettlementNode20",
|
||||||
|
SORTIE_BOSS_RAPTOR: "SolNode210",
|
||||||
|
SORTIE_BOSS_LEPHANTIS: "SolNode712",
|
||||||
|
SORTIE_BOSS_INFALAD: "SolNode705"
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EPOCH = 1734307200 * 1000; // Monday, Dec 16, 2024 @ 00:00 UTC+0; should logically be winter in 1999 iteration 0
|
||||||
|
|
||||||
|
export const getSortieTime = (day: number): number => {
|
||||||
|
const dayStart = EPOCH + day * 86400000;
|
||||||
|
const date = new Date(dayStart);
|
||||||
|
date.setUTCHours(12);
|
||||||
|
const isDst = new Intl.DateTimeFormat("en-US", {
|
||||||
|
timeZone: "America/Toronto",
|
||||||
|
timeZoneName: "short"
|
||||||
|
})
|
||||||
|
.formatToParts(date)
|
||||||
|
.find(part => part.type === "timeZoneName")!
|
||||||
|
.value.includes("DT");
|
||||||
|
return dayStart + (isDst ? 16 : 17) * 3600000;
|
||||||
|
};
|
@ -29,7 +29,8 @@ const dojoDecoSchema = new Schema<IDojoDecoDatabase>({
|
|||||||
MiscItems: { type: [typeCountSchema], default: undefined },
|
MiscItems: { type: [typeCountSchema], default: undefined },
|
||||||
CompletionTime: Date,
|
CompletionTime: Date,
|
||||||
RushPlatinum: Number,
|
RushPlatinum: Number,
|
||||||
PictureFrameInfo: pictureFrameInfoSchema
|
PictureFrameInfo: pictureFrameInfoSchema,
|
||||||
|
Pending: Boolean
|
||||||
});
|
});
|
||||||
|
|
||||||
const dojoLeaderboardEntrySchema = new Schema<IDojoLeaderboardEntry>(
|
const dojoLeaderboardEntrySchema = new Schema<IDojoLeaderboardEntry>(
|
||||||
@ -57,6 +58,12 @@ const dojoComponentSchema = new Schema<IDojoComponentDatabase>({
|
|||||||
DestructionTime: Date,
|
DestructionTime: Date,
|
||||||
Decos: [dojoDecoSchema],
|
Decos: [dojoDecoSchema],
|
||||||
DecoCapacity: Number,
|
DecoCapacity: Number,
|
||||||
|
PaintBot: Schema.Types.ObjectId,
|
||||||
|
PendingColors: { type: [Number], default: undefined },
|
||||||
|
Colors: { type: [Number], default: undefined },
|
||||||
|
PendingLights: { type: [Number], default: undefined },
|
||||||
|
Lights: { type: [Number], default: undefined },
|
||||||
|
Settings: String,
|
||||||
Leaderboard: { type: [dojoLeaderboardEntrySchema], default: undefined }
|
Leaderboard: { type: [dojoLeaderboardEntrySchema], default: undefined }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4,7 +4,8 @@ import { typeCountSchema } from "@/src/models/inventoryModels/inventoryModel";
|
|||||||
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
||||||
import { ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
|
||||||
export interface IMessageClient extends Omit<IMessageDatabase, "_id" | "date" | "startDate" | "endDate" | "ownerId"> {
|
export interface IMessageClient
|
||||||
|
extends Omit<IMessageDatabase, "_id" | "date" | "startDate" | "endDate" | "ownerId" | "attVisualOnly"> {
|
||||||
_id?: IOid;
|
_id?: IOid;
|
||||||
date: IMongoDate;
|
date: IMongoDate;
|
||||||
startDate?: IMongoDate;
|
startDate?: IMongoDate;
|
||||||
@ -29,6 +30,7 @@ export interface IMessage {
|
|||||||
endDate?: Date;
|
endDate?: Date;
|
||||||
att?: string[];
|
att?: string[];
|
||||||
countedAtt?: ITypeCount[];
|
countedAtt?: ITypeCount[];
|
||||||
|
attVisualOnly?: boolean;
|
||||||
transmission?: string;
|
transmission?: string;
|
||||||
arg?: Arg[];
|
arg?: Arg[];
|
||||||
gifts?: IGift[];
|
gifts?: IGift[];
|
||||||
@ -108,6 +110,7 @@ const messageSchema = new Schema<IMessageDatabase>(
|
|||||||
att: { type: [String], default: undefined },
|
att: { type: [String], default: undefined },
|
||||||
gifts: { type: [giftSchema], default: undefined },
|
gifts: { type: [giftSchema], default: undefined },
|
||||||
countedAtt: { type: [typeCountSchema], default: undefined },
|
countedAtt: { type: [typeCountSchema], default: undefined },
|
||||||
|
attVisualOnly: Boolean,
|
||||||
transmission: String,
|
transmission: String,
|
||||||
arg: {
|
arg: {
|
||||||
type: [
|
type: [
|
||||||
@ -141,6 +144,7 @@ messageSchema.set("toJSON", {
|
|||||||
|
|
||||||
delete returnedObject._id;
|
delete returnedObject._id;
|
||||||
delete returnedObject.__v;
|
delete returnedObject.__v;
|
||||||
|
delete returnedObject.attVisualOnly;
|
||||||
|
|
||||||
messageClient.date = toMongoDate(messageDatabase.date);
|
messageClient.date = toMongoDate(messageDatabase.date);
|
||||||
|
|
||||||
|
@ -872,6 +872,7 @@ const EquipmentSchema = new Schema<IEquipmentDatabase>(
|
|||||||
OffensiveUpgrade: String,
|
OffensiveUpgrade: String,
|
||||||
DefensiveUpgrade: String,
|
DefensiveUpgrade: String,
|
||||||
UpgradesExpiry: Date,
|
UpgradesExpiry: Date,
|
||||||
|
UmbraDate: Date,
|
||||||
ArchonCrystalUpgrades: { type: [ArchonCrystalUpgradeSchema], default: undefined },
|
ArchonCrystalUpgrades: { type: [ArchonCrystalUpgradeSchema], default: undefined },
|
||||||
Weapon: crewShipWeaponSchema,
|
Weapon: crewShipWeaponSchema,
|
||||||
Customization: crewShipCustomizationSchema,
|
Customization: crewShipCustomizationSchema,
|
||||||
@ -902,6 +903,9 @@ EquipmentSchema.set("toJSON", {
|
|||||||
if (db.UpgradesExpiry) {
|
if (db.UpgradesExpiry) {
|
||||||
client.UpgradesExpiry = toMongoDate(db.UpgradesExpiry);
|
client.UpgradesExpiry = toMongoDate(db.UpgradesExpiry);
|
||||||
}
|
}
|
||||||
|
if (db.UmbraDate) {
|
||||||
|
client.UmbraDate = toMongoDate(db.UmbraDate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -105,7 +105,9 @@ import { setActiveQuestController } from "@/src/controllers/api/setActiveQuestCo
|
|||||||
import { setActiveShipController } from "@/src/controllers/api/setActiveShipController";
|
import { setActiveShipController } from "@/src/controllers/api/setActiveShipController";
|
||||||
import { setAllianceGuildPermissionsController } from "@/src/controllers/api/setAllianceGuildPermissionsController";
|
import { setAllianceGuildPermissionsController } from "@/src/controllers/api/setAllianceGuildPermissionsController";
|
||||||
import { setBootLocationController } from "@/src/controllers/api/setBootLocationController";
|
import { setBootLocationController } from "@/src/controllers/api/setBootLocationController";
|
||||||
|
import { setDojoComponentColorsController } from "@/src/controllers/api/setDojoComponentColorsController";
|
||||||
import { setDojoComponentMessageController } from "@/src/controllers/api/setDojoComponentMessageController";
|
import { setDojoComponentMessageController } from "@/src/controllers/api/setDojoComponentMessageController";
|
||||||
|
import { setDojoComponentSettingsController } from "@/src/controllers/api/setDojoComponentSettingsController";
|
||||||
import { setEquippedInstrumentController } from "@/src/controllers/api/setEquippedInstrumentController";
|
import { setEquippedInstrumentController } from "@/src/controllers/api/setEquippedInstrumentController";
|
||||||
import { setGuildMotdController } from "@/src/controllers/api/setGuildMotdController";
|
import { setGuildMotdController } from "@/src/controllers/api/setGuildMotdController";
|
||||||
import { setPlacedDecoInfoController } from "@/src/controllers/api/setPlacedDecoInfoController";
|
import { setPlacedDecoInfoController } from "@/src/controllers/api/setPlacedDecoInfoController";
|
||||||
@ -261,7 +263,9 @@ apiRouter.post("/saveLoadout.php", saveLoadoutController);
|
|||||||
apiRouter.post("/saveSettings.php", saveSettingsController);
|
apiRouter.post("/saveSettings.php", saveSettingsController);
|
||||||
apiRouter.post("/saveVaultAutoContribute.php", saveVaultAutoContributeController);
|
apiRouter.post("/saveVaultAutoContribute.php", saveVaultAutoContributeController);
|
||||||
apiRouter.post("/sell.php", sellController);
|
apiRouter.post("/sell.php", sellController);
|
||||||
|
apiRouter.post("/setDojoComponentColors.php", setDojoComponentColorsController);
|
||||||
apiRouter.post("/setDojoComponentMessage.php", setDojoComponentMessageController);
|
apiRouter.post("/setDojoComponentMessage.php", setDojoComponentMessageController);
|
||||||
|
apiRouter.post("/setDojoComponentSettings.php", setDojoComponentSettingsController);
|
||||||
apiRouter.post("/setEquippedInstrument.php", setEquippedInstrumentController);
|
apiRouter.post("/setEquippedInstrument.php", setEquippedInstrumentController);
|
||||||
apiRouter.post("/setGuildMotd.php", setGuildMotdController);
|
apiRouter.post("/setGuildMotd.php", setGuildMotdController);
|
||||||
apiRouter.post("/setPlacedDecoInfo.php", setPlacedDecoInfoController);
|
apiRouter.post("/setPlacedDecoInfo.php", setPlacedDecoInfoController);
|
||||||
|
@ -39,6 +39,7 @@ interface IConfig {
|
|||||||
noVendorPurchaseLimits?: boolean;
|
noVendorPurchaseLimits?: boolean;
|
||||||
instantResourceExtractorDrones?: boolean;
|
instantResourceExtractorDrones?: boolean;
|
||||||
noDojoRoomBuildStage?: boolean;
|
noDojoRoomBuildStage?: boolean;
|
||||||
|
noDecoBuildStage?: boolean;
|
||||||
fastDojoRoomDestruction?: boolean;
|
fastDojoRoomDestruction?: boolean;
|
||||||
noDojoResearchCosts?: boolean;
|
noDojoResearchCosts?: boolean;
|
||||||
noDojoResearchTime?: boolean;
|
noDojoResearchTime?: boolean;
|
||||||
|
@ -141,6 +141,7 @@ export const getDojoClient = async (
|
|||||||
DojoComponents: []
|
DojoComponents: []
|
||||||
};
|
};
|
||||||
const roomsToRemove: Types.ObjectId[] = [];
|
const roomsToRemove: Types.ObjectId[] = [];
|
||||||
|
const decosToRemoveNoRefund: { componentId: Types.ObjectId; decoId: Types.ObjectId }[] = [];
|
||||||
let needSave = false;
|
let needSave = false;
|
||||||
for (const dojoComponent of guild.DojoComponents) {
|
for (const dojoComponent of guild.DojoComponents) {
|
||||||
if (!componentId || dojoComponent._id.equals(componentId)) {
|
if (!componentId || dojoComponent._id.equals(componentId)) {
|
||||||
@ -150,7 +151,8 @@ export const getDojoClient = async (
|
|||||||
ppf: dojoComponent.ppf,
|
ppf: dojoComponent.ppf,
|
||||||
Name: dojoComponent.Name,
|
Name: dojoComponent.Name,
|
||||||
Message: dojoComponent.Message,
|
Message: dojoComponent.Message,
|
||||||
DecoCapacity: dojoComponent.DecoCapacity ?? 600
|
DecoCapacity: dojoComponent.DecoCapacity ?? 600,
|
||||||
|
Settings: dojoComponent.Settings
|
||||||
};
|
};
|
||||||
if (dojoComponent.pi) {
|
if (dojoComponent.pi) {
|
||||||
clientComponent.pi = toOid(dojoComponent.pi);
|
clientComponent.pi = toOid(dojoComponent.pi);
|
||||||
@ -212,6 +214,21 @@ export const getDojoClient = async (
|
|||||||
PictureFrameInfo: deco.PictureFrameInfo
|
PictureFrameInfo: deco.PictureFrameInfo
|
||||||
};
|
};
|
||||||
if (deco.CompletionTime) {
|
if (deco.CompletionTime) {
|
||||||
|
if (
|
||||||
|
deco.Type == "/Lotus/Objects/Tenno/Props/TnoPaintBotDojoDeco" &&
|
||||||
|
Date.now() >= deco.CompletionTime.getTime()
|
||||||
|
) {
|
||||||
|
if (dojoComponent.PendingColors) {
|
||||||
|
dojoComponent.Colors = dojoComponent.PendingColors;
|
||||||
|
dojoComponent.PendingColors = undefined;
|
||||||
|
}
|
||||||
|
if (dojoComponent.PendingLights) {
|
||||||
|
dojoComponent.Lights = dojoComponent.PendingLights;
|
||||||
|
dojoComponent.PendingLights = undefined;
|
||||||
|
}
|
||||||
|
decosToRemoveNoRefund.push({ componentId: dojoComponent._id, decoId: deco._id });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
clientDeco.CompletionTime = toMongoDate(deco.CompletionTime);
|
clientDeco.CompletionTime = toMongoDate(deco.CompletionTime);
|
||||||
} else {
|
} else {
|
||||||
clientDeco.RegularCredits = deco.RegularCredits;
|
clientDeco.RegularCredits = deco.RegularCredits;
|
||||||
@ -220,6 +237,10 @@ export const getDojoClient = async (
|
|||||||
clientComponent.Decos.push(clientDeco);
|
clientComponent.Decos.push(clientDeco);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
clientComponent.PendingColors = dojoComponent.PendingColors;
|
||||||
|
clientComponent.Colors = dojoComponent.Colors;
|
||||||
|
clientComponent.PendingLights = dojoComponent.PendingLights;
|
||||||
|
clientComponent.Lights = dojoComponent.Lights;
|
||||||
dojo.DojoComponents.push(clientComponent);
|
dojo.DojoComponents.push(clientComponent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,6 +251,15 @@ export const getDojoClient = async (
|
|||||||
}
|
}
|
||||||
needSave = true;
|
needSave = true;
|
||||||
}
|
}
|
||||||
|
for (const deco of decosToRemoveNoRefund) {
|
||||||
|
logger.debug(`removing polychrome`, deco);
|
||||||
|
const component = guild.DojoComponents.id(deco.componentId)!;
|
||||||
|
component.Decos!.splice(
|
||||||
|
component.Decos!.findIndex(x => x._id.equals(deco.decoId)),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
needSave = true;
|
||||||
|
}
|
||||||
if (needSave) {
|
if (needSave) {
|
||||||
await guild.save();
|
await guild.save();
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ const convertEquipment = (client: IEquipmentClient): IEquipmentDatabase => {
|
|||||||
InfestationDate: convertOptionalDate(client.InfestationDate),
|
InfestationDate: convertOptionalDate(client.InfestationDate),
|
||||||
Expiry: convertOptionalDate(client.Expiry),
|
Expiry: convertOptionalDate(client.Expiry),
|
||||||
UpgradesExpiry: convertOptionalDate(client.UpgradesExpiry),
|
UpgradesExpiry: convertOptionalDate(client.UpgradesExpiry),
|
||||||
|
UmbraDate: convertOptionalDate(client.UmbraDate),
|
||||||
CrewMembers: client.CrewMembers ? convertCrewShipMembers(client.CrewMembers) : undefined,
|
CrewMembers: client.CrewMembers ? convertCrewShipMembers(client.CrewMembers) : undefined,
|
||||||
Details: client.Details ? convertKubrowDetails(client.Details) : undefined,
|
Details: client.Details ? convertKubrowDetails(client.Details) : undefined,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Inventory, TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
import { Inventory, TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { SlotNames, IInventoryChanges, IBinChanges, slotNames } from "@/src/types/purchaseTypes";
|
import { SlotNames, IInventoryChanges, IBinChanges, slotNames, IAffiliationMods } from "@/src/types/purchaseTypes";
|
||||||
import {
|
import {
|
||||||
IChallengeProgress,
|
IChallengeProgress,
|
||||||
IFlavourItem,
|
IFlavourItem,
|
||||||
@ -45,6 +45,7 @@ import {
|
|||||||
ExportGear,
|
ExportGear,
|
||||||
ExportKeys,
|
ExportKeys,
|
||||||
ExportMisc,
|
ExportMisc,
|
||||||
|
ExportNightwave,
|
||||||
ExportRailjackWeapons,
|
ExportRailjackWeapons,
|
||||||
ExportRecipes,
|
ExportRecipes,
|
||||||
ExportResources,
|
ExportResources,
|
||||||
@ -538,15 +539,9 @@ export const addItem = async (
|
|||||||
if (!key) return {};
|
if (!key) return {};
|
||||||
return { QuestKeys: [key] };
|
return { QuestKeys: [key] };
|
||||||
} else {
|
} else {
|
||||||
const key = { ItemType: typeName, ItemCount: quantity };
|
const levelKeyChanges = [{ ItemType: typeName, ItemCount: quantity }];
|
||||||
|
addLevelKeys(inventory, levelKeyChanges);
|
||||||
const index = inventory.LevelKeys.findIndex(levelKey => levelKey.ItemType == typeName);
|
return { LevelKeys: levelKeyChanges };
|
||||||
if (index != -1) {
|
|
||||||
inventory.LevelKeys[index].ItemCount += quantity;
|
|
||||||
} else {
|
|
||||||
inventory.LevelKeys.push(key);
|
|
||||||
}
|
|
||||||
return { LevelKeys: [key] };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typeName in ExportDrones) {
|
if (typeName in ExportDrones) {
|
||||||
@ -664,6 +659,8 @@ export const addItem = async (
|
|||||||
return {
|
return {
|
||||||
MiscItems: miscItemChanges
|
MiscItems: miscItemChanges
|
||||||
};
|
};
|
||||||
|
} else if (typeName == "/Lotus/Types/Game/CrewShip/RailJack/DefaultHarness") {
|
||||||
|
return addCrewShipHarness(inventory, typeName);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1240,6 +1237,10 @@ export const addRecipes = (inventory: TInventoryDatabaseDocument, itemsArray: IT
|
|||||||
applyArrayChanges(inventory.Recipes, itemsArray);
|
applyArrayChanges(inventory.Recipes, itemsArray);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const addLevelKeys = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[]): void => {
|
||||||
|
applyArrayChanges(inventory.LevelKeys, itemsArray);
|
||||||
|
};
|
||||||
|
|
||||||
export const addMods = (inventory: TInventoryDatabaseDocument, itemsArray: IRawUpgrade[]): void => {
|
export const addMods = (inventory: TInventoryDatabaseDocument, itemsArray: IRawUpgrade[]): void => {
|
||||||
const { RawUpgrades } = inventory;
|
const { RawUpgrades } = inventory;
|
||||||
|
|
||||||
@ -1304,35 +1305,52 @@ export const addFocusXpIncreases = (inventory: TInventoryDatabaseDocument, focus
|
|||||||
inventory.DailyFocus -= focusXpPlus.reduce((a, b) => a + b, 0);
|
inventory.DailyFocus -= focusXpPlus.reduce((a, b) => a + b, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addSeasonalChallengeHistory = (
|
export const addChallenges = (
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
itemsArray: ISeasonChallenge[]
|
ChallengeProgress: IChallengeProgress[],
|
||||||
): void => {
|
SeasonChallengeCompletions: ISeasonChallenge[] | undefined
|
||||||
const category = inventory.SeasonChallengeHistory;
|
): IAffiliationMods[] => {
|
||||||
|
ChallengeProgress.forEach(({ Name, Progress }) => {
|
||||||
itemsArray.forEach(({ challenge, id }) => {
|
const itemIndex = inventory.ChallengeProgress.findIndex(i => i.Name === Name);
|
||||||
const itemIndex = category.findIndex(i => i.challenge === challenge);
|
|
||||||
|
|
||||||
if (itemIndex !== -1) {
|
if (itemIndex !== -1) {
|
||||||
category[itemIndex].id = id;
|
inventory.ChallengeProgress[itemIndex].Progress = Progress;
|
||||||
} else {
|
} else {
|
||||||
category.push({ challenge, id });
|
inventory.ChallengeProgress.push({ Name, Progress });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
export const addChallenges = (inventory: TInventoryDatabaseDocument, itemsArray: IChallengeProgress[]): void => {
|
const affiliationMods: IAffiliationMods[] = [];
|
||||||
const category = inventory.ChallengeProgress;
|
if (SeasonChallengeCompletions) {
|
||||||
|
for (const challenge of SeasonChallengeCompletions) {
|
||||||
|
// Ignore challenges that weren't completed just now
|
||||||
|
if (!ChallengeProgress.find(x => challenge.challenge.indexOf(x.Name) != -1)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
itemsArray.forEach(({ Name, Progress }) => {
|
const meta = ExportNightwave.challenges[challenge.challenge];
|
||||||
const itemIndex = category.findIndex(i => i.Name === Name);
|
logger.debug("Completed challenge", meta);
|
||||||
|
|
||||||
if (itemIndex !== -1) {
|
let affiliation = inventory.Affiliations.find(x => x.Tag == ExportNightwave.affiliationTag);
|
||||||
category[itemIndex].Progress = Progress;
|
if (!affiliation) {
|
||||||
} else {
|
affiliation =
|
||||||
category.push({ Name, Progress });
|
inventory.Affiliations[
|
||||||
|
inventory.Affiliations.push({
|
||||||
|
Tag: ExportNightwave.affiliationTag,
|
||||||
|
Standing: 0
|
||||||
|
}) - 1
|
||||||
|
];
|
||||||
|
}
|
||||||
|
affiliation.Standing += meta.standing;
|
||||||
|
|
||||||
|
if (affiliationMods.length == 0) {
|
||||||
|
affiliationMods.push({ Tag: ExportNightwave.affiliationTag });
|
||||||
|
}
|
||||||
|
affiliationMods[0].Standing ??= 0;
|
||||||
|
affiliationMods[0].Standing += meta.standing;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
return affiliationMods;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addMissionComplete = (inventory: TInventoryDatabaseDocument, { Tag, Completes }: IMission): void => {
|
export const addMissionComplete = (inventory: TInventoryDatabaseDocument, { Tag, Completes }: IMission): void => {
|
||||||
|
@ -22,6 +22,7 @@ import {
|
|||||||
addFusionTreasures,
|
addFusionTreasures,
|
||||||
addGearExpByCategory,
|
addGearExpByCategory,
|
||||||
addItem,
|
addItem,
|
||||||
|
addLevelKeys,
|
||||||
addMiscItems,
|
addMiscItems,
|
||||||
addMissionComplete,
|
addMissionComplete,
|
||||||
addMods,
|
addMods,
|
||||||
@ -77,19 +78,52 @@ export const addMissionInventoryUpdates = async (
|
|||||||
inventoryUpdates: IMissionInventoryUpdateRequest
|
inventoryUpdates: IMissionInventoryUpdateRequest
|
||||||
): Promise<IInventoryChanges> => {
|
): Promise<IInventoryChanges> => {
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
if (
|
if (inventoryUpdates.EndOfMatchUpload) {
|
||||||
inventoryUpdates.EndOfMatchUpload &&
|
if (inventoryUpdates.Missions && inventoryUpdates.Missions.Tag in ExportRegions) {
|
||||||
inventoryUpdates.Missions &&
|
const node = ExportRegions[inventoryUpdates.Missions.Tag];
|
||||||
inventoryUpdates.Missions.Tag in ExportRegions
|
if (node.miscItemFee) {
|
||||||
) {
|
addMiscItems(inventory, [
|
||||||
const node = ExportRegions[inventoryUpdates.Missions.Tag];
|
{
|
||||||
if (node.miscItemFee) {
|
ItemType: node.miscItemFee.ItemType,
|
||||||
addMiscItems(inventory, [
|
ItemCount: node.miscItemFee.ItemCount * -1
|
||||||
{
|
}
|
||||||
ItemType: node.miscItemFee.ItemType,
|
]);
|
||||||
ItemCount: node.miscItemFee.ItemCount * -1
|
}
|
||||||
}
|
}
|
||||||
]);
|
if (inventoryUpdates.KeyToRemove) {
|
||||||
|
if (!inventoryUpdates.KeyOwner || inventory.accountOwnerId.equals(inventoryUpdates.KeyOwner)) {
|
||||||
|
addLevelKeys(inventory, [
|
||||||
|
{
|
||||||
|
ItemType: inventoryUpdates.KeyToRemove,
|
||||||
|
ItemCount: -1
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
inventoryUpdates.MissionFailed &&
|
||||||
|
inventoryUpdates.MissionStatus == "GS_FAILURE" &&
|
||||||
|
inventoryUpdates.ObjectiveReached &&
|
||||||
|
!inventoryUpdates.LockedWeaponGroup
|
||||||
|
) {
|
||||||
|
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "NORMAL"))!;
|
||||||
|
const config = loadout.NORMAL.id(inventory.CurrentLoadOutIds[0].$oid)!;
|
||||||
|
const SuitId = new Types.ObjectId(config.s!.ItemId.$oid);
|
||||||
|
|
||||||
|
inventory.BrandedSuits ??= [];
|
||||||
|
if (!inventory.BrandedSuits.find(x => x.equals(SuitId))) {
|
||||||
|
inventory.BrandedSuits.push(SuitId);
|
||||||
|
|
||||||
|
await createMessage(inventory.accountOwnerId, [
|
||||||
|
{
|
||||||
|
sndr: "/Lotus/Language/Menu/Mailbox_WarframeSender",
|
||||||
|
msg: "/Lotus/Language/G1Quests/BrandedMessage",
|
||||||
|
sub: "/Lotus/Language/G1Quests/BrandedTitle",
|
||||||
|
att: ["/Lotus/Types/Recipes/Components/BrandRemovalBlueprint"],
|
||||||
|
highPriority: true // TOVERIFY: I cannot find any content of this within the last 10 years so I can only assume that highPriority is set (it certainly would make sense), but I just don't know for sure that it is so on live.
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (inventoryUpdates.RewardInfo) {
|
if (inventoryUpdates.RewardInfo) {
|
||||||
@ -110,32 +144,6 @@ export const addMissionInventoryUpdates = async (
|
|||||||
inventory.NemesisAbandonedRewards = inventoryUpdates.RewardInfo.NemesisAbandonedRewards;
|
inventory.NemesisAbandonedRewards = inventoryUpdates.RewardInfo.NemesisAbandonedRewards;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
inventoryUpdates.MissionFailed &&
|
|
||||||
inventoryUpdates.MissionStatus == "GS_FAILURE" &&
|
|
||||||
inventoryUpdates.EndOfMatchUpload &&
|
|
||||||
inventoryUpdates.ObjectiveReached &&
|
|
||||||
!inventoryUpdates.LockedWeaponGroup
|
|
||||||
) {
|
|
||||||
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "NORMAL"))!;
|
|
||||||
const config = loadout.NORMAL.id(inventory.CurrentLoadOutIds[0].$oid)!;
|
|
||||||
const SuitId = new Types.ObjectId(config.s!.ItemId.$oid);
|
|
||||||
|
|
||||||
inventory.BrandedSuits ??= [];
|
|
||||||
if (!inventory.BrandedSuits.find(x => x.equals(SuitId))) {
|
|
||||||
inventory.BrandedSuits.push(SuitId);
|
|
||||||
|
|
||||||
await createMessage(inventory.accountOwnerId, [
|
|
||||||
{
|
|
||||||
sndr: "/Lotus/Language/Menu/Mailbox_WarframeSender",
|
|
||||||
msg: "/Lotus/Language/G1Quests/BrandedMessage",
|
|
||||||
sub: "/Lotus/Language/G1Quests/BrandedTitle",
|
|
||||||
att: ["/Lotus/Types/Recipes/Components/BrandRemovalBlueprint"],
|
|
||||||
highPriority: true // TOVERIFY: I cannot find any content of this within the last 10 years so I can only assume that highPriority is set (it certainly would make sense), but I just don't know for sure that it is so on live.
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const [key, value] of getEntriesUnsafe(inventoryUpdates)) {
|
for (const [key, value] of getEntriesUnsafe(inventoryUpdates)) {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
logger.error(`Inventory update key ${key} has no value `);
|
logger.error(`Inventory update key ${key} has no value `);
|
||||||
@ -187,7 +195,7 @@ export const addMissionInventoryUpdates = async (
|
|||||||
addRecipes(inventory, value);
|
addRecipes(inventory, value);
|
||||||
break;
|
break;
|
||||||
case "ChallengeProgress":
|
case "ChallengeProgress":
|
||||||
addChallenges(inventory, value);
|
addChallenges(inventory, value, inventoryUpdates.SeasonChallengeCompletions);
|
||||||
break;
|
break;
|
||||||
case "FusionTreasures":
|
case "FusionTreasures":
|
||||||
addFusionTreasures(inventory, value);
|
addFusionTreasures(inventory, value);
|
||||||
@ -594,10 +602,24 @@ export const addMissionRewards = async (
|
|||||||
if (!droptable) {
|
if (!droptable) {
|
||||||
logger.error(`unknown droptable ${si.DropTable}`);
|
logger.error(`unknown droptable ${si.DropTable}`);
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i != si.DROP_MOD.length; ++i) {
|
const modsPool = droptable[0].items;
|
||||||
for (const pool of droptable) {
|
const blueprintsPool = (droptable.length > 1 ? droptable[1] : droptable[0]).items;
|
||||||
const reward = getRandomReward(pool.items)!;
|
if (si.DROP_MOD) {
|
||||||
logger.debug(`stripped droptable rolled`, reward);
|
for (let i = 0; i != si.DROP_MOD.length; ++i) {
|
||||||
|
const reward = getRandomReward(modsPool)!;
|
||||||
|
logger.debug(`stripped droptable (mods pool) rolled`, reward);
|
||||||
|
await addItem(inventory, reward.type);
|
||||||
|
MissionRewards.push({
|
||||||
|
StoreItem: toStoreItem(reward.type),
|
||||||
|
ItemCount: 1,
|
||||||
|
FromEnemyCache: true // to show "identified"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (si.DROP_BLUEPRINT) {
|
||||||
|
for (let i = 0; i != si.DROP_BLUEPRINT.length; ++i) {
|
||||||
|
const reward = getRandomReward(blueprintsPool)!;
|
||||||
|
logger.debug(`stripped droptable (blueprints pool) rolled`, reward);
|
||||||
await addItem(inventory, reward.type);
|
await addItem(inventory, reward.type);
|
||||||
MissionRewards.push({
|
MissionRewards.push({
|
||||||
StoreItem: toStoreItem(reward.type),
|
StoreItem: toStoreItem(reward.type),
|
||||||
|
@ -161,6 +161,7 @@ export interface IDojoClient {
|
|||||||
|
|
||||||
export interface IDojoComponentClient {
|
export interface IDojoComponentClient {
|
||||||
id: IOid;
|
id: IOid;
|
||||||
|
SortId?: IOid;
|
||||||
pf: string; // Prefab (.level)
|
pf: string; // Prefab (.level)
|
||||||
ppf: string;
|
ppf: string;
|
||||||
pi?: IOid; // Parent ID. N/A to root.
|
pi?: IOid; // Parent ID. N/A to root.
|
||||||
@ -175,16 +176,26 @@ export interface IDojoComponentClient {
|
|||||||
DestructionTime?: IMongoDate;
|
DestructionTime?: IMongoDate;
|
||||||
Decos?: IDojoDecoClient[];
|
Decos?: IDojoDecoClient[];
|
||||||
DecoCapacity?: number;
|
DecoCapacity?: number;
|
||||||
|
PaintBot?: IOid;
|
||||||
|
PendingColors?: number[];
|
||||||
|
Colors?: number[];
|
||||||
|
PendingLights?: number[];
|
||||||
|
Lights?: number[];
|
||||||
|
Settings?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDojoComponentDatabase
|
export interface IDojoComponentDatabase
|
||||||
extends Omit<IDojoComponentClient, "id" | "pi" | "CompletionTime" | "DestructionTime" | "Decos"> {
|
extends Omit<
|
||||||
|
IDojoComponentClient,
|
||||||
|
"id" | "SortId" | "pi" | "CompletionTime" | "DestructionTime" | "Decos" | "PaintBot"
|
||||||
|
> {
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
pi?: Types.ObjectId;
|
pi?: Types.ObjectId;
|
||||||
CompletionTime?: Date;
|
CompletionTime?: Date;
|
||||||
CompletionLogPending?: boolean;
|
CompletionLogPending?: boolean;
|
||||||
DestructionTime?: Date;
|
DestructionTime?: Date;
|
||||||
Decos?: IDojoDecoDatabase[];
|
Decos?: IDojoDecoDatabase[];
|
||||||
|
PaintBot?: Types.ObjectId;
|
||||||
Leaderboard?: IDojoLeaderboardEntry[];
|
Leaderboard?: IDojoLeaderboardEntry[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,6 +211,7 @@ export interface IDojoDecoClient {
|
|||||||
CompletionTime?: IMongoDate;
|
CompletionTime?: IMongoDate;
|
||||||
RushPlatinum?: number;
|
RushPlatinum?: number;
|
||||||
PictureFrameInfo?: IPictureFrameInfo;
|
PictureFrameInfo?: IPictureFrameInfo;
|
||||||
|
Pending?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDojoDecoDatabase extends Omit<IDojoDecoClient, "id" | "CompletionTime"> {
|
export interface IDojoDecoDatabase extends Omit<IDojoDecoClient, "id" | "CompletionTime"> {
|
||||||
|
@ -90,12 +90,13 @@ export interface IEquipmentSelection {
|
|||||||
export interface IEquipmentClient
|
export interface IEquipmentClient
|
||||||
extends Omit<
|
extends Omit<
|
||||||
IEquipmentDatabase,
|
IEquipmentDatabase,
|
||||||
"_id" | "InfestationDate" | "Expiry" | "UpgradesExpiry" | "CrewMembers" | "Details"
|
"_id" | "InfestationDate" | "Expiry" | "UpgradesExpiry" | "UmbraDate" | "CrewMembers" | "Details"
|
||||||
> {
|
> {
|
||||||
ItemId: IOid;
|
ItemId: IOid;
|
||||||
InfestationDate?: IMongoDate;
|
InfestationDate?: IMongoDate;
|
||||||
Expiry?: IMongoDate;
|
Expiry?: IMongoDate;
|
||||||
UpgradesExpiry?: IMongoDate;
|
UpgradesExpiry?: IMongoDate;
|
||||||
|
UmbraDate?: IMongoDate;
|
||||||
CrewMembers?: ICrewShipMembersClient;
|
CrewMembers?: ICrewShipMembersClient;
|
||||||
Details?: IKubrowPetDetailsClient;
|
Details?: IKubrowPetDetailsClient;
|
||||||
}
|
}
|
||||||
@ -134,6 +135,7 @@ export interface IEquipmentDatabase {
|
|||||||
OffensiveUpgrade?: string;
|
OffensiveUpgrade?: string;
|
||||||
DefensiveUpgrade?: string;
|
DefensiveUpgrade?: string;
|
||||||
UpgradesExpiry?: Date;
|
UpgradesExpiry?: Date;
|
||||||
|
UmbraDate?: Date; // related to scrapped "echoes of umbra" feature
|
||||||
ArchonCrystalUpgrades?: IArchonCrystalUpgrade[];
|
ArchonCrystalUpgrades?: IArchonCrystalUpgrade[];
|
||||||
Weapon?: ICrewShipWeapon;
|
Weapon?: ICrewShipWeapon;
|
||||||
Customization?: ICrewShipCustomization;
|
Customization?: ICrewShipCustomization;
|
||||||
|
@ -49,6 +49,9 @@ export type IMissionInventoryUpdateRequest = {
|
|||||||
rewardsMultiplier?: number;
|
rewardsMultiplier?: number;
|
||||||
GoalTag: string;
|
GoalTag: string;
|
||||||
LevelKeyName: string;
|
LevelKeyName: string;
|
||||||
|
KeyOwner?: string;
|
||||||
|
KeyRemovalHash?: string;
|
||||||
|
KeyToRemove?: string;
|
||||||
ActiveBoosters?: IBooster[];
|
ActiveBoosters?: IBooster[];
|
||||||
RawUpgrades?: IRawUpgrade[];
|
RawUpgrades?: IRawUpgrade[];
|
||||||
FusionTreasures?: IFusionTreasure[];
|
FusionTreasures?: IFusionTreasure[];
|
||||||
@ -98,7 +101,8 @@ export type IMissionInventoryUpdateRequest = {
|
|||||||
Upgrades?: IUpgradeClient[]; // riven challenge progress
|
Upgrades?: IUpgradeClient[]; // riven challenge progress
|
||||||
StrippedItems?: {
|
StrippedItems?: {
|
||||||
DropTable: string;
|
DropTable: string;
|
||||||
DROP_MOD: number[];
|
DROP_MOD?: number[];
|
||||||
|
DROP_BLUEPRINT?: number[];
|
||||||
}[];
|
}[];
|
||||||
DeathMarks?: string[];
|
DeathMarks?: string[];
|
||||||
Nemesis?: number;
|
Nemesis?: number;
|
||||||
|
@ -62,23 +62,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Sorties": [
|
|
||||||
{
|
|
||||||
"_id": { "$oid": "663a4c7d4d932c97c0a3acd7" },
|
|
||||||
"Activation": { "$date": { "$numberLong": "1715097600000" } },
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
|
|
||||||
"Reward": "/Lotus/Types/Game/MissionDecks/SortieRewards",
|
|
||||||
"Seed": 24491,
|
|
||||||
"Boss": "SORTIE_BOSS_TYL",
|
|
||||||
"ExtraDrops": [],
|
|
||||||
"Variants": [
|
|
||||||
{ "missionType": "MT_TERRITORY", "modifierType": "SORTIE_MODIFIER_ARMOR", "node": "SolNode122", "tileset": "GrineerOceanTileset" },
|
|
||||||
{ "missionType": "MT_MOBILE_DEFENSE", "modifierType": "SORTIE_MODIFIER_LOW_ENERGY", "node": "SolNode184", "tileset": "GrineerGalleonTileset" },
|
|
||||||
{ "missionType": "MT_LANDSCAPE", "modifierType": "SORTIE_MODIFIER_EXIMUS", "node": "SolNode228", "tileset": "EidolonTileset" }
|
|
||||||
],
|
|
||||||
"Twitter": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"SyndicateMissions": [
|
"SyndicateMissions": [
|
||||||
{
|
{
|
||||||
"_id": { "$oid": "663a4fc5ba6f84724fa48049" },
|
"_id": { "$oid": "663a4fc5ba6f84724fa48049" },
|
||||||
|
@ -608,6 +608,10 @@
|
|||||||
<input class="form-check-input" type="checkbox" id="noDojoRoomBuildStage" />
|
<input class="form-check-input" type="checkbox" id="noDojoRoomBuildStage" />
|
||||||
<label class="form-check-label" for="noDojoRoomBuildStage" data-loc="cheats_noDojoRoomBuildStage"></label>
|
<label class="form-check-label" for="noDojoRoomBuildStage" data-loc="cheats_noDojoRoomBuildStage"></label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="noDecoBuildStage" />
|
||||||
|
<label class="form-check-label" for="noDecoBuildStage" data-loc="cheats_noDecoBuildStage"></label>
|
||||||
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="fastDojoRoomDestruction" />
|
<input class="form-check-input" type="checkbox" id="fastDojoRoomDestruction" />
|
||||||
<label class="form-check-label" for="fastDojoRoomDestruction" data-loc="cheats_fastDojoRoomDestruction"></label>
|
<label class="form-check-label" for="fastDojoRoomDestruction" data-loc="cheats_fastDojoRoomDestruction"></label>
|
||||||
|
@ -221,6 +221,11 @@ function fetchItemList() {
|
|||||||
name: loc("code_zanuka")
|
name: loc("code_zanuka")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
data.miscitems.push({
|
||||||
|
uniqueName: "/Lotus/Types/Items/Research/DojoColors/GenericDojoColorPigment",
|
||||||
|
name: loc("code_pigment")
|
||||||
|
});
|
||||||
|
|
||||||
const itemMap = {
|
const itemMap = {
|
||||||
// Generics for rivens
|
// Generics for rivens
|
||||||
"/Lotus/Weapons/Tenno/Archwing/Primary/ArchGun": { name: loc("code_archgun") },
|
"/Lotus/Weapons/Tenno/Archwing/Primary/ArchGun": { name: loc("code_archgun") },
|
||||||
@ -260,6 +265,7 @@ function fetchItemList() {
|
|||||||
} else if (type == "uniqueLevelCaps") {
|
} else if (type == "uniqueLevelCaps") {
|
||||||
uniqueLevelCaps = items;
|
uniqueLevelCaps = items;
|
||||||
} else {
|
} else {
|
||||||
|
const nameSet = new Set();
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
if (item.name.includes("<ARCHWING> ")) {
|
if (item.name.includes("<ARCHWING> ")) {
|
||||||
item.name = item.name.replace("<ARCHWING> ", "");
|
item.name = item.name.replace("<ARCHWING> ", "");
|
||||||
@ -306,20 +312,19 @@ function fetchItemList() {
|
|||||||
document
|
document
|
||||||
.getElementById("datalist-" + type + "-" + item.partType.slice(5))
|
.getElementById("datalist-" + type + "-" + item.partType.slice(5))
|
||||||
.appendChild(option);
|
.appendChild(option);
|
||||||
|
}
|
||||||
|
} else if (item.badReason != "notraw") {
|
||||||
|
if (nameSet.has(item.name)) {
|
||||||
|
//console.log(`Not adding ${item.uniqueName} to datalist for ${type} due to duplicate display name: ${item.name}`);
|
||||||
} else {
|
} else {
|
||||||
console.log(item.partType);
|
nameSet.add(item.name);
|
||||||
|
|
||||||
const option = document.createElement("option");
|
const option = document.createElement("option");
|
||||||
option.setAttribute("data-key", item.uniqueName);
|
option.setAttribute("data-key", item.uniqueName);
|
||||||
option.value = item.name;
|
option.value = item.name;
|
||||||
document.getElementById("datalist-" + type).appendChild(option);
|
document.getElementById("datalist-" + type).appendChild(option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item.badReason != "notraw") {
|
|
||||||
const option = document.createElement("option");
|
|
||||||
option.setAttribute("data-key", item.uniqueName);
|
|
||||||
option.value = item.name;
|
|
||||||
document.getElementById("datalist-" + type).appendChild(option);
|
|
||||||
}
|
|
||||||
itemMap[item.uniqueName] = { ...item, type };
|
itemMap[item.uniqueName] = { ...item, type };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ dict = {
|
|||||||
code_setInactive: `Quest inaktiv setzen`,
|
code_setInactive: `Quest inaktiv setzen`,
|
||||||
code_completed: `Abgeschlossen`,
|
code_completed: `Abgeschlossen`,
|
||||||
code_active: `Aktiv`,
|
code_active: `Aktiv`,
|
||||||
|
code_pigment: `Pigment`,
|
||||||
login_description: `Melde dich mit deinem OpenWF-Account an (denselben Angaben wie im Spiel, wenn du dich mit diesem Server verbindest).`,
|
login_description: `Melde dich mit deinem OpenWF-Account an (denselben Angaben wie im Spiel, wenn du dich mit diesem Server verbindest).`,
|
||||||
login_emailLabel: `E-Mail-Adresse`,
|
login_emailLabel: `E-Mail-Adresse`,
|
||||||
login_passwordLabel: `Passwort`,
|
login_passwordLabel: `Passwort`,
|
||||||
@ -136,6 +137,7 @@ dict = {
|
|||||||
cheats_noVendorPurchaseLimits: `Keine Kaufbeschränkungen bei Händlern`,
|
cheats_noVendorPurchaseLimits: `Keine Kaufbeschränkungen bei Händlern`,
|
||||||
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
|
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
|
||||||
cheats_noDojoRoomBuildStage: `Kein Dojo-Raum-Bauvorgang`,
|
cheats_noDojoRoomBuildStage: `Kein Dojo-Raum-Bauvorgang`,
|
||||||
|
cheats_noDecoBuildStage: `[UNTRANSLATED] No Decoration Build Stage`,
|
||||||
cheats_fastDojoRoomDestruction: `Schnelle Dojo-Raum-Zerstörung`,
|
cheats_fastDojoRoomDestruction: `Schnelle Dojo-Raum-Zerstörung`,
|
||||||
cheats_noDojoResearchCosts: `Keine Dojo-Forschungskosten`,
|
cheats_noDojoResearchCosts: `Keine Dojo-Forschungskosten`,
|
||||||
cheats_noDojoResearchTime: `Keine Dojo-Forschungszeit`,
|
cheats_noDojoResearchTime: `Keine Dojo-Forschungszeit`,
|
||||||
|
@ -52,6 +52,7 @@ dict = {
|
|||||||
code_setInactive: `Make the quest inactive`,
|
code_setInactive: `Make the quest inactive`,
|
||||||
code_completed: `Completed`,
|
code_completed: `Completed`,
|
||||||
code_active: `Active`,
|
code_active: `Active`,
|
||||||
|
code_pigment: `Pigment`,
|
||||||
login_description: `Login using your OpenWF account credentials (same as in-game when connecting to this server).`,
|
login_description: `Login using your OpenWF account credentials (same as in-game when connecting to this server).`,
|
||||||
login_emailLabel: `Email address`,
|
login_emailLabel: `Email address`,
|
||||||
login_passwordLabel: `Password`,
|
login_passwordLabel: `Password`,
|
||||||
@ -135,6 +136,7 @@ dict = {
|
|||||||
cheats_noVendorPurchaseLimits: `No Vendor Purchase Limits`,
|
cheats_noVendorPurchaseLimits: `No Vendor Purchase Limits`,
|
||||||
cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`,
|
cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`,
|
||||||
cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`,
|
cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`,
|
||||||
|
cheats_noDecoBuildStage: `No Decoration Build Stage`,
|
||||||
cheats_fastDojoRoomDestruction: `Fast Dojo Room Destruction`,
|
cheats_fastDojoRoomDestruction: `Fast Dojo Room Destruction`,
|
||||||
cheats_noDojoResearchCosts: `No Dojo Research Costs`,
|
cheats_noDojoResearchCosts: `No Dojo Research Costs`,
|
||||||
cheats_noDojoResearchTime: `No Dojo Research Time`,
|
cheats_noDojoResearchTime: `No Dojo Research Time`,
|
||||||
|
@ -53,6 +53,7 @@ dict = {
|
|||||||
code_setInactive: `[UNTRANSLATED] Make the quest inactive`,
|
code_setInactive: `[UNTRANSLATED] Make the quest inactive`,
|
||||||
code_completed: `[UNTRANSLATED] Completed`,
|
code_completed: `[UNTRANSLATED] Completed`,
|
||||||
code_active: `[UNTRANSLATED] Active`,
|
code_active: `[UNTRANSLATED] Active`,
|
||||||
|
code_pigment: `Pigment`,
|
||||||
login_description: `Connexion avec les informations de connexion OpenWF.`,
|
login_description: `Connexion avec les informations de connexion OpenWF.`,
|
||||||
login_emailLabel: `Email`,
|
login_emailLabel: `Email`,
|
||||||
login_passwordLabel: `Mot de passe`,
|
login_passwordLabel: `Mot de passe`,
|
||||||
@ -136,6 +137,7 @@ dict = {
|
|||||||
cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`,
|
cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`,
|
||||||
cheats_instantResourceExtractorDrones: `Ressources de drone d'extraction instantannées`,
|
cheats_instantResourceExtractorDrones: `Ressources de drone d'extraction instantannées`,
|
||||||
cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`,
|
cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`,
|
||||||
|
cheats_noDecoBuildStage: `[UNTRANSLATED] No Decoration Build Stage`,
|
||||||
cheats_fastDojoRoomDestruction: `[UNTRANSLATED] Fast Dojo Room Destruction`,
|
cheats_fastDojoRoomDestruction: `[UNTRANSLATED] Fast Dojo Room Destruction`,
|
||||||
cheats_noDojoResearchCosts: `Aucun coût de recherche (Dojo)`,
|
cheats_noDojoResearchCosts: `Aucun coût de recherche (Dojo)`,
|
||||||
cheats_noDojoResearchTime: `Aucun temps de recherche (Dojo)`,
|
cheats_noDojoResearchTime: `Aucun temps de recherche (Dojo)`,
|
||||||
|
@ -53,6 +53,7 @@ dict = {
|
|||||||
code_setInactive: `Сделать квест неактивным`,
|
code_setInactive: `Сделать квест неактивным`,
|
||||||
code_completed: `Завершено`,
|
code_completed: `Завершено`,
|
||||||
code_active: `Активный`,
|
code_active: `Активный`,
|
||||||
|
code_pigment: `Пигмент`,
|
||||||
login_description: `Войдите, используя учетные данные OpenWF (те же, что и в игре при подключении к этому серверу).`,
|
login_description: `Войдите, используя учетные данные OpenWF (те же, что и в игре при подключении к этому серверу).`,
|
||||||
login_emailLabel: `Адрес электронной почты`,
|
login_emailLabel: `Адрес электронной почты`,
|
||||||
login_passwordLabel: `Пароль`,
|
login_passwordLabel: `Пароль`,
|
||||||
@ -136,6 +137,7 @@ dict = {
|
|||||||
cheats_noVendorPurchaseLimits: `Отсутствие лимитов на покупки у вендоров`,
|
cheats_noVendorPurchaseLimits: `Отсутствие лимитов на покупки у вендоров`,
|
||||||
cheats_instantResourceExtractorDrones: `Мгновенные Экстракторы Ресурсов`,
|
cheats_instantResourceExtractorDrones: `Мгновенные Экстракторы Ресурсов`,
|
||||||
cheats_noDojoRoomBuildStage: `Мгновенное Строительтво Комнат Додзё`,
|
cheats_noDojoRoomBuildStage: `Мгновенное Строительтво Комнат Додзё`,
|
||||||
|
cheats_noDecoBuildStage: `Мгновенное Строительтво Украшений`,
|
||||||
cheats_fastDojoRoomDestruction: `Мгновенные Уничтожение Комнат Додзё`,
|
cheats_fastDojoRoomDestruction: `Мгновенные Уничтожение Комнат Додзё`,
|
||||||
cheats_noDojoResearchCosts: `Бесплатные Исследование Додзё`,
|
cheats_noDojoResearchCosts: `Бесплатные Исследование Додзё`,
|
||||||
cheats_noDojoResearchTime: `Мгновенные Исследование Додзё`,
|
cheats_noDojoResearchTime: `Мгновенные Исследование Додзё`,
|
||||||
|
@ -53,6 +53,7 @@ dict = {
|
|||||||
code_setInactive: `[UNTRANSLATED] Make the quest inactive`,
|
code_setInactive: `[UNTRANSLATED] Make the quest inactive`,
|
||||||
code_completed: `[UNTRANSLATED] Completed`,
|
code_completed: `[UNTRANSLATED] Completed`,
|
||||||
code_active: `[UNTRANSLATED] Active`,
|
code_active: `[UNTRANSLATED] Active`,
|
||||||
|
code_pigment: `颜料`,
|
||||||
login_description: `使用您的 OpenWF 账户凭证登录(与游戏内连接本服务器时使用的昵称相同)。`,
|
login_description: `使用您的 OpenWF 账户凭证登录(与游戏内连接本服务器时使用的昵称相同)。`,
|
||||||
login_emailLabel: `电子邮箱`,
|
login_emailLabel: `电子邮箱`,
|
||||||
login_passwordLabel: `密码`,
|
login_passwordLabel: `密码`,
|
||||||
@ -136,6 +137,7 @@ dict = {
|
|||||||
cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`,
|
cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`,
|
||||||
cheats_instantResourceExtractorDrones: `即时资源采集无人机`,
|
cheats_instantResourceExtractorDrones: `即时资源采集无人机`,
|
||||||
cheats_noDojoRoomBuildStage: `无视道场房间建造阶段`,
|
cheats_noDojoRoomBuildStage: `无视道场房间建造阶段`,
|
||||||
|
cheats_noDecoBuildStage: `[UNTRANSLATED] No Decoration Build Stage`,
|
||||||
cheats_fastDojoRoomDestruction: `快速拆除道场房间`,
|
cheats_fastDojoRoomDestruction: `快速拆除道场房间`,
|
||||||
cheats_noDojoResearchCosts: `无视道场研究消耗`,
|
cheats_noDojoResearchCosts: `无视道场研究消耗`,
|
||||||
cheats_noDojoResearchTime: `无视道场研究时间`,
|
cheats_noDojoResearchTime: `无视道场研究时间`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user