forked from OpenWF/SpaceNinjaServer
Compare commits
94 Commits
sentinel-i
...
main
Author | SHA1 | Date | |
---|---|---|---|
2c3043f40e | |||
7d02906656 | |||
ed54e00a03 | |||
3d6c880c96 | |||
660768b53b | |||
3de68e51d5 | |||
c06abded11 | |||
9468768947 | |||
0af7f41201 | |||
de1e2a25f2 | |||
1cf7b41d3f | |||
ab9cc685eb | |||
743b784754 | |||
5df533a7fb | |||
9417aa3c84 | |||
a1872e2b07 | |||
9042e85355 | |||
66ee550ccd | |||
7a295a86ec | |||
88d00eaaa1 | |||
1e8f2fc766 | |||
0d842ade90 | |||
4e3a2e17ee | |||
61864b2be1 | |||
45748fa8be | |||
afec59e8a6 | |||
ee1a49f5f2 | |||
9e94083875 | |||
db0e0d80dd | |||
5cda2e2d08 | |||
e23d865044 | |||
c7658b5b20 | |||
9993500eca | |||
267357871b | |||
cf5ed0442d | |||
de36e2ee8d | |||
ca1b6c31b6 | |||
d66c474bfc | |||
781f01520f | |||
ac37702468 | |||
75c011e3cb | |||
4d4f885c8e | |||
66d1a65e63 | |||
48eefd8db1 | |||
4a6a5ea9cc | |||
95c0ad7892 | |||
a90d3a5156 | |||
d0c9409a2d | |||
bbde7b2141 | |||
5271123090 | |||
f3e56480e5 | |||
6f46ace40c | |||
883426e429 | |||
13432bf034 | |||
a1267e5f64 | |||
2058207b6a | |||
c7c416c100 | |||
90e97d7888 | |||
3f6734ac1c | |||
6f64690b91 | |||
fb5a7320bb | |||
143b358a03 | |||
0b75757277 | |||
fd7f4c9e92 | |||
fa6fac494b | |||
6b3f524574 | |||
506365f97e | |||
70646160c3 | |||
3ffa4a7fd3 | |||
826a09a473 | |||
100aefcee4 | |||
409c089d11 | |||
8c32dc2670 | |||
a67f99b665 | |||
756a01d270 | |||
efc7467a99 | |||
99e1a66da8 | |||
370f8c1008 | |||
f039998d71 | |||
eb594af9d8 | |||
bb8596fa87 | |||
a85539a686 | |||
ada6a4bad0 | |||
948104a9a6 | |||
7a8b12b372 | |||
26d644a982 | |||
d6750cd84b | |||
f3601ec43e | |||
15aaa28a4f | |||
ce5b0fc9e2 | |||
64290b72c0 | |||
570c6fe0d1 | |||
146dbd1b89 | |||
e17d43dcb6 |
@ -1,7 +1,6 @@
|
|||||||
@echo off
|
@echo off
|
||||||
|
|
||||||
echo Updating SpaceNinjaServer...
|
echo Updating SpaceNinjaServer...
|
||||||
git config remote.origin.url https://openwf.io/SpaceNinjaServer.git
|
|
||||||
git fetch --prune
|
git fetch --prune
|
||||||
git stash
|
git stash
|
||||||
git reset --hard origin/main
|
git reset --hard origin/main
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
"infiniteEndo": false,
|
"infiniteEndo": false,
|
||||||
"infiniteRegalAya": false,
|
"infiniteRegalAya": false,
|
||||||
"infiniteHelminthMaterials": false,
|
"infiniteHelminthMaterials": false,
|
||||||
|
"dontSubtractConsumables": false,
|
||||||
"unlockAllShipFeatures": false,
|
"unlockAllShipFeatures": false,
|
||||||
"unlockAllShipDecorations": false,
|
"unlockAllShipDecorations": false,
|
||||||
"unlockAllFlavourItems": false,
|
"unlockAllFlavourItems": false,
|
||||||
@ -37,6 +38,7 @@
|
|||||||
"noKimCooldowns": false,
|
"noKimCooldowns": false,
|
||||||
"instantResourceExtractorDrones": false,
|
"instantResourceExtractorDrones": false,
|
||||||
"noResourceExtractorDronesDamage": false,
|
"noResourceExtractorDronesDamage": false,
|
||||||
|
"skipClanKeyCrafting": false,
|
||||||
"noDojoRoomBuildStage": false,
|
"noDojoRoomBuildStage": false,
|
||||||
"noDecoBuildStage": false,
|
"noDecoBuildStage": false,
|
||||||
"fastDojoRoomDestruction": false,
|
"fastDojoRoomDestruction": false,
|
||||||
|
8
package-lock.json
generated
8
package-lock.json
generated
@ -18,7 +18,7 @@
|
|||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"ncp": "^2.0.0",
|
"ncp": "^2.0.0",
|
||||||
"typescript": "^5.5",
|
"typescript": "^5.5",
|
||||||
"warframe-public-export-plus": "^0.5.56",
|
"warframe-public-export-plus": "^0.5.59",
|
||||||
"warframe-riven-info": "^0.1.2",
|
"warframe-riven-info": "^0.1.2",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0"
|
"winston-daily-rotate-file": "^5.0.0"
|
||||||
@ -3789,9 +3789,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/warframe-public-export-plus": {
|
"node_modules/warframe-public-export-plus": {
|
||||||
"version": "0.5.56",
|
"version": "0.5.59",
|
||||||
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.56.tgz",
|
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.59.tgz",
|
||||||
"integrity": "sha512-px+J7tUm6fkSzwKkvL73ySQReDq9oM1UrHSLM3vbYGBvELM892iBgPYG45okIhScCSdwmmXTiWZTf4x/I4qiNQ=="
|
"integrity": "sha512-/SUCVjngVDBz6gahz7CdVLywtHLODL6O5nmNtQcxFDUwrUGnF1lETcG8/UO+WLeGxBVAy4BDPbq+9ZWlYZM4uQ=="
|
||||||
},
|
},
|
||||||
"node_modules/warframe-riven-info": {
|
"node_modules/warframe-riven-info": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"ncp": "^2.0.0",
|
"ncp": "^2.0.0",
|
||||||
"typescript": "^5.5",
|
"typescript": "^5.5",
|
||||||
"warframe-public-export-plus": "^0.5.56",
|
"warframe-public-export-plus": "^0.5.59",
|
||||||
"warframe-riven-info": "^0.1.2",
|
"warframe-riven-info": "^0.1.2",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0"
|
"winston-daily-rotate-file": "^5.0.0"
|
||||||
|
@ -2,15 +2,18 @@ const millisecondsPerSecond = 1000;
|
|||||||
const secondsPerMinute = 60;
|
const secondsPerMinute = 60;
|
||||||
const minutesPerHour = 60;
|
const minutesPerHour = 60;
|
||||||
const hoursPerDay = 24;
|
const hoursPerDay = 24;
|
||||||
|
const daysPerWeek = 7;
|
||||||
|
|
||||||
const unixSecond = millisecondsPerSecond;
|
const unixSecond = millisecondsPerSecond;
|
||||||
const unixMinute = secondsPerMinute * millisecondsPerSecond;
|
const unixMinute = secondsPerMinute * millisecondsPerSecond;
|
||||||
const unixHour = unixMinute * minutesPerHour;
|
const unixHour = unixMinute * minutesPerHour;
|
||||||
const unixDay = hoursPerDay * unixHour;
|
const unixDay = hoursPerDay * unixHour;
|
||||||
|
const unixWeek = daysPerWeek * unixDay;
|
||||||
|
|
||||||
export const unixTimesInMs = {
|
export const unixTimesInMs = {
|
||||||
second: unixSecond,
|
second: unixSecond,
|
||||||
minute: unixMinute,
|
minute: unixMinute,
|
||||||
hour: unixHour,
|
hour: unixHour,
|
||||||
day: unixDay
|
day: unixDay,
|
||||||
|
week: unixWeek
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@ export const activateRandomModController: RequestHandler = async (req, res) => {
|
|||||||
ItemCount: -1
|
ItemCount: -1
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType]);
|
const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType])!;
|
||||||
const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
|
const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
|
||||||
const upgradeIndex =
|
const upgradeIndex =
|
||||||
inventory.Upgrades.push({
|
inventory.Upgrades.push({
|
||||||
|
@ -28,7 +28,7 @@ export const artifactTransmutationController: RequestHandler = async (req, res)
|
|||||||
});
|
});
|
||||||
|
|
||||||
const rawRivenType = getRandomRawRivenType();
|
const rawRivenType = getRandomRawRivenType();
|
||||||
const rivenType = getRandomElement(rivenRawToRealWeighted[rawRivenType]);
|
const rivenType = getRandomElement(rivenRawToRealWeighted[rawRivenType])!;
|
||||||
const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
|
const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
|
||||||
|
|
||||||
const upgradeIndex =
|
const upgradeIndex =
|
||||||
|
@ -133,7 +133,14 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
|
|||||||
if (recipe.secretIngredientAction != "SIA_UNBRAND") {
|
if (recipe.secretIngredientAction != "SIA_UNBRAND") {
|
||||||
InventoryChanges = {
|
InventoryChanges = {
|
||||||
...InventoryChanges,
|
...InventoryChanges,
|
||||||
...(await addItem(inventory, recipe.resultType, recipe.num, false))
|
...(await addItem(
|
||||||
|
inventory,
|
||||||
|
recipe.resultType,
|
||||||
|
recipe.num,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
pendingRecipe.TargetFingerprint
|
||||||
|
))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { addFusionPoints, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ export const claimLibraryDailyTaskRewardController: RequestHandler = async (req,
|
|||||||
}
|
}
|
||||||
syndicate.Standing += rewardStanding;
|
syndicate.Standing += rewardStanding;
|
||||||
|
|
||||||
inventory.FusionPoints += 80 * rewardQuantity;
|
addFusionPoints(inventory, 80 * rewardQuantity);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
|
41
src/controllers/api/completeCalendarEventController.ts
Normal file
41
src/controllers/api/completeCalendarEventController.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { getCalendarProgress, getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||||
|
import { getWorldState } from "@/src/services/worldStateService";
|
||||||
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
// GET request; query parameters: CompletedEventIdx=0&Iteration=4&Version=19&Season=CST_SUMMER
|
||||||
|
export const completeCalendarEventController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId);
|
||||||
|
const calendarProgress = getCalendarProgress(inventory);
|
||||||
|
const currentSeason = getWorldState().KnownCalendarSeasons[0];
|
||||||
|
let inventoryChanges: IInventoryChanges = {};
|
||||||
|
let dayIndex = 0;
|
||||||
|
for (const day of currentSeason.Days) {
|
||||||
|
if (day.events.length == 0 || day.events[0].type != "CET_CHALLENGE") {
|
||||||
|
if (dayIndex == calendarProgress.SeasonProgress.LastCompletedDayIdx) {
|
||||||
|
if (day.events.length != 0) {
|
||||||
|
const selection = day.events[parseInt(req.query.CompletedEventIdx as string)];
|
||||||
|
if (selection.type == "CET_REWARD") {
|
||||||
|
inventoryChanges = (await handleStoreItemAcquisition(selection.reward!, inventory))
|
||||||
|
.InventoryChanges;
|
||||||
|
} else if (selection.type == "CET_UPGRADE") {
|
||||||
|
calendarProgress.YearProgress.Upgrades.push(selection.upgrade!);
|
||||||
|
} else if (selection.type != "CET_PLOT") {
|
||||||
|
throw new Error(`unexpected selection type: ${selection.type}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++dayIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
calendarProgress.SeasonProgress.LastCompletedDayIdx++;
|
||||||
|
await inventory.save();
|
||||||
|
res.json({
|
||||||
|
InventoryChanges: inventoryChanges,
|
||||||
|
CalendarProgress: inventory.CalendarProgress
|
||||||
|
});
|
||||||
|
};
|
@ -1,8 +1,14 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Guild, GuildMember } from "@/src/models/guildModel";
|
import { Guild, GuildMember } from "@/src/models/guildModel";
|
||||||
import { Account } from "@/src/models/loginModel";
|
import { Account } from "@/src/models/loginModel";
|
||||||
import { deleteGuild, getGuildClient, hasGuildPermission, removeDojoKeyItems } from "@/src/services/guildService";
|
import {
|
||||||
import { addRecipes, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
|
deleteGuild,
|
||||||
|
getGuildClient,
|
||||||
|
giveClanKey,
|
||||||
|
hasGuildPermission,
|
||||||
|
removeDojoKeyItems
|
||||||
|
} from "@/src/services/guildService";
|
||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "@/src/services/loginService";
|
import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "@/src/services/loginService";
|
||||||
import { GuildPermission } from "@/src/types/guildTypes";
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
@ -41,14 +47,7 @@ export const confirmGuildInvitationGetController: RequestHandler = async (req, r
|
|||||||
// Update inventory of new member
|
// Update inventory of new member
|
||||||
const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes");
|
const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes");
|
||||||
inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
|
inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
|
||||||
const recipeChanges = [
|
giveClanKey(inventory, inventoryChanges);
|
||||||
{
|
|
||||||
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
];
|
|
||||||
addRecipes(inventory, recipeChanges);
|
|
||||||
combineInventoryChanges(inventoryChanges, { Recipes: recipeChanges });
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
const guild = (await Guild.findById(req.query.clanId as string))!;
|
const guild = (await Guild.findById(req.query.clanId as string))!;
|
||||||
@ -96,14 +95,9 @@ export const confirmGuildInvitationPostController: RequestHandler = async (req,
|
|||||||
await GuildMember.deleteMany({ accountId: guildMember.accountId, status: 1 });
|
await GuildMember.deleteMany({ accountId: guildMember.accountId, status: 1 });
|
||||||
|
|
||||||
// Update inventory of new member
|
// Update inventory of new member
|
||||||
const inventory = await getInventory(guildMember.accountId.toString(), "GuildId Recipes");
|
const inventory = await getInventory(guildMember.accountId.toString(), "GuildId LevelKeys Recipes");
|
||||||
inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
|
inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
|
||||||
addRecipes(inventory, [
|
giveClanKey(inventory);
|
||||||
{
|
|
||||||
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
// Add join to clan log
|
// Add join to clan log
|
||||||
|
@ -2,7 +2,7 @@ import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Guild } from "@/src/models/guildModel";
|
import { Guild } from "@/src/models/guildModel";
|
||||||
import { checkClanAscensionHasRequiredContributors } from "@/src/services/guildService";
|
import { checkClanAscensionHasRequiredContributors } from "@/src/services/guildService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { addFusionPoints, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
@ -36,7 +36,7 @@ export const contributeGuildClassController: RequestHandler = async (req, res) =
|
|||||||
|
|
||||||
// Either way, endo is given to the contributor.
|
// Either way, endo is given to the contributor.
|
||||||
const inventory = await getInventory(accountId, "FusionPoints");
|
const inventory = await getInventory(accountId, "FusionPoints");
|
||||||
inventory.FusionPoints += guild.CeremonyEndo!;
|
addFusionPoints(inventory, guild.CeremonyEndo!);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
|
@ -2,8 +2,9 @@ import { RequestHandler } from "express";
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Guild, GuildMember } from "@/src/models/guildModel";
|
import { Guild, GuildMember } from "@/src/models/guildModel";
|
||||||
import { createUniqueClanName, getGuildClient } from "@/src/services/guildService";
|
import { createUniqueClanName, getGuildClient, giveClanKey } from "@/src/services/guildService";
|
||||||
import { addRecipes, getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
|
|
||||||
export const createGuildController: RequestHandler = async (req, res) => {
|
export const createGuildController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -26,26 +27,15 @@ export const createGuildController: RequestHandler = async (req, res) => {
|
|||||||
rank: 0
|
rank: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
const inventory = await getInventory(accountId, "GuildId Recipes");
|
const inventory = await getInventory(accountId, "GuildId LevelKeys Recipes");
|
||||||
inventory.GuildId = guild._id;
|
inventory.GuildId = guild._id;
|
||||||
addRecipes(inventory, [
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
{
|
giveClanKey(inventory, inventoryChanges);
|
||||||
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
...(await getGuildClient(guild, accountId)),
|
...(await getGuildClient(guild, accountId)),
|
||||||
InventoryChanges: {
|
InventoryChanges: inventoryChanges
|
||||||
Recipes: [
|
|
||||||
{
|
|
||||||
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,14 +62,7 @@ export const crewShipIdentifySalvageController: RequestHandler = async (req, res
|
|||||||
} satisfies IInnateDamageFingerprint)
|
} satisfies IInnateDamageFingerprint)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
addEquipment(
|
addEquipment(inventory, "CrewShipSalvagedWeapons", payload.ItemType, defaultOverwrites, inventoryChanges);
|
||||||
inventory,
|
|
||||||
"CrewShipSalvagedWeapons",
|
|
||||||
payload.ItemType,
|
|
||||||
undefined,
|
|
||||||
inventoryChanges,
|
|
||||||
defaultOverwrites
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inventoryChanges.CrewShipRawSalvage = [
|
inventoryChanges.CrewShipRawSalvage = [
|
||||||
|
@ -21,10 +21,12 @@ export const entratiLabConquestModeController: RequestHandler = async (req, res)
|
|||||||
inventory.EntratiVaultCountResetDate = new Date(weekEnd);
|
inventory.EntratiVaultCountResetDate = new Date(weekEnd);
|
||||||
if (inventory.EntratiLabConquestUnlocked) {
|
if (inventory.EntratiLabConquestUnlocked) {
|
||||||
inventory.EntratiLabConquestUnlocked = 0;
|
inventory.EntratiLabConquestUnlocked = 0;
|
||||||
|
inventory.EntratiLabConquestCacheScoreMission = 0;
|
||||||
inventory.EntratiLabConquestActiveFrameVariants = [];
|
inventory.EntratiLabConquestActiveFrameVariants = [];
|
||||||
}
|
}
|
||||||
if (inventory.EchoesHexConquestUnlocked) {
|
if (inventory.EchoesHexConquestUnlocked) {
|
||||||
inventory.EchoesHexConquestUnlocked = 0;
|
inventory.EchoesHexConquestUnlocked = 0;
|
||||||
|
inventory.EchoesHexConquestCacheScoreMission = 0;
|
||||||
inventory.EchoesHexConquestActiveFrameVariants = [];
|
inventory.EchoesHexConquestActiveFrameVariants = [];
|
||||||
inventory.EchoesHexConquestActiveStickers = [];
|
inventory.EchoesHexConquestActiveStickers = [];
|
||||||
}
|
}
|
||||||
|
@ -104,13 +104,14 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
case FocusOperation.SentTrainingAmplifier: {
|
case FocusOperation.SentTrainingAmplifier: {
|
||||||
const request = JSON.parse(String(req.body)) as ISentTrainingAmplifierRequest;
|
const request = JSON.parse(String(req.body)) as ISentTrainingAmplifierRequest;
|
||||||
const parts: string[] = [
|
|
||||||
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingGrip",
|
|
||||||
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingChassis",
|
|
||||||
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingBarrel"
|
|
||||||
];
|
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
const inventoryChanges = addEquipment(inventory, "OperatorAmps", request.StartingWeaponType, parts);
|
const inventoryChanges = addEquipment(inventory, "OperatorAmps", request.StartingWeaponType, {
|
||||||
|
ModularParts: [
|
||||||
|
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingGrip",
|
||||||
|
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingChassis",
|
||||||
|
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingBarrel"
|
||||||
|
]
|
||||||
|
});
|
||||||
occupySlot(inventory, InventorySlot.AMPS, false);
|
occupySlot(inventory, InventorySlot.AMPS, false);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json((inventoryChanges.OperatorAmps as IEquipmentClient[])[0]);
|
res.json((inventoryChanges.OperatorAmps as IEquipmentClient[])[0]);
|
||||||
|
84
src/controllers/api/gardeningController.ts
Normal file
84
src/controllers/api/gardeningController.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
||||||
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
|
import { addMiscItem, getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { toStoreItem } from "@/src/services/itemDataService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { createGarden, getPersonalRooms } from "@/src/services/personalRoomsService";
|
||||||
|
import { IMongoDate } from "@/src/types/commonTypes";
|
||||||
|
import { IMissionReward } from "@/src/types/missionTypes";
|
||||||
|
import { IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
|
||||||
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
|
import { IGardeningClient } from "@/src/types/shipTypes";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { dict_en, ExportResources } from "warframe-public-export-plus";
|
||||||
|
|
||||||
|
export const gardeningController: RequestHandler = async (req, res) => {
|
||||||
|
const data = getJSONfromString<IGardeningRequest>(String(req.body));
|
||||||
|
if (data.Mode != "HarvestAll") {
|
||||||
|
throw new Error(`unexpected gardening mode: ${data.Mode}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const [inventory, personalRooms] = await Promise.all([
|
||||||
|
getInventory(accountId, "MiscItems"),
|
||||||
|
getPersonalRooms(accountId, "Apartment")
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Harvest plants
|
||||||
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
|
const rewards: Record<string, IMissionReward[][]> = {};
|
||||||
|
for (const planter of personalRooms.Apartment.Gardening.Planters) {
|
||||||
|
rewards[planter.Name] = [];
|
||||||
|
for (const plant of planter.Plants) {
|
||||||
|
const itemType =
|
||||||
|
"/Lotus/Types/Gameplay/Duviri/Resource/DuviriPlantItem" +
|
||||||
|
plant.PlantType.substring(plant.PlantType.length - 1);
|
||||||
|
const itemCount = Math.random() < 0.775 ? 2 : 4;
|
||||||
|
|
||||||
|
addMiscItem(inventory, itemType, itemCount, inventoryChanges);
|
||||||
|
|
||||||
|
rewards[planter.Name].push([
|
||||||
|
{
|
||||||
|
StoreItem: toStoreItem(itemType),
|
||||||
|
TypeName: itemType,
|
||||||
|
ItemCount: itemCount,
|
||||||
|
DailyCooldown: false,
|
||||||
|
Rarity: itemCount == 2 ? 0.7743589743589744 : 0.22564102564102564,
|
||||||
|
TweetText: `${itemCount}x ${dict_en[ExportResources[itemType].name]} (Resource)`,
|
||||||
|
ProductCategory: "MiscItems"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh garden
|
||||||
|
personalRooms.Apartment.Gardening = createGarden();
|
||||||
|
|
||||||
|
await Promise.all([inventory.save(), personalRooms.save()]);
|
||||||
|
|
||||||
|
const planter = personalRooms.Apartment.Gardening.Planters[personalRooms.Apartment.Gardening.Planters.length - 1];
|
||||||
|
const plant = planter.Plants[planter.Plants.length - 1];
|
||||||
|
res.json({
|
||||||
|
GardenTagName: planter.Name,
|
||||||
|
PlantType: plant.PlantType,
|
||||||
|
PlotIndex: plant.PlotIndex,
|
||||||
|
EndTime: toMongoDate(plant.EndTime),
|
||||||
|
InventoryChanges: inventoryChanges,
|
||||||
|
Gardening: personalRooms.toJSON<IPersonalRoomsClient>().Apartment.Gardening,
|
||||||
|
Rewards: rewards
|
||||||
|
} satisfies IGardeningResponse);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IGardeningRequest {
|
||||||
|
Mode: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGardeningResponse {
|
||||||
|
GardenTagName: string;
|
||||||
|
PlantType: string;
|
||||||
|
PlotIndex: number;
|
||||||
|
EndTime: IMongoDate;
|
||||||
|
InventoryChanges: IInventoryChanges;
|
||||||
|
Gardening: IGardeningClient;
|
||||||
|
Rewards: Record<string, IMissionReward[][]>;
|
||||||
|
}
|
@ -2,17 +2,24 @@ import { RequestHandler } from "express";
|
|||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
import allShipFeatures from "@/static/fixed_responses/allShipFeatures.json";
|
import allShipFeatures from "@/static/fixed_responses/allShipFeatures.json";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
import { createGarden, getPersonalRooms } from "@/src/services/personalRoomsService";
|
||||||
import { getShip } from "@/src/services/shipService";
|
import { getShip } from "@/src/services/shipService";
|
||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
|
import { toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import { IGetShipResponse } from "@/src/types/shipTypes";
|
import { IGetShipResponse } from "@/src/types/shipTypes";
|
||||||
import { IPersonalRooms } from "@/src/types/personalRoomsTypes";
|
import { IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
|
||||||
import { getLoadout } from "@/src/services/loadoutService";
|
import { getLoadout } from "@/src/services/loadoutService";
|
||||||
|
|
||||||
export const getShipController: RequestHandler = async (req, res) => {
|
export const getShipController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const personalRoomsDb = await getPersonalRooms(accountId);
|
const personalRoomsDb = await getPersonalRooms(accountId);
|
||||||
const personalRooms = personalRoomsDb.toJSON<IPersonalRooms>();
|
|
||||||
|
// Setup gardening if it's missing. Maybe should be done as part of some quest completion in the future.
|
||||||
|
if (personalRoomsDb.Apartment.Gardening.Planters.length == 0) {
|
||||||
|
personalRoomsDb.Apartment.Gardening = createGarden();
|
||||||
|
await personalRoomsDb.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
const personalRooms = personalRoomsDb.toJSON<IPersonalRoomsClient>();
|
||||||
const loadout = await getLoadout(accountId);
|
const loadout = await getLoadout(accountId);
|
||||||
const ship = await getShip(personalRoomsDb.activeShipId, "ShipAttachments SkinFlavourItem");
|
const ship = await getShip(personalRoomsDb.activeShipId, "ShipAttachments SkinFlavourItem");
|
||||||
|
|
||||||
|
@ -441,16 +441,9 @@ const finishComponentRepair = (
|
|||||||
const inventoryChanges = {
|
const inventoryChanges = {
|
||||||
...(category == "CrewShipWeaponSkins"
|
...(category == "CrewShipWeaponSkins"
|
||||||
? addCrewShipWeaponSkin(inventory, salvageItem.ItemType, salvageItem.UpgradeFingerprint)
|
? addCrewShipWeaponSkin(inventory, salvageItem.ItemType, salvageItem.UpgradeFingerprint)
|
||||||
: addEquipment(
|
: addEquipment(inventory, category, salvageItem.ItemType, {
|
||||||
inventory,
|
UpgradeFingerprint: salvageItem.UpgradeFingerprint
|
||||||
category,
|
})),
|
||||||
salvageItem.ItemType,
|
|
||||||
undefined,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
UpgradeFingerprint: salvageItem.UpgradeFingerprint
|
|
||||||
}
|
|
||||||
)),
|
|
||||||
...occupySlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS, false)
|
...occupySlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS, false)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,8 +11,10 @@ import {
|
|||||||
import { getAccountForRequest, getAccountFromSuffixedName, getSuffixedName } from "@/src/services/loginService";
|
import { getAccountForRequest, getAccountFromSuffixedName, getSuffixedName } from "@/src/services/loginService";
|
||||||
import { addItems, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
|
import { addItems, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { ExportFlavour, ExportGear } from "warframe-public-export-plus";
|
import { ExportFlavour } from "warframe-public-export-plus";
|
||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||||
|
import { fromStoreItem, isStoreItem } from "@/src/services/itemDataService";
|
||||||
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
|
|
||||||
export const inboxController: RequestHandler = async (req, res) => {
|
export const inboxController: RequestHandler = async (req, res) => {
|
||||||
const { deleteId, lastMessage: latestClientMessageId, messageId } = req.query;
|
const { deleteId, lastMessage: latestClientMessageId, messageId } = req.query;
|
||||||
@ -27,10 +29,10 @@ export const inboxController: RequestHandler = async (req, res) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await deleteMessageRead(deleteId as string);
|
await deleteMessageRead(parseOid(deleteId as string));
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
} else if (messageId) {
|
} else if (messageId) {
|
||||||
const message = await getMessage(messageId as string);
|
const message = await getMessage(parseOid(messageId as string));
|
||||||
message.r = true;
|
message.r = true;
|
||||||
await message.save();
|
await message.save();
|
||||||
|
|
||||||
@ -48,8 +50,8 @@ export const inboxController: RequestHandler = async (req, res) => {
|
|||||||
await addItems(
|
await addItems(
|
||||||
inventory,
|
inventory,
|
||||||
attachmentItems.map(attItem => ({
|
attachmentItems.map(attItem => ({
|
||||||
ItemType: attItem,
|
ItemType: isStoreItem(attItem) ? fromStoreItem(attItem) : attItem,
|
||||||
ItemCount: attItem in ExportGear ? (ExportGear[attItem].purchaseQuantity ?? 1) : 1
|
ItemCount: 1
|
||||||
})),
|
})),
|
||||||
inventoryChanges
|
inventoryChanges
|
||||||
);
|
);
|
||||||
@ -99,7 +101,7 @@ export const inboxController: RequestHandler = async (req, res) => {
|
|||||||
await createNewEventMessages(req);
|
await createNewEventMessages(req);
|
||||||
const messages = await Inbox.find({ ownerId: accountId }).sort({ date: 1 });
|
const messages = await Inbox.find({ ownerId: accountId }).sort({ date: 1 });
|
||||||
|
|
||||||
const latestClientMessage = messages.find(m => m._id.toString() === latestClientMessageId);
|
const latestClientMessage = messages.find(m => m._id.toString() === parseOid(latestClientMessageId as string));
|
||||||
|
|
||||||
if (!latestClientMessage) {
|
if (!latestClientMessage) {
|
||||||
logger.debug(`this should only happen after DeleteAllRead `);
|
logger.debug(`this should only happen after DeleteAllRead `);
|
||||||
@ -122,3 +124,11 @@ export const inboxController: RequestHandler = async (req, res) => {
|
|||||||
res.json({ Inbox: inbox });
|
res.json({ Inbox: inbox });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 33.6.0 has query arguments like lastMessage={"$oid":"68112baebf192e786d1502bb"} instead of lastMessage=68112baebf192e786d1502bb
|
||||||
|
const parseOid = (oid: string): string => {
|
||||||
|
if (oid[0] == "{") {
|
||||||
|
return (JSON.parse(oid) as IOid).$oid;
|
||||||
|
}
|
||||||
|
return oid;
|
||||||
|
};
|
||||||
|
@ -18,10 +18,12 @@ import {
|
|||||||
addMiscItems,
|
addMiscItems,
|
||||||
allDailyAffiliationKeys,
|
allDailyAffiliationKeys,
|
||||||
cleanupInventory,
|
cleanupInventory,
|
||||||
createLibraryDailyTask
|
createLibraryDailyTask,
|
||||||
|
generateRewardSeed
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
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";
|
||||||
|
|
||||||
export const inventoryController: RequestHandler = async (request, response) => {
|
export const inventoryController: RequestHandler = async (request, response) => {
|
||||||
const accountId = await getAccountIdForRequest(request);
|
const accountId = await getAccountIdForRequest(request);
|
||||||
@ -87,7 +89,7 @@ export const inventoryController: RequestHandler = async (request, response) =>
|
|||||||
cleanupInventory(inventory);
|
cleanupInventory(inventory);
|
||||||
|
|
||||||
inventory.NextRefill = new Date((Math.trunc(Date.now() / 86400000) + 1) * 86400000);
|
inventory.NextRefill = new Date((Math.trunc(Date.now() / 86400000) + 1) * 86400000);
|
||||||
await inventory.save();
|
//await inventory.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -96,9 +98,27 @@ export const inventoryController: RequestHandler = async (request, response) =>
|
|||||||
new Date() >= inventory.InfestedFoundry.AbilityOverrideUnlockCooldown
|
new Date() >= inventory.InfestedFoundry.AbilityOverrideUnlockCooldown
|
||||||
) {
|
) {
|
||||||
handleSubsumeCompletion(inventory);
|
handleSubsumeCompletion(inventory);
|
||||||
await inventory.save();
|
//await inventory.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inventory.LastInventorySync) {
|
||||||
|
const lastSyncDuviriMood = Math.trunc(inventory.LastInventorySync.getTimestamp().getTime() / 7200000);
|
||||||
|
const currentDuviriMood = Math.trunc(Date.now() / 7200000);
|
||||||
|
if (lastSyncDuviriMood != currentDuviriMood) {
|
||||||
|
logger.debug(`refreshing duviri seed`);
|
||||||
|
if (!inventory.DuviriInfo) {
|
||||||
|
inventory.DuviriInfo = {
|
||||||
|
Seed: generateRewardSeed(),
|
||||||
|
NumCompletions: 0
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
inventory.DuviriInfo.Seed = generateRewardSeed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inventory.LastInventorySync = new Types.ObjectId();
|
||||||
|
await inventory.save();
|
||||||
|
|
||||||
response.json(await getInventoryResponse(inventory, "xpBasedLevelCapDisabled" in request.query));
|
response.json(await getInventoryResponse(inventory, "xpBasedLevelCapDisabled" in request.query));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -274,7 +294,7 @@ export const getInventoryResponse = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Omitting this field so opening the navigation resyncs the inventory which is more desirable for typical usage.
|
// Omitting this field so opening the navigation resyncs the inventory which is more desirable for typical usage.
|
||||||
//inventoryResponse.LastInventorySync = toOid(new Types.ObjectId());
|
inventoryResponse.LastInventorySync = undefined;
|
||||||
|
|
||||||
// Set 2FA enabled so trading post can be used
|
// Set 2FA enabled so trading post can be used
|
||||||
inventoryResponse.HWIDProtectEnabled = true;
|
inventoryResponse.HWIDProtectEnabled = true;
|
||||||
|
@ -7,6 +7,7 @@ import { Account } from "@/src/models/loginModel";
|
|||||||
import { createAccount, isCorrectPassword, isNameTaken } from "@/src/services/loginService";
|
import { createAccount, isCorrectPassword, isNameTaken } from "@/src/services/loginService";
|
||||||
import { IDatabaseAccountJson, ILoginRequest, ILoginResponse } from "@/src/types/loginTypes";
|
import { IDatabaseAccountJson, ILoginRequest, ILoginResponse } from "@/src/types/loginTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
|
import { version_compare } from "@/src/services/worldStateService";
|
||||||
|
|
||||||
export const loginController: RequestHandler = async (request, response) => {
|
export const loginController: RequestHandler = async (request, response) => {
|
||||||
const loginRequest = JSON.parse(String(request.body)) as ILoginRequest; // parse octet stream of json data to json object
|
const loginRequest = JSON.parse(String(request.body)) as ILoginRequest; // parse octet stream of json data to json object
|
||||||
@ -21,7 +22,11 @@ export const loginController: RequestHandler = async (request, response) => {
|
|||||||
|
|
||||||
const myAddress = request.host.indexOf("warframe.com") == -1 ? request.host : config.myAddress;
|
const myAddress = request.host.indexOf("warframe.com") == -1 ? request.host : config.myAddress;
|
||||||
|
|
||||||
if (!account && config.autoCreateAccount && loginRequest.ClientType != "webui") {
|
if (
|
||||||
|
!account &&
|
||||||
|
((config.autoCreateAccount && loginRequest.ClientType != "webui") ||
|
||||||
|
loginRequest.ClientType == "webui-register")
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const nameFromEmail = loginRequest.email.substring(0, loginRequest.email.indexOf("@"));
|
const nameFromEmail = loginRequest.email.substring(0, loginRequest.email.indexOf("@"));
|
||||||
let name = nameFromEmail || loginRequest.email.substring(1) || "SpaceNinja";
|
let name = nameFromEmail || loginRequest.email.substring(1) || "SpaceNinja";
|
||||||
@ -37,7 +42,7 @@ export const loginController: RequestHandler = async (request, response) => {
|
|||||||
password: loginRequest.password,
|
password: loginRequest.password,
|
||||||
DisplayName: name,
|
DisplayName: name,
|
||||||
CountryCode: loginRequest.lang.toUpperCase(),
|
CountryCode: loginRequest.lang.toUpperCase(),
|
||||||
ClientType: loginRequest.ClientType,
|
ClientType: loginRequest.ClientType == "webui-register" ? "webui" : loginRequest.ClientType,
|
||||||
CrossPlatformAllowed: true,
|
CrossPlatformAllowed: true,
|
||||||
ForceLogoutVersion: 0,
|
ForceLogoutVersion: 0,
|
||||||
ConsentNeeded: false,
|
ConsentNeeded: false,
|
||||||
@ -59,6 +64,11 @@ export const loginController: RequestHandler = async (request, response) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (loginRequest.ClientType == "webui-register") {
|
||||||
|
response.status(400).json({ error: "account already exists" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isCorrectPassword(loginRequest.password, account.password)) {
|
if (!isCorrectPassword(loginRequest.password, account.password)) {
|
||||||
response.status(400).json({ error: "incorrect login data" });
|
response.status(400).json({ error: "incorrect login data" });
|
||||||
return;
|
return;
|
||||||
@ -85,7 +95,7 @@ export const loginController: RequestHandler = async (request, response) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const createLoginResponse = (myAddress: string, account: IDatabaseAccountJson, buildLabel: string): ILoginResponse => {
|
const createLoginResponse = (myAddress: string, account: IDatabaseAccountJson, buildLabel: string): ILoginResponse => {
|
||||||
return {
|
const resp: ILoginResponse = {
|
||||||
id: account.id,
|
id: account.id,
|
||||||
DisplayName: account.DisplayName,
|
DisplayName: account.DisplayName,
|
||||||
CountryCode: account.CountryCode,
|
CountryCode: account.CountryCode,
|
||||||
@ -99,11 +109,14 @@ const createLoginResponse = (myAddress: string, account: IDatabaseAccountJson, b
|
|||||||
Nonce: account.Nonce,
|
Nonce: account.Nonce,
|
||||||
Groups: [],
|
Groups: [],
|
||||||
IRC: config.myIrcAddresses ?? [myAddress],
|
IRC: config.myIrcAddresses ?? [myAddress],
|
||||||
platformCDNs: [`https://${myAddress}/`],
|
|
||||||
HUB: `https://${myAddress}/api/`,
|
HUB: `https://${myAddress}/api/`,
|
||||||
NRS: config.NRS,
|
NRS: config.NRS,
|
||||||
DTLS: 99,
|
DTLS: 99,
|
||||||
BuildLabel: buildLabel,
|
BuildLabel: buildLabel,
|
||||||
MatchmakingBuildId: buildConfig.matchmakingBuildId
|
MatchmakingBuildId: buildConfig.matchmakingBuildId
|
||||||
};
|
};
|
||||||
|
if (version_compare(buildLabel, "2023.04.25.23.40") >= 0) {
|
||||||
|
resp.platformCDNs = [`https://${myAddress}/`];
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
};
|
};
|
||||||
|
@ -3,9 +3,10 @@ import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";
|
import { IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";
|
||||||
import { addMissionInventoryUpdates, addMissionRewards } from "@/src/services/missionInventoryUpdateService";
|
import { addMissionInventoryUpdates, addMissionRewards } from "@/src/services/missionInventoryUpdateService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { generateRewardSeed, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getInventoryResponse } from "./inventoryController";
|
import { getInventoryResponse } from "./inventoryController";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
|
import { IMissionInventoryUpdateResponse } from "@/src/types/missionTypes";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
**** INPUT ****
|
**** INPUT ****
|
||||||
@ -62,6 +63,7 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
|||||||
missionReport.MissionStatus !== "GS_SUCCESS" &&
|
missionReport.MissionStatus !== "GS_SUCCESS" &&
|
||||||
!(missionReport.RewardInfo?.jobId || missionReport.RewardInfo?.challengeMissionId)
|
!(missionReport.RewardInfo?.jobId || missionReport.RewardInfo?.challengeMissionId)
|
||||||
) {
|
) {
|
||||||
|
inventory.RewardSeed = generateRewardSeed();
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
const inventoryResponse = await getInventoryResponse(inventory, true);
|
const inventoryResponse = await getInventoryResponse(inventory, true);
|
||||||
res.json({
|
res.json({
|
||||||
@ -71,9 +73,16 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { MissionRewards, inventoryChanges, credits, AffiliationMods, SyndicateXPItemReward } =
|
const {
|
||||||
await addMissionRewards(inventory, missionReport, firstCompletion);
|
MissionRewards,
|
||||||
|
inventoryChanges,
|
||||||
|
credits,
|
||||||
|
AffiliationMods,
|
||||||
|
SyndicateXPItemReward,
|
||||||
|
ConquestCompletedMissionsCount
|
||||||
|
} = await addMissionRewards(inventory, missionReport, firstCompletion);
|
||||||
|
|
||||||
|
inventory.RewardSeed = generateRewardSeed();
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
const inventoryResponse = await getInventoryResponse(inventory, true);
|
const inventoryResponse = await getInventoryResponse(inventory, true);
|
||||||
|
|
||||||
@ -86,8 +95,9 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
|||||||
...inventoryUpdates,
|
...inventoryUpdates,
|
||||||
//FusionPoints: inventoryChanges?.FusionPoints, // This in combination with InventoryJson or InventoryChanges seems to just double the number of endo shown, so unsure when this is needed.
|
//FusionPoints: inventoryChanges?.FusionPoints, // This in combination with InventoryJson or InventoryChanges seems to just double the number of endo shown, so unsure when this is needed.
|
||||||
SyndicateXPItemReward,
|
SyndicateXPItemReward,
|
||||||
AffiliationMods
|
AffiliationMods,
|
||||||
});
|
ConquestCompletedMissionsCount
|
||||||
|
} satisfies IMissionInventoryUpdateResponse);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -17,7 +17,7 @@ import { getDefaultUpgrades } from "@/src/services/itemDataService";
|
|||||||
import { modularWeaponTypes } from "@/src/helpers/modularWeaponHelper";
|
import { modularWeaponTypes } from "@/src/helpers/modularWeaponHelper";
|
||||||
import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { getRandomInt } from "@/src/services/rngService";
|
import { getRandomInt } from "@/src/services/rngService";
|
||||||
import { ExportSentinels, IDefaultUpgrade } from "warframe-public-export-plus";
|
import { ExportSentinels, ExportWeapons, IDefaultUpgrade } from "warframe-public-export-plus";
|
||||||
import { Status } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { Status } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
|
||||||
interface IModularCraftRequest {
|
interface IModularCraftRequest {
|
||||||
@ -36,7 +36,9 @@ export const modularWeaponCraftingController: RequestHandler = async (req, res)
|
|||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
|
|
||||||
let defaultUpgrades: IDefaultUpgrade[] | undefined;
|
let defaultUpgrades: IDefaultUpgrade[] | undefined;
|
||||||
const defaultOverwrites: Partial<IEquipmentDatabase> = {};
|
const defaultOverwrites: Partial<IEquipmentDatabase> = {
|
||||||
|
ModularParts: data.Parts
|
||||||
|
};
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
if (category == "KubrowPets") {
|
if (category == "KubrowPets") {
|
||||||
const traits = {
|
const traits = {
|
||||||
@ -138,8 +140,20 @@ export const modularWeaponCraftingController: RequestHandler = async (req, res)
|
|||||||
} else {
|
} else {
|
||||||
defaultUpgrades = getDefaultUpgrades(data.Parts);
|
defaultUpgrades = getDefaultUpgrades(data.Parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (category == "MoaPets") {
|
||||||
|
const weapon = ExportSentinels[data.WeaponType].defaultWeapon;
|
||||||
|
if (weapon) {
|
||||||
|
const category = ExportWeapons[weapon].productCategory;
|
||||||
|
addEquipment(inventory, category, weapon, undefined, inventoryChanges);
|
||||||
|
combineInventoryChanges(
|
||||||
|
inventoryChanges,
|
||||||
|
occupySlot(inventory, productCategoryToInventoryBin(category)!, !!data.isWebUi)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
defaultOverwrites.Configs = applyDefaultUpgrades(inventory, defaultUpgrades);
|
defaultOverwrites.Configs = applyDefaultUpgrades(inventory, defaultUpgrades);
|
||||||
addEquipment(inventory, category, data.WeaponType, data.Parts, inventoryChanges, defaultOverwrites);
|
addEquipment(inventory, category, data.WeaponType, defaultOverwrites, inventoryChanges);
|
||||||
combineInventoryChanges(
|
combineInventoryChanges(
|
||||||
inventoryChanges,
|
inventoryChanges,
|
||||||
occupySlot(inventory, productCategoryToInventoryBin(category)!, !!data.isWebUi)
|
occupySlot(inventory, productCategoryToInventoryBin(category)!, !!data.isWebUi)
|
||||||
|
@ -21,7 +21,11 @@ import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|||||||
export const modularWeaponSaleController: RequestHandler = async (req, res) => {
|
export const modularWeaponSaleController: RequestHandler = async (req, res) => {
|
||||||
const partTypeToParts: Record<string, string[]> = {};
|
const partTypeToParts: Record<string, string[]> = {};
|
||||||
for (const [uniqueName, data] of Object.entries(ExportWeapons)) {
|
for (const [uniqueName, data] of Object.entries(ExportWeapons)) {
|
||||||
if (data.partType && data.premiumPrice) {
|
if (
|
||||||
|
data.partType &&
|
||||||
|
data.premiumPrice &&
|
||||||
|
!data.excludeFromCodex // exclude pvp variants
|
||||||
|
) {
|
||||||
partTypeToParts[data.partType] ??= [];
|
partTypeToParts[data.partType] ??= [];
|
||||||
partTypeToParts[data.partType].push(uniqueName);
|
partTypeToParts[data.partType].push(uniqueName);
|
||||||
}
|
}
|
||||||
@ -41,24 +45,18 @@ export const modularWeaponSaleController: RequestHandler = async (req, res) => {
|
|||||||
const defaultUpgrades = getDefaultUpgrades(weaponInfo.ModularParts);
|
const defaultUpgrades = getDefaultUpgrades(weaponInfo.ModularParts);
|
||||||
const configs = applyDefaultUpgrades(inventory, defaultUpgrades);
|
const configs = applyDefaultUpgrades(inventory, defaultUpgrades);
|
||||||
const inventoryChanges: IInventoryChanges = {
|
const inventoryChanges: IInventoryChanges = {
|
||||||
...addEquipment(
|
...addEquipment(inventory, category, weaponInfo.ItemType, {
|
||||||
inventory,
|
Features: EquipmentFeatures.DOUBLE_CAPACITY | EquipmentFeatures.GILDED,
|
||||||
category,
|
ItemName: payload.ItemName,
|
||||||
weaponInfo.ItemType,
|
Configs: configs,
|
||||||
weaponInfo.ModularParts,
|
ModularParts: weaponInfo.ModularParts,
|
||||||
{},
|
Polarity: [
|
||||||
{
|
{
|
||||||
Features: EquipmentFeatures.DOUBLE_CAPACITY | EquipmentFeatures.GILDED,
|
Slot: payload.PolarizeSlot,
|
||||||
ItemName: payload.ItemName,
|
Value: payload.PolarizeValue
|
||||||
Configs: configs,
|
}
|
||||||
Polarity: [
|
]
|
||||||
{
|
}),
|
||||||
Slot: payload.PolarizeSlot,
|
|
||||||
Value: payload.PolarizeValue
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
),
|
|
||||||
...occupySlot(inventory, productCategoryToInventoryBin(category)!, true),
|
...occupySlot(inventory, productCategoryToInventoryBin(category)!, true),
|
||||||
...updateCurrency(inventory, weaponInfo.PremiumPrice, true)
|
...updateCurrency(inventory, weaponInfo.PremiumPrice, true)
|
||||||
};
|
};
|
||||||
@ -143,7 +141,7 @@ const getModularWeaponSale = (
|
|||||||
getItemType: (parts: string[]) => string
|
getItemType: (parts: string[]) => string
|
||||||
): IModularWeaponSaleInfo => {
|
): IModularWeaponSaleInfo => {
|
||||||
const rng = new CRng(day);
|
const rng = new CRng(day);
|
||||||
const parts = partTypes.map(partType => rng.randomElement(partTypeToParts[partType]));
|
const parts = partTypes.map(partType => rng.randomElement(partTypeToParts[partType])!);
|
||||||
let partsCost = 0;
|
let partsCost = 0;
|
||||||
for (const part of parts) {
|
for (const part of parts) {
|
||||||
partsCost += ExportWeapons[part].premiumPrice!;
|
partsCost += ExportWeapons[part].premiumPrice!;
|
||||||
|
@ -2,8 +2,12 @@ import {
|
|||||||
consumeModCharge,
|
consumeModCharge,
|
||||||
encodeNemesisGuess,
|
encodeNemesisGuess,
|
||||||
getInfNodes,
|
getInfNodes,
|
||||||
|
getKnifeUpgrade,
|
||||||
getNemesisPasscode,
|
getNemesisPasscode,
|
||||||
IKnifeResponse
|
getNemesisPasscodeModTypes,
|
||||||
|
getWeaponsForManifest,
|
||||||
|
IKnifeResponse,
|
||||||
|
showdownNodes
|
||||||
} from "@/src/helpers/nemesisHelpers";
|
} from "@/src/helpers/nemesisHelpers";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
||||||
@ -14,6 +18,8 @@ import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
|||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import {
|
import {
|
||||||
IInnateDamageFingerprint,
|
IInnateDamageFingerprint,
|
||||||
|
IInventoryClient,
|
||||||
|
INemesisClient,
|
||||||
InventorySlot,
|
InventorySlot,
|
||||||
IUpgradeClient,
|
IUpgradeClient,
|
||||||
IWeaponSkinClient,
|
IWeaponSkinClient,
|
||||||
@ -99,50 +105,45 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
encodeNemesisGuess(guess[0], result1, guess[1], result2, guess[2], result3)
|
encodeNemesisGuess(guess[0], result1, guess[1], result2, guess[2], result3)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Increase antivirus
|
// Increase antivirus if correct antivirus mod is installed
|
||||||
let antivirusGain = 5;
|
|
||||||
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
|
|
||||||
const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
|
|
||||||
const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0;
|
|
||||||
const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!;
|
|
||||||
const response: IKnifeResponse = {};
|
const response: IKnifeResponse = {};
|
||||||
for (const upgrade of body.knife!.AttachedUpgrades) {
|
if (result1 == 0 || result2 == 0 || result3 == 0) {
|
||||||
switch (upgrade.ItemType) {
|
let antivirusGain = 5;
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod":
|
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
|
||||||
antivirusGain += 10;
|
const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0;
|
||||||
break;
|
const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!;
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod":
|
for (const upgrade of body.knife!.AttachedUpgrades) {
|
||||||
antivirusGain += 10;
|
switch (upgrade.ItemType) {
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod":
|
||||||
break;
|
antivirusGain += 10;
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod": // Instant Secure
|
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||||
antivirusGain += 15;
|
break;
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod":
|
||||||
break;
|
antivirusGain += 10;
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod": // Immuno Shield
|
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||||
antivirusGain += 15;
|
break;
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod": // Instant Secure
|
||||||
break;
|
antivirusGain += 15;
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod":
|
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||||
antivirusGain += 10;
|
break;
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod": // Immuno Shield
|
||||||
break;
|
antivirusGain += 15;
|
||||||
|
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||||
|
break;
|
||||||
|
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod":
|
||||||
|
antivirusGain += 10;
|
||||||
|
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
inventory.Nemesis!.HenchmenKilled += antivirusGain;
|
||||||
}
|
}
|
||||||
inventory.Nemesis!.HenchmenKilled += antivirusGain;
|
|
||||||
if (inventory.Nemesis!.HenchmenKilled >= 100) {
|
if (inventory.Nemesis!.HenchmenKilled >= 100) {
|
||||||
inventory.Nemesis!.HenchmenKilled = 100;
|
inventory.Nemesis!.HenchmenKilled = 100;
|
||||||
inventory.Nemesis!.InfNodes = [
|
|
||||||
{
|
|
||||||
Node: "CrewBattleNode559",
|
|
||||||
Influence: 1
|
|
||||||
}
|
|
||||||
];
|
|
||||||
inventory.Nemesis!.Weakened = true;
|
|
||||||
} else {
|
|
||||||
inventory.Nemesis!.InfNodes = getInfNodes("FC_INFESTATION", 0);
|
|
||||||
}
|
}
|
||||||
|
inventory.Nemesis!.InfNodes = getInfNodes("FC_INFESTATION", 0);
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json(response);
|
res.json(response);
|
||||||
@ -170,18 +171,7 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
let weaponIdx = -1;
|
let weaponIdx = -1;
|
||||||
if (body.target.Faction != "FC_INFESTATION") {
|
if (body.target.Faction != "FC_INFESTATION") {
|
||||||
let weapons: readonly string[];
|
const weapons = getWeaponsForManifest(body.target.manifest);
|
||||||
if (body.target.manifest == "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionSix") {
|
|
||||||
weapons = kuvaLichVersionSixWeapons;
|
|
||||||
} else if (
|
|
||||||
body.target.manifest == "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour" ||
|
|
||||||
body.target.manifest == "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree"
|
|
||||||
) {
|
|
||||||
weapons = corpusVersionThreeWeapons;
|
|
||||||
} else {
|
|
||||||
throw new Error(`unknown nemesis manifest: ${body.target.manifest}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
@ -223,6 +213,38 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
res.json({
|
res.json({
|
||||||
target: inventory.toJSON().Nemesis
|
target: inventory.toJSON().Nemesis
|
||||||
});
|
});
|
||||||
|
} else if ((req.query.mode as string) == "w") {
|
||||||
|
const inventory = await getInventory(
|
||||||
|
accountId,
|
||||||
|
"Nemesis LoadOutPresets CurrentLoadOutIds DataKnives Upgrades RawUpgrades"
|
||||||
|
);
|
||||||
|
//const body = getJSONfromString<INemesisWeakenRequest>(String(req.body));
|
||||||
|
|
||||||
|
inventory.Nemesis!.InfNodes = [
|
||||||
|
{
|
||||||
|
Node: showdownNodes[inventory.Nemesis!.Faction],
|
||||||
|
Influence: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
inventory.Nemesis!.Weakened = true;
|
||||||
|
|
||||||
|
const response: IKnifeResponse & { target: INemesisClient } = {
|
||||||
|
target: inventory.toJSON<IInventoryClient>().Nemesis!
|
||||||
|
};
|
||||||
|
|
||||||
|
// Consume charge of the correct requiem mod(s)
|
||||||
|
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
|
||||||
|
const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
|
||||||
|
const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0;
|
||||||
|
const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!;
|
||||||
|
const modTypes = getNemesisPasscodeModTypes(inventory.Nemesis!);
|
||||||
|
for (const modType of modTypes) {
|
||||||
|
const upgrade = getKnifeUpgrade(inventory, dataknifeUpgrades, modType);
|
||||||
|
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||||
|
}
|
||||||
|
|
||||||
|
await inventory.save();
|
||||||
|
res.json(response);
|
||||||
} else {
|
} else {
|
||||||
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
||||||
throw new Error(`unknown nemesis mode: ${String(req.query.mode)}`);
|
throw new Error(`unknown nemesis mode: ${String(req.query.mode)}`);
|
||||||
@ -274,48 +296,19 @@ interface INemesisRequiemRequest {
|
|||||||
guess: number; // grn/crp: 4 bits | coda: 3x 4 bits
|
guess: number; // grn/crp: 4 bits | coda: 3x 4 bits
|
||||||
position: number; // grn/crp: 0-2 | coda: 0
|
position: number; // grn/crp: 0-2 | coda: 0
|
||||||
// knife field provided for coda only
|
// knife field provided for coda only
|
||||||
knife?: {
|
knife?: IKnife;
|
||||||
Item: IEquipmentClient;
|
|
||||||
Skins: IWeaponSkinClient[];
|
|
||||||
ModSlot: number;
|
|
||||||
CustSlot: number;
|
|
||||||
AttachedUpgrades: IUpgradeClient[];
|
|
||||||
HiddenWhenHolstered: boolean;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const kuvaLichVersionSixWeapons = [
|
// interface INemesisWeakenRequest {
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Drakgoon/KuvaDrakgoon",
|
// target: INemesisClient;
|
||||||
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Karak/KuvaKarak",
|
// knife: IKnife;
|
||||||
"/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 = [
|
interface IKnife {
|
||||||
"/Lotus/Weapons/Corpus/LongGuns/CrpBriefcaseLauncher/CrpBriefcaseLauncher",
|
Item: IEquipmentClient;
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEArcaPlasmor/CrpBEArcaPlasmor",
|
Skins: IWeaponSkinClient[];
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEFluxRifle/CrpBEFluxRifle",
|
ModSlot: number;
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBETetra/CrpBETetra",
|
CustSlot: number;
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBECycron/CrpBECycron",
|
AttachedUpgrades: IUpgradeClient[];
|
||||||
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEDetron/CrpBEDetron",
|
HiddenWhenHolstered: boolean;
|
||||||
"/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"
|
|
||||||
];
|
|
||||||
|
@ -37,6 +37,7 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) =
|
|||||||
const deco = component.Decos.find(x => x._id.equals(request.MoveId))!;
|
const deco = component.Decos.find(x => x._id.equals(request.MoveId))!;
|
||||||
deco.Pos = request.Pos;
|
deco.Pos = request.Pos;
|
||||||
deco.Rot = request.Rot;
|
deco.Rot = request.Rot;
|
||||||
|
deco.Scale = request.Scale;
|
||||||
} else {
|
} else {
|
||||||
const deco =
|
const deco =
|
||||||
component.Decos[
|
component.Decos[
|
||||||
@ -45,6 +46,7 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) =
|
|||||||
Type: request.Type,
|
Type: request.Type,
|
||||||
Pos: request.Pos,
|
Pos: request.Pos,
|
||||||
Rot: request.Rot,
|
Rot: request.Rot,
|
||||||
|
Scale: request.Scale,
|
||||||
Name: request.Name,
|
Name: request.Name,
|
||||||
Sockets: request.Sockets
|
Sockets: request.Sockets
|
||||||
}) - 1
|
}) - 1
|
||||||
@ -113,9 +115,9 @@ interface IPlaceDecoInComponentRequest {
|
|||||||
Type: string;
|
Type: string;
|
||||||
Pos: number[];
|
Pos: number[];
|
||||||
Rot: number[];
|
Rot: number[];
|
||||||
|
Scale?: number;
|
||||||
Name?: string;
|
Name?: string;
|
||||||
Sockets?: number;
|
Sockets?: number;
|
||||||
Scale?: number; // only provided alongside MoveId and seems to always be 1
|
|
||||||
MoveId?: string;
|
MoveId?: string;
|
||||||
ShipDeco?: boolean;
|
ShipDeco?: boolean;
|
||||||
VaultDeco?: boolean;
|
VaultDeco?: boolean;
|
||||||
|
@ -4,7 +4,6 @@ import { addEmailItem, getInventory, updateCurrency } from "@/src/services/inven
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { ICompletedDialogue, IDialogueDatabase } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { ICompletedDialogue, IDialogueDatabase } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const saveDialogueController: RequestHandler = async (req, res) => {
|
export const saveDialogueController: RequestHandler = async (req, res) => {
|
||||||
@ -27,33 +26,33 @@ export const saveDialogueController: RequestHandler = async (req, res) => {
|
|||||||
const dialogue = getDialogue(inventory, request.DialogueName);
|
const dialogue = getDialogue(inventory, request.DialogueName);
|
||||||
dialogue.Rank = request.Rank;
|
dialogue.Rank = request.Rank;
|
||||||
dialogue.Chemistry = request.Chemistry;
|
dialogue.Chemistry = request.Chemistry;
|
||||||
|
dialogue.QueuedDialogues = request.QueuedDialogues;
|
||||||
|
for (const bool of request.Booleans) {
|
||||||
|
dialogue.Booleans.push(bool);
|
||||||
|
if (bool == "LizzieShawzin") {
|
||||||
|
await addEmailItem(
|
||||||
|
inventory,
|
||||||
|
"/Lotus/Types/Items/EmailItems/LizzieShawzinSkinEmailItem",
|
||||||
|
inventoryChanges
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const bool of request.ResetBooleans) {
|
||||||
|
const index = dialogue.Booleans.findIndex(x => x == bool);
|
||||||
|
if (index != -1) {
|
||||||
|
dialogue.Booleans.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const info of request.OtherDialogueInfos) {
|
||||||
|
const otherDialogue = getDialogue(inventory, info.Dialogue);
|
||||||
|
if (info.Tag != "") {
|
||||||
|
otherDialogue.QueuedDialogues.push(info.Tag);
|
||||||
|
}
|
||||||
|
otherDialogue.Chemistry += info.Value; // unsure
|
||||||
|
}
|
||||||
if (request.Data) {
|
if (request.Data) {
|
||||||
dialogue.QueuedDialogues = request.QueuedDialogues;
|
|
||||||
for (const bool of request.Booleans) {
|
|
||||||
dialogue.Booleans.push(bool);
|
|
||||||
if (bool == "LizzieShawzin") {
|
|
||||||
await addEmailItem(
|
|
||||||
inventory,
|
|
||||||
"/Lotus/Types/Items/EmailItems/LizzieShawzinSkinEmailItem",
|
|
||||||
inventoryChanges
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const bool of request.ResetBooleans) {
|
|
||||||
const index = dialogue.Booleans.findIndex(x => x == bool);
|
|
||||||
if (index != -1) {
|
|
||||||
dialogue.Booleans.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dialogue.Completed.push(request.Data);
|
dialogue.Completed.push(request.Data);
|
||||||
dialogue.AvailableDate = new Date(tomorrowAt0Utc);
|
dialogue.AvailableDate = new Date(tomorrowAt0Utc);
|
||||||
for (const info of request.OtherDialogueInfos) {
|
|
||||||
const otherDialogue = getDialogue(inventory, info.Dialogue);
|
|
||||||
if (info.Tag != "") {
|
|
||||||
otherDialogue.QueuedDialogues.push(info.Tag);
|
|
||||||
}
|
|
||||||
otherDialogue.Chemistry += info.Value; // unsure
|
|
||||||
}
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
InventoryChanges: inventoryChanges,
|
InventoryChanges: inventoryChanges,
|
||||||
@ -74,7 +73,7 @@ export const saveDialogueController: RequestHandler = async (req, res) => {
|
|||||||
AvailableGiftDate: { $date: { $numberLong: tomorrowAt0Utc.toString() } }
|
AvailableGiftDate: { $date: { $numberLong: tomorrowAt0Utc.toString() } }
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
logger.error(`saveDialogue request not fully handled: ${String(req.body)}`);
|
res.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,8 @@ import {
|
|||||||
addConsumables,
|
addConsumables,
|
||||||
freeUpSlot,
|
freeUpSlot,
|
||||||
combineInventoryChanges,
|
combineInventoryChanges,
|
||||||
addCrewShipRawSalvage
|
addCrewShipRawSalvage,
|
||||||
|
addFusionPoints
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
||||||
@ -44,7 +45,7 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
if (payload.Items.SpaceGuns || payload.Items.SpaceMelee) {
|
if (payload.Items.SpaceGuns || payload.Items.SpaceMelee) {
|
||||||
requiredFields.add(InventorySlot.SPACEWEAPONS);
|
requiredFields.add(InventorySlot.SPACEWEAPONS);
|
||||||
}
|
}
|
||||||
if (payload.Items.Sentinels || payload.Items.SentinelWeapons) {
|
if (payload.Items.Sentinels || payload.Items.SentinelWeapons || payload.Items.MoaPets) {
|
||||||
requiredFields.add(InventorySlot.SENTINELS);
|
requiredFields.add(InventorySlot.SENTINELS);
|
||||||
}
|
}
|
||||||
if (payload.Items.OperatorAmps) {
|
if (payload.Items.OperatorAmps) {
|
||||||
@ -69,7 +70,7 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
if (payload.SellCurrency == "SC_RegularCredits") {
|
if (payload.SellCurrency == "SC_RegularCredits") {
|
||||||
inventory.RegularCredits += payload.SellPrice;
|
inventory.RegularCredits += payload.SellPrice;
|
||||||
} else if (payload.SellCurrency == "SC_FusionPoints") {
|
} else if (payload.SellCurrency == "SC_FusionPoints") {
|
||||||
inventory.FusionPoints += payload.SellPrice;
|
addFusionPoints(inventory, payload.SellPrice);
|
||||||
} else if (payload.SellCurrency == "SC_PrimeBucks") {
|
} else if (payload.SellCurrency == "SC_PrimeBucks") {
|
||||||
addMiscItems(inventory, [
|
addMiscItems(inventory, [
|
||||||
{
|
{
|
||||||
@ -147,6 +148,12 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
freeUpSlot(inventory, InventorySlot.SENTINELS);
|
freeUpSlot(inventory, InventorySlot.SENTINELS);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (payload.Items.MoaPets) {
|
||||||
|
payload.Items.MoaPets.forEach(sellItem => {
|
||||||
|
inventory.MoaPets.pull({ _id: sellItem.String });
|
||||||
|
freeUpSlot(inventory, InventorySlot.SENTINELS);
|
||||||
|
});
|
||||||
|
}
|
||||||
if (payload.Items.OperatorAmps) {
|
if (payload.Items.OperatorAmps) {
|
||||||
payload.Items.OperatorAmps.forEach(sellItem => {
|
payload.Items.OperatorAmps.forEach(sellItem => {
|
||||||
inventory.OperatorAmps.pull({ _id: sellItem.String });
|
inventory.OperatorAmps.pull({ _id: sellItem.String });
|
||||||
@ -280,6 +287,7 @@ interface ISellRequest {
|
|||||||
SpaceMelee?: ISellItem[];
|
SpaceMelee?: ISellItem[];
|
||||||
Sentinels?: ISellItem[];
|
Sentinels?: ISellItem[];
|
||||||
SentinelWeapons?: ISellItem[];
|
SentinelWeapons?: ISellItem[];
|
||||||
|
MoaPets?: ISellItem[];
|
||||||
OperatorAmps?: ISellItem[];
|
OperatorAmps?: ISellItem[];
|
||||||
Hoverboards?: ISellItem[];
|
Hoverboards?: ISellItem[];
|
||||||
Drones?: ISellItem[];
|
Drones?: ISellItem[];
|
||||||
|
@ -20,7 +20,7 @@ export const setShipFavouriteLoadoutController: RequestHandler = async (req, res
|
|||||||
throw new Error(`unexpected BootLocation: ${body.BootLocation}`);
|
throw new Error(`unexpected BootLocation: ${body.BootLocation}`);
|
||||||
}
|
}
|
||||||
await personalRooms.save();
|
await personalRooms.save();
|
||||||
res.json({});
|
res.json(body);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ISetShipFavouriteLoadoutRequest {
|
interface ISetShipFavouriteLoadoutRequest {
|
||||||
|
@ -6,6 +6,9 @@ import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
|||||||
import { addMiscItems, combineInventoryChanges, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
import { addMiscItems, combineInventoryChanges, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { isStoreItem, toStoreItem } from "@/src/services/itemDataService";
|
import { isStoreItem, toStoreItem } from "@/src/services/itemDataService";
|
||||||
|
import { logger } from "@/src/utils/logger";
|
||||||
|
|
||||||
|
const nightwaveCredsItemType = ExportNightwave.rewards[ExportNightwave.rewards.length - 1].uniqueName;
|
||||||
|
|
||||||
export const syndicateSacrificeController: RequestHandler = async (request, response) => {
|
export const syndicateSacrificeController: RequestHandler = async (request, response) => {
|
||||||
const accountId = await getAccountIdForRequest(request);
|
const accountId = await getAccountIdForRequest(request);
|
||||||
@ -74,10 +77,14 @@ export const syndicateSacrificeController: RequestHandler = async (request, resp
|
|||||||
if (!isStoreItem(rewardType)) {
|
if (!isStoreItem(rewardType)) {
|
||||||
rewardType = toStoreItem(rewardType);
|
rewardType = toStoreItem(rewardType);
|
||||||
}
|
}
|
||||||
combineInventoryChanges(
|
const rewardInventoryChanges = (await handleStoreItemAcquisition(rewardType, inventory, reward.itemCount))
|
||||||
res.InventoryChanges,
|
.InventoryChanges;
|
||||||
(await handleStoreItemAcquisition(rewardType, inventory, reward.itemCount)).InventoryChanges
|
if (Object.keys(rewardInventoryChanges).length == 0) {
|
||||||
);
|
logger.debug(`nightwave rank up reward did not seem to get added, giving 50 creds instead`);
|
||||||
|
rewardInventoryChanges.MiscItems = [{ ItemType: nightwaveCredsItemType, ItemCount: 50 }];
|
||||||
|
addMiscItems(inventory, rewardInventoryChanges.MiscItems);
|
||||||
|
}
|
||||||
|
combineInventoryChanges(res.InventoryChanges, rewardInventoryChanges);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { addFusionPoints, getInventory } from "@/src/services/inventoryService";
|
||||||
|
|
||||||
export const addCurrencyController: RequestHandler = async (req, res) => {
|
export const addCurrencyController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const request = req.body as IAddCurrencyRequest;
|
const request = req.body as IAddCurrencyRequest;
|
||||||
inventory[request.currency] += request.delta;
|
const inventory = await getInventory(accountId, request.currency);
|
||||||
|
if (request.currency == "FusionPoints") {
|
||||||
|
addFusionPoints(inventory, request.delta);
|
||||||
|
} else {
|
||||||
|
inventory[request.currency] += request.delta;
|
||||||
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.end();
|
res.end();
|
||||||
};
|
};
|
||||||
|
44
src/controllers/custom/addMissingMaxRankModsController.ts
Normal file
44
src/controllers/custom/addMissingMaxRankModsController.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { ExportArcanes, ExportUpgrades } from "warframe-public-export-plus";
|
||||||
|
|
||||||
|
export const addMissingMaxRankModsController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId, "Upgrades");
|
||||||
|
|
||||||
|
const maxOwnedRanks: Record<string, number> = {};
|
||||||
|
for (const upgrade of inventory.Upgrades) {
|
||||||
|
const fingerprint = JSON.parse(upgrade.UpgradeFingerprint ?? "{}") as { lvl?: number };
|
||||||
|
if (fingerprint.lvl) {
|
||||||
|
maxOwnedRanks[upgrade.ItemType] ??= 0;
|
||||||
|
if (fingerprint.lvl > maxOwnedRanks[upgrade.ItemType]) {
|
||||||
|
maxOwnedRanks[upgrade.ItemType] = fingerprint.lvl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [uniqueName, data] of Object.entries(ExportUpgrades)) {
|
||||||
|
if (data.fusionLimit != 0 && data.type != "PARAZON" && maxOwnedRanks[uniqueName] != data.fusionLimit) {
|
||||||
|
inventory.Upgrades.push({
|
||||||
|
ItemType: uniqueName,
|
||||||
|
UpgradeFingerprint: JSON.stringify({ lvl: data.fusionLimit })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [uniqueName, data] of Object.entries(ExportArcanes)) {
|
||||||
|
if (
|
||||||
|
data.name != "/Lotus/Language/Items/GenericCosmeticEnhancerName" &&
|
||||||
|
maxOwnedRanks[uniqueName] != data.fusionLimit
|
||||||
|
) {
|
||||||
|
inventory.Upgrades.push({
|
||||||
|
ItemType: uniqueName,
|
||||||
|
UpgradeFingerprint: JSON.stringify({ lvl: data.fusionLimit })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await inventory.save();
|
||||||
|
res.end();
|
||||||
|
};
|
@ -1,4 +1,4 @@
|
|||||||
import { addGearExpByCategory, getInventory } from "@/src/services/inventoryService";
|
import { applyClientEquipmentUpdates, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
@ -20,7 +20,7 @@ export const addXpController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addGearExpByCategory(inventory, gear, category as TEquipmentKey);
|
applyClientEquipmentUpdates(inventory, gear, category as TEquipmentKey);
|
||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.end();
|
res.end();
|
||||||
|
@ -20,6 +20,7 @@ import {
|
|||||||
TRelicQuality
|
TRelicQuality
|
||||||
} from "warframe-public-export-plus";
|
} from "warframe-public-export-plus";
|
||||||
import archonCrystalUpgrades from "@/static/fixed_responses/webuiArchonCrystalUpgrades.json";
|
import archonCrystalUpgrades from "@/static/fixed_responses/webuiArchonCrystalUpgrades.json";
|
||||||
|
import allIncarnons from "@/static/fixed_responses/allIncarnonList.json";
|
||||||
|
|
||||||
interface ListedItem {
|
interface ListedItem {
|
||||||
uniqueName: string;
|
uniqueName: string;
|
||||||
@ -32,6 +33,29 @@ interface ListedItem {
|
|||||||
parazon?: boolean;
|
parazon?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ItemLists {
|
||||||
|
archonCrystalUpgrades: Record<string, string>;
|
||||||
|
uniqueLevelCaps: Record<string, number>;
|
||||||
|
Suits: ListedItem[];
|
||||||
|
LongGuns: ListedItem[];
|
||||||
|
Melee: ListedItem[];
|
||||||
|
ModularParts: ListedItem[];
|
||||||
|
Pistols: ListedItem[];
|
||||||
|
Sentinels: ListedItem[];
|
||||||
|
SentinelWeapons: ListedItem[];
|
||||||
|
SpaceGuns: ListedItem[];
|
||||||
|
SpaceMelee: ListedItem[];
|
||||||
|
SpaceSuits: ListedItem[];
|
||||||
|
MechSuits: ListedItem[];
|
||||||
|
miscitems: ListedItem[];
|
||||||
|
Syndicates: ListedItem[];
|
||||||
|
OperatorAmps: ListedItem[];
|
||||||
|
QuestKeys: ListedItem[];
|
||||||
|
KubrowPets: ListedItem[];
|
||||||
|
EvolutionProgress: ListedItem[];
|
||||||
|
mods: ListedItem[];
|
||||||
|
}
|
||||||
|
|
||||||
const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
||||||
VPQ_BRONZE: "",
|
VPQ_BRONZE: "",
|
||||||
VPQ_SILVER: " [Flawless]",
|
VPQ_SILVER: " [Flawless]",
|
||||||
@ -41,23 +65,28 @@ const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
|||||||
|
|
||||||
const getItemListsController: RequestHandler = (req, response) => {
|
const getItemListsController: RequestHandler = (req, response) => {
|
||||||
const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en");
|
const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en");
|
||||||
const res: Record<string, ListedItem[]> = {};
|
const res: ItemLists = {
|
||||||
res.Suits = [];
|
archonCrystalUpgrades,
|
||||||
res.LongGuns = [];
|
uniqueLevelCaps: ExportMisc.uniqueLevelCaps,
|
||||||
res.Melee = [];
|
Suits: [],
|
||||||
res.ModularParts = [];
|
LongGuns: [],
|
||||||
res.Pistols = [];
|
Melee: [],
|
||||||
res.Sentinels = [];
|
ModularParts: [],
|
||||||
res.SentinelWeapons = [];
|
Pistols: [],
|
||||||
res.SpaceGuns = [];
|
Sentinels: [],
|
||||||
res.SpaceMelee = [];
|
SentinelWeapons: [],
|
||||||
res.SpaceSuits = [];
|
SpaceGuns: [],
|
||||||
res.MechSuits = [];
|
SpaceMelee: [],
|
||||||
res.miscitems = [];
|
SpaceSuits: [],
|
||||||
res.Syndicates = [];
|
MechSuits: [],
|
||||||
res.OperatorAmps = [];
|
miscitems: [],
|
||||||
res.QuestKeys = [];
|
Syndicates: [],
|
||||||
res.KubrowPets = [];
|
OperatorAmps: [],
|
||||||
|
QuestKeys: [],
|
||||||
|
KubrowPets: [],
|
||||||
|
EvolutionProgress: [],
|
||||||
|
mods: []
|
||||||
|
};
|
||||||
for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
|
for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
|
||||||
res[item.productCategory].push({
|
res[item.productCategory].push({
|
||||||
uniqueName,
|
uniqueName,
|
||||||
@ -66,7 +95,7 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (const [uniqueName, item] of Object.entries(ExportSentinels)) {
|
for (const [uniqueName, item] of Object.entries(ExportSentinels)) {
|
||||||
if (item.productCategory != "SpecialItems") {
|
if (item.productCategory == "Sentinels" || item.productCategory == "KubrowPets") {
|
||||||
res[item.productCategory].push({
|
res[item.productCategory].push({
|
||||||
uniqueName,
|
uniqueName,
|
||||||
name: getString(item.name, lang),
|
name: getString(item.name, lang),
|
||||||
@ -115,12 +144,28 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
let name = getString(item.name, lang);
|
let name = getString(item.name, lang);
|
||||||
if ("dissectionParts" in item) {
|
if ("dissectionParts" in item) {
|
||||||
name = getString("/Lotus/Language/Fish/FishDisplayName", lang).split("|FISH_NAME|").join(name);
|
name = getString("/Lotus/Language/Fish/FishDisplayName", lang).split("|FISH_NAME|").join(name);
|
||||||
if (uniqueName.indexOf("Large") != -1) {
|
if (item.syndicateTag == "CetusSyndicate") {
|
||||||
name = name.split("|FISH_SIZE|").join(getString("/Lotus/Language/Fish/FishSizeLargeAbbrev", lang));
|
if (uniqueName.indexOf("Large") != -1) {
|
||||||
} else if (uniqueName.indexOf("Medium") != -1) {
|
name = name.split("|FISH_SIZE|").join(getString("/Lotus/Language/Fish/FishSizeLargeAbbrev", lang));
|
||||||
name = name.split("|FISH_SIZE|").join(getString("/Lotus/Language/Fish/FishSizeMediumAbbrev", lang));
|
} else if (uniqueName.indexOf("Medium") != -1) {
|
||||||
|
name = name.split("|FISH_SIZE|").join(getString("/Lotus/Language/Fish/FishSizeMediumAbbrev", lang));
|
||||||
|
} else {
|
||||||
|
name = name.split("|FISH_SIZE|").join(getString("/Lotus/Language/Fish/FishSizeSmallAbbrev", lang));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
name = name.split("|FISH_SIZE|").join(getString("/Lotus/Language/Fish/FishSizeSmallAbbrev", lang));
|
if (uniqueName.indexOf("Large") != -1) {
|
||||||
|
name = name
|
||||||
|
.split("|FISH_SIZE|")
|
||||||
|
.join(getString("/Lotus/Language/SolarisVenus/RobofishAgeCategoryElderAbbrev", lang));
|
||||||
|
} else if (uniqueName.indexOf("Medium") != -1) {
|
||||||
|
name = name
|
||||||
|
.split("|FISH_SIZE|")
|
||||||
|
.join(getString("/Lotus/Language/SolarisVenus/RobofishAgeCategoryMatureAbbrev", lang));
|
||||||
|
} else {
|
||||||
|
name = name
|
||||||
|
.split("|FISH_SIZE|")
|
||||||
|
.join(getString("/Lotus/Language/SolarisVenus/RobofishAgeCategoryYoungAbbrev", lang));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@ -184,7 +229,6 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
res.mods = [];
|
|
||||||
for (const [uniqueName, upgrade] of Object.entries(ExportUpgrades)) {
|
for (const [uniqueName, upgrade] of Object.entries(ExportUpgrades)) {
|
||||||
const mod: ListedItem = {
|
const mod: ListedItem = {
|
||||||
uniqueName,
|
uniqueName,
|
||||||
@ -242,12 +286,14 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (const uniqueName of allIncarnons) {
|
||||||
|
res.EvolutionProgress.push({
|
||||||
|
uniqueName,
|
||||||
|
name: getString(getItemName(uniqueName) || "", lang)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
response.json({
|
response.json(res);
|
||||||
archonCrystalUpgrades,
|
|
||||||
uniqueLevelCaps: ExportMisc.uniqueLevelCaps,
|
|
||||||
...res
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { getItemListsController };
|
export { getItemListsController };
|
||||||
|
33
src/controllers/custom/setEvolutionProgressController.ts
Normal file
33
src/controllers/custom/setEvolutionProgressController.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
export const setEvolutionProgressController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId);
|
||||||
|
const payload = req.body as ISetEvolutionProgressRequest;
|
||||||
|
|
||||||
|
inventory.EvolutionProgress ??= [];
|
||||||
|
payload.forEach(element => {
|
||||||
|
const entry = inventory.EvolutionProgress!.find(entry => entry.ItemType === element.ItemType);
|
||||||
|
|
||||||
|
if (entry) {
|
||||||
|
entry.Progress = 0;
|
||||||
|
entry.Rank = element.Rank;
|
||||||
|
} else {
|
||||||
|
inventory.EvolutionProgress!.push({
|
||||||
|
Progress: 0,
|
||||||
|
Rank: element.Rank,
|
||||||
|
ItemType: element.ItemType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await inventory.save();
|
||||||
|
res.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
type ISetEvolutionProgressRequest = {
|
||||||
|
ItemType: string;
|
||||||
|
Rank: number;
|
||||||
|
}[];
|
@ -27,7 +27,15 @@ const viewController: RequestHandler = async (req, res) => {
|
|||||||
for (const type of Object.keys(ExportEnemies.avatars)) {
|
for (const type of Object.keys(ExportEnemies.avatars)) {
|
||||||
if (!scans.has(type)) scans.add(type);
|
if (!scans.has(type)) scans.add(type);
|
||||||
}
|
}
|
||||||
responseJson.Scans ??= [];
|
|
||||||
|
// Take any existing scans and also set them to 9999
|
||||||
|
if (responseJson.Scans) {
|
||||||
|
for (const scan of responseJson.Scans) {
|
||||||
|
scans.add(scan.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
responseJson.Scans = [];
|
||||||
|
|
||||||
for (const type of scans) {
|
for (const type of scans) {
|
||||||
responseJson.Scans.push({ type: type, scans: 9999 });
|
responseJson.Scans.push({ type: type, scans: 9999 });
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,10 @@ export const toMongoDate = (date: Date): IMongoDate => {
|
|||||||
return { $date: { $numberLong: date.getTime().toString() } };
|
return { $date: { $numberLong: date.getTime().toString() } };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const fromMongoData = (date: IMongoDate): Date => {
|
||||||
|
return new Date(parseInt(date.$date.$numberLong));
|
||||||
|
};
|
||||||
|
|
||||||
export const kubrowWeights: Record<TRarity, number> = {
|
export const kubrowWeights: Record<TRarity, number> = {
|
||||||
COMMON: 6,
|
COMMON: 6,
|
||||||
UNCOMMON: 4,
|
UNCOMMON: 4,
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import { ExportRegions } from "warframe-public-export-plus";
|
import { ExportRegions, ExportWarframes } from "warframe-public-export-plus";
|
||||||
import { IInfNode } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IInfNode, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { SRng } from "@/src/services/rngService";
|
import { getRewardAtPercentage, SRng } from "@/src/services/rngService";
|
||||||
import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
|
import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
|
||||||
import { logger } from "../utils/logger";
|
import { logger } from "../utils/logger";
|
||||||
import { IOid } from "../types/commonTypes";
|
import { IOid } from "../types/commonTypes";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { addMods } from "../services/inventoryService";
|
import { addMods, generateRewardSeed } from "../services/inventoryService";
|
||||||
|
import { isArchwingMission } from "../services/worldStateService";
|
||||||
|
import { fromStoreItem, toStoreItem } from "../services/itemDataService";
|
||||||
|
import { createMessage } from "../services/inboxService";
|
||||||
|
|
||||||
export const getInfNodes = (faction: string, rank: number): IInfNode[] => {
|
export const getInfNodes = (faction: string, rank: number): IInfNode[] => {
|
||||||
const infNodes = [];
|
const infNodes = [];
|
||||||
@ -22,7 +25,7 @@ export const getInfNodes = (faction: string, rank: number): IInfNode[] => {
|
|||||||
value.missionIndex != 42 && // not face off
|
value.missionIndex != 42 && // not face off
|
||||||
value.name.indexOf("1999NodeI") == -1 && // not stage defence
|
value.name.indexOf("1999NodeI") == -1 && // not stage defence
|
||||||
value.name.indexOf("1999NodeJ") == -1 && // not lich bounty
|
value.name.indexOf("1999NodeJ") == -1 && // not lich bounty
|
||||||
value.name.indexOf("Archwing") == -1
|
!isArchwingMission(value)
|
||||||
) {
|
) {
|
||||||
//console.log(dict_en[value.name]);
|
//console.log(dict_en[value.name]);
|
||||||
infNodes.push({ Node: key, Influence: 1 });
|
infNodes.push({ Node: key, Influence: 1 });
|
||||||
@ -37,17 +40,59 @@ const systemIndexes: Record<string, number[]> = {
|
|||||||
FC_INFESTATION: [23]
|
FC_INFESTATION: [23]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const showdownNodes: Record<string, string> = {
|
||||||
|
FC_GRINEER: "CrewBattleNode557",
|
||||||
|
FC_CORPUS: "CrewBattleNode558",
|
||||||
|
FC_INFESTATION: "CrewBattleNode559"
|
||||||
|
};
|
||||||
|
|
||||||
// Get a parazon 'passcode' based on the nemesis fingerprint so it's always the same for the same nemesis.
|
// Get a parazon 'passcode' based on the nemesis fingerprint so it's always the same for the same nemesis.
|
||||||
export const getNemesisPasscode = (nemesis: { fp: bigint; Faction: string }): number[] => {
|
export const getNemesisPasscode = (nemesis: { fp: bigint; Faction: string }): number[] => {
|
||||||
const rng = new SRng(nemesis.fp);
|
const rng = new SRng(nemesis.fp);
|
||||||
const passcode = [rng.randomInt(0, 7)];
|
const choices = [0, 1, 2, 3, 5, 6, 7];
|
||||||
|
let choiceIndex = rng.randomInt(0, choices.length - 1);
|
||||||
|
const passcode = [choices[choiceIndex]];
|
||||||
if (nemesis.Faction != "FC_INFESTATION") {
|
if (nemesis.Faction != "FC_INFESTATION") {
|
||||||
passcode.push(rng.randomInt(0, 7));
|
choices.splice(choiceIndex, 1);
|
||||||
passcode.push(rng.randomInt(0, 7));
|
choiceIndex = rng.randomInt(0, choices.length - 1);
|
||||||
|
passcode.push(choices[choiceIndex]);
|
||||||
|
|
||||||
|
choices.splice(choiceIndex, 1);
|
||||||
|
choiceIndex = rng.randomInt(0, choices.length - 1);
|
||||||
|
passcode.push(choices[choiceIndex]);
|
||||||
}
|
}
|
||||||
return passcode;
|
return passcode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const reqiuemMods: readonly string[] = [
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalOneMod",
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalTwoMod",
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalThreeMod",
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalFourMod",
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalFiveMod",
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalSixMod",
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalSevenMod",
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalEightMod"
|
||||||
|
];
|
||||||
|
|
||||||
|
const antivirusMods: readonly string[] = [
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/AntivirusOneMod",
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/AntivirusTwoMod",
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/AntivirusThreeMod",
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/AntivirusFourMod",
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/AntivirusFiveMod",
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/AntivirusSixMod",
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/AntivirusSevenMod",
|
||||||
|
"/Lotus/Upgrades/Mods/Immortal/AntivirusEightMod"
|
||||||
|
];
|
||||||
|
|
||||||
|
export const getNemesisPasscodeModTypes = (nemesis: { fp: bigint; Faction: string }): string[] => {
|
||||||
|
const passcode = getNemesisPasscode(nemesis);
|
||||||
|
return nemesis.Faction == "FC_INFESTATION"
|
||||||
|
? passcode.map(i => antivirusMods[i])
|
||||||
|
: passcode.map(i => reqiuemMods[i]);
|
||||||
|
};
|
||||||
|
|
||||||
export const encodeNemesisGuess = (
|
export const encodeNemesisGuess = (
|
||||||
symbol1: number,
|
symbol1: number,
|
||||||
result1: number,
|
result1: number,
|
||||||
@ -78,6 +123,31 @@ export interface IKnifeResponse {
|
|||||||
HasKnife?: boolean;
|
HasKnife?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getKnifeUpgrade = (
|
||||||
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
dataknifeUpgrades: string[],
|
||||||
|
type: string
|
||||||
|
): { ItemId: IOid; ItemType: string } => {
|
||||||
|
if (dataknifeUpgrades.indexOf(type) != -1) {
|
||||||
|
return {
|
||||||
|
ItemId: { $oid: "000000000000000000000000" },
|
||||||
|
ItemType: type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
for (const upgradeId of dataknifeUpgrades) {
|
||||||
|
if (upgradeId.length == 24) {
|
||||||
|
const upgrade = inventory.Upgrades.id(upgradeId);
|
||||||
|
if (upgrade && upgrade.ItemType == type) {
|
||||||
|
return {
|
||||||
|
ItemId: { $oid: upgradeId },
|
||||||
|
ItemType: type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error(`${type} does not seem to be installed on parazon?!`);
|
||||||
|
};
|
||||||
|
|
||||||
export const consumeModCharge = (
|
export const consumeModCharge = (
|
||||||
response: IKnifeResponse,
|
response: IKnifeResponse,
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
@ -128,3 +198,181 @@ export const consumeModCharge = (
|
|||||||
response.UpgradeNew.push(true);
|
response.UpgradeNew.push(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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":
|
||||||
|
return kuvaLichVersionSixWeapons;
|
||||||
|
case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree":
|
||||||
|
case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour":
|
||||||
|
return corpusVersionThreeWeapons;
|
||||||
|
}
|
||||||
|
throw new Error(`unknown nemesis manifest: ${manifest}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getInnateDamageTag = (
|
||||||
|
KillingSuit: string
|
||||||
|
):
|
||||||
|
| "InnateElectricityDamage"
|
||||||
|
| "InnateFreezeDamage"
|
||||||
|
| "InnateHeatDamage"
|
||||||
|
| "InnateImpactDamage"
|
||||||
|
| "InnateMagDamage"
|
||||||
|
| "InnateRadDamage"
|
||||||
|
| "InnateToxinDamage" => {
|
||||||
|
return ExportWarframes[KillingSuit].nemesisUpgradeTag!;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: For -1399275245665749231n, the value should be 75306944, but we're off by 59 with 75307003.
|
||||||
|
export const getInnateDamageValue = (fp: bigint): number => {
|
||||||
|
const rng = new SRng(fp);
|
||||||
|
rng.randomFloat(); // used for the weapon index
|
||||||
|
const WeaponUpgradeValueAttenuationExponent = 2.25;
|
||||||
|
let value = Math.pow(rng.randomFloat(), WeaponUpgradeValueAttenuationExponent);
|
||||||
|
if (value >= 0.941428) {
|
||||||
|
value = 1;
|
||||||
|
}
|
||||||
|
return Math.trunc(value * 0x40000000);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getKillTokenRewardCount = (fp: bigint): number => {
|
||||||
|
const rng = new SRng(fp);
|
||||||
|
return rng.randomInt(10, 15);
|
||||||
|
};
|
||||||
|
|
||||||
|
// /Lotus/Types/Enemies/InfestedLich/InfestedLichRewardManifest
|
||||||
|
const infestedLichRotA = [
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDJRomHuman", probability: 0.046 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDJRomInfested", probability: 0.045 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDrillbitHuman", probability: 0.046 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDrillbitInfested", probability: 0.045 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyHarddriveHuman", probability: 0.046 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyHarddriveInfested", probability: 0.045 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyPacketHuman", probability: 0.046 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyPacketInfested", probability: 0.045 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyZekeHuman", probability: 0.046 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyZekeInfested", probability: 0.045 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandBillboardPosterA", probability: 0.045 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandBillboardPosterB", probability: 0.046 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandDespairPoster", probability: 0.045 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandGridPoster", probability: 0.046 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandHuddlePoster", probability: 0.045 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandJumpPoster", probability: 0.046 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLimoPoster", probability: 0.045 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLookingDownPosterDay", probability: 0.046 },
|
||||||
|
{
|
||||||
|
type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLookingDownPosterNight",
|
||||||
|
probability: 0.045
|
||||||
|
},
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandSillyPoster", probability: 0.046 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandWhiteBluePoster", probability: 0.045 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandWhitePinkPoster", probability: 0.045 }
|
||||||
|
];
|
||||||
|
const infestedLichRotB = [
|
||||||
|
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraA", probability: 0.072 },
|
||||||
|
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraB", probability: 0.071 },
|
||||||
|
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraC", probability: 0.072 },
|
||||||
|
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraD", probability: 0.071 },
|
||||||
|
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraE", probability: 0.072 },
|
||||||
|
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraF", probability: 0.071 },
|
||||||
|
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraG", probability: 0.071 },
|
||||||
|
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraH", probability: 0.072 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DanceDJRomHype", probability: 0.071 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DancePacketWindmillShuffle", probability: 0.072 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DanceHarddrivePony", probability: 0.071 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DanceDrillbitCrisscross", probability: 0.072 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DanceZekeCanthavethis", probability: 0.071 },
|
||||||
|
{ type: "/Lotus/StoreItems/Types/Items/PhotoBooth/PhotoboothTileRJLasXStadiumBossArena", probability: 0.071 }
|
||||||
|
];
|
||||||
|
export const getInfestedLichItemRewards = (fp: bigint): string[] => {
|
||||||
|
const rng = new SRng(fp);
|
||||||
|
const rotAReward = getRewardAtPercentage(infestedLichRotA, rng.randomFloat())!.type;
|
||||||
|
rng.randomFloat(); // unused afaict
|
||||||
|
const rotBReward = getRewardAtPercentage(infestedLichRotB, rng.randomFloat())!.type;
|
||||||
|
return [rotAReward, rotBReward];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sendCodaFinishedMessage = async (
|
||||||
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
fp: bigint = generateRewardSeed(),
|
||||||
|
name: string = "ZEKE_BEATWOMAN_TM.1999",
|
||||||
|
killed: boolean = true
|
||||||
|
): Promise<void> => {
|
||||||
|
const att: string[] = [];
|
||||||
|
|
||||||
|
// First vanquish/convert gives a sigil
|
||||||
|
const sigil = killed
|
||||||
|
? "/Lotus/Upgrades/Skins/Sigils/InfLichVanquishedSigil"
|
||||||
|
: "/Lotus/Upgrades/Skins/Sigils/InfLichConvertedSigil";
|
||||||
|
if (!inventory.WeaponSkins.find(x => x.ItemType == sigil)) {
|
||||||
|
att.push(toStoreItem(sigil));
|
||||||
|
}
|
||||||
|
|
||||||
|
const [rotAReward, rotBReward] = getInfestedLichItemRewards(fp);
|
||||||
|
att.push(fromStoreItem(rotAReward));
|
||||||
|
att.push(fromStoreItem(rotBReward));
|
||||||
|
|
||||||
|
let countedAtt: ITypeCount[] | undefined;
|
||||||
|
if (killed) {
|
||||||
|
countedAtt = [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/CodaWeaponBucks",
|
||||||
|
ItemCount: getKillTokenRewardCount(fp)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
await createMessage(inventory.accountOwnerId, [
|
||||||
|
{
|
||||||
|
sndr: "/Lotus/Language/Bosses/Ordis",
|
||||||
|
msg: "/Lotus/Language/Inbox/VanquishBandMsgBody",
|
||||||
|
arg: [
|
||||||
|
{
|
||||||
|
Key: "LICH_NAME",
|
||||||
|
Tag: name
|
||||||
|
}
|
||||||
|
],
|
||||||
|
att: att,
|
||||||
|
countedAtt: countedAtt,
|
||||||
|
sub: "/Lotus/Language/Inbox/VanquishBandMsgTitle",
|
||||||
|
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
|
||||||
|
highPriority: true
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
@ -31,7 +31,7 @@ export interface IFingerprintStat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const createVeiledRivenFingerprint = (meta: IUpgrade): IVeiledRivenFingerprint => {
|
export const createVeiledRivenFingerprint = (meta: IUpgrade): IVeiledRivenFingerprint => {
|
||||||
const challenge = getRandomElement(meta.availableChallenges!);
|
const challenge = getRandomElement(meta.availableChallenges!)!;
|
||||||
const fingerprintChallenge: IRivenChallenge = {
|
const fingerprintChallenge: IRivenChallenge = {
|
||||||
Type: challenge.fullName,
|
Type: challenge.fullName,
|
||||||
Progress: 0,
|
Progress: 0,
|
||||||
@ -54,11 +54,11 @@ export const createVeiledRivenFingerprint = (meta: IUpgrade): IVeiledRivenFinger
|
|||||||
|
|
||||||
export const createUnveiledRivenFingerprint = (meta: IUpgrade): IUnveiledRivenFingerprint => {
|
export const createUnveiledRivenFingerprint = (meta: IUpgrade): IUnveiledRivenFingerprint => {
|
||||||
const fingerprint: IUnveiledRivenFingerprint = {
|
const fingerprint: IUnveiledRivenFingerprint = {
|
||||||
compat: getRandomElement(meta.compatibleItems!),
|
compat: getRandomElement(meta.compatibleItems!)!,
|
||||||
lim: 0,
|
lim: 0,
|
||||||
lvl: 0,
|
lvl: 0,
|
||||||
lvlReq: getRandomInt(8, 16),
|
lvlReq: getRandomInt(8, 16),
|
||||||
pol: getRandomElement(["AP_ATTACK", "AP_DEFENSE", "AP_TACTIC"]),
|
pol: getRandomElement(["AP_ATTACK", "AP_DEFENSE", "AP_TACTIC"])!,
|
||||||
buffs: [],
|
buffs: [],
|
||||||
curses: []
|
curses: []
|
||||||
};
|
};
|
||||||
@ -81,7 +81,7 @@ export const randomiseRivenStats = (meta: IUpgrade, fingerprint: IUnveiledRivenF
|
|||||||
if (Math.random() < 0.5) {
|
if (Math.random() < 0.5) {
|
||||||
const entry = getRandomElement(
|
const entry = getRandomElement(
|
||||||
meta.upgradeEntries!.filter(x => x.canBeCurse && !fingerprint.buffs.find(y => y.Tag == x.tag))
|
meta.upgradeEntries!.filter(x => x.canBeCurse && !fingerprint.buffs.find(y => y.Tag == x.tag))
|
||||||
);
|
)!;
|
||||||
fingerprint.curses.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) });
|
fingerprint.curses.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -23,6 +23,7 @@ const dojoDecoSchema = new Schema<IDojoDecoDatabase>({
|
|||||||
Type: String,
|
Type: String,
|
||||||
Pos: [Number],
|
Pos: [Number],
|
||||||
Rot: [Number],
|
Rot: [Number],
|
||||||
|
Scale: Number,
|
||||||
Name: String,
|
Name: String,
|
||||||
Sockets: Number,
|
Sockets: Number,
|
||||||
RegularCredits: Number,
|
RegularCredits: Number,
|
||||||
|
@ -96,7 +96,8 @@ import {
|
|||||||
IInvasionProgressDatabase,
|
IInvasionProgressDatabase,
|
||||||
IInvasionProgressClient,
|
IInvasionProgressClient,
|
||||||
IAccolades,
|
IAccolades,
|
||||||
IHubNpcCustomization
|
IHubNpcCustomization,
|
||||||
|
ILotusCustomization
|
||||||
} from "../../types/inventoryTypes/inventoryTypes";
|
} from "../../types/inventoryTypes/inventoryTypes";
|
||||||
import { IOid } from "../../types/commonTypes";
|
import { IOid } from "../../types/commonTypes";
|
||||||
import {
|
import {
|
||||||
@ -390,8 +391,8 @@ MailboxSchema.set("toJSON", {
|
|||||||
|
|
||||||
const DuviriInfoSchema = new Schema<IDuviriInfo>(
|
const DuviriInfoSchema = new Schema<IDuviriInfo>(
|
||||||
{
|
{
|
||||||
Seed: Number,
|
Seed: { type: BigInt, required: true },
|
||||||
NumCompletions: { type: Number, default: 0 }
|
NumCompletions: { type: Number, required: true }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_id: false,
|
_id: false,
|
||||||
@ -780,6 +781,26 @@ const loreFragmentScansSchema = new Schema<ILoreFragmentScan>(
|
|||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// const lotusCustomizationSchema = new Schema<ILotusCustomization>().add(ItemConfigSchema).add({
|
||||||
|
// Persona: String
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Laxer schema for cleanupInventory
|
||||||
|
const lotusCustomizationSchema = new Schema<ILotusCustomization>(
|
||||||
|
{
|
||||||
|
Skins: [String],
|
||||||
|
pricol: colorSchema,
|
||||||
|
attcol: Schema.Types.Mixed,
|
||||||
|
sigcol: Schema.Types.Mixed,
|
||||||
|
eyecol: Schema.Types.Mixed,
|
||||||
|
facial: Schema.Types.Mixed,
|
||||||
|
cloth: Schema.Types.Mixed,
|
||||||
|
syancol: Schema.Types.Mixed,
|
||||||
|
Persona: String
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
||||||
|
|
||||||
const evolutionProgressSchema = new Schema<IEvolutionProgress>(
|
const evolutionProgressSchema = new Schema<IEvolutionProgress>(
|
||||||
{
|
{
|
||||||
Progress: Number,
|
Progress: Number,
|
||||||
@ -1034,6 +1055,8 @@ const pendingRecipeSchema = new Schema<IPendingRecipeDatabase>(
|
|||||||
{
|
{
|
||||||
ItemType: String,
|
ItemType: String,
|
||||||
CompletionDate: Date,
|
CompletionDate: Date,
|
||||||
|
TargetItemId: String,
|
||||||
|
TargetFingerprint: String,
|
||||||
LongGuns: { type: [EquipmentSchema], default: undefined },
|
LongGuns: { type: [EquipmentSchema], default: undefined },
|
||||||
Pistols: { type: [EquipmentSchema], default: undefined },
|
Pistols: { type: [EquipmentSchema], default: undefined },
|
||||||
Melee: { type: [EquipmentSchema], default: undefined },
|
Melee: { type: [EquipmentSchema], default: undefined },
|
||||||
@ -1125,15 +1148,15 @@ const CustomMarkersSchema = new Schema<ICustomMarkers>(
|
|||||||
const calenderProgressSchema = new Schema<ICalendarProgress>(
|
const calenderProgressSchema = new Schema<ICalendarProgress>(
|
||||||
{
|
{
|
||||||
Version: { type: Number, default: 19 },
|
Version: { type: Number, default: 19 },
|
||||||
Iteration: { type: Number, default: 2 },
|
Iteration: { type: Number, required: true },
|
||||||
YearProgress: {
|
YearProgress: {
|
||||||
Upgrades: { type: [] }
|
Upgrades: { type: [String], default: [] }
|
||||||
},
|
},
|
||||||
SeasonProgress: {
|
SeasonProgress: {
|
||||||
SeasonType: String,
|
SeasonType: { type: String, required: true },
|
||||||
LastCompletedDayIdx: { type: Number, default: -1 },
|
LastCompletedDayIdx: { type: Number, default: 0 },
|
||||||
LastCompletedChallengeDayIdx: { type: Number, default: -1 },
|
LastCompletedChallengeDayIdx: { type: Number, default: 0 },
|
||||||
ActivatedChallenges: []
|
ActivatedChallenges: { type: [String], default: [] }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ _id: false }
|
{ _id: false }
|
||||||
@ -1255,11 +1278,11 @@ const nemesisSchema = new Schema<INemesisDatabase>(
|
|||||||
PrevOwners: Number,
|
PrevOwners: Number,
|
||||||
SecondInCommand: Boolean,
|
SecondInCommand: Boolean,
|
||||||
Weakened: Boolean,
|
Weakened: Boolean,
|
||||||
InfNodes: [infNodeSchema],
|
InfNodes: { type: [infNodeSchema], default: undefined },
|
||||||
HenchmenKilled: Number,
|
HenchmenKilled: Number,
|
||||||
HintProgress: Number,
|
HintProgress: Number,
|
||||||
Hints: [Number],
|
Hints: { type: [Number], default: undefined },
|
||||||
GuessHistory: [Number],
|
GuessHistory: { type: [Number], default: undefined },
|
||||||
MissionCount: Number,
|
MissionCount: Number,
|
||||||
LastEnc: Number
|
LastEnc: Number
|
||||||
},
|
},
|
||||||
@ -1376,7 +1399,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
//How many Gift do you have left*(gift spends the trade)
|
//How many Gift do you have left*(gift spends the trade)
|
||||||
GiftsRemaining: { type: Number, default: 8 },
|
GiftsRemaining: { type: Number, default: 8 },
|
||||||
//Curent trade info Giving or Getting items
|
//Curent trade info Giving or Getting items
|
||||||
PendingTrades: [Schema.Types.Mixed],
|
//PendingTrades: [Schema.Types.Mixed],
|
||||||
|
|
||||||
//Syndicate currently being pledged to.
|
//Syndicate currently being pledged to.
|
||||||
SupportedSyndicate: String,
|
SupportedSyndicate: String,
|
||||||
@ -1426,7 +1449,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
|
|
||||||
KubrowPetEggs: [kubrowPetEggSchema],
|
KubrowPetEggs: [kubrowPetEggSchema],
|
||||||
//Prints Cat(3 Prints)\Kubrow(2 Prints) Pets
|
//Prints Cat(3 Prints)\Kubrow(2 Prints) Pets
|
||||||
KubrowPetPrints: [Schema.Types.Mixed],
|
//KubrowPetPrints: [Schema.Types.Mixed],
|
||||||
|
|
||||||
//Item for EquippedGear example:Scaner,LoadoutTechSummon etc
|
//Item for EquippedGear example:Scaner,LoadoutTechSummon etc
|
||||||
Consumables: [typeCountSchema],
|
Consumables: [typeCountSchema],
|
||||||
@ -1472,7 +1495,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
//item like DojoKey or Boss missions key
|
//item like DojoKey or Boss missions key
|
||||||
LevelKeys: [typeCountSchema],
|
LevelKeys: [typeCountSchema],
|
||||||
//Active quests
|
//Active quests
|
||||||
Quests: [Schema.Types.Mixed],
|
//Quests: [Schema.Types.Mixed],
|
||||||
|
|
||||||
//Cosmetics like profile glyphs\Kavasa Prime Kubrow Collar\Game Theme etc
|
//Cosmetics like profile glyphs\Kavasa Prime Kubrow Collar\Game Theme etc
|
||||||
FlavourItems: [FlavourItemSchema],
|
FlavourItems: [FlavourItemSchema],
|
||||||
@ -1511,7 +1534,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
TauntHistory: { type: [tauntSchema], default: undefined },
|
TauntHistory: { type: [tauntSchema], default: undefined },
|
||||||
|
|
||||||
//noShow2FA,VisitPrimeVault etc
|
//noShow2FA,VisitPrimeVault etc
|
||||||
WebFlags: Schema.Types.Mixed,
|
//WebFlags: Schema.Types.Mixed,
|
||||||
//Id CompletedAlerts
|
//Id CompletedAlerts
|
||||||
CompletedAlerts: [String],
|
CompletedAlerts: [String],
|
||||||
|
|
||||||
@ -1531,7 +1554,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
//the color your clan requests like Items/Research/DojoColors/DojoColorPlainsB
|
//the color your clan requests like Items/Research/DojoColors/DojoColorPlainsB
|
||||||
ActiveDojoColorResearch: String,
|
ActiveDojoColorResearch: String,
|
||||||
|
|
||||||
SentientSpawnChanceBoosters: Schema.Types.Mixed,
|
//SentientSpawnChanceBoosters: Schema.Types.Mixed,
|
||||||
|
|
||||||
QualifyingInvasions: [invasionProgressSchema],
|
QualifyingInvasions: [invasionProgressSchema],
|
||||||
FactionScores: [Number],
|
FactionScores: [Number],
|
||||||
@ -1566,10 +1589,10 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
// open location store like EidolonPlainsDiscoverable or OrbVallisCaveDiscoverable
|
// open location store like EidolonPlainsDiscoverable or OrbVallisCaveDiscoverable
|
||||||
DiscoveredMarkers: [discoveredMarkerSchema],
|
DiscoveredMarkers: [discoveredMarkerSchema],
|
||||||
//Open location mission like "JobId" + "StageCompletions"
|
//Open location mission like "JobId" + "StageCompletions"
|
||||||
CompletedJobs: [Schema.Types.Mixed],
|
//CompletedJobs: [Schema.Types.Mixed],
|
||||||
|
|
||||||
//Game mission\ivent score example "Tag": "WaterFight", "Best": 170, "Count": 1258,
|
//Game mission\ivent score example "Tag": "WaterFight", "Best": 170, "Count": 1258,
|
||||||
PersonalGoalProgress: [Schema.Types.Mixed],
|
//PersonalGoalProgress: [Schema.Types.Mixed],
|
||||||
|
|
||||||
//Setting interface Style
|
//Setting interface Style
|
||||||
ThemeStyle: String,
|
ThemeStyle: String,
|
||||||
@ -1599,13 +1622,13 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
LibraryActiveDailyTaskInfo: libraryDailyTaskInfoSchema,
|
LibraryActiveDailyTaskInfo: libraryDailyTaskInfoSchema,
|
||||||
|
|
||||||
//https://warframe.fandom.com/wiki/Invasion
|
//https://warframe.fandom.com/wiki/Invasion
|
||||||
InvasionChainProgress: [Schema.Types.Mixed],
|
//InvasionChainProgress: [Schema.Types.Mixed],
|
||||||
|
|
||||||
//CorpusLich or GrineerLich
|
//CorpusLich or GrineerLich
|
||||||
NemesisAbandonedRewards: { type: [String], default: [] },
|
NemesisAbandonedRewards: { type: [String], default: [] },
|
||||||
Nemesis: nemesisSchema,
|
Nemesis: nemesisSchema,
|
||||||
NemesisHistory: [Schema.Types.Mixed],
|
NemesisHistory: { type: [nemesisSchema], default: undefined },
|
||||||
LastNemesisAllySpawnTime: Schema.Types.Mixed,
|
//LastNemesisAllySpawnTime: Schema.Types.Mixed,
|
||||||
|
|
||||||
//TradingRulesConfirmed,ShowFriendInvNotifications(Option->Social)
|
//TradingRulesConfirmed,ShowFriendInvNotifications(Option->Social)
|
||||||
Settings: settingsSchema,
|
Settings: settingsSchema,
|
||||||
@ -1619,7 +1642,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
PlayerSkills: { type: playerSkillsSchema, default: {} },
|
PlayerSkills: { type: playerSkillsSchema, default: {} },
|
||||||
|
|
||||||
//TradeBannedUntil data
|
//TradeBannedUntil data
|
||||||
TradeBannedUntil: Schema.Types.Mixed,
|
//TradeBannedUntil: Schema.Types.Mixed,
|
||||||
|
|
||||||
//https://warframe.fandom.com/wiki/Helminth
|
//https://warframe.fandom.com/wiki/Helminth
|
||||||
InfestedFoundry: infestedFoundrySchema,
|
InfestedFoundry: infestedFoundrySchema,
|
||||||
@ -1628,7 +1651,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
|
|
||||||
//Purchase this new permanent skin from the Lotus customization options in Personal Quarters located in your Orbiter.
|
//Purchase this new permanent skin from the Lotus customization options in Personal Quarters located in your Orbiter.
|
||||||
//https://warframe.fandom.com/wiki/Lotus#The_New_War
|
//https://warframe.fandom.com/wiki/Lotus#The_New_War
|
||||||
LotusCustomization: Schema.Types.Mixed,
|
LotusCustomization: { type: lotusCustomizationSchema, default: undefined },
|
||||||
|
|
||||||
//Progress+Rank+ItemType(ZarimanPumpShotgun)
|
//Progress+Rank+ItemType(ZarimanPumpShotgun)
|
||||||
//https://warframe.fandom.com/wiki/Incarnon
|
//https://warframe.fandom.com/wiki/Incarnon
|
||||||
@ -1639,23 +1662,24 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
|
|
||||||
//Unknown and system
|
//Unknown and system
|
||||||
DuviriInfo: DuviriInfoSchema,
|
DuviriInfo: DuviriInfoSchema,
|
||||||
|
LastInventorySync: Schema.Types.ObjectId,
|
||||||
Mailbox: MailboxSchema,
|
Mailbox: MailboxSchema,
|
||||||
HandlerPoints: Number,
|
HandlerPoints: Number,
|
||||||
ChallengesFixVersion: { type: Number, default: 6 },
|
ChallengesFixVersion: { type: Number, default: 6 },
|
||||||
PlayedParkourTutorial: Boolean,
|
PlayedParkourTutorial: Boolean,
|
||||||
ActiveLandscapeTraps: [Schema.Types.Mixed],
|
//ActiveLandscapeTraps: [Schema.Types.Mixed],
|
||||||
RepVotes: [Schema.Types.Mixed],
|
//RepVotes: [Schema.Types.Mixed],
|
||||||
LeagueTickets: [Schema.Types.Mixed],
|
//LeagueTickets: [Schema.Types.Mixed],
|
||||||
HasContributedToDojo: Boolean,
|
HasContributedToDojo: Boolean,
|
||||||
HWIDProtectEnabled: Boolean,
|
HWIDProtectEnabled: Boolean,
|
||||||
LoadOutPresets: { type: Schema.Types.ObjectId, ref: "Loadout" },
|
LoadOutPresets: { type: Schema.Types.ObjectId, ref: "Loadout" },
|
||||||
CurrentLoadOutIds: [oidSchema],
|
CurrentLoadOutIds: [oidSchema],
|
||||||
RandomUpgradesIdentified: Number,
|
RandomUpgradesIdentified: Number,
|
||||||
BountyScore: Number,
|
BountyScore: Number,
|
||||||
ChallengeInstanceStates: [Schema.Types.Mixed],
|
//ChallengeInstanceStates: [Schema.Types.Mixed],
|
||||||
RecentVendorPurchases: { type: [recentVendorPurchaseSchema], default: undefined },
|
RecentVendorPurchases: { type: [recentVendorPurchaseSchema], default: undefined },
|
||||||
Robotics: [Schema.Types.Mixed],
|
//Robotics: [Schema.Types.Mixed],
|
||||||
UsedDailyDeals: [Schema.Types.Mixed],
|
//UsedDailyDeals: [Schema.Types.Mixed],
|
||||||
CollectibleSeries: { type: [collectibleEntrySchema], default: undefined },
|
CollectibleSeries: { type: [collectibleEntrySchema], default: undefined },
|
||||||
HasResetAccount: { type: Boolean, default: false },
|
HasResetAccount: { type: Boolean, default: false },
|
||||||
|
|
||||||
@ -1664,9 +1688,9 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
//Like BossAladV,BossCaptainVor come for you on missions % chance
|
//Like BossAladV,BossCaptainVor come for you on missions % chance
|
||||||
DeathMarks: { type: [String], default: [] },
|
DeathMarks: { type: [String], default: [] },
|
||||||
//Zanuka
|
//Zanuka
|
||||||
Harvestable: Boolean,
|
Harvestable: { type: Boolean, default: true },
|
||||||
//Grustag three
|
//Grustag three
|
||||||
DeathSquadable: Boolean,
|
DeathSquadable: { type: Boolean, default: true },
|
||||||
|
|
||||||
EndlessXP: { type: [endlessXpProgressSchema], default: undefined },
|
EndlessXP: { type: [endlessXpProgressSchema], default: undefined },
|
||||||
|
|
||||||
@ -1736,6 +1760,9 @@ inventorySchema.set("toJSON", {
|
|||||||
sn: inventoryDatabase.LockedWeaponGroup.sn ? toOid(inventoryDatabase.LockedWeaponGroup.sn) : undefined
|
sn: inventoryDatabase.LockedWeaponGroup.sn ? toOid(inventoryDatabase.LockedWeaponGroup.sn) : undefined
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (inventoryDatabase.LastInventorySync) {
|
||||||
|
inventoryResponse.LastInventorySync = toOid(inventoryDatabase.LastInventorySync);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
|
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import { colorSchema } from "@/src/models/inventoryModels/inventoryModel";
|
import { colorSchema } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { IOrbiter, IPersonalRoomsDatabase, PersonalRoomsModelType } from "@/src/types/personalRoomsTypes";
|
import { IOrbiter, IPersonalRoomsDatabase, PersonalRoomsModelType } from "@/src/types/personalRoomsTypes";
|
||||||
import {
|
import {
|
||||||
IFavouriteLoadoutDatabase,
|
IFavouriteLoadoutDatabase,
|
||||||
IGardening,
|
IGardeningDatabase,
|
||||||
IPlacedDecosDatabase,
|
IPlacedDecosDatabase,
|
||||||
IPictureFrameInfo,
|
IPictureFrameInfo,
|
||||||
IRoom,
|
IRoom,
|
||||||
ITailorShopDatabase,
|
ITailorShopDatabase,
|
||||||
IApartmentDatabase
|
IApartmentDatabase,
|
||||||
|
IPlanterDatabase,
|
||||||
|
IPlantDatabase,
|
||||||
|
IPlantClient
|
||||||
} from "@/src/types/shipTypes";
|
} from "@/src/types/shipTypes";
|
||||||
import { Schema, model } from "mongoose";
|
import { Schema, model } from "mongoose";
|
||||||
|
|
||||||
@ -77,15 +80,45 @@ favouriteLoadoutSchema.set("toJSON", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const gardeningSchema = new Schema<IGardening>({
|
const plantSchema = new Schema<IPlantDatabase>(
|
||||||
Planters: [Schema.Types.Mixed] //TODO: add when implementing gardening
|
{
|
||||||
|
PlantType: String,
|
||||||
|
EndTime: Date,
|
||||||
|
PlotIndex: Number
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
plantSchema.set("toJSON", {
|
||||||
|
virtuals: true,
|
||||||
|
transform(_doc, obj) {
|
||||||
|
const client = obj as IPlantClient;
|
||||||
|
const db = obj as IPlantDatabase;
|
||||||
|
|
||||||
|
client.EndTime = toMongoDate(db.EndTime);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const planterSchema = new Schema<IPlanterDatabase>(
|
||||||
|
{
|
||||||
|
Name: { type: String, required: true },
|
||||||
|
Plants: { type: [plantSchema], default: [] }
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
const gardeningSchema = new Schema<IGardeningDatabase>(
|
||||||
|
{
|
||||||
|
Planters: { type: [planterSchema], default: [] }
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
||||||
|
|
||||||
const apartmentSchema = new Schema<IApartmentDatabase>(
|
const apartmentSchema = new Schema<IApartmentDatabase>(
|
||||||
{
|
{
|
||||||
Rooms: [roomSchema],
|
Rooms: [roomSchema],
|
||||||
FavouriteLoadouts: [favouriteLoadoutSchema],
|
FavouriteLoadouts: [favouriteLoadoutSchema],
|
||||||
Gardening: gardeningSchema // TODO: ensure this is correct
|
Gardening: gardeningSchema
|
||||||
},
|
},
|
||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
@ -98,7 +131,9 @@ const apartmentDefault: IApartmentDatabase = {
|
|||||||
{ Name: "DuviriHallway", MaxCapacity: 1600 }
|
{ Name: "DuviriHallway", MaxCapacity: 1600 }
|
||||||
],
|
],
|
||||||
FavouriteLoadouts: [],
|
FavouriteLoadouts: [],
|
||||||
Gardening: {}
|
Gardening: {
|
||||||
|
Planters: []
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const orbiterSchema = new Schema<IOrbiter>(
|
const orbiterSchema = new Schema<IOrbiter>(
|
||||||
|
@ -19,6 +19,7 @@ import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompl
|
|||||||
import { claimLibraryDailyTaskRewardController } from "@/src/controllers/api/claimLibraryDailyTaskRewardController";
|
import { claimLibraryDailyTaskRewardController } from "@/src/controllers/api/claimLibraryDailyTaskRewardController";
|
||||||
import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
|
import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
|
||||||
import { clearNewEpisodeRewardController } from "@/src/controllers/api/clearNewEpisodeRewardController";
|
import { clearNewEpisodeRewardController } from "@/src/controllers/api/clearNewEpisodeRewardController";
|
||||||
|
import { completeCalendarEventController } from "@/src/controllers/api/completeCalendarEventController";
|
||||||
import { completeRandomModChallengeController } from "@/src/controllers/api/completeRandomModChallengeController";
|
import { completeRandomModChallengeController } from "@/src/controllers/api/completeRandomModChallengeController";
|
||||||
import { confirmAllianceInvitationController } from "@/src/controllers/api/confirmAllianceInvitationController";
|
import { confirmAllianceInvitationController } from "@/src/controllers/api/confirmAllianceInvitationController";
|
||||||
import { confirmGuildInvitationGetController, confirmGuildInvitationPostController } from "@/src/controllers/api/confirmGuildInvitationController";
|
import { confirmGuildInvitationGetController, confirmGuildInvitationPostController } from "@/src/controllers/api/confirmGuildInvitationController";
|
||||||
@ -47,6 +48,7 @@ import { findSessionsController } from "@/src/controllers/api/findSessionsContro
|
|||||||
import { fishmongerController } from "@/src/controllers/api/fishmongerController";
|
import { fishmongerController } from "@/src/controllers/api/fishmongerController";
|
||||||
import { focusController } from "@/src/controllers/api/focusController";
|
import { focusController } from "@/src/controllers/api/focusController";
|
||||||
import { fusionTreasuresController } from "@/src/controllers/api/fusionTreasuresController";
|
import { fusionTreasuresController } from "@/src/controllers/api/fusionTreasuresController";
|
||||||
|
import { gardeningController } from "@/src/controllers/api/gardeningController";
|
||||||
import { genericUpdateController } from "@/src/controllers/api/genericUpdateController";
|
import { genericUpdateController } from "@/src/controllers/api/genericUpdateController";
|
||||||
import { getAllianceController } from "@/src/controllers/api/getAllianceController";
|
import { getAllianceController } from "@/src/controllers/api/getAllianceController";
|
||||||
import { getDailyDealStockLevelsController } from "@/src/controllers/api/getDailyDealStockLevelsController";
|
import { getDailyDealStockLevelsController } from "@/src/controllers/api/getDailyDealStockLevelsController";
|
||||||
@ -158,6 +160,7 @@ apiRouter.get("/changeDojoRoot.php", changeDojoRootController);
|
|||||||
apiRouter.get("/changeGuildRank.php", changeGuildRankController);
|
apiRouter.get("/changeGuildRank.php", changeGuildRankController);
|
||||||
apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController);
|
apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController);
|
||||||
apiRouter.get("/claimLibraryDailyTaskReward.php", claimLibraryDailyTaskRewardController);
|
apiRouter.get("/claimLibraryDailyTaskReward.php", claimLibraryDailyTaskRewardController);
|
||||||
|
apiRouter.get("/completeCalendarEvent.php", completeCalendarEventController);
|
||||||
apiRouter.get("/confirmAllianceInvitation.php", confirmAllianceInvitationController);
|
apiRouter.get("/confirmAllianceInvitation.php", confirmAllianceInvitationController);
|
||||||
apiRouter.get("/confirmGuildInvitation.php", confirmGuildInvitationGetController);
|
apiRouter.get("/confirmGuildInvitation.php", confirmGuildInvitationGetController);
|
||||||
apiRouter.get("/credits.php", creditsController);
|
apiRouter.get("/credits.php", creditsController);
|
||||||
@ -238,6 +241,7 @@ apiRouter.post("/findSessions.php", findSessionsController);
|
|||||||
apiRouter.post("/fishmonger.php", fishmongerController);
|
apiRouter.post("/fishmonger.php", fishmongerController);
|
||||||
apiRouter.post("/focus.php", focusController);
|
apiRouter.post("/focus.php", focusController);
|
||||||
apiRouter.post("/fusionTreasures.php", fusionTreasuresController);
|
apiRouter.post("/fusionTreasures.php", fusionTreasuresController);
|
||||||
|
apiRouter.post("/gardening.php", gardeningController);
|
||||||
apiRouter.post("/genericUpdate.php", genericUpdateController);
|
apiRouter.post("/genericUpdate.php", genericUpdateController);
|
||||||
apiRouter.post("/getAlliance.php", getAllianceController);
|
apiRouter.post("/getAlliance.php", getAllianceController);
|
||||||
apiRouter.post("/getFriends.php", getFriendsController);
|
apiRouter.post("/getFriends.php", getFriendsController);
|
||||||
|
@ -10,6 +10,7 @@ import { getAccountInfoController } from "@/src/controllers/custom/getAccountInf
|
|||||||
import { renameAccountController } from "@/src/controllers/custom/renameAccountController";
|
import { renameAccountController } from "@/src/controllers/custom/renameAccountController";
|
||||||
import { ircDroppedController } from "@/src/controllers/custom/ircDroppedController";
|
import { ircDroppedController } from "@/src/controllers/custom/ircDroppedController";
|
||||||
import { unlockAllIntrinsicsController } from "@/src/controllers/custom/unlockAllIntrinsicsController";
|
import { unlockAllIntrinsicsController } from "@/src/controllers/custom/unlockAllIntrinsicsController";
|
||||||
|
import { addMissingMaxRankModsController } from "@/src/controllers/custom/addMissingMaxRankModsController";
|
||||||
|
|
||||||
import { createAccountController } from "@/src/controllers/custom/createAccountController";
|
import { createAccountController } from "@/src/controllers/custom/createAccountController";
|
||||||
import { createMessageController } from "@/src/controllers/custom/createMessageController";
|
import { createMessageController } from "@/src/controllers/custom/createMessageController";
|
||||||
@ -17,10 +18,11 @@ import { addCurrencyController } from "@/src/controllers/custom/addCurrencyContr
|
|||||||
import { addItemsController } from "@/src/controllers/custom/addItemsController";
|
import { addItemsController } from "@/src/controllers/custom/addItemsController";
|
||||||
import { addXpController } from "@/src/controllers/custom/addXpController";
|
import { addXpController } from "@/src/controllers/custom/addXpController";
|
||||||
import { importController } from "@/src/controllers/custom/importController";
|
import { importController } from "@/src/controllers/custom/importController";
|
||||||
|
import { manageQuestsController } from "@/src/controllers/custom/manageQuestsController";
|
||||||
|
import { setEvolutionProgressController } from "@/src/controllers/custom/setEvolutionProgressController";
|
||||||
|
|
||||||
import { getConfigDataController } from "@/src/controllers/custom/getConfigDataController";
|
import { getConfigDataController } from "@/src/controllers/custom/getConfigDataController";
|
||||||
import { updateConfigDataController } from "@/src/controllers/custom/updateConfigDataController";
|
import { updateConfigDataController } from "@/src/controllers/custom/updateConfigDataController";
|
||||||
import { manageQuestsController } from "@/src/controllers/custom/manageQuestsController";
|
|
||||||
|
|
||||||
const customRouter = express.Router();
|
const customRouter = express.Router();
|
||||||
|
|
||||||
@ -34,6 +36,7 @@ customRouter.get("/getAccountInfo", getAccountInfoController);
|
|||||||
customRouter.get("/renameAccount", renameAccountController);
|
customRouter.get("/renameAccount", renameAccountController);
|
||||||
customRouter.get("/ircDropped", ircDroppedController);
|
customRouter.get("/ircDropped", ircDroppedController);
|
||||||
customRouter.get("/unlockAllIntrinsics", unlockAllIntrinsicsController);
|
customRouter.get("/unlockAllIntrinsics", unlockAllIntrinsicsController);
|
||||||
|
customRouter.get("/addMissingMaxRankMods", addMissingMaxRankModsController);
|
||||||
|
|
||||||
customRouter.post("/createAccount", createAccountController);
|
customRouter.post("/createAccount", createAccountController);
|
||||||
customRouter.post("/createMessage", createMessageController);
|
customRouter.post("/createMessage", createMessageController);
|
||||||
@ -42,6 +45,7 @@ customRouter.post("/addItems", addItemsController);
|
|||||||
customRouter.post("/addXp", addXpController);
|
customRouter.post("/addXp", addXpController);
|
||||||
customRouter.post("/import", importController);
|
customRouter.post("/import", importController);
|
||||||
customRouter.post("/manageQuests", manageQuestsController);
|
customRouter.post("/manageQuests", manageQuestsController);
|
||||||
|
customRouter.post("/setEvolutionProgress", setEvolutionProgressController);
|
||||||
|
|
||||||
customRouter.get("/config", getConfigDataController);
|
customRouter.get("/config", getConfigDataController);
|
||||||
customRouter.post("/config", updateConfigDataController);
|
customRouter.post("/config", updateConfigDataController);
|
||||||
|
@ -24,6 +24,7 @@ interface IConfig {
|
|||||||
infiniteEndo?: boolean;
|
infiniteEndo?: boolean;
|
||||||
infiniteRegalAya?: boolean;
|
infiniteRegalAya?: boolean;
|
||||||
infiniteHelminthMaterials?: boolean;
|
infiniteHelminthMaterials?: boolean;
|
||||||
|
dontSubtractConsumables?: boolean;
|
||||||
unlockAllShipFeatures?: boolean;
|
unlockAllShipFeatures?: boolean;
|
||||||
unlockAllShipDecorations?: boolean;
|
unlockAllShipDecorations?: boolean;
|
||||||
unlockAllFlavourItems?: boolean;
|
unlockAllFlavourItems?: boolean;
|
||||||
@ -43,6 +44,7 @@ interface IConfig {
|
|||||||
noKimCooldowns?: boolean;
|
noKimCooldowns?: boolean;
|
||||||
instantResourceExtractorDrones?: boolean;
|
instantResourceExtractorDrones?: boolean;
|
||||||
noResourceExtractorDronesDamage?: boolean;
|
noResourceExtractorDronesDamage?: boolean;
|
||||||
|
skipClanKeyCrafting?: boolean;
|
||||||
noDojoRoomBuildStage?: boolean;
|
noDojoRoomBuildStage?: boolean;
|
||||||
noDojoDecoBuildStage?: boolean;
|
noDojoDecoBuildStage?: boolean;
|
||||||
fastDojoRoomDestruction?: boolean;
|
fastDojoRoomDestruction?: boolean;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Request } from "express";
|
import { Request } from "express";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { addLevelKeys, addRecipes, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
|
||||||
import { Alliance, AllianceMember, Guild, GuildAd, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
|
import { Alliance, AllianceMember, Guild, GuildAd, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
|
||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import {
|
import {
|
||||||
@ -105,6 +105,7 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
|
|||||||
Members: members,
|
Members: members,
|
||||||
Ranks: guild.Ranks,
|
Ranks: guild.Ranks,
|
||||||
Tier: guild.Tier,
|
Tier: guild.Tier,
|
||||||
|
Emblem: guild.Emblem,
|
||||||
Vault: getGuildVault(guild),
|
Vault: getGuildVault(guild),
|
||||||
ActiveDojoColorResearch: guild.ActiveDojoColorResearch,
|
ActiveDojoColorResearch: guild.ActiveDojoColorResearch,
|
||||||
Class: guild.Class,
|
Class: guild.Class,
|
||||||
@ -133,7 +134,7 @@ export const getGuildVault = (guild: TGuildDatabaseDocument): IGuildVault => {
|
|||||||
export const getDojoClient = async (
|
export const getDojoClient = async (
|
||||||
guild: TGuildDatabaseDocument,
|
guild: TGuildDatabaseDocument,
|
||||||
status: number,
|
status: number,
|
||||||
componentId: Types.ObjectId | string | undefined = undefined
|
componentId?: Types.ObjectId | string
|
||||||
): Promise<IDojoClient> => {
|
): Promise<IDojoClient> => {
|
||||||
const dojo: IDojoClient = {
|
const dojo: IDojoClient = {
|
||||||
_id: { $oid: guild._id.toString() },
|
_id: { $oid: guild._id.toString() },
|
||||||
@ -222,6 +223,7 @@ export const getDojoClient = async (
|
|||||||
Type: deco.Type,
|
Type: deco.Type,
|
||||||
Pos: deco.Pos,
|
Pos: deco.Pos,
|
||||||
Rot: deco.Rot,
|
Rot: deco.Rot,
|
||||||
|
Scale: deco.Scale,
|
||||||
Name: deco.Name,
|
Name: deco.Name,
|
||||||
Sockets: deco.Sockets,
|
Sockets: deco.Sockets,
|
||||||
PictureFrameInfo: deco.PictureFrameInfo
|
PictureFrameInfo: deco.PictureFrameInfo
|
||||||
@ -503,7 +505,7 @@ export const hasGuildPermissionEx = (
|
|||||||
|
|
||||||
export const removePigmentsFromGuildMembers = async (guildId: string | Types.ObjectId): Promise<void> => {
|
export const removePigmentsFromGuildMembers = async (guildId: string | Types.ObjectId): Promise<void> => {
|
||||||
const members = await GuildMember.find({ guildId, status: 0 }, "accountId");
|
const members = await GuildMember.find({ guildId, status: 0 }, "accountId");
|
||||||
for (const member of members) {
|
await parallelForeach(members, async member => {
|
||||||
const inventory = await getInventory(member.accountId.toString(), "MiscItems");
|
const inventory = await getInventory(member.accountId.toString(), "MiscItems");
|
||||||
const index = inventory.MiscItems.findIndex(
|
const index = inventory.MiscItems.findIndex(
|
||||||
x => x.ItemType == "/Lotus/Types/Items/Research/DojoColors/GenericDojoColorPigment"
|
x => x.ItemType == "/Lotus/Types/Items/Research/DojoColors/GenericDojoColorPigment"
|
||||||
@ -512,7 +514,7 @@ export const removePigmentsFromGuildMembers = async (guildId: string | Types.Obj
|
|||||||
inventory.MiscItems.splice(index, 1);
|
inventory.MiscItems.splice(index, 1);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const processGuildTechProjectContributionsUpdate = async (
|
export const processGuildTechProjectContributionsUpdate = async (
|
||||||
@ -552,7 +554,7 @@ export const setGuildTechLogState = (
|
|||||||
guild: TGuildDatabaseDocument,
|
guild: TGuildDatabaseDocument,
|
||||||
type: string,
|
type: string,
|
||||||
state: number,
|
state: number,
|
||||||
dateTime: Date | undefined = undefined
|
dateTime?: Date
|
||||||
): boolean => {
|
): boolean => {
|
||||||
guild.TechChanges ??= [];
|
guild.TechChanges ??= [];
|
||||||
const entry = guild.TechChanges.find(x => x.details == type);
|
const entry = guild.TechChanges.find(x => x.details == type);
|
||||||
@ -655,6 +657,32 @@ export const checkClanAscensionHasRequiredContributors = async (guild: TGuildDat
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const giveClanKey = (inventory: TInventoryDatabaseDocument, inventoryChanges?: IInventoryChanges): void => {
|
||||||
|
if (config.skipClanKeyCrafting) {
|
||||||
|
const levelKeyChanges = [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Keys/DojoKey",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
addLevelKeys(inventory, levelKeyChanges);
|
||||||
|
if (inventoryChanges) {
|
||||||
|
combineInventoryChanges(inventoryChanges, { LevelKeys: levelKeyChanges });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const recipeChanges = [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
addRecipes(inventory, recipeChanges);
|
||||||
|
if (inventoryChanges) {
|
||||||
|
combineInventoryChanges(inventoryChanges, { Recipes: recipeChanges });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const removeDojoKeyItems = (inventory: TInventoryDatabaseDocument): IInventoryChanges => {
|
export const removeDojoKeyItems = (inventory: TInventoryDatabaseDocument): IInventoryChanges => {
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import { Types } from "mongoose";
|
|||||||
import {
|
import {
|
||||||
IEquipmentClient,
|
IEquipmentClient,
|
||||||
IEquipmentDatabase,
|
IEquipmentDatabase,
|
||||||
|
IItemConfig,
|
||||||
IOperatorConfigClient,
|
IOperatorConfigClient,
|
||||||
IOperatorConfigDatabase
|
IOperatorConfigDatabase
|
||||||
} from "../types/inventoryTypes/commonInventoryTypes";
|
} from "../types/inventoryTypes/commonInventoryTypes";
|
||||||
@ -37,6 +38,7 @@ import {
|
|||||||
} from "../types/inventoryTypes/inventoryTypes";
|
} from "../types/inventoryTypes/inventoryTypes";
|
||||||
import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
|
import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
|
||||||
import { ILoadoutConfigDatabase, ILoadoutDatabase } from "../types/saveLoadoutTypes";
|
import { ILoadoutConfigDatabase, ILoadoutDatabase } from "../types/saveLoadoutTypes";
|
||||||
|
import { slotNames } from "../types/purchaseTypes";
|
||||||
|
|
||||||
const convertDate = (value: IMongoDate): Date => {
|
const convertDate = (value: IMongoDate): Date => {
|
||||||
return new Date(parseInt(value.$date.$numberLong));
|
return new Date(parseInt(value.$date.$numberLong));
|
||||||
@ -168,10 +170,25 @@ const convertPendingRecipe = (client: IPendingRecipeClient): IPendingRecipeDatab
|
|||||||
const convertNemesis = (client: INemesisClient): INemesisDatabase => {
|
const convertNemesis = (client: INemesisClient): INemesisDatabase => {
|
||||||
return {
|
return {
|
||||||
...client,
|
...client,
|
||||||
|
fp: BigInt(client.fp),
|
||||||
d: convertDate(client.d)
|
d: convertDate(client.d)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Empty objects from live may have been encoded as empty arrays because of PHP.
|
||||||
|
const convertItemConfig = <T extends IItemConfig>(client: T): T => {
|
||||||
|
return {
|
||||||
|
...client,
|
||||||
|
pricol: Array.isArray(client.pricol) ? {} : client.pricol,
|
||||||
|
attcol: Array.isArray(client.attcol) ? {} : client.attcol,
|
||||||
|
sigcol: Array.isArray(client.sigcol) ? {} : client.sigcol,
|
||||||
|
eyecol: Array.isArray(client.eyecol) ? {} : client.eyecol,
|
||||||
|
facial: Array.isArray(client.facial) ? {} : client.facial,
|
||||||
|
cloth: Array.isArray(client.cloth) ? {} : client.cloth,
|
||||||
|
syancol: Array.isArray(client.syancol) ? {} : client.syancol
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<IInventoryClient>): void => {
|
export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<IInventoryClient>): void => {
|
||||||
for (const key of equipmentKeys) {
|
for (const key of equipmentKeys) {
|
||||||
if (client[key] !== undefined) {
|
if (client[key] !== undefined) {
|
||||||
@ -212,20 +229,7 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
replaceArray<IOperatorConfigDatabase>(db[key], client[key].map(convertOperatorConfig));
|
replaceArray<IOperatorConfigDatabase>(db[key], client[key].map(convertOperatorConfig));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const key of [
|
for (const key of slotNames) {
|
||||||
"SuitBin",
|
|
||||||
"WeaponBin",
|
|
||||||
"SentinelBin",
|
|
||||||
"SpaceSuitBin",
|
|
||||||
"SpaceWeaponBin",
|
|
||||||
"PvpBonusLoadoutBin",
|
|
||||||
"PveBonusLoadoutBin",
|
|
||||||
"RandomModBin",
|
|
||||||
"MechBin",
|
|
||||||
"CrewMemberBin",
|
|
||||||
"OperatorAmpBin",
|
|
||||||
"CrewShipSalvageBin"
|
|
||||||
] as const) {
|
|
||||||
if (client[key] !== undefined) {
|
if (client[key] !== undefined) {
|
||||||
replaceSlots(db[key], client[key]);
|
replaceSlots(db[key], client[key]);
|
||||||
}
|
}
|
||||||
@ -363,7 +367,7 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
db.PlayerSkills = client.PlayerSkills;
|
db.PlayerSkills = client.PlayerSkills;
|
||||||
}
|
}
|
||||||
if (client.LotusCustomization !== undefined) {
|
if (client.LotusCustomization !== undefined) {
|
||||||
db.LotusCustomization = client.LotusCustomization;
|
db.LotusCustomization = convertItemConfig(client.LotusCustomization);
|
||||||
}
|
}
|
||||||
if (client.CollectibleSeries !== undefined) {
|
if (client.CollectibleSeries !== undefined) {
|
||||||
db.CollectibleSeries = client.CollectibleSeries;
|
db.CollectibleSeries = client.CollectibleSeries;
|
||||||
|
@ -18,7 +18,6 @@ import {
|
|||||||
IKubrowPetEggDatabase,
|
IKubrowPetEggDatabase,
|
||||||
IKubrowPetEggClient,
|
IKubrowPetEggClient,
|
||||||
ILibraryDailyTaskInfo,
|
ILibraryDailyTaskInfo,
|
||||||
ICalendarProgress,
|
|
||||||
IDroneClient,
|
IDroneClient,
|
||||||
IUpgradeClient,
|
IUpgradeClient,
|
||||||
TPartialStartingGear,
|
TPartialStartingGear,
|
||||||
@ -26,7 +25,10 @@ import {
|
|||||||
ICrewMemberClient,
|
ICrewMemberClient,
|
||||||
Status,
|
Status,
|
||||||
IKubrowPetDetailsDatabase,
|
IKubrowPetDetailsDatabase,
|
||||||
ITraits
|
ITraits,
|
||||||
|
ICalendarProgress,
|
||||||
|
INemesisWeaponTargetFingerprint,
|
||||||
|
INemesisPetTargetFingerprint
|
||||||
} from "@/src/types/inventoryTypes/inventoryTypes";
|
} from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate";
|
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate";
|
||||||
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
|
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
|
||||||
@ -67,6 +69,7 @@ import {
|
|||||||
import { createShip } from "./shipService";
|
import { createShip } from "./shipService";
|
||||||
import {
|
import {
|
||||||
catbrowDetails,
|
catbrowDetails,
|
||||||
|
fromMongoData,
|
||||||
kubrowDetails,
|
kubrowDetails,
|
||||||
kubrowFurPatternsWeights,
|
kubrowFurPatternsWeights,
|
||||||
kubrowWeights,
|
kubrowWeights,
|
||||||
@ -78,6 +81,8 @@ import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
|
|||||||
import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from "./rngService";
|
import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from "./rngService";
|
||||||
import { createMessage } from "./inboxService";
|
import { createMessage } from "./inboxService";
|
||||||
import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
|
import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
|
||||||
|
import { getWorldState } from "./worldStateService";
|
||||||
|
import { getInnateDamageTag, getInnateDamageValue } from "../helpers/nemesisHelpers";
|
||||||
|
|
||||||
export const createInventory = async (
|
export const createInventory = async (
|
||||||
accountOwnerId: Types.ObjectId,
|
accountOwnerId: Types.ObjectId,
|
||||||
@ -91,7 +96,6 @@ export const createInventory = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
inventory.LibraryAvailableDailyTaskInfo = createLibraryDailyTask();
|
inventory.LibraryAvailableDailyTaskInfo = createLibraryDailyTask();
|
||||||
inventory.CalendarProgress = createCalendar();
|
|
||||||
inventory.RewardSeed = generateRewardSeed();
|
inventory.RewardSeed = generateRewardSeed();
|
||||||
inventory.DuviriInfo = {
|
inventory.DuviriInfo = {
|
||||||
Seed: generateRewardSeed(),
|
Seed: generateRewardSeed(),
|
||||||
@ -120,10 +124,15 @@ export const createInventory = async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const generateRewardSeed = (): number => {
|
export const generateRewardSeed = (): bigint => {
|
||||||
const min = -Number.MAX_SAFE_INTEGER;
|
const hiDword = getRandomInt(0, 0x7fffffff);
|
||||||
const max = Number.MAX_SAFE_INTEGER;
|
const loDword = getRandomInt(0, 0xffffffff);
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
let seed = (BigInt(hiDword) << 32n) | BigInt(loDword);
|
||||||
|
if (Math.random() < 0.5) {
|
||||||
|
seed *= -1n;
|
||||||
|
seed -= 1n;
|
||||||
|
}
|
||||||
|
return seed;
|
||||||
};
|
};
|
||||||
|
|
||||||
//TODO: RawUpgrades might need to return a LastAdded
|
//TODO: RawUpgrades might need to return a LastAdded
|
||||||
@ -138,7 +147,7 @@ const awakeningRewards = [
|
|||||||
|
|
||||||
export const addStartingGear = async (
|
export const addStartingGear = async (
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
startingGear: TPartialStartingGear | undefined = undefined
|
startingGear?: TPartialStartingGear
|
||||||
): Promise<IInventoryChanges> => {
|
): Promise<IInventoryChanges> => {
|
||||||
const { LongGuns, Pistols, Suits, Melee } = startingGear || {
|
const { LongGuns, Pistols, Suits, Melee } = startingGear || {
|
||||||
LongGuns: [{ ItemType: "/Lotus/Weapons/Tenno/Rifle/Rifle" }],
|
LongGuns: [{ ItemType: "/Lotus/Weapons/Tenno/Rifle/Rifle" }],
|
||||||
@ -149,23 +158,22 @@ export const addStartingGear = async (
|
|||||||
|
|
||||||
//TODO: properly merge weapon bin changes it is currently static here
|
//TODO: properly merge weapon bin changes it is currently static here
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
addEquipment(inventory, "LongGuns", LongGuns[0].ItemType, undefined, inventoryChanges);
|
addEquipment(inventory, "LongGuns", LongGuns[0].ItemType, { IsNew: false }, inventoryChanges);
|
||||||
addEquipment(inventory, "Pistols", Pistols[0].ItemType, undefined, inventoryChanges);
|
addEquipment(inventory, "Pistols", Pistols[0].ItemType, { IsNew: false }, inventoryChanges);
|
||||||
addEquipment(inventory, "Melee", Melee[0].ItemType, undefined, inventoryChanges);
|
addEquipment(inventory, "Melee", Melee[0].ItemType, { IsNew: false }, inventoryChanges);
|
||||||
await addPowerSuit(inventory, Suits[0].ItemType, inventoryChanges);
|
await addPowerSuit(inventory, Suits[0].ItemType, { IsNew: false }, inventoryChanges);
|
||||||
addEquipment(
|
addEquipment(
|
||||||
inventory,
|
inventory,
|
||||||
"DataKnives",
|
"DataKnives",
|
||||||
"/Lotus/Weapons/Tenno/HackingDevices/TnHackingDevice/TnHackingDeviceWeapon",
|
"/Lotus/Weapons/Tenno/HackingDevices/TnHackingDevice/TnHackingDeviceWeapon",
|
||||||
undefined,
|
{ XP: 450_000, IsNew: false },
|
||||||
inventoryChanges,
|
inventoryChanges
|
||||||
{ XP: 450_000 }
|
|
||||||
);
|
);
|
||||||
addEquipment(
|
addEquipment(
|
||||||
inventory,
|
inventory,
|
||||||
"Scoops",
|
"Scoops",
|
||||||
"/Lotus/Weapons/Tenno/Speedball/SpeedballWeaponTest",
|
"/Lotus/Weapons/Tenno/Speedball/SpeedballWeaponTest",
|
||||||
undefined,
|
{ IsNew: false },
|
||||||
inventoryChanges
|
inventoryChanges
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -208,6 +216,15 @@ export const combineInventoryChanges = (InventoryChanges: IInventoryChanges, del
|
|||||||
for (const key in delta) {
|
for (const key in delta) {
|
||||||
if (!(key in InventoryChanges)) {
|
if (!(key in InventoryChanges)) {
|
||||||
InventoryChanges[key] = delta[key];
|
InventoryChanges[key] = delta[key];
|
||||||
|
} else if (key == "MiscItems") {
|
||||||
|
for (const deltaItem of delta[key]!) {
|
||||||
|
const existing = InventoryChanges[key]!.find(x => x.ItemType == deltaItem.ItemType);
|
||||||
|
if (existing) {
|
||||||
|
existing.ItemCount += deltaItem.ItemCount;
|
||||||
|
} else {
|
||||||
|
InventoryChanges[key]!.push(deltaItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (Array.isArray(delta[key])) {
|
} else if (Array.isArray(delta[key])) {
|
||||||
const left = InventoryChanges[key] as object[];
|
const left = InventoryChanges[key] as object[];
|
||||||
const right: object[] = delta[key];
|
const right: object[] = delta[key];
|
||||||
@ -240,7 +257,7 @@ export const combineInventoryChanges = (InventoryChanges: IInventoryChanges, del
|
|||||||
|
|
||||||
export const getInventory = async (
|
export const getInventory = async (
|
||||||
accountOwnerId: string,
|
accountOwnerId: string,
|
||||||
projection: string | undefined = undefined
|
projection?: string
|
||||||
): Promise<TInventoryDatabaseDocument> => {
|
): Promise<TInventoryDatabaseDocument> => {
|
||||||
const inventory = await Inventory.findOne({ accountOwnerId: accountOwnerId }, projection);
|
const inventory = await Inventory.findOne({ accountOwnerId: accountOwnerId }, projection);
|
||||||
|
|
||||||
@ -314,7 +331,8 @@ export const addItem = async (
|
|||||||
typeName: string,
|
typeName: string,
|
||||||
quantity: number = 1,
|
quantity: number = 1,
|
||||||
premiumPurchase: boolean = false,
|
premiumPurchase: boolean = false,
|
||||||
seed?: bigint
|
seed?: bigint,
|
||||||
|
targetFingerprint?: string
|
||||||
): Promise<IInventoryChanges> => {
|
): Promise<IInventoryChanges> => {
|
||||||
// Bundles are technically StoreItems but a) they don't have a normal counterpart, and b) they are used in non-StoreItem contexts, e.g. email attachments.
|
// Bundles are technically StoreItems but a) they don't have a normal counterpart, and b) they are used in non-StoreItem contexts, e.g. email attachments.
|
||||||
if (typeName in ExportBundles) {
|
if (typeName in ExportBundles) {
|
||||||
@ -469,6 +487,10 @@ export const addItem = async (
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (typeName in ExportGear) {
|
if (typeName in ExportGear) {
|
||||||
|
// Multipling by purchase quantity for gear because:
|
||||||
|
// - The Saya's Vigil scanner message has it as a non-counted attachment.
|
||||||
|
// - Blueprints for Ancient Protector Specter, Shield Osprey Specter, etc. have num=1 despite giving their purchaseQuantity.
|
||||||
|
quantity *= ExportGear[typeName].purchaseQuantity ?? 1;
|
||||||
const consumablesChanges = [
|
const consumablesChanges = [
|
||||||
{
|
{
|
||||||
ItemType: typeName,
|
ItemType: typeName,
|
||||||
@ -517,14 +539,13 @@ export const addItem = async (
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const inventoryChanges = addEquipment(
|
if (targetFingerprint) {
|
||||||
inventory,
|
const targetFingerprintObj = JSON.parse(targetFingerprint) as INemesisWeaponTargetFingerprint;
|
||||||
weapon.productCategory,
|
defaultOverwrites.UpgradeType = targetFingerprintObj.ItemType;
|
||||||
typeName,
|
defaultOverwrites.UpgradeFingerprint = JSON.stringify(targetFingerprintObj.UpgradeFingerprint);
|
||||||
[],
|
defaultOverwrites.ItemName = targetFingerprintObj.Name;
|
||||||
{},
|
}
|
||||||
defaultOverwrites
|
const inventoryChanges = addEquipment(inventory, weapon.productCategory, typeName, defaultOverwrites);
|
||||||
);
|
|
||||||
if (weapon.additionalItems) {
|
if (weapon.additionalItems) {
|
||||||
for (const item of weapon.additionalItems) {
|
for (const item of weapon.additionalItems) {
|
||||||
combineInventoryChanges(inventoryChanges, await addItem(inventory, item, 1));
|
combineInventoryChanges(inventoryChanges, await addItem(inventory, item, 1));
|
||||||
@ -532,7 +553,32 @@ export const addItem = async (
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
...inventoryChanges,
|
...inventoryChanges,
|
||||||
...occupySlot(inventory, InventorySlot.WEAPONS, premiumPurchase)
|
...occupySlot(
|
||||||
|
inventory,
|
||||||
|
productCategoryToInventoryBin(weapon.productCategory) ?? InventorySlot.WEAPONS,
|
||||||
|
premiumPurchase
|
||||||
|
)
|
||||||
|
};
|
||||||
|
} else if (targetFingerprint) {
|
||||||
|
// Sister's Hound
|
||||||
|
const targetFingerprintObj = JSON.parse(targetFingerprint) as INemesisPetTargetFingerprint;
|
||||||
|
const head = targetFingerprintObj.Parts[0];
|
||||||
|
const defaultOverwrites: Partial<IEquipmentDatabase> = {
|
||||||
|
ModularParts: targetFingerprintObj.Parts,
|
||||||
|
ItemName: targetFingerprintObj.Name,
|
||||||
|
Configs: applyDefaultUpgrades(inventory, ExportWeapons[head].defaultUpgrades)
|
||||||
|
};
|
||||||
|
const itemType = {
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadA":
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetAPowerSuit",
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadB":
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetBPowerSuit",
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadC":
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetCPowerSuit"
|
||||||
|
}[head] as string;
|
||||||
|
return {
|
||||||
|
...addEquipment(inventory, "MoaPets", itemType, defaultOverwrites),
|
||||||
|
...occupySlot(inventory, InventorySlot.SENTINELS, premiumPurchase)
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// Modular weapon parts
|
// Modular weapon parts
|
||||||
@ -580,7 +626,7 @@ export const addItem = async (
|
|||||||
}
|
}
|
||||||
if (typeName in ExportFusionBundles) {
|
if (typeName in ExportFusionBundles) {
|
||||||
const fusionPointsTotal = ExportFusionBundles[typeName].fusionPoints * quantity;
|
const fusionPointsTotal = ExportFusionBundles[typeName].fusionPoints * quantity;
|
||||||
inventory.FusionPoints += fusionPointsTotal;
|
addFusionPoints(inventory, fusionPointsTotal);
|
||||||
return {
|
return {
|
||||||
FusionPoints: fusionPointsTotal
|
FusionPoints: fusionPointsTotal
|
||||||
};
|
};
|
||||||
@ -621,12 +667,9 @@ export const addItem = async (
|
|||||||
switch (typeName.substr(1).split("/")[2]) {
|
switch (typeName.substr(1).split("/")[2]) {
|
||||||
default: {
|
default: {
|
||||||
return {
|
return {
|
||||||
...(await addPowerSuit(
|
...(await addPowerSuit(inventory, typeName, {
|
||||||
inventory,
|
Features: premiumPurchase ? EquipmentFeatures.DOUBLE_CAPACITY : undefined
|
||||||
typeName,
|
})),
|
||||||
{},
|
|
||||||
premiumPurchase ? EquipmentFeatures.DOUBLE_CAPACITY : undefined
|
|
||||||
)),
|
|
||||||
...occupySlot(inventory, InventorySlot.SUITS, premiumPurchase)
|
...occupySlot(inventory, InventorySlot.SUITS, premiumPurchase)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -821,7 +864,8 @@ const addSentinel = (
|
|||||||
|
|
||||||
const features = premiumPurchase ? EquipmentFeatures.DOUBLE_CAPACITY : undefined;
|
const features = premiumPurchase ? EquipmentFeatures.DOUBLE_CAPACITY : undefined;
|
||||||
const sentinelIndex =
|
const sentinelIndex =
|
||||||
inventory.Sentinels.push({ ItemType: sentinelName, Configs: configs, XP: 0, Features: features }) - 1;
|
inventory.Sentinels.push({ ItemType: sentinelName, Configs: configs, XP: 0, Features: features, IsNew: true }) -
|
||||||
|
1;
|
||||||
inventoryChanges.Sentinels ??= [];
|
inventoryChanges.Sentinels ??= [];
|
||||||
inventoryChanges.Sentinels.push(inventory.Sentinels[sentinelIndex].toJSON<IEquipmentClient>());
|
inventoryChanges.Sentinels.push(inventory.Sentinels[sentinelIndex].toJSON<IEquipmentClient>());
|
||||||
|
|
||||||
@ -845,8 +889,8 @@ const addSentinelWeapon = (
|
|||||||
export const addPowerSuit = async (
|
export const addPowerSuit = async (
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
powersuitName: string,
|
powersuitName: string,
|
||||||
inventoryChanges: IInventoryChanges = {},
|
defaultOverwrites?: Partial<IEquipmentDatabase>,
|
||||||
features: number | undefined = undefined
|
inventoryChanges: IInventoryChanges = {}
|
||||||
): Promise<IInventoryChanges> => {
|
): Promise<IInventoryChanges> => {
|
||||||
const powersuit = ExportWarframes[powersuitName] as IPowersuit | undefined;
|
const powersuit = ExportWarframes[powersuitName] as IPowersuit | undefined;
|
||||||
const exalted = powersuit?.exalted ?? [];
|
const exalted = powersuit?.exalted ?? [];
|
||||||
@ -860,15 +904,20 @@ export const addPowerSuit = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const suitIndex =
|
const suit: Omit<IEquipmentDatabase, "_id"> = Object.assign(
|
||||||
inventory.Suits.push({
|
{
|
||||||
ItemType: powersuitName,
|
ItemType: powersuitName,
|
||||||
Configs: [],
|
Configs: [],
|
||||||
UpgradeVer: 101,
|
UpgradeVer: 101,
|
||||||
XP: 0,
|
XP: 0,
|
||||||
Features: features,
|
|
||||||
IsNew: true
|
IsNew: true
|
||||||
}) - 1;
|
},
|
||||||
|
defaultOverwrites
|
||||||
|
);
|
||||||
|
if (!suit.IsNew) {
|
||||||
|
suit.IsNew = undefined;
|
||||||
|
}
|
||||||
|
const suitIndex = inventory.Suits.push(suit) - 1;
|
||||||
inventoryChanges.Suits ??= [];
|
inventoryChanges.Suits ??= [];
|
||||||
inventoryChanges.Suits.push(inventory.Suits[suitIndex].toJSON<IEquipmentClient>());
|
inventoryChanges.Suits.push(inventory.Suits[suitIndex].toJSON<IEquipmentClient>());
|
||||||
return inventoryChanges;
|
return inventoryChanges;
|
||||||
@ -878,7 +927,7 @@ export const addMechSuit = async (
|
|||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
mechsuitName: string,
|
mechsuitName: string,
|
||||||
inventoryChanges: IInventoryChanges = {},
|
inventoryChanges: IInventoryChanges = {},
|
||||||
features: number | undefined = undefined
|
features?: number
|
||||||
): Promise<IInventoryChanges> => {
|
): Promise<IInventoryChanges> => {
|
||||||
const powersuit = ExportWarframes[mechsuitName] as IPowersuit | undefined;
|
const powersuit = ExportWarframes[mechsuitName] as IPowersuit | undefined;
|
||||||
const exalted = powersuit?.exalted ?? [];
|
const exalted = powersuit?.exalted ?? [];
|
||||||
@ -930,7 +979,7 @@ export const addSpaceSuit = (
|
|||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
spacesuitName: string,
|
spacesuitName: string,
|
||||||
inventoryChanges: IInventoryChanges = {},
|
inventoryChanges: IInventoryChanges = {},
|
||||||
features: number | undefined = undefined
|
features?: number
|
||||||
): IInventoryChanges => {
|
): IInventoryChanges => {
|
||||||
const suitIndex =
|
const suitIndex =
|
||||||
inventory.SpaceSuits.push({
|
inventory.SpaceSuits.push({
|
||||||
@ -1069,6 +1118,15 @@ export const updateCurrency = (
|
|||||||
return currencyChanges;
|
return currencyChanges;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const addFusionPoints = (inventory: TInventoryDatabaseDocument, add: number): number => {
|
||||||
|
if (inventory.FusionPoints + add > 2147483647) {
|
||||||
|
logger.warn(`capping FusionPoints balance at 2147483647`);
|
||||||
|
add = 2147483647 - inventory.FusionPoints;
|
||||||
|
}
|
||||||
|
inventory.FusionPoints += add;
|
||||||
|
return add;
|
||||||
|
};
|
||||||
|
|
||||||
const standingLimitBinToInventoryKey: Record<
|
const standingLimitBinToInventoryKey: Record<
|
||||||
Exclude<TStandingLimitBin, "STANDING_LIMIT_BIN_NONE">,
|
Exclude<TStandingLimitBin, "STANDING_LIMIT_BIN_NONE">,
|
||||||
keyof IDailyAffiliations
|
keyof IDailyAffiliations
|
||||||
@ -1180,20 +1238,21 @@ export const addEquipment = (
|
|||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
category: TEquipmentKey,
|
category: TEquipmentKey,
|
||||||
type: string,
|
type: string,
|
||||||
modularParts: string[] | undefined = undefined,
|
defaultOverwrites?: Partial<IEquipmentDatabase>,
|
||||||
inventoryChanges: IInventoryChanges = {},
|
inventoryChanges: IInventoryChanges = {}
|
||||||
defaultOverwrites: Partial<IEquipmentDatabase> | undefined = undefined
|
|
||||||
): IInventoryChanges => {
|
): IInventoryChanges => {
|
||||||
const equipment = Object.assign(
|
const equipment: Omit<IEquipmentDatabase, "_id"> = Object.assign(
|
||||||
{
|
{
|
||||||
ItemType: type,
|
ItemType: type,
|
||||||
Configs: [],
|
Configs: [],
|
||||||
XP: 0,
|
XP: 0,
|
||||||
ModularParts: modularParts,
|
IsNew: category != "CrewShipWeapons" && category != "CrewShipSalvagedWeapons"
|
||||||
IsNew: category != "CrewShipWeapons" && category != "CrewShipSalvagedWeapons" ? true : undefined
|
|
||||||
},
|
},
|
||||||
defaultOverwrites
|
defaultOverwrites
|
||||||
);
|
);
|
||||||
|
if (!equipment.IsNew) {
|
||||||
|
equipment.IsNew = undefined;
|
||||||
|
}
|
||||||
const index = inventory[category].push(equipment) - 1;
|
const index = inventory[category].push(equipment) - 1;
|
||||||
|
|
||||||
inventoryChanges[category] ??= [];
|
inventoryChanges[category] ??= [];
|
||||||
@ -1222,12 +1281,16 @@ export const addSkin = (
|
|||||||
typeName: string,
|
typeName: string,
|
||||||
inventoryChanges: IInventoryChanges = {}
|
inventoryChanges: IInventoryChanges = {}
|
||||||
): IInventoryChanges => {
|
): IInventoryChanges => {
|
||||||
const index = inventory.WeaponSkins.push({ ItemType: typeName, IsNew: true }) - 1;
|
if (inventory.WeaponSkins.find(x => x.ItemType == typeName)) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
logger.debug(`refusing to add WeaponSkin ${typeName} because account already owns it`);
|
||||||
inventoryChanges.WeaponSkins ??= [];
|
} else {
|
||||||
(inventoryChanges.WeaponSkins as IWeaponSkinClient[]).push(
|
const index = inventory.WeaponSkins.push({ ItemType: typeName, IsNew: true }) - 1;
|
||||||
inventory.WeaponSkins[index].toJSON<IWeaponSkinClient>()
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
);
|
inventoryChanges.WeaponSkins ??= [];
|
||||||
|
(inventoryChanges.WeaponSkins as IWeaponSkinClient[]).push(
|
||||||
|
inventory.WeaponSkins[index].toJSON<IWeaponSkinClient>()
|
||||||
|
);
|
||||||
|
}
|
||||||
return inventoryChanges;
|
return inventoryChanges;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1413,21 +1476,20 @@ export const addEmailItem = async (
|
|||||||
return inventoryChanges;
|
return inventoryChanges;
|
||||||
};
|
};
|
||||||
|
|
||||||
//TODO: wrong id is not erroring
|
export const applyClientEquipmentUpdates = (
|
||||||
export const addGearExpByCategory = (
|
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
gearArray: IEquipmentClient[],
|
gearArray: IEquipmentClient[],
|
||||||
categoryName: TEquipmentKey
|
categoryName: TEquipmentKey
|
||||||
): void => {
|
): void => {
|
||||||
const category = inventory[categoryName];
|
const category = inventory[categoryName];
|
||||||
|
|
||||||
gearArray.forEach(({ ItemId, XP }) => {
|
gearArray.forEach(({ ItemId, XP, InfestationDate }) => {
|
||||||
if (!XP) {
|
const item = category.id(ItemId.$oid);
|
||||||
return;
|
if (!item) {
|
||||||
|
throw new Error(`No item with id ${ItemId.$oid} in ${categoryName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const item = category.id(ItemId.$oid);
|
if (XP) {
|
||||||
if (item) {
|
|
||||||
item.XP ??= 0;
|
item.XP ??= 0;
|
||||||
item.XP += XP;
|
item.XP += XP;
|
||||||
|
|
||||||
@ -1442,9 +1504,29 @@ export const addGearExpByCategory = (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (InfestationDate) {
|
||||||
|
item.InfestationDate = fromMongoData(InfestationDate);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const addMiscItem = (
|
||||||
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
type: string,
|
||||||
|
count: number,
|
||||||
|
inventoryChanges: IInventoryChanges
|
||||||
|
): void => {
|
||||||
|
const miscItemChanges: IMiscItem[] = [
|
||||||
|
{
|
||||||
|
ItemType: type,
|
||||||
|
ItemCount: count
|
||||||
|
}
|
||||||
|
];
|
||||||
|
addMiscItems(inventory, miscItemChanges);
|
||||||
|
combineInventoryChanges(inventoryChanges, { MiscItems: miscItemChanges });
|
||||||
|
};
|
||||||
|
|
||||||
export const addMiscItems = (inventory: TInventoryDatabaseDocument, itemsArray: IMiscItem[]): void => {
|
export const addMiscItems = (inventory: TInventoryDatabaseDocument, itemsArray: IMiscItem[]): void => {
|
||||||
const { MiscItems } = inventory;
|
const { MiscItems } = inventory;
|
||||||
|
|
||||||
@ -1724,7 +1806,7 @@ export const addKeyChainItems = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const createLibraryDailyTask = (): ILibraryDailyTaskInfo => {
|
export const createLibraryDailyTask = (): ILibraryDailyTaskInfo => {
|
||||||
const enemyTypes = getRandomElement(libraryDailyTasks);
|
const enemyTypes = getRandomElement(libraryDailyTasks)!;
|
||||||
const enemyAvatar = ExportEnemies.avatars[enemyTypes[0]];
|
const enemyAvatar = ExportEnemies.avatars[enemyTypes[0]];
|
||||||
const scansRequired = getRandomInt(2, 4);
|
const scansRequired = getRandomInt(2, 4);
|
||||||
return {
|
return {
|
||||||
@ -1738,20 +1820,6 @@ export const createLibraryDailyTask = (): ILibraryDailyTaskInfo => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const createCalendar = (): ICalendarProgress => {
|
|
||||||
return {
|
|
||||||
Version: 19,
|
|
||||||
Iteration: 2,
|
|
||||||
YearProgress: { Upgrades: [] },
|
|
||||||
SeasonProgress: {
|
|
||||||
SeasonType: "CST_SPRING",
|
|
||||||
LastCompletedDayIdx: -1,
|
|
||||||
LastCompletedChallengeDayIdx: -1,
|
|
||||||
ActivatedChallenges: []
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setupKahlSyndicate = (inventory: TInventoryDatabaseDocument): void => {
|
export const setupKahlSyndicate = (inventory: TInventoryDatabaseDocument): void => {
|
||||||
inventory.Affiliations.push({
|
inventory.Affiliations.push({
|
||||||
Title: 1,
|
Title: 1,
|
||||||
@ -1787,4 +1855,132 @@ export const cleanupInventory = (inventory: TInventoryDatabaseDocument): void =>
|
|||||||
logger.debug(`removing FreeFavorsEarned from LibrarySyndicate`);
|
logger.debug(`removing FreeFavorsEarned from LibrarySyndicate`);
|
||||||
LibrarySyndicate.FreeFavorsEarned = undefined;
|
LibrarySyndicate.FreeFavorsEarned = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inventory.LotusCustomization) {
|
||||||
|
if (
|
||||||
|
Array.isArray(inventory.LotusCustomization.attcol) ||
|
||||||
|
Array.isArray(inventory.LotusCustomization.sigcol) ||
|
||||||
|
Array.isArray(inventory.LotusCustomization.eyecol) ||
|
||||||
|
Array.isArray(inventory.LotusCustomization.facial) ||
|
||||||
|
Array.isArray(inventory.LotusCustomization.cloth) ||
|
||||||
|
Array.isArray(inventory.LotusCustomization.syancol)
|
||||||
|
) {
|
||||||
|
logger.debug(`fixing empty objects represented as empty arrays in LotusCustomization`);
|
||||||
|
inventory.LotusCustomization.attcol = {};
|
||||||
|
inventory.LotusCustomization.sigcol = {};
|
||||||
|
inventory.LotusCustomization.eyecol = {};
|
||||||
|
inventory.LotusCustomization.facial = {};
|
||||||
|
inventory.LotusCustomization.cloth = {};
|
||||||
|
inventory.LotusCustomization.syancol = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getCalendarProgress = (inventory: TInventoryDatabaseDocument): ICalendarProgress => {
|
||||||
|
const currentSeason = getWorldState().KnownCalendarSeasons[0];
|
||||||
|
|
||||||
|
if (!inventory.CalendarProgress) {
|
||||||
|
inventory.CalendarProgress = {
|
||||||
|
Version: 19,
|
||||||
|
Iteration: currentSeason.YearIteration,
|
||||||
|
YearProgress: {
|
||||||
|
Upgrades: []
|
||||||
|
},
|
||||||
|
SeasonProgress: {
|
||||||
|
SeasonType: currentSeason.Season,
|
||||||
|
LastCompletedDayIdx: 0,
|
||||||
|
LastCompletedChallengeDayIdx: 0,
|
||||||
|
ActivatedChallenges: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const yearRolledOver = inventory.CalendarProgress.Iteration != currentSeason.YearIteration;
|
||||||
|
if (yearRolledOver) {
|
||||||
|
inventory.CalendarProgress.Iteration = currentSeason.YearIteration;
|
||||||
|
inventory.CalendarProgress.YearProgress.Upgrades = [];
|
||||||
|
}
|
||||||
|
if (yearRolledOver || inventory.CalendarProgress.SeasonProgress.SeasonType != currentSeason.Season) {
|
||||||
|
inventory.CalendarProgress.SeasonProgress.SeasonType = currentSeason.Season;
|
||||||
|
inventory.CalendarProgress.SeasonProgress.LastCompletedDayIdx = -1;
|
||||||
|
inventory.CalendarProgress.SeasonProgress.LastCompletedChallengeDayIdx = -1;
|
||||||
|
inventory.CalendarProgress.SeasonProgress.ActivatedChallenges = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return inventory.CalendarProgress;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const giveNemesisWeaponRecipe = (
|
||||||
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
weaponType: string,
|
||||||
|
nemesisName: string = "AGOR ROK",
|
||||||
|
weaponLoc?: string,
|
||||||
|
KillingSuit: string = "/Lotus/Powersuits/Ember/Ember",
|
||||||
|
fp: bigint = generateRewardSeed()
|
||||||
|
): void => {
|
||||||
|
if (!weaponLoc) {
|
||||||
|
weaponLoc = ExportWeapons[weaponType].name;
|
||||||
|
}
|
||||||
|
const recipeType = Object.entries(ExportRecipes).find(arr => arr[1].resultType == weaponType)![0];
|
||||||
|
addRecipes(inventory, [
|
||||||
|
{
|
||||||
|
ItemType: recipeType,
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
inventory.PendingRecipes.push({
|
||||||
|
CompletionDate: new Date(),
|
||||||
|
ItemType: recipeType,
|
||||||
|
TargetFingerprint: JSON.stringify({
|
||||||
|
ItemType: "/Lotus/Weapons/Grineer/KuvaLich/Upgrades/InnateDamageRandomMod",
|
||||||
|
UpgradeFingerprint: {
|
||||||
|
compat: weaponType,
|
||||||
|
buffs: [
|
||||||
|
{
|
||||||
|
Tag: getInnateDamageTag(KillingSuit),
|
||||||
|
Value: getInnateDamageValue(fp)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
Name: weaponLoc + "|" + nemesisName
|
||||||
|
} satisfies INemesisWeaponTargetFingerprint)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const giveNemesisPetRecipe = (inventory: TInventoryDatabaseDocument, nemesisName: string = "AGOR ROK"): void => {
|
||||||
|
const head = getRandomElement([
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadA",
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadB",
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadC"
|
||||||
|
])!;
|
||||||
|
const body = getRandomElement([
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyA",
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyB",
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyC"
|
||||||
|
])!;
|
||||||
|
const legs = getRandomElement([
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsA",
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsB",
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsC"
|
||||||
|
])!;
|
||||||
|
const tail = getRandomElement([
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailA",
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailB",
|
||||||
|
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailC"
|
||||||
|
])!;
|
||||||
|
const recipeType = Object.entries(ExportRecipes).find(arr => arr[1].resultType == head)![0];
|
||||||
|
addRecipes(inventory, [
|
||||||
|
{
|
||||||
|
ItemType: recipeType,
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
inventory.PendingRecipes.push({
|
||||||
|
CompletionDate: new Date(),
|
||||||
|
ItemType: recipeType,
|
||||||
|
TargetFingerprint: JSON.stringify({
|
||||||
|
Parts: [head, body, legs, tail],
|
||||||
|
Name: "/Lotus/Language/Pets/ZanukaPetName|" + nemesisName
|
||||||
|
} satisfies INemesisPetTargetFingerprint)
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
@ -17,6 +17,7 @@ import {
|
|||||||
dict_uk,
|
dict_uk,
|
||||||
dict_zh,
|
dict_zh,
|
||||||
ExportArcanes,
|
ExportArcanes,
|
||||||
|
ExportBoosters,
|
||||||
ExportCustoms,
|
ExportCustoms,
|
||||||
ExportDrones,
|
ExportDrones,
|
||||||
ExportGear,
|
ExportGear,
|
||||||
@ -217,15 +218,30 @@ export const convertInboxMessage = (message: IInboxMessage): IMessage => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const isStoreItem = (type: string): boolean => {
|
export const isStoreItem = (type: string): boolean => {
|
||||||
return type.startsWith("/Lotus/StoreItems/");
|
return type.startsWith("/Lotus/StoreItems/") || type in ExportBoosters;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const toStoreItem = (type: string): string => {
|
export const toStoreItem = (type: string): string => {
|
||||||
|
if (type.startsWith("/Lotus/Types/StoreItems/Boosters/")) {
|
||||||
|
const boosterEntry = Object.entries(ExportBoosters).find(arr => arr[1].typeName == type);
|
||||||
|
if (boosterEntry) {
|
||||||
|
return boosterEntry[0];
|
||||||
|
}
|
||||||
|
throw new Error(`could not convert ${type} to a store item`);
|
||||||
|
}
|
||||||
return "/Lotus/StoreItems/" + type.substring("/Lotus/".length);
|
return "/Lotus/StoreItems/" + type.substring("/Lotus/".length);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fromStoreItem = (type: string): string => {
|
export const fromStoreItem = (type: string): string => {
|
||||||
return "/Lotus/" + type.substring("/Lotus/StoreItems/".length);
|
if (type.startsWith("/Lotus/StoreItems/")) {
|
||||||
|
return "/Lotus/" + type.substring("/Lotus/StoreItems/".length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type in ExportBoosters) {
|
||||||
|
return ExportBoosters[type].typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`${type} is not a store item`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDefaultUpgrades = (parts: string[]): IDefaultUpgrade[] | undefined => {
|
export const getDefaultUpgrades = (parts: string[]): IDefaultUpgrade[] | undefined => {
|
||||||
|
@ -77,7 +77,6 @@ const getRandomLoginReward = (rng: CRng, day: number, inventory: TInventoryDatab
|
|||||||
const reward = rng.randomReward(randomRewards)!;
|
const reward = rng.randomReward(randomRewards)!;
|
||||||
//const reward = randomRewards.find(x => x.RewardType == "RT_BOOSTER")!;
|
//const reward = randomRewards.find(x => x.RewardType == "RT_BOOSTER")!;
|
||||||
if (reward.RewardType == "RT_RANDOM_RECIPE") {
|
if (reward.RewardType == "RT_RANDOM_RECIPE") {
|
||||||
// Not very faithful implementation but roughly the same idea
|
|
||||||
const masteredItems = new Set();
|
const masteredItems = new Set();
|
||||||
for (const entry of inventory.XPInfo) {
|
for (const entry of inventory.XPInfo) {
|
||||||
masteredItems.add(entry.ItemType);
|
masteredItems.add(entry.ItemType);
|
||||||
@ -95,15 +94,15 @@ const getRandomLoginReward = (rng: CRng, day: number, inventory: TInventoryDatab
|
|||||||
}
|
}
|
||||||
const eligibleRecipes: string[] = [];
|
const eligibleRecipes: string[] = [];
|
||||||
for (const [uniqueName, recipe] of Object.entries(ExportRecipes)) {
|
for (const [uniqueName, recipe] of Object.entries(ExportRecipes)) {
|
||||||
if (unmasteredItems.has(recipe.resultType)) {
|
if (!recipe.excludeFromMarket && unmasteredItems.has(recipe.resultType)) {
|
||||||
eligibleRecipes.push(uniqueName);
|
eligibleRecipes.push(uniqueName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (eligibleRecipes.length == 0) {
|
if (eligibleRecipes.length == 0) {
|
||||||
// This account has all warframes and weapons already mastered (filthy cheater), need a different reward.
|
// This account has all applicable warframes and weapons already mastered (filthy cheater), need a different reward.
|
||||||
return getRandomLoginReward(rng, day, inventory);
|
return getRandomLoginReward(rng, day, inventory);
|
||||||
}
|
}
|
||||||
reward.StoreItemType = toStoreItem(rng.randomElement(eligibleRecipes));
|
reward.StoreItemType = toStoreItem(rng.randomElement(eligibleRecipes)!);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
//_id: toOid(new Types.ObjectId()),
|
//_id: toOid(new Types.ObjectId()),
|
||||||
|
@ -19,8 +19,8 @@ import {
|
|||||||
addCrewShipRawSalvage,
|
addCrewShipRawSalvage,
|
||||||
addEmailItem,
|
addEmailItem,
|
||||||
addFocusXpIncreases,
|
addFocusXpIncreases,
|
||||||
|
addFusionPoints,
|
||||||
addFusionTreasures,
|
addFusionTreasures,
|
||||||
addGearExpByCategory,
|
|
||||||
addItem,
|
addItem,
|
||||||
addLevelKeys,
|
addLevelKeys,
|
||||||
addLoreFragmentScans,
|
addLoreFragmentScans,
|
||||||
@ -29,9 +29,14 @@ import {
|
|||||||
addMods,
|
addMods,
|
||||||
addRecipes,
|
addRecipes,
|
||||||
addShipDecorations,
|
addShipDecorations,
|
||||||
|
addSkin,
|
||||||
addStanding,
|
addStanding,
|
||||||
|
applyClientEquipmentUpdates,
|
||||||
combineInventoryChanges,
|
combineInventoryChanges,
|
||||||
generateRewardSeed,
|
generateRewardSeed,
|
||||||
|
getCalendarProgress,
|
||||||
|
giveNemesisPetRecipe,
|
||||||
|
giveNemesisWeaponRecipe,
|
||||||
updateCurrency,
|
updateCurrency,
|
||||||
updateSyndicate
|
updateSyndicate
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
@ -43,14 +48,14 @@ import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/invento
|
|||||||
import { getEntriesUnsafe } from "@/src/utils/ts-utils";
|
import { getEntriesUnsafe } from "@/src/utils/ts-utils";
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { handleStoreItemAcquisition } from "./purchaseService";
|
import { handleStoreItemAcquisition } from "./purchaseService";
|
||||||
import { IMissionReward } from "../types/missionTypes";
|
import { IMissionCredits, IMissionReward } from "../types/missionTypes";
|
||||||
import { crackRelic } from "@/src/helpers/relicHelper";
|
import { crackRelic } from "@/src/helpers/relicHelper";
|
||||||
import { createMessage } from "./inboxService";
|
import { createMessage } from "./inboxService";
|
||||||
import kuriaMessage50 from "@/static/fixed_responses/kuriaMessages/fiftyPercent.json";
|
import kuriaMessage50 from "@/static/fixed_responses/kuriaMessages/fiftyPercent.json";
|
||||||
import kuriaMessage75 from "@/static/fixed_responses/kuriaMessages/seventyFivePercent.json";
|
import kuriaMessage75 from "@/static/fixed_responses/kuriaMessages/seventyFivePercent.json";
|
||||||
import kuriaMessage100 from "@/static/fixed_responses/kuriaMessages/oneHundredPercent.json";
|
import kuriaMessage100 from "@/static/fixed_responses/kuriaMessages/oneHundredPercent.json";
|
||||||
import conservationAnimals from "@/static/fixed_responses/conservationAnimals.json";
|
import conservationAnimals from "@/static/fixed_responses/conservationAnimals.json";
|
||||||
import { getInfNodes } from "@/src/helpers/nemesisHelpers";
|
import { getInfNodes, getWeaponsForManifest, sendCodaFinishedMessage } 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";
|
||||||
import { getLiteSortie, getWorldState, idToWeek } from "./worldStateService";
|
import { getLiteSortie, getWorldState, idToWeek } from "./worldStateService";
|
||||||
@ -67,18 +72,22 @@ const getRotations = (rewardInfo: IRewardInfo, tierOverride?: number): number[]
|
|||||||
return rotations;
|
return rotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
|
const missionIndex: number | undefined = ExportRegions[rewardInfo.node]?.missionIndex;
|
||||||
|
|
||||||
// For Rescue missions
|
// For Rescue missions
|
||||||
if (rewardInfo.node in ExportRegions && ExportRegions[rewardInfo.node].missionIndex == 3 && rewardInfo.rewardTier) {
|
if (missionIndex == 3 && rewardInfo.rewardTier) {
|
||||||
return [rewardInfo.rewardTier];
|
return [rewardInfo.rewardTier];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aborting a railjack mission should not give any rewards (https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1741)
|
const rotationCount = rewardInfo.rewardQualifications?.length || 0;
|
||||||
if (rewardInfo.rewardQualifications === undefined) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const rotationCount = rewardInfo.rewardQualifications.length || 0;
|
// Empty or absent rewardQualifications should not give rewards when:
|
||||||
if (rotationCount === 0) return [0];
|
// - Completing only 1 zone of (E)SO (https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1823)
|
||||||
|
// - Aborting a railjack mission (https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1741)
|
||||||
|
if (rotationCount == 0 && missionIndex != 30 && missionIndex != 32) {
|
||||||
|
return [0];
|
||||||
|
}
|
||||||
|
|
||||||
const rotationPattern =
|
const rotationPattern =
|
||||||
tierOverride === undefined
|
tierOverride === undefined
|
||||||
@ -134,38 +143,6 @@ export const addMissionInventoryUpdates = async (
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Somewhat heuristically detect G3 capture:
|
|
||||||
// - https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1365
|
|
||||||
// - https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1694
|
|
||||||
// - https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1724
|
|
||||||
if (
|
|
||||||
inventoryUpdates.MissionFailed &&
|
|
||||||
inventoryUpdates.MissionStatus == "GS_FAILURE" &&
|
|
||||||
inventoryUpdates.ObjectiveReached &&
|
|
||||||
!inventoryUpdates.LockedWeaponGroup &&
|
|
||||||
!inventory.LockedWeaponGroup &&
|
|
||||||
!inventoryUpdates.LevelKeyName
|
|
||||||
) {
|
|
||||||
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) {
|
||||||
if (inventoryUpdates.RewardInfo.periodicMissionTag) {
|
if (inventoryUpdates.RewardInfo.periodicMissionTag) {
|
||||||
@ -184,6 +161,12 @@ export const addMissionInventoryUpdates = async (
|
|||||||
if (inventoryUpdates.RewardInfo.NemesisAbandonedRewards) {
|
if (inventoryUpdates.RewardInfo.NemesisAbandonedRewards) {
|
||||||
inventory.NemesisAbandonedRewards = inventoryUpdates.RewardInfo.NemesisAbandonedRewards;
|
inventory.NemesisAbandonedRewards = inventoryUpdates.RewardInfo.NemesisAbandonedRewards;
|
||||||
}
|
}
|
||||||
|
if (inventoryUpdates.RewardInfo.NemesisHenchmenKills && inventory.Nemesis) {
|
||||||
|
inventory.Nemesis.HenchmenKilled += inventoryUpdates.RewardInfo.NemesisHenchmenKills;
|
||||||
|
}
|
||||||
|
if (inventoryUpdates.RewardInfo.NemesisHintProgress && inventory.Nemesis) {
|
||||||
|
inventory.Nemesis.HintProgress += inventoryUpdates.RewardInfo.NemesisHintProgress;
|
||||||
|
}
|
||||||
if (inventoryUpdates.MissionStatus == "GS_SUCCESS" && inventoryUpdates.RewardInfo.jobId) {
|
if (inventoryUpdates.MissionStatus == "GS_SUCCESS" && inventoryUpdates.RewardInfo.jobId) {
|
||||||
// e.g. for Profit-Taker Phase 1:
|
// e.g. for Profit-Taker Phase 1:
|
||||||
// JobTier: -6,
|
// JobTier: -6,
|
||||||
@ -265,7 +248,14 @@ export const addMissionInventoryUpdates = async (
|
|||||||
addMiscItems(inventory, value);
|
addMiscItems(inventory, value);
|
||||||
break;
|
break;
|
||||||
case "Consumables":
|
case "Consumables":
|
||||||
addConsumables(inventory, value);
|
if (config.dontSubtractConsumables) {
|
||||||
|
addConsumables(
|
||||||
|
inventory,
|
||||||
|
value.filter(x => x.ItemCount > 0)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
addConsumables(inventory, value);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "Recipes":
|
case "Recipes":
|
||||||
addRecipes(inventory, value);
|
addRecipes(inventory, value);
|
||||||
@ -287,14 +277,14 @@ export const addMissionInventoryUpdates = async (
|
|||||||
addShipDecorations(inventory, value);
|
addShipDecorations(inventory, value);
|
||||||
break;
|
break;
|
||||||
case "FusionBundles": {
|
case "FusionBundles": {
|
||||||
let fusionPoints = 0;
|
let fusionPointsDelta = 0;
|
||||||
for (const fusionBundle of value) {
|
for (const fusionBundle of value) {
|
||||||
const fusionPointsTotal =
|
fusionPointsDelta += addFusionPoints(
|
||||||
ExportFusionBundles[fusionBundle.ItemType].fusionPoints * fusionBundle.ItemCount;
|
inventory,
|
||||||
inventory.FusionPoints += fusionPointsTotal;
|
ExportFusionBundles[fusionBundle.ItemType].fusionPoints * fusionBundle.ItemCount
|
||||||
fusionPoints += fusionPointsTotal;
|
);
|
||||||
}
|
}
|
||||||
inventoryChanges.FusionPoints = fusionPoints;
|
inventoryChanges.FusionPoints = fusionPointsDelta;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "EmailItems": {
|
case "EmailItems": {
|
||||||
@ -358,6 +348,7 @@ export const addMissionInventoryUpdates = async (
|
|||||||
: 10)
|
: 10)
|
||||||
) {
|
) {
|
||||||
progress.Completed = true;
|
progress.Completed = true;
|
||||||
|
inventory.LibraryPersonalTarget = undefined;
|
||||||
}
|
}
|
||||||
logger.debug(`synthesis of ${scan.EnemyType} added to personal target progress`);
|
logger.debug(`synthesis of ${scan.EnemyType} added to personal target progress`);
|
||||||
synthesisIgnored = false;
|
synthesisIgnored = false;
|
||||||
@ -411,6 +402,11 @@ export const addMissionInventoryUpdates = async (
|
|||||||
upgrade.UpgradeFingerprint = clientUpgrade.UpgradeFingerprint; // primitive way to copy over the riven challenge progress
|
upgrade.UpgradeFingerprint = clientUpgrade.UpgradeFingerprint; // primitive way to copy over the riven challenge progress
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case "WeaponSkins":
|
||||||
|
for (const item of value) {
|
||||||
|
addSkin(inventory, item.ItemType);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "Boosters":
|
case "Boosters":
|
||||||
value.forEach(booster => {
|
value.forEach(booster => {
|
||||||
addBooster(booster.ItemType, booster.ExpiryDate, inventory);
|
addBooster(booster.ItemType, booster.ExpiryDate, inventory);
|
||||||
@ -488,6 +484,16 @@ export const addMissionInventoryUpdates = async (
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "KubrowPetEggs": {
|
||||||
|
for (const egg of value) {
|
||||||
|
inventory.KubrowPetEggs ??= [];
|
||||||
|
inventory.KubrowPetEggs.push({
|
||||||
|
ItemType: egg.ItemType,
|
||||||
|
_id: new Types.ObjectId()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "DiscoveredMarkers": {
|
case "DiscoveredMarkers": {
|
||||||
for (const clientMarker of value) {
|
for (const clientMarker of value) {
|
||||||
const dbMarker = inventory.DiscoveredMarkers.find(x => x.tag == clientMarker.tag);
|
const dbMarker = inventory.DiscoveredMarkers.find(x => x.tag == clientMarker.tag);
|
||||||
@ -499,6 +505,23 @@ export const addMissionInventoryUpdates = async (
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "BrandedSuits": {
|
||||||
|
inventory.BrandedSuits ??= [];
|
||||||
|
if (!inventory.BrandedSuits.find(x => x.equals(value.$oid))) {
|
||||||
|
inventory.BrandedSuits.push(new Types.ObjectId(value.$oid));
|
||||||
|
|
||||||
|
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.
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "LockedWeaponGroup": {
|
case "LockedWeaponGroup": {
|
||||||
inventory.LockedWeaponGroup = {
|
inventory.LockedWeaponGroup = {
|
||||||
s: new Types.ObjectId(value.s.$oid),
|
s: new Types.ObjectId(value.s.$oid),
|
||||||
@ -507,12 +530,17 @@ export const addMissionInventoryUpdates = async (
|
|||||||
m: value.m ? new Types.ObjectId(value.m.$oid) : undefined,
|
m: value.m ? new Types.ObjectId(value.m.$oid) : undefined,
|
||||||
sn: value.sn ? new Types.ObjectId(value.sn.$oid) : undefined
|
sn: value.sn ? new Types.ObjectId(value.sn.$oid) : undefined
|
||||||
};
|
};
|
||||||
|
inventory.Harvestable = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "UnlockWeapons": {
|
case "UnlockWeapons": {
|
||||||
inventory.LockedWeaponGroup = undefined;
|
inventory.LockedWeaponGroup = undefined;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "IncHarvester": {
|
||||||
|
inventory.Harvestable = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "CurrentLoadOutIds": {
|
case "CurrentLoadOutIds": {
|
||||||
if (value.LoadOuts) {
|
if (value.LoadOuts) {
|
||||||
const loadout = await Loadout.findOne({ loadoutOwnerId: inventory.accountOwnerId });
|
const loadout = await Loadout.findOne({ loadoutOwnerId: inventory.accountOwnerId });
|
||||||
@ -561,10 +589,79 @@ export const addMissionInventoryUpdates = async (
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "CalendarProgress": {
|
||||||
|
const calendarProgress = getCalendarProgress(inventory);
|
||||||
|
for (const progress of value) {
|
||||||
|
const challengeName = progress.challenge.substring(progress.challenge.lastIndexOf("/") + 1);
|
||||||
|
calendarProgress.SeasonProgress.LastCompletedChallengeDayIdx++;
|
||||||
|
calendarProgress.SeasonProgress.ActivatedChallenges.push(challengeName);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "duviriCaveOffers": {
|
||||||
|
// Duviri cave offers (generated with the duviri seed) change after completing one of its game modes (not when aborting).
|
||||||
|
if (inventoryUpdates.MissionStatus != "GS_QUIT") {
|
||||||
|
inventory.DuviriInfo!.Seed = generateRewardSeed();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "NemesisKillConvert":
|
||||||
|
if (inventory.Nemesis) {
|
||||||
|
inventory.NemesisHistory ??= [];
|
||||||
|
inventory.NemesisHistory.push({
|
||||||
|
// Copy over all 'base' values
|
||||||
|
fp: inventory.Nemesis.fp,
|
||||||
|
d: inventory.Nemesis.d,
|
||||||
|
manifest: inventory.Nemesis.manifest,
|
||||||
|
KillingSuit: inventory.Nemesis.KillingSuit,
|
||||||
|
killingDamageType: inventory.Nemesis.killingDamageType,
|
||||||
|
ShoulderHelmet: inventory.Nemesis.ShoulderHelmet,
|
||||||
|
WeaponIdx: inventory.Nemesis.WeaponIdx,
|
||||||
|
AgentIdx: inventory.Nemesis.AgentIdx,
|
||||||
|
BirthNode: inventory.Nemesis.BirthNode,
|
||||||
|
Faction: inventory.Nemesis.Faction,
|
||||||
|
Rank: inventory.Nemesis.Rank,
|
||||||
|
Traded: inventory.Nemesis.Traded,
|
||||||
|
PrevOwners: inventory.Nemesis.PrevOwners,
|
||||||
|
SecondInCommand: inventory.Nemesis.SecondInCommand,
|
||||||
|
Weakened: inventory.Nemesis.Weakened,
|
||||||
|
// And set killed flag
|
||||||
|
k: value.killed
|
||||||
|
});
|
||||||
|
|
||||||
|
if (value.killed) {
|
||||||
|
if (
|
||||||
|
value.weaponLoc &&
|
||||||
|
inventory.Nemesis.Faction != "FC_INFESTATION" // weaponLoc is "/Lotus/Language/Weapons/DerelictCernosName" for these for some reason
|
||||||
|
) {
|
||||||
|
const weaponType = getWeaponsForManifest(inventory.Nemesis.manifest)[
|
||||||
|
inventory.Nemesis.WeaponIdx
|
||||||
|
];
|
||||||
|
giveNemesisWeaponRecipe(
|
||||||
|
inventory,
|
||||||
|
weaponType,
|
||||||
|
value.nemesisName,
|
||||||
|
value.weaponLoc,
|
||||||
|
inventory.Nemesis.KillingSuit,
|
||||||
|
inventory.Nemesis.fp
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (value.petLoc) {
|
||||||
|
giveNemesisPetRecipe(inventory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TOVERIFY: Is the inbox message also sent when converting a lich? If not, how are the rewards given?
|
||||||
|
if (inventory.Nemesis.Faction == "FC_INFESTATION") {
|
||||||
|
await sendCodaFinishedMessage(inventory, inventory.Nemesis.fp, value.nemesisName, value.killed);
|
||||||
|
}
|
||||||
|
|
||||||
|
inventory.Nemesis = undefined;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// Equipment XP updates
|
|
||||||
if (equipmentKeys.includes(key as TEquipmentKey)) {
|
if (equipmentKeys.includes(key as TEquipmentKey)) {
|
||||||
addGearExpByCategory(inventory, value as IEquipmentClient[], key as TEquipmentKey);
|
applyClientEquipmentUpdates(inventory, value as IEquipmentClient[], key as TEquipmentKey);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// if (
|
// if (
|
||||||
@ -586,8 +683,140 @@ interface AddMissionRewardsReturnType {
|
|||||||
credits?: IMissionCredits;
|
credits?: IMissionCredits;
|
||||||
AffiliationMods?: IAffiliationMods[];
|
AffiliationMods?: IAffiliationMods[];
|
||||||
SyndicateXPItemReward?: number;
|
SyndicateXPItemReward?: number;
|
||||||
|
ConquestCompletedMissionsCount?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IConquestReward {
|
||||||
|
at: number;
|
||||||
|
pool: IRngResult[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const labConquestRewards: IConquestReward[] = [
|
||||||
|
{
|
||||||
|
at: 5,
|
||||||
|
pool: ExportRewards[
|
||||||
|
"/Lotus/Types/Game/MissionDecks/EntratiLabConquestRewards/EntratiLabConquestSilverRewards"
|
||||||
|
][0] as IRngResult[]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at: 10,
|
||||||
|
pool: ExportRewards[
|
||||||
|
"/Lotus/Types/Game/MissionDecks/EntratiLabConquestRewards/EntratiLabConquestSilverRewards"
|
||||||
|
][0] as IRngResult[]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at: 15,
|
||||||
|
pool: [
|
||||||
|
{
|
||||||
|
type: "/Lotus/StoreItems/Types/Gameplay/EntratiLab/Resources/EntratiLanthornBundle",
|
||||||
|
itemCount: 3,
|
||||||
|
probability: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at: 20,
|
||||||
|
pool: ExportRewards[
|
||||||
|
"/Lotus/Types/Game/MissionDecks/EntratiLabConquestRewards/EntratiLabConquestGoldRewards"
|
||||||
|
][0] as IRngResult[]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at: 28,
|
||||||
|
pool: [
|
||||||
|
{
|
||||||
|
type: "/Lotus/StoreItems/Types/Items/MiscItems/DistillPoints",
|
||||||
|
itemCount: 20,
|
||||||
|
probability: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at: 31,
|
||||||
|
pool: ExportRewards[
|
||||||
|
"/Lotus/Types/Game/MissionDecks/EntratiLabConquestRewards/EntratiLabConquestGoldRewards"
|
||||||
|
][0] as IRngResult[]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at: 34,
|
||||||
|
pool: ExportRewards[
|
||||||
|
"/Lotus/Types/Game/MissionDecks/EntratiLabConquestRewards/EntratiLabConquestArcaneRewards"
|
||||||
|
][0] as IRngResult[]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at: 37,
|
||||||
|
pool: [
|
||||||
|
{
|
||||||
|
type: "/Lotus/StoreItems/Types/Items/MiscItems/DistillPoints",
|
||||||
|
itemCount: 50,
|
||||||
|
probability: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const hexConquestRewards: IConquestReward[] = [
|
||||||
|
{
|
||||||
|
at: 5,
|
||||||
|
pool: ExportRewards[
|
||||||
|
"/Lotus/Types/Game/MissionDecks/1999ConquestRewards/1999ConquestSilverRewards"
|
||||||
|
][0] as IRngResult[]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at: 10,
|
||||||
|
pool: ExportRewards[
|
||||||
|
"/Lotus/Types/Game/MissionDecks/1999ConquestRewards/1999ConquestSilverRewards"
|
||||||
|
][0] as IRngResult[]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at: 15,
|
||||||
|
pool: [
|
||||||
|
{
|
||||||
|
type: "/Lotus/StoreItems/Types/BoosterPacks/1999StickersPackEchoesArchimedea",
|
||||||
|
itemCount: 1,
|
||||||
|
probability: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at: 20,
|
||||||
|
pool: ExportRewards[
|
||||||
|
"/Lotus/Types/Game/MissionDecks/1999ConquestRewards/1999ConquestGoldRewards"
|
||||||
|
][0] as IRngResult[]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at: 28,
|
||||||
|
pool: [
|
||||||
|
{
|
||||||
|
type: "/Lotus/StoreItems/Types/Items/MiscItems/1999ConquestBucks",
|
||||||
|
itemCount: 6,
|
||||||
|
probability: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at: 31,
|
||||||
|
pool: ExportRewards[
|
||||||
|
"/Lotus/Types/Game/MissionDecks/1999ConquestRewards/1999ConquestGoldRewards"
|
||||||
|
][0] as IRngResult[]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at: 34,
|
||||||
|
pool: ExportRewards[
|
||||||
|
"/Lotus/Types/Game/MissionDecks/1999ConquestRewards/1999ConquestArcaneRewards"
|
||||||
|
][0] as IRngResult[]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at: 37,
|
||||||
|
pool: [
|
||||||
|
{
|
||||||
|
type: "/Lotus/StoreItems/Types/Items/MiscItems/1999ConquestBucks",
|
||||||
|
itemCount: 9,
|
||||||
|
probability: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
//TODO: return type of partial missioninventoryupdate response
|
//TODO: return type of partial missioninventoryupdate response
|
||||||
export const addMissionRewards = async (
|
export const addMissionRewards = async (
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
@ -609,17 +838,13 @@ export const addMissionRewards = async (
|
|||||||
return { MissionRewards: [] };
|
return { MissionRewards: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rewardInfo.rewardSeed) {
|
|
||||||
// We're using a reward seed, so give the client a new one in the response. On live, missionInventoryUpdate seems to always provide a fresh one in the response.
|
|
||||||
inventory.RewardSeed = generateRewardSeed();
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: check double reward merging
|
//TODO: check double reward merging
|
||||||
const MissionRewards: IMissionReward[] = getRandomMissionDrops(inventory, rewardInfo, wagerTier, firstCompletion);
|
const MissionRewards: IMissionReward[] = getRandomMissionDrops(inventory, rewardInfo, wagerTier, firstCompletion);
|
||||||
logger.debug("random mission drops:", MissionRewards);
|
logger.debug("random mission drops:", MissionRewards);
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
const AffiliationMods: IAffiliationMods[] = [];
|
const AffiliationMods: IAffiliationMods[] = [];
|
||||||
let SyndicateXPItemReward;
|
let SyndicateXPItemReward;
|
||||||
|
let ConquestCompletedMissionsCount;
|
||||||
|
|
||||||
let missionCompletionCredits = 0;
|
let missionCompletionCredits = 0;
|
||||||
//inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display
|
//inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display
|
||||||
@ -658,7 +883,8 @@ export const addMissionRewards = async (
|
|||||||
missions.Tag != "SolNode761" && // the index
|
missions.Tag != "SolNode761" && // the index
|
||||||
missions.Tag != "SolNode762" && // the index
|
missions.Tag != "SolNode762" && // the index
|
||||||
missions.Tag != "SolNode763" && // the index
|
missions.Tag != "SolNode763" && // the index
|
||||||
missions.Tag != "CrewBattleNode556" // free flight
|
missions.Tag != "CrewBattleNode556" && // free flight
|
||||||
|
getRotations(rewardInfo).length > 0 // (E)SO should not give credits for only completing zone 1, in which case it has no rewardQualifications (https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1823)
|
||||||
) {
|
) {
|
||||||
const levelCreditReward = getLevelCreditRewards(node);
|
const levelCreditReward = getLevelCreditRewards(node);
|
||||||
missionCompletionCredits += levelCreditReward;
|
missionCompletionCredits += levelCreditReward;
|
||||||
@ -670,6 +896,14 @@ export const addMissionRewards = async (
|
|||||||
missionCompletionCredits += addFixedLevelRewards(node.missionReward, inventory, MissionRewards, rewardInfo);
|
missionCompletionCredits += addFixedLevelRewards(node.missionReward, inventory, MissionRewards, rewardInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rewardInfo.sortieTag == "Mission1") {
|
||||||
|
missionCompletionCredits += 20_000;
|
||||||
|
} else if (rewardInfo.sortieTag == "Mission2") {
|
||||||
|
missionCompletionCredits += 30_000;
|
||||||
|
} else if (rewardInfo.sortieTag == "Final") {
|
||||||
|
missionCompletionCredits += 50_000;
|
||||||
|
}
|
||||||
|
|
||||||
if (missions.Tag == "PlutoToErisJunction") {
|
if (missions.Tag == "PlutoToErisJunction") {
|
||||||
await createMessage(inventory.accountOwnerId, [
|
await createMessage(inventory.accountOwnerId, [
|
||||||
{
|
{
|
||||||
@ -686,11 +920,67 @@ export const addMissionRewards = async (
|
|||||||
|
|
||||||
if (rewardInfo.useVaultManifest) {
|
if (rewardInfo.useVaultManifest) {
|
||||||
MissionRewards.push({
|
MissionRewards.push({
|
||||||
StoreItem: getRandomElement(corruptedMods),
|
StoreItem: getRandomElement(corruptedMods)!,
|
||||||
ItemCount: 1
|
ItemCount: 1
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rewardInfo.ConquestCompleted !== undefined) {
|
||||||
|
let score = 1;
|
||||||
|
if (rewardInfo.ConquestHardModeActive === 1) score += 3;
|
||||||
|
|
||||||
|
if (rewardInfo.ConquestPersonalModifiersActive !== undefined)
|
||||||
|
score += rewardInfo.ConquestPersonalModifiersActive;
|
||||||
|
if (rewardInfo.ConquestEquipmentSuggestionsFulfilled !== undefined)
|
||||||
|
score += rewardInfo.ConquestEquipmentSuggestionsFulfilled;
|
||||||
|
|
||||||
|
score *= rewardInfo.ConquestCompleted + 1;
|
||||||
|
|
||||||
|
if (rewardInfo.ConquestCompleted == 2 && rewardInfo.ConquestHardModeActive === 1) score += 1;
|
||||||
|
|
||||||
|
logger.debug(`completed conquest mission ${rewardInfo.ConquestCompleted + 1} for a score of ${score}`);
|
||||||
|
|
||||||
|
const conquestType = rewardInfo.ConquestType;
|
||||||
|
const conquestNode =
|
||||||
|
conquestType == "HexConquest" ? "EchoesHexConquestHardModeUnlocked" : "EntratiLabConquestHardModeUnlocked";
|
||||||
|
if (score >= 25 && inventory.NodeIntrosCompleted.indexOf(conquestNode) == -1)
|
||||||
|
inventory.NodeIntrosCompleted.push(conquestNode);
|
||||||
|
|
||||||
|
if (conquestType == "HexConquest") {
|
||||||
|
inventory.EchoesHexConquestCacheScoreMission ??= 0;
|
||||||
|
if (score > inventory.EchoesHexConquestCacheScoreMission) {
|
||||||
|
for (const reward of hexConquestRewards) {
|
||||||
|
if (score >= reward.at && inventory.EchoesHexConquestCacheScoreMission < reward.at) {
|
||||||
|
const rolled = getRandomReward(reward.pool)!;
|
||||||
|
logger.debug(`rolled hex conquest reward for reaching ${reward.at} points`, rolled);
|
||||||
|
MissionRewards.push({
|
||||||
|
StoreItem: rolled.type,
|
||||||
|
ItemCount: rolled.itemCount
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inventory.EchoesHexConquestCacheScoreMission = score;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inventory.EntratiLabConquestCacheScoreMission ??= 0;
|
||||||
|
if (score > inventory.EntratiLabConquestCacheScoreMission) {
|
||||||
|
for (const reward of labConquestRewards) {
|
||||||
|
if (score >= reward.at && inventory.EntratiLabConquestCacheScoreMission < reward.at) {
|
||||||
|
const rolled = getRandomReward(reward.pool)!;
|
||||||
|
logger.debug(`rolled lab conquest reward for reaching ${reward.at} points`, rolled);
|
||||||
|
MissionRewards.push({
|
||||||
|
StoreItem: rolled.type,
|
||||||
|
ItemCount: rolled.itemCount
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inventory.EntratiLabConquestCacheScoreMission = score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConquestCompletedMissionsCount = rewardInfo.ConquestCompleted == 2 ? 0 : rewardInfo.ConquestCompleted + 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (const reward of MissionRewards) {
|
for (const reward of MissionRewards) {
|
||||||
const inventoryChange = await handleStoreItemAcquisition(
|
const inventoryChange = await handleStoreItemAcquisition(
|
||||||
reward.StoreItem,
|
reward.StoreItem,
|
||||||
@ -882,16 +1172,16 @@ export const addMissionRewards = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { inventoryChanges, MissionRewards, credits, AffiliationMods, SyndicateXPItemReward };
|
return {
|
||||||
|
inventoryChanges,
|
||||||
|
MissionRewards,
|
||||||
|
credits,
|
||||||
|
AffiliationMods,
|
||||||
|
SyndicateXPItemReward,
|
||||||
|
ConquestCompletedMissionsCount
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IMissionCredits {
|
|
||||||
MissionCredits: number[];
|
|
||||||
CreditBonus: number[];
|
|
||||||
TotalCredits: number[];
|
|
||||||
DailyMissionBonus?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
//creditBonus is not entirely accurate.
|
//creditBonus is not entirely accurate.
|
||||||
//TODO: consider ActiveBoosters
|
//TODO: consider ActiveBoosters
|
||||||
export const addCredits = (
|
export const addCredits = (
|
||||||
@ -1068,6 +1358,9 @@ function getRandomMissionDrops(
|
|||||||
// Invasion assassination has Phorid has the boss who should drop Nyx parts
|
// Invasion assassination has Phorid has the boss who should drop Nyx parts
|
||||||
// TODO: Check that the invasion faction is indeed FC_INFESTATION once the Invasions in worldState are more dynamic
|
// TODO: Check that the invasion faction is indeed FC_INFESTATION once the Invasions in worldState are more dynamic
|
||||||
rewardManifests = ["/Lotus/Types/Game/MissionDecks/BossMissionRewards/NyxRewards"];
|
rewardManifests = ["/Lotus/Types/Game/MissionDecks/BossMissionRewards/NyxRewards"];
|
||||||
|
} else if (RewardInfo.sortieId && region.missionIndex != 0) {
|
||||||
|
// Sortie mission types differ from the underlying node and hence also don't give rewards from the underlying nodes. Assassinations are an exception to this.
|
||||||
|
rewardManifests = [];
|
||||||
} else {
|
} else {
|
||||||
rewardManifests = region.rewardManifests;
|
rewardManifests = region.rewardManifests;
|
||||||
}
|
}
|
||||||
@ -1216,6 +1509,11 @@ function getRandomMissionDrops(
|
|||||||
if (rewardManifests.length != 0) {
|
if (rewardManifests.length != 0) {
|
||||||
logger.debug(`generating random mission rewards`, { rewardManifests, rotations });
|
logger.debug(`generating random mission rewards`, { rewardManifests, rotations });
|
||||||
}
|
}
|
||||||
|
if (RewardInfo.rewardSeed) {
|
||||||
|
if (RewardInfo.rewardSeed != inventory.RewardSeed) {
|
||||||
|
logger.warn(`RewardSeed mismatch:`, { client: RewardInfo.rewardSeed, database: inventory.RewardSeed });
|
||||||
|
}
|
||||||
|
}
|
||||||
const rng = new SRng(BigInt(RewardInfo.rewardSeed ?? generateRewardSeed()) ^ 0xffffffffffffffffn);
|
const rng = new SRng(BigInt(RewardInfo.rewardSeed ?? generateRewardSeed()) ^ 0xffffffffffffffffn);
|
||||||
rewardManifests.forEach(name => {
|
rewardManifests.forEach(name => {
|
||||||
const table = ExportRewards[name];
|
const table = ExportRewards[name];
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
import { PersonalRooms } from "@/src/models/personalRoomsModel";
|
import { PersonalRooms } from "@/src/models/personalRoomsModel";
|
||||||
import { addItem, getInventory } from "@/src/services/inventoryService";
|
import { addItem, getInventory } from "@/src/services/inventoryService";
|
||||||
import { TPersonalRoomsDatabaseDocument } from "../types/personalRoomsTypes";
|
import { TPersonalRoomsDatabaseDocument } from "../types/personalRoomsTypes";
|
||||||
|
import { IGardeningDatabase } from "../types/shipTypes";
|
||||||
|
import { getRandomElement } from "./rngService";
|
||||||
|
|
||||||
export const getPersonalRooms = async (accountId: string): Promise<TPersonalRoomsDatabaseDocument> => {
|
export const getPersonalRooms = async (
|
||||||
const personalRooms = await PersonalRooms.findOne({ personalRoomsOwnerId: accountId });
|
accountId: string,
|
||||||
|
projection?: string
|
||||||
|
): Promise<TPersonalRoomsDatabaseDocument> => {
|
||||||
|
const personalRooms = await PersonalRooms.findOne({ personalRoomsOwnerId: accountId }, projection);
|
||||||
|
|
||||||
if (!personalRooms) {
|
if (!personalRooms) {
|
||||||
throw new Error(`personal rooms not found for account ${accountId}`);
|
throw new Error(`personal rooms not found for account ${accountId}`);
|
||||||
@ -25,3 +30,64 @@ export const updateShipFeature = async (accountId: string, shipFeature: string):
|
|||||||
await addItem(inventory, shipFeature, -1);
|
await addItem(inventory, shipFeature, -1);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const createGarden = (): IGardeningDatabase => {
|
||||||
|
const plantTypes = [
|
||||||
|
"/Lotus/Types/Items/Plants/MiscItems/DuvxDuviriGrowingPlantA",
|
||||||
|
"/Lotus/Types/Items/Plants/MiscItems/DuvxDuviriGrowingPlantB",
|
||||||
|
"/Lotus/Types/Items/Plants/MiscItems/DuvxDuviriGrowingPlantC",
|
||||||
|
"/Lotus/Types/Items/Plants/MiscItems/DuvxDuviriGrowingPlantD",
|
||||||
|
"/Lotus/Types/Items/Plants/MiscItems/DuvxDuviriGrowingPlantE",
|
||||||
|
"/Lotus/Types/Items/Plants/MiscItems/DuvxDuviriGrowingPlantF"
|
||||||
|
];
|
||||||
|
const endTime = new Date((Math.trunc(Date.now() / 1000) + 79200) * 1000); // Plants will take 22 hours to grow
|
||||||
|
return {
|
||||||
|
Planters: [
|
||||||
|
{
|
||||||
|
Name: "Garden0",
|
||||||
|
Plants: [
|
||||||
|
{
|
||||||
|
PlantType: getRandomElement(plantTypes)!,
|
||||||
|
EndTime: endTime,
|
||||||
|
PlotIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PlantType: getRandomElement(plantTypes)!,
|
||||||
|
EndTime: endTime,
|
||||||
|
PlotIndex: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Garden1",
|
||||||
|
Plants: [
|
||||||
|
{
|
||||||
|
PlantType: getRandomElement(plantTypes)!,
|
||||||
|
EndTime: endTime,
|
||||||
|
PlotIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PlantType: getRandomElement(plantTypes)!,
|
||||||
|
EndTime: endTime,
|
||||||
|
PlotIndex: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Garden2",
|
||||||
|
Plants: [
|
||||||
|
{
|
||||||
|
PlantType: getRandomElement(plantTypes)!,
|
||||||
|
EndTime: endTime,
|
||||||
|
PlotIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PlantType: getRandomElement(plantTypes)!,
|
||||||
|
EndTime: endTime,
|
||||||
|
PlotIndex: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -66,6 +66,18 @@ export const handlePurchase = async (
|
|||||||
if (!offer) {
|
if (!offer) {
|
||||||
throw new Error(`unknown vendor offer: ${ItemId ? ItemId : purchaseRequest.PurchaseParams.StoreItem}`);
|
throw new Error(`unknown vendor offer: ${ItemId ? ItemId : purchaseRequest.PurchaseParams.StoreItem}`);
|
||||||
}
|
}
|
||||||
|
if (offer.RegularPrice) {
|
||||||
|
combineInventoryChanges(
|
||||||
|
prePurchaseInventoryChanges,
|
||||||
|
updateCurrency(inventory, offer.RegularPrice[0], false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (offer.PremiumPrice) {
|
||||||
|
combineInventoryChanges(
|
||||||
|
prePurchaseInventoryChanges,
|
||||||
|
updateCurrency(inventory, offer.PremiumPrice[0], true)
|
||||||
|
);
|
||||||
|
}
|
||||||
if (offer.ItemPrices) {
|
if (offer.ItemPrices) {
|
||||||
handleItemPrices(
|
handleItemPrices(
|
||||||
inventory,
|
inventory,
|
||||||
@ -170,6 +182,9 @@ export const handlePurchase = async (
|
|||||||
purchaseResponse.InventoryChanges,
|
purchaseResponse.InventoryChanges,
|
||||||
updateCurrency(inventory, offer.RegularPrice, false)
|
updateCurrency(inventory, offer.RegularPrice, false)
|
||||||
);
|
);
|
||||||
|
if (purchaseRequest.PurchaseParams.ExpectedPrice) {
|
||||||
|
throw new Error(`vendor purchase should not have an expected price`);
|
||||||
|
}
|
||||||
|
|
||||||
const invItem: IMiscItem = {
|
const invItem: IMiscItem = {
|
||||||
ItemType: "/Lotus/Types/Items/MiscItems/PrimeBucks",
|
ItemType: "/Lotus/Types/Items/MiscItems/PrimeBucks",
|
||||||
@ -223,12 +238,18 @@ export const handlePurchase = async (
|
|||||||
const vendor = ExportVendors[purchaseRequest.PurchaseParams.SourceId!];
|
const vendor = ExportVendors[purchaseRequest.PurchaseParams.SourceId!];
|
||||||
const offer = vendor.items.find(x => x.storeItem == purchaseRequest.PurchaseParams.StoreItem);
|
const offer = vendor.items.find(x => x.storeItem == purchaseRequest.PurchaseParams.StoreItem);
|
||||||
if (offer) {
|
if (offer) {
|
||||||
if (offer.credits) {
|
if (typeof offer.credits == "number") {
|
||||||
combineInventoryChanges(
|
combineInventoryChanges(
|
||||||
purchaseResponse.InventoryChanges,
|
purchaseResponse.InventoryChanges,
|
||||||
updateCurrency(inventory, offer.credits, false)
|
updateCurrency(inventory, offer.credits, false)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (typeof offer.platinum == "number") {
|
||||||
|
combineInventoryChanges(
|
||||||
|
purchaseResponse.InventoryChanges,
|
||||||
|
updateCurrency(inventory, offer.platinum, true)
|
||||||
|
);
|
||||||
|
}
|
||||||
if (offer.itemPrices) {
|
if (offer.itemPrices) {
|
||||||
handleItemPrices(
|
handleItemPrices(
|
||||||
inventory,
|
inventory,
|
||||||
@ -239,6 +260,9 @@ export const handlePurchase = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (purchaseRequest.PurchaseParams.ExpectedPrice) {
|
||||||
|
throw new Error(`vendor purchase should not have an expected price`);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 18: {
|
case 18: {
|
||||||
if (purchaseRequest.PurchaseParams.SourceId! != worldState.PrimeVaultTraders[0]._id.$oid) {
|
if (purchaseRequest.PurchaseParams.SourceId! != worldState.PrimeVaultTraders[0]._id.$oid) {
|
||||||
|
@ -6,7 +6,7 @@ export interface IRngResult {
|
|||||||
probability: number;
|
probability: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getRandomElement = <T>(arr: T[]): T => {
|
export const getRandomElement = <T>(arr: readonly T[]): T | undefined => {
|
||||||
return arr[Math.floor(Math.random() * arr.length)];
|
return arr[Math.floor(Math.random() * arr.length)];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -18,7 +18,10 @@ export const getRandomInt = (min: number, max: number): number => {
|
|||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRewardAtPercentage = <T extends { probability: number }>(pool: T[], percentage: number): T | undefined => {
|
export const getRewardAtPercentage = <T extends { probability: number }>(
|
||||||
|
pool: T[],
|
||||||
|
percentage: number
|
||||||
|
): T | undefined => {
|
||||||
if (pool.length == 0) return;
|
if (pool.length == 0) return;
|
||||||
|
|
||||||
const totalChance = pool.reduce((accum, item) => accum + item.probability, 0);
|
const totalChance = pool.reduce((accum, item) => accum + item.probability, 0);
|
||||||
@ -97,12 +100,20 @@ export class CRng {
|
|||||||
}
|
}
|
||||||
|
|
||||||
randomInt(min: number, max: number): number {
|
randomInt(min: number, max: number): number {
|
||||||
min = Math.ceil(min);
|
const diff = max - min;
|
||||||
max = Math.floor(max);
|
if (diff != 0) {
|
||||||
return Math.floor(this.random() * (max - min + 1)) + min;
|
if (diff < 0) {
|
||||||
|
throw new Error(`max must be greater than min`);
|
||||||
|
}
|
||||||
|
if (diff > 0x3fffffff) {
|
||||||
|
throw new Error(`insufficient entropy`);
|
||||||
|
}
|
||||||
|
min += Math.floor(this.random() * (diff + 1));
|
||||||
|
}
|
||||||
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
randomElement<T>(arr: T[]): T {
|
randomElement<T>(arr: readonly T[]): T | undefined {
|
||||||
return arr[Math.floor(this.random() * arr.length)];
|
return arr[Math.floor(this.random() * arr.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +145,7 @@ export class SRng {
|
|||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
randomElement<T>(arr: T[]): T {
|
randomElement<T>(arr: readonly T[]): T | undefined {
|
||||||
return arr[this.randomInt(0, arr.length - 1)];
|
return arr[this.randomInt(0, arr.length - 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,6 +161,11 @@ export const handleInventoryItemConfigChange = async (
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "LotusCustomization": {
|
||||||
|
logger.debug(`saved LotusCustomization`, equipmentChanges.LotusCustomization);
|
||||||
|
inventory.LotusCustomization = equipmentChanges.LotusCustomization;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
if (equipmentKeys.includes(equipmentName as TEquipmentKey) && equipmentName != "ValidNewLoadoutId") {
|
if (equipmentKeys.includes(equipmentName as TEquipmentKey) && equipmentName != "ValidNewLoadoutId") {
|
||||||
logger.debug(`general Item config saved of type ${equipmentName}`, {
|
logger.debug(`general Item config saved of type ${equipmentName}`, {
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
||||||
|
import { catBreadHash } from "@/src/helpers/stringHelpers";
|
||||||
import { CRng, mixSeeds } from "@/src/services/rngService";
|
import { CRng, mixSeeds } from "@/src/services/rngService";
|
||||||
import { IMongoDate } from "@/src/types/commonTypes";
|
import { IMongoDate } from "@/src/types/commonTypes";
|
||||||
import {
|
import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes";
|
||||||
IItemManifestPreprocessed,
|
import { ExportVendors, IRange } from "warframe-public-export-plus";
|
||||||
IRawVendorManifest,
|
|
||||||
IVendorInfo,
|
|
||||||
IVendorManifestPreprocessed
|
|
||||||
} from "@/src/types/vendorTypes";
|
|
||||||
import { ExportVendors } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
|
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
|
||||||
import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
|
import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
|
||||||
import DeimosFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosFishmongerVendorManifest.json";
|
|
||||||
import DeimosHivemindCommisionsManifestFishmonger from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestFishmonger.json";
|
import DeimosHivemindCommisionsManifestFishmonger from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestFishmonger.json";
|
||||||
import DeimosHivemindCommisionsManifestPetVendor from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestPetVendor.json";
|
import DeimosHivemindCommisionsManifestPetVendor from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestPetVendor.json";
|
||||||
import DeimosHivemindCommisionsManifestProspector from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestProspector.json";
|
import DeimosHivemindCommisionsManifestProspector from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestProspector.json";
|
||||||
@ -23,26 +18,22 @@ import DeimosProspectorVendorManifest from "@/static/fixed_responses/getVendorIn
|
|||||||
import DuviriAcrithisVendorManifest from "@/static/fixed_responses/getVendorInfo/DuviriAcrithisVendorManifest.json";
|
import DuviriAcrithisVendorManifest from "@/static/fixed_responses/getVendorInfo/DuviriAcrithisVendorManifest.json";
|
||||||
import EntratiLabsEntratiLabsCommisionsManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabsCommisionsManifest.json";
|
import EntratiLabsEntratiLabsCommisionsManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabsCommisionsManifest.json";
|
||||||
import EntratiLabsEntratiLabVendorManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabVendorManifest.json";
|
import EntratiLabsEntratiLabVendorManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabVendorManifest.json";
|
||||||
import GuildAdvertisementVendorManifest from "@/static/fixed_responses/getVendorInfo/GuildAdvertisementVendorManifest.json";
|
|
||||||
import HubsIronwakeDondaVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsIronwakeDondaVendorManifest.json";
|
import HubsIronwakeDondaVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsIronwakeDondaVendorManifest.json";
|
||||||
import HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json";
|
import HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json";
|
||||||
import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json";
|
import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json";
|
||||||
import Nova1999ConquestShopManifest from "@/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json";
|
import Nova1999ConquestShopManifest from "@/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json";
|
||||||
import OstronFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronFishmongerVendorManifest.json";
|
|
||||||
import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json";
|
import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json";
|
||||||
import OstronProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronProspectorVendorManifest.json";
|
import OstronProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronProspectorVendorManifest.json";
|
||||||
import RadioLegionIntermission12VendorManifest from "@/static/fixed_responses/getVendorInfo/RadioLegionIntermission12VendorManifest.json";
|
import RadioLegionIntermission12VendorManifest from "@/static/fixed_responses/getVendorInfo/RadioLegionIntermission12VendorManifest.json";
|
||||||
import SolarisDebtTokenVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorManifest.json";
|
|
||||||
import SolarisDebtTokenVendorRepossessionsManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorRepossessionsManifest.json";
|
import SolarisDebtTokenVendorRepossessionsManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorRepossessionsManifest.json";
|
||||||
import SolarisFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisFishmongerVendorManifest.json";
|
|
||||||
import SolarisProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisProspectorVendorManifest.json";
|
import SolarisProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisProspectorVendorManifest.json";
|
||||||
|
import Temple1999VendorManifest from "@/static/fixed_responses/getVendorInfo/Temple1999VendorManifest.json";
|
||||||
import TeshinHardModeVendorManifest from "@/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json";
|
import TeshinHardModeVendorManifest from "@/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json";
|
||||||
import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVendorInfo/ZarimanCommisionsManifestArchimedean.json";
|
import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVendorInfo/ZarimanCommisionsManifestArchimedean.json";
|
||||||
|
|
||||||
const rawVendorManifests: IRawVendorManifest[] = [
|
const rawVendorManifests: IVendorManifest[] = [
|
||||||
ArchimedeanVendorManifest,
|
ArchimedeanVendorManifest,
|
||||||
DeimosEntratiFragmentVendorProductsManifest,
|
DeimosEntratiFragmentVendorProductsManifest,
|
||||||
DeimosFishmongerVendorManifest,
|
|
||||||
DeimosHivemindCommisionsManifestFishmonger,
|
DeimosHivemindCommisionsManifestFishmonger,
|
||||||
DeimosHivemindCommisionsManifestPetVendor,
|
DeimosHivemindCommisionsManifestPetVendor,
|
||||||
DeimosHivemindCommisionsManifestProspector,
|
DeimosHivemindCommisionsManifestProspector,
|
||||||
@ -54,25 +45,22 @@ const rawVendorManifests: IRawVendorManifest[] = [
|
|||||||
DuviriAcrithisVendorManifest,
|
DuviriAcrithisVendorManifest,
|
||||||
EntratiLabsEntratiLabsCommisionsManifest,
|
EntratiLabsEntratiLabsCommisionsManifest,
|
||||||
EntratiLabsEntratiLabVendorManifest,
|
EntratiLabsEntratiLabVendorManifest,
|
||||||
GuildAdvertisementVendorManifest, // uses preprocessing
|
|
||||||
HubsIronwakeDondaVendorManifest, // uses preprocessing
|
HubsIronwakeDondaVendorManifest, // uses preprocessing
|
||||||
HubsRailjackCrewMemberVendorManifest,
|
HubsRailjackCrewMemberVendorManifest,
|
||||||
MaskSalesmanManifest,
|
MaskSalesmanManifest,
|
||||||
Nova1999ConquestShopManifest,
|
Nova1999ConquestShopManifest,
|
||||||
OstronFishmongerVendorManifest,
|
|
||||||
OstronPetVendorManifest,
|
OstronPetVendorManifest,
|
||||||
OstronProspectorVendorManifest,
|
OstronProspectorVendorManifest,
|
||||||
RadioLegionIntermission12VendorManifest,
|
RadioLegionIntermission12VendorManifest,
|
||||||
SolarisDebtTokenVendorManifest,
|
|
||||||
SolarisDebtTokenVendorRepossessionsManifest,
|
SolarisDebtTokenVendorRepossessionsManifest,
|
||||||
SolarisFishmongerVendorManifest,
|
|
||||||
SolarisProspectorVendorManifest,
|
SolarisProspectorVendorManifest,
|
||||||
|
Temple1999VendorManifest,
|
||||||
TeshinHardModeVendorManifest, // uses preprocessing
|
TeshinHardModeVendorManifest, // uses preprocessing
|
||||||
ZarimanCommisionsManifestArchimedean
|
ZarimanCommisionsManifestArchimedean
|
||||||
];
|
];
|
||||||
|
|
||||||
interface IGeneratableVendorInfo extends Omit<IVendorInfo, "ItemManifest" | "Expiry"> {
|
interface IGeneratableVendorInfo extends Omit<IVendorInfo, "ItemManifest" | "Expiry"> {
|
||||||
cycleStart: number;
|
cycleOffset?: number;
|
||||||
cycleDuration: number;
|
cycleDuration: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,30 +68,37 @@ const generatableVendors: IGeneratableVendorInfo[] = [
|
|||||||
{
|
{
|
||||||
_id: { $oid: "67dadc30e4b6e0e5979c8d84" },
|
_id: { $oid: "67dadc30e4b6e0e5979c8d84" },
|
||||||
TypeName: "/Lotus/Types/Game/VendorManifests/TheHex/InfestedLichWeaponVendorManifest",
|
TypeName: "/Lotus/Types/Game/VendorManifests/TheHex/InfestedLichWeaponVendorManifest",
|
||||||
PropertyTextHash: "77093DD05A8561A022DEC9A4B9BB4A56",
|
|
||||||
RandomSeedType: "VRST_WEAPON",
|
RandomSeedType: "VRST_WEAPON",
|
||||||
RequiredGoalTag: "",
|
RequiredGoalTag: "",
|
||||||
WeaponUpgradeValueAttenuationExponent: 2.25,
|
WeaponUpgradeValueAttenuationExponent: 2.25,
|
||||||
cycleStart: 1740960000_000,
|
cycleOffset: 1740960000_000,
|
||||||
cycleDuration: 4 * unixTimesInMs.day
|
cycleDuration: 4 * unixTimesInMs.day
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_id: { $oid: "60ad3b6ec96976e97d227e19" },
|
_id: { $oid: "60ad3b6ec96976e97d227e19" },
|
||||||
TypeName: "/Lotus/Types/Game/VendorManifests/Hubs/PerrinSequenceWeaponVendorManifest",
|
TypeName: "/Lotus/Types/Game/VendorManifests/Hubs/PerrinSequenceWeaponVendorManifest",
|
||||||
PropertyTextHash: "34F8CF1DFF745F0D67433A5EF0A03E70",
|
|
||||||
RandomSeedType: "VRST_WEAPON",
|
RandomSeedType: "VRST_WEAPON",
|
||||||
WeaponUpgradeValueAttenuationExponent: 2.25,
|
WeaponUpgradeValueAttenuationExponent: 2.25,
|
||||||
cycleStart: 1744934400_000,
|
cycleOffset: 1744934400_000,
|
||||||
cycleDuration: 4 * unixTimesInMs.day
|
cycleDuration: 4 * unixTimesInMs.day
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_id: { $oid: "61ba123467e5d37975aeeb03" },
|
||||||
|
TypeName: "/Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest",
|
||||||
|
RandomSeedType: "VRST_FLAVOUR_TEXT",
|
||||||
|
cycleDuration: unixTimesInMs.week // TODO: Auto-detect this based on the items, so we don't need to specify it explicitly.
|
||||||
}
|
}
|
||||||
// {
|
// {
|
||||||
// _id: { $oid: "5dbb4c41e966f7886c3ce939" },
|
// _id: { $oid: "5dbb4c41e966f7886c3ce939" },
|
||||||
// TypeName: "/Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest",
|
// TypeName: "/Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest"
|
||||||
// PropertyTextHash: "62B64A8065B7C0FA345895D4BC234621"
|
|
||||||
// }
|
// }
|
||||||
];
|
];
|
||||||
|
|
||||||
export const getVendorManifestByTypeName = (typeName: string): IVendorManifestPreprocessed | undefined => {
|
const getVendorOid = (typeName: string): string => {
|
||||||
|
return "5be4a159b144f3cd" + catBreadHash(typeName).toString(16).padStart(8, "0");
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getVendorManifestByTypeName = (typeName: string): IVendorManifest | undefined => {
|
||||||
for (const vendorManifest of rawVendorManifests) {
|
for (const vendorManifest of rawVendorManifests) {
|
||||||
if (vendorManifest.VendorInfo.TypeName == typeName) {
|
if (vendorManifest.VendorInfo.TypeName == typeName) {
|
||||||
return preprocessVendorManifest(vendorManifest);
|
return preprocessVendorManifest(vendorManifest);
|
||||||
@ -114,10 +109,18 @@ export const getVendorManifestByTypeName = (typeName: string): IVendorManifestPr
|
|||||||
return generateVendorManifest(vendorInfo);
|
return generateVendorManifest(vendorInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (typeName in ExportVendors) {
|
||||||
|
return generateVendorManifest({
|
||||||
|
_id: { $oid: getVendorOid(typeName) },
|
||||||
|
TypeName: typeName,
|
||||||
|
RandomSeedType: ExportVendors[typeName].randomSeedType,
|
||||||
|
cycleDuration: unixTimesInMs.hour
|
||||||
|
});
|
||||||
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getVendorManifestByOid = (oid: string): IVendorManifestPreprocessed | undefined => {
|
export const getVendorManifestByOid = (oid: string): IVendorManifest | undefined => {
|
||||||
for (const vendorManifest of rawVendorManifests) {
|
for (const vendorManifest of rawVendorManifests) {
|
||||||
if (vendorManifest.VendorInfo._id.$oid == oid) {
|
if (vendorManifest.VendorInfo._id.$oid == oid) {
|
||||||
return preprocessVendorManifest(vendorManifest);
|
return preprocessVendorManifest(vendorManifest);
|
||||||
@ -128,32 +131,34 @@ export const getVendorManifestByOid = (oid: string): IVendorManifestPreprocessed
|
|||||||
return generateVendorManifest(vendorInfo);
|
return generateVendorManifest(vendorInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (const [typeName, manifest] of Object.entries(ExportVendors)) {
|
||||||
|
const typeNameOid = getVendorOid(typeName);
|
||||||
|
if (typeNameOid == oid) {
|
||||||
|
return generateVendorManifest({
|
||||||
|
_id: { $oid: typeNameOid },
|
||||||
|
TypeName: typeName,
|
||||||
|
RandomSeedType: manifest.randomSeedType,
|
||||||
|
cycleDuration: unixTimesInMs.hour
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const preprocessVendorManifest = (originalManifest: IRawVendorManifest): IVendorManifestPreprocessed => {
|
const preprocessVendorManifest = (originalManifest: IVendorManifest): IVendorManifest => {
|
||||||
if (Date.now() >= parseInt(originalManifest.VendorInfo.Expiry.$date.$numberLong)) {
|
if (Date.now() >= parseInt(originalManifest.VendorInfo.Expiry.$date.$numberLong)) {
|
||||||
const manifest = structuredClone(originalManifest);
|
const manifest = structuredClone(originalManifest);
|
||||||
const info = manifest.VendorInfo;
|
const info = manifest.VendorInfo;
|
||||||
refreshExpiry(info.Expiry);
|
refreshExpiry(info.Expiry);
|
||||||
for (const offer of info.ItemManifest) {
|
for (const offer of info.ItemManifest) {
|
||||||
const iteration = refreshExpiry(offer.Expiry);
|
refreshExpiry(offer.Expiry);
|
||||||
if (offer.ItemPrices) {
|
|
||||||
for (const price of offer.ItemPrices) {
|
|
||||||
if (typeof price.ItemType != "string") {
|
|
||||||
const itemSeed = parseInt(offer.Id.$oid.substring(16), 16);
|
|
||||||
const rng = new CRng(mixSeeds(itemSeed, iteration));
|
|
||||||
price.ItemType = rng.randomElement(price.ItemType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return manifest as IVendorManifestPreprocessed;
|
return manifest;
|
||||||
}
|
}
|
||||||
return originalManifest as IVendorManifestPreprocessed;
|
return originalManifest;
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshExpiry = (expiry: IMongoDate): number => {
|
const refreshExpiry = (expiry: IMongoDate): void => {
|
||||||
const period = parseInt(expiry.$date.$numberLong);
|
const period = parseInt(expiry.$date.$numberLong);
|
||||||
if (Date.now() >= period) {
|
if (Date.now() >= period) {
|
||||||
const epoch = 1734307200_000; // Monday (for weekly schedules)
|
const epoch = 1734307200_000; // Monday (for weekly schedules)
|
||||||
@ -161,65 +166,143 @@ const refreshExpiry = (expiry: IMongoDate): number => {
|
|||||||
const start = epoch + iteration * period;
|
const start = epoch + iteration * period;
|
||||||
const end = start + period;
|
const end = start + period;
|
||||||
expiry.$date.$numberLong = end.toString();
|
expiry.$date.$numberLong = end.toString();
|
||||||
return iteration;
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorManifestPreprocessed => {
|
const toRange = (value: IRange | number): IRange => {
|
||||||
const EPOCH = vendorInfo.cycleStart;
|
if (typeof value == "number") {
|
||||||
const manifest = ExportVendors[vendorInfo.TypeName];
|
return { minValue: value, maxValue: value };
|
||||||
let binThisCycle;
|
|
||||||
if (manifest.isOneBinPerCycle) {
|
|
||||||
const cycleDuration = vendorInfo.cycleDuration; // manifest.items[0].durationHours! * 3600_000;
|
|
||||||
const cycleIndex = Math.trunc((Date.now() - EPOCH) / cycleDuration);
|
|
||||||
binThisCycle = cycleIndex % 2; // Note: May want to auto-compute the bin size, but this is only used for coda weapons right now.
|
|
||||||
}
|
}
|
||||||
const items: IItemManifestPreprocessed[] = [];
|
return value;
|
||||||
let soonestOfferExpiry: number = Number.MAX_SAFE_INTEGER;
|
};
|
||||||
for (let i = 0; i != manifest.items.length; ++i) {
|
|
||||||
const rawItem = manifest.items[i];
|
const vendorInfoCache: Record<string, IVendorInfo> = {};
|
||||||
if (manifest.isOneBinPerCycle && rawItem.bin != binThisCycle) {
|
|
||||||
continue;
|
const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorManifest => {
|
||||||
|
if (!(vendorInfo.TypeName in vendorInfoCache)) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { cycleOffset, cycleDuration, ...clientVendorInfo } = vendorInfo;
|
||||||
|
vendorInfoCache[vendorInfo.TypeName] = {
|
||||||
|
...clientVendorInfo,
|
||||||
|
ItemManifest: [],
|
||||||
|
Expiry: { $date: { $numberLong: "0" } }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const processed = vendorInfoCache[vendorInfo.TypeName];
|
||||||
|
if (Date.now() >= parseInt(processed.Expiry.$date.$numberLong)) {
|
||||||
|
// Remove expired offers
|
||||||
|
for (let i = 0; i != processed.ItemManifest.length; ) {
|
||||||
|
if (Date.now() >= parseInt(processed.ItemManifest[i].Expiry.$date.$numberLong)) {
|
||||||
|
processed.ItemManifest.splice(i, 1);
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const cycleDuration = vendorInfo.cycleDuration; // rawItem.durationHours! * 3600_000;
|
|
||||||
const cycleIndex = Math.trunc((Date.now() - EPOCH) / cycleDuration);
|
// Add new offers
|
||||||
const cycleStart = EPOCH + cycleIndex * cycleDuration;
|
const vendorSeed = parseInt(vendorInfo._id.$oid.substring(16), 16);
|
||||||
const cycleEnd = cycleStart + cycleDuration;
|
const cycleOffset = vendorInfo.cycleOffset ?? 1734307200_000;
|
||||||
if (soonestOfferExpiry > cycleEnd) {
|
const cycleDuration = vendorInfo.cycleDuration;
|
||||||
soonestOfferExpiry = cycleEnd;
|
const cycleIndex = Math.trunc((Date.now() - cycleOffset) / cycleDuration);
|
||||||
|
const rng = new CRng(mixSeeds(vendorSeed, cycleIndex));
|
||||||
|
const manifest = ExportVendors[vendorInfo.TypeName];
|
||||||
|
const offersToAdd = [];
|
||||||
|
if (manifest.numItems && !manifest.isOneBinPerCycle) {
|
||||||
|
const numItemsTarget = rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue);
|
||||||
|
while (processed.ItemManifest.length + offersToAdd.length < numItemsTarget) {
|
||||||
|
// TODO: Consider per-bin item limits
|
||||||
|
// TODO: Consider item probability weightings
|
||||||
|
offersToAdd.push(rng.randomElement(manifest.items)!);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let binThisCycle;
|
||||||
|
if (manifest.isOneBinPerCycle) {
|
||||||
|
binThisCycle = cycleIndex % 2; // Note: May want to auto-compute the bin size, but this is only used for coda weapons right now.
|
||||||
|
}
|
||||||
|
for (const rawItem of manifest.items) {
|
||||||
|
if (!manifest.isOneBinPerCycle || rawItem.bin == binThisCycle) {
|
||||||
|
offersToAdd.push(rawItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For most vendors, the offers seem to roughly be in reverse order from the manifest. Coda weapons are an odd exception.
|
||||||
|
if (!manifest.isOneBinPerCycle) {
|
||||||
|
offersToAdd.reverse();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const rng = new CRng(cycleIndex);
|
const cycleStart = cycleOffset + cycleIndex * cycleDuration;
|
||||||
rng.churnSeed(i);
|
for (const rawItem of offersToAdd) {
|
||||||
/*for (let j = -1; j != rawItem.duplicates; ++j)*/ {
|
const durationHoursRange = toRange(rawItem.durationHours);
|
||||||
const item: IItemManifestPreprocessed = {
|
const expiry =
|
||||||
|
cycleStart +
|
||||||
|
rng.randomInt(durationHoursRange.minValue, durationHoursRange.maxValue) * unixTimesInMs.hour;
|
||||||
|
const item: IItemManifest = {
|
||||||
StoreItem: rawItem.storeItem,
|
StoreItem: rawItem.storeItem,
|
||||||
ItemPrices: rawItem.itemPrices!.map(itemPrice => ({ ...itemPrice, ProductCategory: "MiscItems" })),
|
ItemPrices: rawItem.itemPrices?.map(itemPrice => ({ ...itemPrice, ProductCategory: "MiscItems" })),
|
||||||
Bin: "BIN_" + rawItem.bin,
|
Bin: "BIN_" + rawItem.bin,
|
||||||
QuantityMultiplier: 1,
|
QuantityMultiplier: 1,
|
||||||
Expiry: { $date: { $numberLong: cycleEnd.toString() } },
|
Expiry: { $date: { $numberLong: expiry.toString() } },
|
||||||
AllowMultipurchase: false,
|
AllowMultipurchase: false,
|
||||||
Id: {
|
Id: {
|
||||||
$oid:
|
$oid:
|
||||||
i.toString(16).padStart(8, "0") +
|
((cycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") +
|
||||||
vendorInfo._id.$oid.substring(8, 16) +
|
vendorInfo._id.$oid.substring(8, 16) +
|
||||||
rng.randomInt(0, 0xffffffff).toString(16).padStart(8, "0")
|
rng.randomInt(0, 0xffff).toString(16).padStart(4, "0") +
|
||||||
|
rng.randomInt(0, 0xffff).toString(16).padStart(4, "0")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (vendorInfo.RandomSeedType) {
|
if (rawItem.numRandomItemPrices) {
|
||||||
item.LocTagRandSeed =
|
item.ItemPrices = [];
|
||||||
(BigInt(rng.randomInt(0, 0xffffffff)) << 32n) | BigInt(rng.randomInt(0, 0xffffffff));
|
for (let i = 0; i != rawItem.numRandomItemPrices; ++i) {
|
||||||
|
let itemPrice: { type: string; count: IRange };
|
||||||
|
do {
|
||||||
|
itemPrice = rng.randomElement(manifest.randomItemPricesPerBin![rawItem.bin])!;
|
||||||
|
} while (item.ItemPrices.find(x => x.ItemType == itemPrice.type));
|
||||||
|
item.ItemPrices.push({
|
||||||
|
ItemType: itemPrice.type,
|
||||||
|
ItemCount: rng.randomInt(itemPrice.count.minValue, itemPrice.count.maxValue),
|
||||||
|
ProductCategory: "MiscItems"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
items.push(item);
|
if (rawItem.credits) {
|
||||||
|
const value =
|
||||||
|
typeof rawItem.credits == "number"
|
||||||
|
? rawItem.credits
|
||||||
|
: rng.randomInt(
|
||||||
|
rawItem.credits.minValue / rawItem.credits.step,
|
||||||
|
rawItem.credits.maxValue / rawItem.credits.step
|
||||||
|
) * rawItem.credits.step;
|
||||||
|
item.RegularPrice = [value, value];
|
||||||
|
}
|
||||||
|
if (rawItem.platinum) {
|
||||||
|
const value =
|
||||||
|
typeof rawItem.platinum == "number"
|
||||||
|
? rawItem.platinum
|
||||||
|
: rng.randomInt(rawItem.platinum.minValue, rawItem.platinum.maxValue);
|
||||||
|
item.PremiumPrice = [value, value];
|
||||||
|
}
|
||||||
|
if (vendorInfo.RandomSeedType) {
|
||||||
|
item.LocTagRandSeed = (rng.randomInt(0, 0xffff) << 16) | rng.randomInt(0, 0xffff);
|
||||||
|
if (vendorInfo.RandomSeedType == "VRST_WEAPON") {
|
||||||
|
const highDword = (rng.randomInt(0, 0xffff) << 16) | rng.randomInt(0, 0xffff);
|
||||||
|
item.LocTagRandSeed = (BigInt(highDword) << 32n) | (BigInt(item.LocTagRandSeed) & 0xffffffffn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processed.ItemManifest.push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update vendor expiry
|
||||||
|
let soonestOfferExpiry: number = Number.MAX_SAFE_INTEGER;
|
||||||
|
for (const offer of processed.ItemManifest) {
|
||||||
|
const offerExpiry = parseInt(offer.Expiry.$date.$numberLong);
|
||||||
|
if (soonestOfferExpiry > offerExpiry) {
|
||||||
|
soonestOfferExpiry = offerExpiry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processed.Expiry.$date.$numberLong = soonestOfferExpiry.toString();
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
const { cycleStart, cycleDuration, ...clientVendorInfo } = vendorInfo;
|
|
||||||
return {
|
return {
|
||||||
VendorInfo: {
|
VendorInfo: processed
|
||||||
...clientVendorInfo,
|
|
||||||
ItemManifest: items,
|
|
||||||
Expiry: { $date: { $numberLong: soonestOfferExpiry.toString() } }
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,10 +1,20 @@
|
|||||||
import staticWorldState from "@/static/fixed_responses/worldState/worldState.json";
|
import staticWorldState from "@/static/fixed_responses/worldState/worldState.json";
|
||||||
|
import sortieTilesets from "@/static/fixed_responses/worldState/sortieTilesets.json";
|
||||||
|
import syndicateMissions from "@/static/fixed_responses/worldState/syndicateMissions.json";
|
||||||
import { buildConfig } from "@/src/services/buildConfigService";
|
import { buildConfig } from "@/src/services/buildConfigService";
|
||||||
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
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 { eMissionType, ExportNightwave, ExportRegions } from "warframe-public-export-plus";
|
import { eMissionType, ExportNightwave, ExportRegions, IRegion } from "warframe-public-export-plus";
|
||||||
import { ICalendarDay, ICalendarSeason, ILiteSortie, ISeasonChallenge, IWorldState } from "../types/worldStateTypes";
|
import {
|
||||||
|
ICalendarDay,
|
||||||
|
ICalendarEvent,
|
||||||
|
ICalendarSeason,
|
||||||
|
ILiteSortie,
|
||||||
|
ISeasonChallenge,
|
||||||
|
ISortieMission,
|
||||||
|
IWorldState
|
||||||
|
} from "../types/worldStateTypes";
|
||||||
|
|
||||||
const sortieBosses = [
|
const sortieBosses = [
|
||||||
"SORTIE_BOSS_HYENA",
|
"SORTIE_BOSS_HYENA",
|
||||||
@ -23,9 +33,11 @@ const sortieBosses = [
|
|||||||
"SORTIE_BOSS_LEPHANTIS",
|
"SORTIE_BOSS_LEPHANTIS",
|
||||||
"SORTIE_BOSS_INFALAD",
|
"SORTIE_BOSS_INFALAD",
|
||||||
"SORTIE_BOSS_CORRUPTED_VOR"
|
"SORTIE_BOSS_CORRUPTED_VOR"
|
||||||
];
|
] as const;
|
||||||
|
|
||||||
const sortieBossToFaction: Record<string, string> = {
|
type TSortieBoss = (typeof sortieBosses)[number];
|
||||||
|
|
||||||
|
const sortieBossToFaction: Record<TSortieBoss, string> = {
|
||||||
SORTIE_BOSS_HYENA: "FC_CORPUS",
|
SORTIE_BOSS_HYENA: "FC_CORPUS",
|
||||||
SORTIE_BOSS_KELA: "FC_GRINEER",
|
SORTIE_BOSS_KELA: "FC_GRINEER",
|
||||||
SORTIE_BOSS_VOR: "FC_GRINEER",
|
SORTIE_BOSS_VOR: "FC_GRINEER",
|
||||||
@ -41,38 +53,45 @@ const sortieBossToFaction: Record<string, string> = {
|
|||||||
SORTIE_BOSS_PHORID: "FC_INFESTATION",
|
SORTIE_BOSS_PHORID: "FC_INFESTATION",
|
||||||
SORTIE_BOSS_LEPHANTIS: "FC_INFESTATION",
|
SORTIE_BOSS_LEPHANTIS: "FC_INFESTATION",
|
||||||
SORTIE_BOSS_INFALAD: "FC_INFESTATION",
|
SORTIE_BOSS_INFALAD: "FC_INFESTATION",
|
||||||
SORTIE_BOSS_CORRUPTED_VOR: "FC_CORRUPTED"
|
SORTIE_BOSS_CORRUPTED_VOR: "FC_OROKIN"
|
||||||
};
|
};
|
||||||
|
|
||||||
const sortieFactionToSystemIndexes: Record<string, number[]> = {
|
const sortieFactionToSystemIndexes: Record<string, number[]> = {
|
||||||
FC_GRINEER: [0, 2, 3, 5, 6, 9, 11, 18],
|
FC_GRINEER: [0, 2, 3, 5, 6, 9, 11, 18],
|
||||||
FC_CORPUS: [1, 4, 7, 8, 12, 15],
|
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_INFESTATION: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15],
|
||||||
FC_CORRUPTED: [14]
|
FC_OROKIN: [14]
|
||||||
};
|
};
|
||||||
|
|
||||||
const sortieFactionToFactionIndexes: Record<string, number[]> = {
|
const sortieFactionToFactionIndexes: Record<string, number[]> = {
|
||||||
FC_GRINEER: [0],
|
FC_GRINEER: [0],
|
||||||
FC_CORPUS: [1],
|
FC_CORPUS: [1],
|
||||||
FC_INFESTATION: [0, 1, 2],
|
FC_INFESTATION: [0, 1, 2],
|
||||||
FC_CORRUPTED: [3]
|
FC_OROKIN: [3]
|
||||||
};
|
};
|
||||||
|
|
||||||
const sortieBossNode: Record<string, string> = {
|
const sortieFactionToSpecialMissionTileset: Record<string, string> = {
|
||||||
SORTIE_BOSS_HYENA: "SolNode127",
|
FC_GRINEER: "GrineerGalleonTileset",
|
||||||
SORTIE_BOSS_KELA: "SolNode193",
|
FC_CORPUS: "CorpusShipTileset",
|
||||||
SORTIE_BOSS_VOR: "SolNode108",
|
FC_INFESTATION: "CorpusShipTileset"
|
||||||
SORTIE_BOSS_RUK: "SolNode32",
|
};
|
||||||
SORTIE_BOSS_HEK: "SolNode24",
|
|
||||||
SORTIE_BOSS_KRIL: "SolNode99",
|
const sortieBossNode: Record<Exclude<TSortieBoss, "SORTIE_BOSS_CORRUPTED_VOR">, string> = {
|
||||||
SORTIE_BOSS_TYL: "SolNode105",
|
|
||||||
SORTIE_BOSS_JACKAL: "SolNode104",
|
|
||||||
SORTIE_BOSS_ALAD: "SolNode53",
|
SORTIE_BOSS_ALAD: "SolNode53",
|
||||||
SORTIE_BOSS_AMBULAS: "SolNode51",
|
SORTIE_BOSS_AMBULAS: "SolNode51",
|
||||||
SORTIE_BOSS_NEF: "SettlementNode20",
|
SORTIE_BOSS_HEK: "SolNode24",
|
||||||
SORTIE_BOSS_RAPTOR: "SolNode210",
|
SORTIE_BOSS_HYENA: "SolNode127",
|
||||||
|
SORTIE_BOSS_INFALAD: "SolNode166",
|
||||||
|
SORTIE_BOSS_JACKAL: "SolNode104",
|
||||||
|
SORTIE_BOSS_KELA: "SolNode193",
|
||||||
|
SORTIE_BOSS_KRIL: "SolNode99",
|
||||||
SORTIE_BOSS_LEPHANTIS: "SolNode712",
|
SORTIE_BOSS_LEPHANTIS: "SolNode712",
|
||||||
SORTIE_BOSS_INFALAD: "SolNode705"
|
SORTIE_BOSS_NEF: "SettlementNode20",
|
||||||
|
SORTIE_BOSS_PHORID: "SolNode171",
|
||||||
|
SORTIE_BOSS_RAPTOR: "SolNode210",
|
||||||
|
SORTIE_BOSS_RUK: "SolNode32",
|
||||||
|
SORTIE_BOSS_TYL: "SolNode105",
|
||||||
|
SORTIE_BOSS_VOR: "SolNode108"
|
||||||
};
|
};
|
||||||
|
|
||||||
const eidolonJobs = [
|
const eidolonJobs = [
|
||||||
@ -174,18 +193,7 @@ const pushSyndicateMissions = (
|
|||||||
idSuffix: string,
|
idSuffix: string,
|
||||||
syndicateTag: string
|
syndicateTag: string
|
||||||
): void => {
|
): void => {
|
||||||
const nodeOptions: string[] = [];
|
const nodeOptions: string[] = [...syndicateMissions];
|
||||||
for (const [key, value] of Object.entries(ExportRegions)) {
|
|
||||||
if (
|
|
||||||
value.name.indexOf("Archwing") == -1 && // no archwing
|
|
||||||
value.systemIndex != 23 && // no 1999 stuff
|
|
||||||
value.missionIndex != 10 && // Exclude MT_PVP (for relays)
|
|
||||||
value.missionIndex != 23 && // no junctions
|
|
||||||
value.missionIndex <= 28 // no railjack or some such
|
|
||||||
) {
|
|
||||||
nodeOptions.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const rng = new CRng(seed);
|
const rng = new CRng(seed);
|
||||||
const nodes: string[] = [];
|
const nodes: string[] = [];
|
||||||
@ -198,7 +206,7 @@ const pushSyndicateMissions = (
|
|||||||
const dayStart = getSortieTime(day);
|
const dayStart = getSortieTime(day);
|
||||||
const dayEnd = getSortieTime(day + 1);
|
const dayEnd = getSortieTime(day + 1);
|
||||||
worldState.SyndicateMissions.push({
|
worldState.SyndicateMissions.push({
|
||||||
_id: { $oid: Math.trunc(dayStart / 1000).toString(16) + idSuffix },
|
_id: { $oid: ((dayStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + idSuffix },
|
||||||
Activation: { $date: { $numberLong: dayStart.toString() } },
|
Activation: { $date: { $numberLong: dayStart.toString() } },
|
||||||
Expiry: { $date: { $numberLong: dayEnd.toString() } },
|
Expiry: { $date: { $numberLong: dayEnd.toString() } },
|
||||||
Tag: syndicateTag,
|
Tag: syndicateTag,
|
||||||
@ -217,9 +225,10 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rng = new CRng(day);
|
const seed = new CRng(day).randomInt(0, 0xffff);
|
||||||
|
const rng = new CRng(seed);
|
||||||
|
|
||||||
const boss = rng.randomElement(sortieBosses);
|
const boss = rng.randomElement(sortieBosses)!;
|
||||||
|
|
||||||
const modifiers = [
|
const modifiers = [
|
||||||
"SORTIE_MODIFIER_LOW_ENERGY",
|
"SORTIE_MODIFIER_LOW_ENERGY",
|
||||||
@ -261,50 +270,61 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => {
|
|||||||
if (
|
if (
|
||||||
sortieFactionToSystemIndexes[sortieBossToFaction[boss]].includes(value.systemIndex) &&
|
sortieFactionToSystemIndexes[sortieBossToFaction[boss]].includes(value.systemIndex) &&
|
||||||
sortieFactionToFactionIndexes[sortieBossToFaction[boss]].includes(value.factionIndex!) &&
|
sortieFactionToFactionIndexes[sortieBossToFaction[boss]].includes(value.factionIndex!) &&
|
||||||
value.name.indexOf("Archwing") == -1 &&
|
key in sortieTilesets
|
||||||
value.missionIndex != 0 && // Exclude MT_ASSASSINATION
|
|
||||||
value.missionIndex != 5 && // Exclude MT_CAPTURE
|
|
||||||
value.missionIndex != 10 && // Exclude MT_PVP (for relays)
|
|
||||||
value.missionIndex != 21 && // Exclude MT_PURIFY
|
|
||||||
value.missionIndex != 22 && // Exclude MT_ARENA
|
|
||||||
value.missionIndex != 23 && // Exclude MT_JUNCTION
|
|
||||||
value.missionIndex <= 28
|
|
||||||
) {
|
) {
|
||||||
if (!availableMissionIndexes.includes(value.missionIndex)) {
|
if (
|
||||||
|
value.missionIndex != 0 && // Assassination will be decided independently
|
||||||
|
value.missionIndex != 5 && // Sorties do not have capture missions
|
||||||
|
!availableMissionIndexes.includes(value.missionIndex)
|
||||||
|
) {
|
||||||
availableMissionIndexes.push(value.missionIndex);
|
availableMissionIndexes.push(value.missionIndex);
|
||||||
}
|
}
|
||||||
nodes.push(key);
|
nodes.push(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedNodes: { missionType: string; modifierType: string; node: string }[] = [];
|
const specialMissionTypes = [1, 3, 5, 9];
|
||||||
|
if (!(sortieBossToFaction[boss] in sortieFactionToSpecialMissionTileset)) {
|
||||||
|
for (const missionType of specialMissionTypes) {
|
||||||
|
const i = availableMissionIndexes.indexOf(missionType);
|
||||||
|
if (i != -1) {
|
||||||
|
availableMissionIndexes.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedNodes: ISortieMission[] = [];
|
||||||
const missionTypes = new Set();
|
const missionTypes = new Set();
|
||||||
|
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
const randomIndex = rng.randomInt(0, nodes.length - 1);
|
let randomIndex;
|
||||||
const node = nodes[randomIndex];
|
let node;
|
||||||
let missionIndex = ExportRegions[node].missionIndex;
|
let missionIndex;
|
||||||
|
do {
|
||||||
|
randomIndex = rng.randomInt(0, nodes.length - 1);
|
||||||
|
node = nodes[randomIndex];
|
||||||
|
|
||||||
if (
|
missionIndex = ExportRegions[node].missionIndex;
|
||||||
!["SolNode404", "SolNode411"].includes(node) && // for some reason the game doesn't like missionType changes for these missions
|
if (missionIndex != 28) {
|
||||||
missionIndex != 28 &&
|
missionIndex = rng.randomElement(availableMissionIndexes)!;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
} while (
|
||||||
|
specialMissionTypes.indexOf(missionIndex) != -1 &&
|
||||||
|
sortieTilesets[node as keyof typeof sortieTilesets] !=
|
||||||
|
sortieFactionToSpecialMissionTileset[sortieBossToFaction[boss]]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (i == 2 && boss != "SORTIE_BOSS_CORRUPTED_VOR" && rng.randomInt(0, 2) == 2) {
|
||||||
|
const filteredModifiers = modifiers.filter(mod => mod !== "SORTIE_MODIFIER_MELEE_ONLY");
|
||||||
|
const modifierType = rng.randomElement(filteredModifiers)!;
|
||||||
|
|
||||||
|
selectedNodes.push({
|
||||||
|
missionType: "MT_ASSASSINATION",
|
||||||
|
modifierType,
|
||||||
|
node: sortieBossNode[boss],
|
||||||
|
tileset: sortieTilesets[sortieBossNode[boss] as keyof typeof sortieTilesets]
|
||||||
|
});
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const missionType = eMissionType[missionIndex].tag;
|
const missionType = eMissionType[missionIndex].tag;
|
||||||
@ -319,19 +339,24 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => {
|
|||||||
? modifiers.filter(mod => mod != "SORTIE_MODIFIER_HAZARD_RADIATION")
|
? modifiers.filter(mod => mod != "SORTIE_MODIFIER_HAZARD_RADIATION")
|
||||||
: modifiers;
|
: modifiers;
|
||||||
|
|
||||||
const modifierType = rng.randomElement(filteredModifiers);
|
const modifierType = rng.randomElement(filteredModifiers)!;
|
||||||
|
|
||||||
selectedNodes.push({ missionType, modifierType, node });
|
selectedNodes.push({
|
||||||
|
missionType,
|
||||||
|
modifierType,
|
||||||
|
node,
|
||||||
|
tileset: sortieTilesets[node as keyof typeof sortieTilesets]
|
||||||
|
});
|
||||||
nodes.splice(randomIndex, 1);
|
nodes.splice(randomIndex, 1);
|
||||||
missionTypes.add(missionType);
|
missionTypes.add(missionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
worldState.Sorties.push({
|
worldState.Sorties.push({
|
||||||
_id: { $oid: Math.trunc(dayStart / 1000).toString(16) + "d4d932c97c0a3acd" },
|
_id: { $oid: ((dayStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "d4d932c97c0a3acd" },
|
||||||
Activation: { $date: { $numberLong: dayStart.toString() } },
|
Activation: { $date: { $numberLong: dayStart.toString() } },
|
||||||
Expiry: { $date: { $numberLong: dayEnd.toString() } },
|
Expiry: { $date: { $numberLong: dayEnd.toString() } },
|
||||||
Reward: "/Lotus/Types/Game/MissionDecks/SortieRewards",
|
Reward: "/Lotus/Types/Game/MissionDecks/SortieRewards",
|
||||||
Seed: day,
|
Seed: seed,
|
||||||
Boss: boss,
|
Boss: boss,
|
||||||
Variants: selectedNodes
|
Variants: selectedNodes
|
||||||
});
|
});
|
||||||
@ -351,13 +376,13 @@ const dailyChallenges = Object.keys(ExportNightwave.challenges).filter(x =>
|
|||||||
const getSeasonDailyChallenge = (day: number): ISeasonChallenge => {
|
const getSeasonDailyChallenge = (day: number): ISeasonChallenge => {
|
||||||
const dayStart = EPOCH + day * 86400000;
|
const dayStart = EPOCH + day * 86400000;
|
||||||
const dayEnd = EPOCH + (day + 3) * 86400000;
|
const dayEnd = EPOCH + (day + 3) * 86400000;
|
||||||
const rng = new CRng(day);
|
const rng = new CRng(new CRng(day).randomInt(0, 0xffff));
|
||||||
return {
|
return {
|
||||||
_id: { $oid: "67e1b5ca9d00cb47" + day.toString().padStart(8, "0") },
|
_id: { $oid: "67e1b5ca9d00cb47" + day.toString().padStart(8, "0") },
|
||||||
Daily: true,
|
Daily: true,
|
||||||
Activation: { $date: { $numberLong: dayStart.toString() } },
|
Activation: { $date: { $numberLong: dayStart.toString() } },
|
||||||
Expiry: { $date: { $numberLong: dayEnd.toString() } },
|
Expiry: { $date: { $numberLong: dayEnd.toString() } },
|
||||||
Challenge: rng.randomElement(dailyChallenges)
|
Challenge: rng.randomElement(dailyChallenges)!
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -371,12 +396,12 @@ const getSeasonWeeklyChallenge = (week: number, id: number): ISeasonChallenge =>
|
|||||||
const weekStart = EPOCH + week * 604800000;
|
const weekStart = EPOCH + week * 604800000;
|
||||||
const weekEnd = weekStart + 604800000;
|
const weekEnd = weekStart + 604800000;
|
||||||
const challengeId = week * 7 + id;
|
const challengeId = week * 7 + id;
|
||||||
const rng = new CRng(challengeId);
|
const rng = new CRng(new CRng(challengeId).randomInt(0, 0xffff));
|
||||||
return {
|
return {
|
||||||
_id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") },
|
_id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") },
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
Challenge: rng.randomElement(weeklyChallenges)
|
Challenge: rng.randomElement(weeklyChallenges)!
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -388,12 +413,12 @@ const getSeasonWeeklyHardChallenge = (week: number, id: number): ISeasonChalleng
|
|||||||
const weekStart = EPOCH + week * 604800000;
|
const weekStart = EPOCH + week * 604800000;
|
||||||
const weekEnd = weekStart + 604800000;
|
const weekEnd = weekStart + 604800000;
|
||||||
const challengeId = week * 7 + id;
|
const challengeId = week * 7 + id;
|
||||||
const rng = new CRng(challengeId);
|
const rng = new CRng(new CRng(challengeId).randomInt(0, 0xffff));
|
||||||
return {
|
return {
|
||||||
_id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") },
|
_id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") },
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
Challenge: rng.randomElement(weeklyHardChallenges)
|
Challenge: rng.randomElement(weeklyHardChallenges)!
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -440,8 +465,8 @@ const birthdays: number[] = [
|
|||||||
|
|
||||||
const getCalendarSeason = (week: number): ICalendarSeason => {
|
const getCalendarSeason = (week: number): ICalendarSeason => {
|
||||||
const seasonIndex = week % 4;
|
const seasonIndex = week % 4;
|
||||||
const seasonDay1 = seasonIndex * 90 + 1;
|
const seasonDay1 = [1, 91, 182, 274][seasonIndex];
|
||||||
const seasonDay91 = seasonIndex * 90 + 91;
|
const seasonDay91 = seasonDay1 + 90;
|
||||||
const eventDays: ICalendarDay[] = [];
|
const eventDays: ICalendarDay[] = [];
|
||||||
for (const day of birthdays) {
|
for (const day of birthdays) {
|
||||||
if (day < seasonDay1) {
|
if (day < seasonDay1) {
|
||||||
@ -453,7 +478,7 @@ const getCalendarSeason = (week: number): ICalendarSeason => {
|
|||||||
//logger.debug(`birthday on day ${day}`);
|
//logger.debug(`birthday on day ${day}`);
|
||||||
eventDays.push({ day, events: [] }); // This is how CET_PLOT looks in worldState as of around 38.5.0
|
eventDays.push({ day, events: [] }); // This is how CET_PLOT looks in worldState as of around 38.5.0
|
||||||
}
|
}
|
||||||
const rng = new CRng(week);
|
const rng = new CRng(new CRng(week).randomInt(0, 0xffff));
|
||||||
const challenges = [
|
const challenges = [
|
||||||
"/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesEasy",
|
"/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesEasy",
|
||||||
"/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesMedium",
|
"/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesMedium",
|
||||||
@ -500,8 +525,12 @@ const getCalendarSeason = (week: number): ICalendarSeason => {
|
|||||||
challengeDay = rng.randomInt(chunkDay1, chunkDay13);
|
challengeDay = rng.randomInt(chunkDay1, chunkDay13);
|
||||||
} while (birthdays.indexOf(challengeDay) != -1);
|
} while (birthdays.indexOf(challengeDay) != -1);
|
||||||
|
|
||||||
const challengeIndex = rng.randomInt(0, challenges.length - 1);
|
let challengeIndex;
|
||||||
const challenge = challenges[challengeIndex];
|
let challenge;
|
||||||
|
do {
|
||||||
|
challengeIndex = rng.randomInt(0, challenges.length - 1);
|
||||||
|
challenge = challenges[challengeIndex];
|
||||||
|
} while (i < 2 && !challenge.endsWith("Easy")); // First 2 challenges should be easy
|
||||||
challenges.splice(challengeIndex, 1);
|
challenges.splice(challengeIndex, 1);
|
||||||
|
|
||||||
//logger.debug(`challenge on day ${challengeDay}`);
|
//logger.debug(`challenge on day ${challengeDay}`);
|
||||||
@ -548,69 +577,100 @@ const getCalendarSeason = (week: number): ICalendarSeason => {
|
|||||||
"/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalViolet"
|
"/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalViolet"
|
||||||
];
|
];
|
||||||
for (let i = 0; i != rewardRanges.length - 1; ++i) {
|
for (let i = 0; i != rewardRanges.length - 1; ++i) {
|
||||||
const rewardIndex = rng.randomInt(0, rewards.length - 1);
|
const events: ICalendarEvent[] = [];
|
||||||
const reward = rewards[rewardIndex];
|
for (let j = 0; j != 2; ++j) {
|
||||||
rewards.splice(rewardIndex, 1);
|
const rewardIndex = rng.randomInt(0, rewards.length - 1);
|
||||||
|
events.push({ type: "CET_REWARD", reward: rewards[rewardIndex] });
|
||||||
|
rewards.splice(rewardIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
//logger.debug(`trying to fit a reward between day ${rewardRanges[i]} and ${rewardRanges[i + 1]}`);
|
//logger.debug(`trying to fit rewards between day ${rewardRanges[i]} and ${rewardRanges[i + 1]}`);
|
||||||
let day: number;
|
let day: number;
|
||||||
do {
|
do {
|
||||||
day = rng.randomInt(rewardRanges[i] + 1, rewardRanges[i + 1] - 1);
|
day = rng.randomInt(rewardRanges[i] + 1, rewardRanges[i + 1] - 1);
|
||||||
} while (eventDays.find(x => x.day == day));
|
} while (eventDays.find(x => x.day == day));
|
||||||
eventDays.push({ day, events: [{ type: "CET_REWARD", reward }] });
|
eventDays.push({ day, events });
|
||||||
}
|
}
|
||||||
|
|
||||||
const upgrades = [
|
const upgradesByHexMember = [
|
||||||
"/Lotus/Upgrades/Calendar/MeleeCritChance",
|
[
|
||||||
"/Lotus/Upgrades/Calendar/MeleeAttackSpeed",
|
"/Lotus/Upgrades/Calendar/AttackAndMovementSpeedOnCritMelee",
|
||||||
"/Lotus/Upgrades/Calendar/EnergyOrbToAbilityRange",
|
"/Lotus/Upgrades/Calendar/ElectricalDamageOnBulletJump",
|
||||||
"/Lotus/Upgrades/Calendar/AbilityStrength",
|
"/Lotus/Upgrades/Calendar/ElectricDamagePerDistance",
|
||||||
"/Lotus/Upgrades/Calendar/Armor",
|
"/Lotus/Upgrades/Calendar/ElectricStatusDamageAndChance",
|
||||||
"/Lotus/Upgrades/Calendar/RadiationProcOnTakeDamage",
|
"/Lotus/Upgrades/Calendar/OvershieldCap",
|
||||||
"/Lotus/Upgrades/Calendar/CompanionDamage",
|
"/Lotus/Upgrades/Calendar/SpeedBuffsWhenAirborne"
|
||||||
"/Lotus/Upgrades/Calendar/GasChanceToPrimaryAndSecondary",
|
],
|
||||||
"/Lotus/Upgrades/Calendar/MagazineCapacity",
|
[
|
||||||
"/Lotus/Upgrades/Calendar/PunchToPrimary",
|
"/Lotus/Upgrades/Calendar/AbilityStrength",
|
||||||
"/Lotus/Upgrades/Calendar/HealingEffects",
|
"/Lotus/Upgrades/Calendar/EnergyOrbToAbilityRange",
|
||||||
"/Lotus/Upgrades/Calendar/EnergyRestoration",
|
"/Lotus/Upgrades/Calendar/MagnetStatusPull",
|
||||||
"/Lotus/Upgrades/Calendar/OvershieldCap",
|
"/Lotus/Upgrades/Calendar/MagnitizeWithinRangeEveryXCasts",
|
||||||
"/Lotus/Upgrades/Calendar/ElectricStatusDamageAndChance",
|
"/Lotus/Upgrades/Calendar/PowerStrengthAndEfficiencyPerEnergySpent",
|
||||||
"/Lotus/Upgrades/Calendar/FinisherChancePerComboMultiplier",
|
"/Lotus/Upgrades/Calendar/SharedFreeAbilityEveryXCasts"
|
||||||
"/Lotus/Upgrades/Calendar/MagnetStatusPull",
|
],
|
||||||
"/Lotus/Upgrades/Calendar/CompanionsBuffNearbyPlayer",
|
[
|
||||||
"/Lotus/Upgrades/Calendar/StatusChancePerAmmoSpent",
|
"/Lotus/Upgrades/Calendar/EnergyWavesOnCombo",
|
||||||
"/Lotus/Upgrades/Calendar/OrbsDuplicateOnPickup",
|
"/Lotus/Upgrades/Calendar/FinisherChancePerComboMultiplier",
|
||||||
"/Lotus/Upgrades/Calendar/AttackAndMovementSpeedOnCritMelee",
|
"/Lotus/Upgrades/Calendar/MeleeAttackSpeed",
|
||||||
"/Lotus/Upgrades/Calendar/RadialJavelinOnHeavy",
|
"/Lotus/Upgrades/Calendar/MeleeCritChance",
|
||||||
"/Lotus/Upgrades/Calendar/MagnitizeWithinRangeEveryXCasts",
|
"/Lotus/Upgrades/Calendar/MeleeSlideFowardMomentumOnEnemyHit",
|
||||||
"/Lotus/Upgrades/Calendar/CompanionsRadiationChance",
|
"/Lotus/Upgrades/Calendar/RadialJavelinOnHeavy"
|
||||||
"/Lotus/Upgrades/Calendar/BlastEveryXShots",
|
],
|
||||||
"/Lotus/Upgrades/Calendar/GenerateOmniOrbsOnWeakKill",
|
[
|
||||||
"/Lotus/Upgrades/Calendar/ElectricDamagePerDistance",
|
"/Lotus/Upgrades/Calendar/Armor",
|
||||||
"/Lotus/Upgrades/Calendar/MeleeSlideFowardMomentumOnEnemyHit",
|
"/Lotus/Upgrades/Calendar/CloneActiveCompanionForEnergySpent",
|
||||||
"/Lotus/Upgrades/Calendar/SharedFreeAbilityEveryXCasts",
|
"/Lotus/Upgrades/Calendar/CompanionDamage",
|
||||||
"/Lotus/Upgrades/Calendar/ReviveEnemyAsSpectreOnKill",
|
"/Lotus/Upgrades/Calendar/CompanionsBuffNearbyPlayer",
|
||||||
"/Lotus/Upgrades/Calendar/RefundBulletOnStatusProc",
|
"/Lotus/Upgrades/Calendar/CompanionsRadiationChance",
|
||||||
"/Lotus/Upgrades/Calendar/ExplodingHealthOrbs",
|
"/Lotus/Upgrades/Calendar/RadiationProcOnTakeDamage",
|
||||||
"/Lotus/Upgrades/Calendar/SpeedBuffsWhenAirborne",
|
"/Lotus/Upgrades/Calendar/ReviveEnemyAsSpectreOnKill"
|
||||||
"/Lotus/Upgrades/Calendar/EnergyWavesOnCombo",
|
],
|
||||||
"/Lotus/Upgrades/Calendar/PowerStrengthAndEfficiencyPerEnergySpent",
|
[
|
||||||
"/Lotus/Upgrades/Calendar/CloneActiveCompanionForEnergySpent",
|
"/Lotus/Upgrades/Calendar/EnergyOrbsGrantShield",
|
||||||
"/Lotus/Upgrades/Calendar/GuidingMissilesChance",
|
"/Lotus/Upgrades/Calendar/EnergyRestoration",
|
||||||
"/Lotus/Upgrades/Calendar/EnergyOrbsGrantShield",
|
"/Lotus/Upgrades/Calendar/ExplodingHealthOrbs",
|
||||||
"/Lotus/Upgrades/Calendar/ElectricalDamageOnBulletJump"
|
"/Lotus/Upgrades/Calendar/GenerateOmniOrbsOnWeakKill",
|
||||||
|
"/Lotus/Upgrades/Calendar/HealingEffects",
|
||||||
|
"/Lotus/Upgrades/Calendar/OrbsDuplicateOnPickup"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"/Lotus/Upgrades/Calendar/BlastEveryXShots",
|
||||||
|
"/Lotus/Upgrades/Calendar/GasChanceToPrimaryAndSecondary",
|
||||||
|
"/Lotus/Upgrades/Calendar/GuidingMissilesChance",
|
||||||
|
"/Lotus/Upgrades/Calendar/MagazineCapacity",
|
||||||
|
"/Lotus/Upgrades/Calendar/PunchToPrimary",
|
||||||
|
"/Lotus/Upgrades/Calendar/RefundBulletOnStatusProc",
|
||||||
|
"/Lotus/Upgrades/Calendar/StatusChancePerAmmoSpent"
|
||||||
|
]
|
||||||
];
|
];
|
||||||
for (let i = 0; i != upgradeRanges.length - 1; ++i) {
|
for (let i = 0; i != upgradeRanges.length - 1; ++i) {
|
||||||
const upgradeIndex = rng.randomInt(0, upgrades.length - 1);
|
// Pick 3 unique hex members
|
||||||
const upgrade = upgrades[upgradeIndex];
|
const hexMembersPickedForThisDay: number[] = [];
|
||||||
upgrades.splice(upgradeIndex, 1);
|
for (let j = 0; j != 3; ++j) {
|
||||||
|
let hexMemberIndex: number;
|
||||||
|
do {
|
||||||
|
hexMemberIndex = rng.randomInt(0, upgradesByHexMember.length - 1);
|
||||||
|
} while (hexMembersPickedForThisDay.indexOf(hexMemberIndex) != -1);
|
||||||
|
hexMembersPickedForThisDay.push(hexMemberIndex);
|
||||||
|
}
|
||||||
|
hexMembersPickedForThisDay.sort(); // Always present them in the same order
|
||||||
|
|
||||||
//logger.debug(`trying to fit an upgrade between day ${upgradeRanges[i]} and ${upgradeRanges[i + 1]}`);
|
// For each hex member, pick an upgrade that was not yet picked this season.
|
||||||
|
const events: ICalendarEvent[] = [];
|
||||||
|
for (const hexMemberIndex of hexMembersPickedForThisDay) {
|
||||||
|
const upgrades = upgradesByHexMember[hexMemberIndex];
|
||||||
|
const upgradeIndex = rng.randomInt(0, upgrades.length - 1);
|
||||||
|
events.push({ type: "CET_UPGRADE", upgrade: upgrades[upgradeIndex] });
|
||||||
|
upgrades.splice(upgradeIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//logger.debug(`trying to fit upgrades between day ${upgradeRanges[i]} and ${upgradeRanges[i + 1]}`);
|
||||||
let day: number;
|
let day: number;
|
||||||
do {
|
do {
|
||||||
day = rng.randomInt(upgradeRanges[i] + 1, upgradeRanges[i + 1] - 1);
|
day = rng.randomInt(upgradeRanges[i] + 1, upgradeRanges[i + 1] - 1);
|
||||||
} while (eventDays.find(x => x.day == day));
|
} while (eventDays.find(x => x.day == day));
|
||||||
eventDays.push({ day, events: [{ type: "CET_UPGRADE", upgrade }] });
|
eventDays.push({ day, events });
|
||||||
}
|
}
|
||||||
|
|
||||||
eventDays.sort((a, b) => a.day - b.day);
|
eventDays.sort((a, b) => a.day - b.day);
|
||||||
@ -621,7 +681,7 @@ const getCalendarSeason = (week: number): ICalendarSeason => {
|
|||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
Days: eventDays,
|
Days: eventDays,
|
||||||
Season: ["CST_WINTER", "CST_SPRING", "CST_SUMMER", "CST_FALL"][seasonIndex],
|
Season: (["CST_WINTER", "CST_SPRING", "CST_SUMMER", "CST_FALL"] as const)[seasonIndex],
|
||||||
YearIteration: Math.trunc(week / 4),
|
YearIteration: Math.trunc(week / 4),
|
||||||
Version: 19,
|
Version: 19,
|
||||||
UpgradeAvaliabilityRequirements: ["/Lotus/Upgrades/Calendar/1999UpgradeApplicationRequirement"]
|
UpgradeAvaliabilityRequirements: ["/Lotus/Upgrades/Calendar/1999UpgradeApplicationRequirement"]
|
||||||
@ -657,6 +717,11 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
SyndicateMissions: [...staticWorldState.SyndicateMissions]
|
SyndicateMissions: [...staticWorldState.SyndicateMissions]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Omit void fissures for versions prior to Whispers in the Walls to avoid errors with the unknown deimos nodes having void fissures.
|
||||||
|
if (buildLabel && version_compare(buildLabel, "2023.11.06.13.39") <= 0) {
|
||||||
|
worldState.ActiveMissions = [];
|
||||||
|
}
|
||||||
|
|
||||||
if (config.worldState?.starDays) {
|
if (config.worldState?.starDays) {
|
||||||
worldState.Goals.push({
|
worldState.Goals.push({
|
||||||
_id: { $oid: "67a4dcce2a198564d62e1647" },
|
_id: { $oid: "67a4dcce2a198564d62e1647" },
|
||||||
@ -687,7 +752,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Elite Sanctuary Onslaught cycling every week
|
// Elite Sanctuary Onslaught cycling every week
|
||||||
worldState.NodeOverrides.find(x => x.Node == "SolNode802")!.Seed = week; // unfaithful
|
worldState.NodeOverrides.find(x => x.Node == "SolNode802")!.Seed = new CRng(week).randomInt(0, 0xffff);
|
||||||
|
|
||||||
// Holdfast, Cavia, & Hex bounties cycling every 2.5 hours; unfaithful implementation
|
// Holdfast, Cavia, & Hex bounties cycling every 2.5 hours; unfaithful implementation
|
||||||
let bountyCycle = Math.trunc(Date.now() / 9000000);
|
let bountyCycle = Math.trunc(Date.now() / 9000000);
|
||||||
@ -696,7 +761,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
const bountyCycleStart = bountyCycle * 9000000;
|
const bountyCycleStart = bountyCycle * 9000000;
|
||||||
bountyCycleEnd = bountyCycleStart + 9000000;
|
bountyCycleEnd = bountyCycleStart + 9000000;
|
||||||
worldState.SyndicateMissions.push({
|
worldState.SyndicateMissions.push({
|
||||||
_id: { $oid: Math.trunc(bountyCycleStart / 1000).toString(16) + "0000000000000029" },
|
_id: { $oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000029" },
|
||||||
Activation: { $date: { $numberLong: bountyCycleStart.toString() } },
|
Activation: { $date: { $numberLong: bountyCycleStart.toString() } },
|
||||||
Expiry: { $date: { $numberLong: bountyCycleEnd.toString() } },
|
Expiry: { $date: { $numberLong: bountyCycleEnd.toString() } },
|
||||||
Tag: "ZarimanSyndicate",
|
Tag: "ZarimanSyndicate",
|
||||||
@ -704,7 +769,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
Nodes: []
|
Nodes: []
|
||||||
});
|
});
|
||||||
worldState.SyndicateMissions.push({
|
worldState.SyndicateMissions.push({
|
||||||
_id: { $oid: Math.trunc(bountyCycleStart / 1000).toString(16) + "0000000000000004" },
|
_id: { $oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000004" },
|
||||||
Activation: { $date: { $numberLong: bountyCycleStart.toString() } },
|
Activation: { $date: { $numberLong: bountyCycleStart.toString() } },
|
||||||
Expiry: { $date: { $numberLong: bountyCycleEnd.toString() } },
|
Expiry: { $date: { $numberLong: bountyCycleEnd.toString() } },
|
||||||
Tag: "EntratiLabSyndicate",
|
Tag: "EntratiLabSyndicate",
|
||||||
@ -712,7 +777,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
Nodes: []
|
Nodes: []
|
||||||
});
|
});
|
||||||
worldState.SyndicateMissions.push({
|
worldState.SyndicateMissions.push({
|
||||||
_id: { $oid: Math.trunc(bountyCycleStart / 1000).toString(16) + "0000000000000006" },
|
_id: { $oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000006" },
|
||||||
Activation: { $date: { $numberLong: bountyCycleStart.toString(10) } },
|
Activation: { $date: { $numberLong: bountyCycleStart.toString(10) } },
|
||||||
Expiry: { $date: { $numberLong: bountyCycleEnd.toString(10) } },
|
Expiry: { $date: { $numberLong: bountyCycleEnd.toString(10) } },
|
||||||
Tag: "HexSyndicate",
|
Tag: "HexSyndicate",
|
||||||
@ -726,14 +791,18 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
|
|
||||||
// TODO: xpAmounts need to be calculated based on the jobType somehow?
|
// TODO: xpAmounts need to be calculated based on the jobType somehow?
|
||||||
|
|
||||||
|
const seed = new CRng(bountyCycle).randomInt(0, 0xffff);
|
||||||
|
|
||||||
{
|
{
|
||||||
const rng = new CRng(bountyCycle);
|
const rng = new CRng(seed);
|
||||||
worldState.SyndicateMissions.push({
|
worldState.SyndicateMissions.push({
|
||||||
_id: { $oid: Math.trunc(bountyCycleStart / 1000).toString(16) + "0000000000000008" },
|
_id: {
|
||||||
|
$oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000008"
|
||||||
|
},
|
||||||
Activation: { $date: { $numberLong: bountyCycleStart.toString(10) } },
|
Activation: { $date: { $numberLong: bountyCycleStart.toString(10) } },
|
||||||
Expiry: { $date: { $numberLong: bountyCycleEnd.toString(10) } },
|
Expiry: { $date: { $numberLong: bountyCycleEnd.toString(10) } },
|
||||||
Tag: "CetusSyndicate",
|
Tag: "CetusSyndicate",
|
||||||
Seed: bountyCycle,
|
Seed: seed,
|
||||||
Nodes: [],
|
Nodes: [],
|
||||||
Jobs: [
|
Jobs: [
|
||||||
{
|
{
|
||||||
@ -797,13 +866,15 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const rng = new CRng(bountyCycle);
|
const rng = new CRng(seed);
|
||||||
worldState.SyndicateMissions.push({
|
worldState.SyndicateMissions.push({
|
||||||
_id: { $oid: Math.trunc(bountyCycleStart / 1000).toString(16) + "0000000000000025" },
|
_id: {
|
||||||
|
$oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000025"
|
||||||
|
},
|
||||||
Activation: { $date: { $numberLong: bountyCycleStart.toString(10) } },
|
Activation: { $date: { $numberLong: bountyCycleStart.toString(10) } },
|
||||||
Expiry: { $date: { $numberLong: bountyCycleEnd.toString(10) } },
|
Expiry: { $date: { $numberLong: bountyCycleEnd.toString(10) } },
|
||||||
Tag: "SolarisSyndicate",
|
Tag: "SolarisSyndicate",
|
||||||
Seed: bountyCycle,
|
Seed: seed,
|
||||||
Nodes: [],
|
Nodes: [],
|
||||||
Jobs: [
|
Jobs: [
|
||||||
{
|
{
|
||||||
@ -867,13 +938,15 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const rng = new CRng(bountyCycle);
|
const rng = new CRng(seed);
|
||||||
worldState.SyndicateMissions.push({
|
worldState.SyndicateMissions.push({
|
||||||
_id: { $oid: Math.trunc(bountyCycleStart / 1000).toString(16) + "0000000000000002" },
|
_id: {
|
||||||
|
$oid: ((bountyCycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "0000000000000002"
|
||||||
|
},
|
||||||
Activation: { $date: { $numberLong: bountyCycleStart.toString(10) } },
|
Activation: { $date: { $numberLong: bountyCycleStart.toString(10) } },
|
||||||
Expiry: { $date: { $numberLong: bountyCycleEnd.toString(10) } },
|
Expiry: { $date: { $numberLong: bountyCycleEnd.toString(10) } },
|
||||||
Tag: "EntratiSyndicate",
|
Tag: "EntratiSyndicate",
|
||||||
Seed: bountyCycle,
|
Seed: seed,
|
||||||
Nodes: [],
|
Nodes: [],
|
||||||
Jobs: [
|
Jobs: [
|
||||||
{
|
{
|
||||||
@ -1089,14 +1162,15 @@ export const getLiteSortie = (week: number): ILiteSortie => {
|
|||||||
value.systemIndex === systemIndex &&
|
value.systemIndex === systemIndex &&
|
||||||
value.factionIndex !== undefined &&
|
value.factionIndex !== undefined &&
|
||||||
value.factionIndex < 2 &&
|
value.factionIndex < 2 &&
|
||||||
value.name.indexOf("Archwing") == -1 &&
|
!isArchwingMission(value) &&
|
||||||
value.missionIndex != 0 // Exclude MT_ASSASSINATION
|
value.missionIndex != 0 // Exclude MT_ASSASSINATION
|
||||||
) {
|
) {
|
||||||
nodes.push(key);
|
nodes.push(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const rng = new CRng(week);
|
const seed = new CRng(week).randomInt(0, 0xffff);
|
||||||
|
const rng = new CRng(seed);
|
||||||
const firstNodeIndex = rng.randomInt(0, nodes.length - 1);
|
const firstNodeIndex = rng.randomInt(0, nodes.length - 1);
|
||||||
const firstNode = nodes[firstNodeIndex];
|
const firstNode = nodes[firstNodeIndex];
|
||||||
nodes.splice(firstNodeIndex, 1);
|
nodes.splice(firstNodeIndex, 1);
|
||||||
@ -1105,12 +1179,12 @@ export const getLiteSortie = (week: number): ILiteSortie => {
|
|||||||
const weekEnd = weekStart + 604800000;
|
const weekEnd = weekStart + 604800000;
|
||||||
return {
|
return {
|
||||||
_id: {
|
_id: {
|
||||||
$oid: Math.trunc(weekStart / 1000).toString(16) + "5e23a244740a190c"
|
$oid: ((weekStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + "5e23a244740a190c"
|
||||||
},
|
},
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
Reward: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards",
|
Reward: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards",
|
||||||
Seed: week,
|
Seed: seed,
|
||||||
Boss: boss,
|
Boss: boss,
|
||||||
Missions: [
|
Missions: [
|
||||||
{
|
{
|
||||||
@ -1120,7 +1194,7 @@ export const getLiteSortie = (week: number): ILiteSortie => {
|
|||||||
"MT_EXTERMINATION",
|
"MT_EXTERMINATION",
|
||||||
"MT_SABOTAGE",
|
"MT_SABOTAGE",
|
||||||
"MT_RESCUE"
|
"MT_RESCUE"
|
||||||
]),
|
])!,
|
||||||
node: firstNode
|
node: firstNode
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1130,8 +1204,8 @@ export const getLiteSortie = (week: number): ILiteSortie => {
|
|||||||
"MT_ARTIFACT",
|
"MT_ARTIFACT",
|
||||||
"MT_EXCAVATE",
|
"MT_EXCAVATE",
|
||||||
"MT_SURVIVAL"
|
"MT_SURVIVAL"
|
||||||
]),
|
])!,
|
||||||
node: rng.randomElement(nodes)
|
node: rng.randomElement(nodes)!
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
missionType: "MT_ASSASSINATION",
|
missionType: "MT_ASSASSINATION",
|
||||||
@ -1140,3 +1214,31 @@ export const getLiteSortie = (week: number): ILiteSortie => {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isArchwingMission = (node: IRegion): boolean => {
|
||||||
|
if (node.name.indexOf("Archwing") != -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// SettlementNode10
|
||||||
|
if (node.missionIndex == 25) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const version_compare = (a: string, b: string): number => {
|
||||||
|
const a_digits = a
|
||||||
|
.split("/")[0]
|
||||||
|
.split(".")
|
||||||
|
.map(x => parseInt(x));
|
||||||
|
const b_digits = b
|
||||||
|
.split("/")[0]
|
||||||
|
.split(".")
|
||||||
|
.map(x => parseInt(x));
|
||||||
|
for (let i = 0; i != a_digits.length; ++i) {
|
||||||
|
if (a_digits[i] != b_digits[i]) {
|
||||||
|
return a_digits[i] > b_digits[i] ? 1 : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
@ -11,6 +11,7 @@ export interface IGuildClient {
|
|||||||
Members: IGuildMemberClient[];
|
Members: IGuildMemberClient[];
|
||||||
Ranks: IGuildRank[];
|
Ranks: IGuildRank[];
|
||||||
Tier: number;
|
Tier: number;
|
||||||
|
Emblem?: boolean;
|
||||||
Vault: IGuildVault;
|
Vault: IGuildVault;
|
||||||
ActiveDojoColorResearch: string;
|
ActiveDojoColorResearch: string;
|
||||||
Class: number;
|
Class: number;
|
||||||
@ -206,6 +207,7 @@ export interface IDojoDecoClient {
|
|||||||
Type: string;
|
Type: string;
|
||||||
Pos: number[];
|
Pos: number[];
|
||||||
Rot: number[];
|
Rot: number[];
|
||||||
|
Scale?: number;
|
||||||
Name?: string; // for teleporters
|
Name?: string; // for teleporters
|
||||||
Sockets?: number;
|
Sockets?: number;
|
||||||
RegularCredits?: number;
|
RegularCredits?: number;
|
||||||
|
@ -43,6 +43,7 @@ export interface IInventoryDatabase
|
|||||||
| "RecentVendorPurchases"
|
| "RecentVendorPurchases"
|
||||||
| "NextRefill"
|
| "NextRefill"
|
||||||
| "Nemesis"
|
| "Nemesis"
|
||||||
|
| "NemesisHistory"
|
||||||
| "EntratiVaultCountResetDate"
|
| "EntratiVaultCountResetDate"
|
||||||
| "BrandedSuits"
|
| "BrandedSuits"
|
||||||
| "LockedWeaponGroup"
|
| "LockedWeaponGroup"
|
||||||
@ -51,6 +52,7 @@ export interface IInventoryDatabase
|
|||||||
| "LastLiteSortieReward"
|
| "LastLiteSortieReward"
|
||||||
| "CrewMembers"
|
| "CrewMembers"
|
||||||
| "QualifyingInvasions"
|
| "QualifyingInvasions"
|
||||||
|
| "LastInventorySync"
|
||||||
| TEquipmentKey
|
| TEquipmentKey
|
||||||
>,
|
>,
|
||||||
InventoryDatabaseEquipment {
|
InventoryDatabaseEquipment {
|
||||||
@ -79,6 +81,7 @@ export interface IInventoryDatabase
|
|||||||
RecentVendorPurchases?: IRecentVendorPurchaseDatabase[];
|
RecentVendorPurchases?: IRecentVendorPurchaseDatabase[];
|
||||||
NextRefill?: Date;
|
NextRefill?: Date;
|
||||||
Nemesis?: INemesisDatabase;
|
Nemesis?: INemesisDatabase;
|
||||||
|
NemesisHistory?: INemesisBaseDatabase[];
|
||||||
EntratiVaultCountResetDate?: Date;
|
EntratiVaultCountResetDate?: Date;
|
||||||
BrandedSuits?: Types.ObjectId[];
|
BrandedSuits?: Types.ObjectId[];
|
||||||
LockedWeaponGroup?: ILockedWeaponGroupDatabase;
|
LockedWeaponGroup?: ILockedWeaponGroupDatabase;
|
||||||
@ -87,6 +90,7 @@ export interface IInventoryDatabase
|
|||||||
LastLiteSortieReward?: ILastSortieRewardDatabase[];
|
LastLiteSortieReward?: ILastSortieRewardDatabase[];
|
||||||
CrewMembers: ICrewMemberDatabase[];
|
CrewMembers: ICrewMemberDatabase[];
|
||||||
QualifyingInvasions: IInvasionProgressDatabase[];
|
QualifyingInvasions: IInvasionProgressDatabase[];
|
||||||
|
LastInventorySync?: Types.ObjectId;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IQuestKeyDatabase {
|
export interface IQuestKeyDatabase {
|
||||||
@ -134,7 +138,7 @@ export const equipmentKeys = [
|
|||||||
export type TEquipmentKey = (typeof equipmentKeys)[number];
|
export type TEquipmentKey = (typeof equipmentKeys)[number];
|
||||||
|
|
||||||
export interface IDuviriInfo {
|
export interface IDuviriInfo {
|
||||||
Seed: number;
|
Seed: bigint;
|
||||||
NumCompletions: number;
|
NumCompletions: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,11 +202,11 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
OperatorLoadOuts: IOperatorConfigClient[];
|
OperatorLoadOuts: IOperatorConfigClient[];
|
||||||
KahlLoadOuts: IOperatorConfigClient[];
|
KahlLoadOuts: IOperatorConfigClient[];
|
||||||
|
|
||||||
DuviriInfo: IDuviriInfo;
|
DuviriInfo?: IDuviriInfo;
|
||||||
Mailbox?: IMailboxClient;
|
Mailbox?: IMailboxClient;
|
||||||
SubscribedToEmails: number;
|
SubscribedToEmails: number;
|
||||||
Created: IMongoDate;
|
Created: IMongoDate;
|
||||||
RewardSeed: number | bigint;
|
RewardSeed: bigint;
|
||||||
RegularCredits: number;
|
RegularCredits: number;
|
||||||
PremiumCredits: number;
|
PremiumCredits: number;
|
||||||
PremiumCreditsFree: number;
|
PremiumCreditsFree: number;
|
||||||
@ -256,7 +260,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
EquippedGear: string[];
|
EquippedGear: string[];
|
||||||
DeathMarks: string[];
|
DeathMarks: string[];
|
||||||
FusionTreasures: IFusionTreasure[];
|
FusionTreasures: IFusionTreasure[];
|
||||||
WebFlags: IWebFlags;
|
//WebFlags: IWebFlags;
|
||||||
CompletedAlerts: string[];
|
CompletedAlerts: string[];
|
||||||
Consumables: ITypeCount[];
|
Consumables: ITypeCount[];
|
||||||
LevelKeys: ITypeCount[];
|
LevelKeys: ITypeCount[];
|
||||||
@ -266,10 +270,10 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
KubrowPetEggs?: IKubrowPetEggClient[];
|
KubrowPetEggs?: IKubrowPetEggClient[];
|
||||||
LoreFragmentScans: ILoreFragmentScan[];
|
LoreFragmentScans: ILoreFragmentScan[];
|
||||||
EquippedEmotes: string[];
|
EquippedEmotes: string[];
|
||||||
PendingTrades: IPendingTrade[];
|
//PendingTrades: IPendingTrade[];
|
||||||
Boosters: IBooster[];
|
Boosters: IBooster[];
|
||||||
ActiveDojoColorResearch: string;
|
ActiveDojoColorResearch: string;
|
||||||
SentientSpawnChanceBoosters: ISentientSpawnChanceBoosters;
|
//SentientSpawnChanceBoosters: ISentientSpawnChanceBoosters;
|
||||||
SupportedSyndicate?: string;
|
SupportedSyndicate?: string;
|
||||||
Affiliations: IAffiliation[];
|
Affiliations: IAffiliation[];
|
||||||
QualifyingInvasions: IInvasionProgressClient[];
|
QualifyingInvasions: IInvasionProgressClient[];
|
||||||
@ -291,19 +295,19 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
ActiveAvatarImageType: string;
|
ActiveAvatarImageType: string;
|
||||||
ShipDecorations: ITypeCount[];
|
ShipDecorations: ITypeCount[];
|
||||||
DiscoveredMarkers: IDiscoveredMarker[];
|
DiscoveredMarkers: IDiscoveredMarker[];
|
||||||
CompletedJobs: ICompletedJob[];
|
//CompletedJobs: ICompletedJob[];
|
||||||
FocusAbility?: string;
|
FocusAbility?: string;
|
||||||
FocusUpgrades: IFocusUpgrade[];
|
FocusUpgrades: IFocusUpgrade[];
|
||||||
HasContributedToDojo?: boolean;
|
HasContributedToDojo?: boolean;
|
||||||
HWIDProtectEnabled?: boolean;
|
HWIDProtectEnabled?: boolean;
|
||||||
KubrowPetPrints: IKubrowPetPrint[];
|
//KubrowPetPrints: IKubrowPetPrint[];
|
||||||
AlignmentReplay?: IAlignment;
|
AlignmentReplay?: IAlignment;
|
||||||
PersonalGoalProgress: IPersonalGoalProgress[];
|
//PersonalGoalProgress: IPersonalGoalProgress[];
|
||||||
ThemeStyle: string;
|
ThemeStyle: string;
|
||||||
ThemeBackground: string;
|
ThemeBackground: string;
|
||||||
ThemeSounds: string;
|
ThemeSounds: string;
|
||||||
BountyScore: number;
|
BountyScore: number;
|
||||||
ChallengeInstanceStates: IChallengeInstanceState[];
|
//ChallengeInstanceStates: IChallengeInstanceState[];
|
||||||
LoginMilestoneRewards: string[];
|
LoginMilestoneRewards: string[];
|
||||||
RecentVendorPurchases?: IRecentVendorPurchaseClient[];
|
RecentVendorPurchases?: IRecentVendorPurchaseClient[];
|
||||||
NodeIntrosCompleted: string[];
|
NodeIntrosCompleted: string[];
|
||||||
@ -311,37 +315,37 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
CompletedJobChains?: ICompletedJobChain[];
|
CompletedJobChains?: ICompletedJobChain[];
|
||||||
SeasonChallengeHistory: ISeasonChallenge[];
|
SeasonChallengeHistory: ISeasonChallenge[];
|
||||||
EquippedInstrument?: string;
|
EquippedInstrument?: string;
|
||||||
InvasionChainProgress: IInvasionChainProgress[];
|
//InvasionChainProgress: IInvasionChainProgress[];
|
||||||
Nemesis?: INemesisClient;
|
Nemesis?: INemesisClient;
|
||||||
NemesisHistory: INemesisBaseClient[];
|
NemesisHistory?: INemesisBaseClient[];
|
||||||
LastNemesisAllySpawnTime?: IMongoDate;
|
//LastNemesisAllySpawnTime?: IMongoDate;
|
||||||
Settings?: ISettings;
|
Settings?: ISettings;
|
||||||
PersonalTechProjects: IPersonalTechProjectClient[];
|
PersonalTechProjects: IPersonalTechProjectClient[];
|
||||||
PlayerSkills: IPlayerSkills;
|
PlayerSkills: IPlayerSkills;
|
||||||
CrewShipAmmo: ITypeCount[];
|
CrewShipAmmo: ITypeCount[];
|
||||||
CrewShipWeaponSkins: IUpgradeClient[];
|
CrewShipWeaponSkins: IUpgradeClient[];
|
||||||
CrewShipSalvagedWeaponSkins: IUpgradeClient[];
|
CrewShipSalvagedWeaponSkins: IUpgradeClient[];
|
||||||
TradeBannedUntil?: IMongoDate;
|
//TradeBannedUntil?: IMongoDate;
|
||||||
PlayedParkourTutorial: boolean;
|
PlayedParkourTutorial: boolean;
|
||||||
SubscribedToEmailsPersonalized: number;
|
SubscribedToEmailsPersonalized: number;
|
||||||
InfestedFoundry?: IInfestedFoundryClient;
|
InfestedFoundry?: IInfestedFoundryClient;
|
||||||
BlessingCooldown?: IMongoDate;
|
BlessingCooldown?: IMongoDate;
|
||||||
CrewShipRawSalvage: ITypeCount[];
|
CrewShipRawSalvage: ITypeCount[];
|
||||||
CrewMembers: ICrewMemberClient[];
|
CrewMembers: ICrewMemberClient[];
|
||||||
LotusCustomization: ILotusCustomization;
|
LotusCustomization?: ILotusCustomization;
|
||||||
UseAdultOperatorLoadout?: boolean;
|
UseAdultOperatorLoadout?: boolean;
|
||||||
NemesisAbandonedRewards: string[];
|
NemesisAbandonedRewards: string[];
|
||||||
LastInventorySync: IOid;
|
LastInventorySync?: IOid;
|
||||||
NextRefill?: IMongoDate;
|
NextRefill?: IMongoDate;
|
||||||
FoundToday?: IMiscItem[]; // for Argon Crystals
|
FoundToday?: IMiscItem[]; // for Argon Crystals
|
||||||
CustomMarkers?: ICustomMarkers[];
|
CustomMarkers?: ICustomMarkers[];
|
||||||
ActiveLandscapeTraps: any[];
|
//ActiveLandscapeTraps: any[];
|
||||||
EvolutionProgress?: IEvolutionProgress[];
|
EvolutionProgress?: IEvolutionProgress[];
|
||||||
RepVotes: any[];
|
//RepVotes: any[];
|
||||||
LeagueTickets: any[];
|
//LeagueTickets: any[];
|
||||||
Quests: any[];
|
//Quests: any[];
|
||||||
Robotics: any[];
|
//Robotics: any[];
|
||||||
UsedDailyDeals: any[];
|
//UsedDailyDeals: any[];
|
||||||
LibraryPersonalTarget?: string;
|
LibraryPersonalTarget?: string;
|
||||||
LibraryPersonalProgress: ILibraryPersonalProgress[];
|
LibraryPersonalProgress: ILibraryPersonalProgress[];
|
||||||
CollectibleSeries?: ICollectibleEntry[];
|
CollectibleSeries?: ICollectibleEntry[];
|
||||||
@ -353,7 +357,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
DeathSquadable: boolean;
|
DeathSquadable: boolean;
|
||||||
EndlessXP?: IEndlessXpProgress[];
|
EndlessXP?: IEndlessXpProgress[];
|
||||||
DialogueHistory?: IDialogueHistoryClient;
|
DialogueHistory?: IDialogueHistoryClient;
|
||||||
CalendarProgress: ICalendarProgress;
|
CalendarProgress?: ICalendarProgress;
|
||||||
SongChallenges?: ISongChallenge[];
|
SongChallenges?: ISongChallenge[];
|
||||||
EntratiVaultCountLastPeriod?: number;
|
EntratiVaultCountLastPeriod?: number;
|
||||||
EntratiVaultCountResetDate?: IMongoDate;
|
EntratiVaultCountResetDate?: IMongoDate;
|
||||||
@ -845,7 +849,7 @@ export interface IMission extends IMissionDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface INemesisBaseClient {
|
export interface INemesisBaseClient {
|
||||||
fp: bigint;
|
fp: bigint | number;
|
||||||
manifest: string;
|
manifest: string;
|
||||||
KillingSuit: string;
|
KillingSuit: string;
|
||||||
killingDamageType: number;
|
killingDamageType: number;
|
||||||
@ -863,7 +867,8 @@ export interface INemesisBaseClient {
|
|||||||
Weakened: boolean;
|
Weakened: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface INemesisBaseDatabase extends Omit<INemesisBaseClient, "d"> {
|
export interface INemesisBaseDatabase extends Omit<INemesisBaseClient, "fp" | "d"> {
|
||||||
|
fp: bigint;
|
||||||
d: Date;
|
d: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -877,7 +882,8 @@ export interface INemesisClient extends INemesisBaseClient {
|
|||||||
LastEnc: number;
|
LastEnc: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface INemesisDatabase extends Omit<INemesisClient, "d"> {
|
export interface INemesisDatabase extends Omit<INemesisClient, "fp" | "d"> {
|
||||||
|
fp: bigint;
|
||||||
d: Date;
|
d: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -900,8 +906,8 @@ export interface IPendingRecipeDatabase {
|
|||||||
ItemType: string;
|
ItemType: string;
|
||||||
CompletionDate: Date;
|
CompletionDate: Date;
|
||||||
ItemId: IOid;
|
ItemId: IOid;
|
||||||
TargetItemId?: string; // likely related to liches
|
TargetItemId?: string; // unsure what this is for
|
||||||
TargetFingerprint?: string; // likely related to liches
|
TargetFingerprint?: string;
|
||||||
LongGuns?: IEquipmentDatabase[];
|
LongGuns?: IEquipmentDatabase[];
|
||||||
Pistols?: IEquipmentDatabase[];
|
Pistols?: IEquipmentDatabase[];
|
||||||
Melee?: IEquipmentDatabase[];
|
Melee?: IEquipmentDatabase[];
|
||||||
@ -949,6 +955,17 @@ export interface ICrewShipComponentFingerprint extends IInnateDamageFingerprint
|
|||||||
SubroutineIndex?: number;
|
SubroutineIndex?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface INemesisWeaponTargetFingerprint {
|
||||||
|
ItemType: string;
|
||||||
|
UpgradeFingerprint: IInnateDamageFingerprint;
|
||||||
|
Name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface INemesisPetTargetFingerprint {
|
||||||
|
Parts: string[];
|
||||||
|
Name: string;
|
||||||
|
}
|
||||||
|
|
||||||
export enum GettingSlotOrderInfo {
|
export enum GettingSlotOrderInfo {
|
||||||
Empty = "",
|
Empty = "",
|
||||||
LotusUpgradesModsRandomizedPlayerMeleeWeaponRandomModRare0 = "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare:0",
|
LotusUpgradesModsRandomizedPlayerMeleeWeaponRandomModRare0 = "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare:0",
|
||||||
@ -1193,17 +1210,18 @@ export interface IMarker {
|
|||||||
z: number;
|
z: number;
|
||||||
showInHud: boolean;
|
showInHud: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISeasonProgress {
|
export interface ISeasonProgress {
|
||||||
SeasonType: "CST_UNDEFINED" | "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
|
SeasonType: "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
|
||||||
LastCompletedDayIdx: number;
|
LastCompletedDayIdx: number;
|
||||||
LastCompletedChallengeDayIdx: number;
|
LastCompletedChallengeDayIdx: number;
|
||||||
ActivatedChallenges: unknown[];
|
ActivatedChallenges: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICalendarProgress {
|
export interface ICalendarProgress {
|
||||||
Version: number;
|
Version: number;
|
||||||
Iteration: number;
|
Iteration: number;
|
||||||
YearProgress: { Upgrades: unknown[] };
|
YearProgress: { Upgrades: string[] };
|
||||||
SeasonProgress: ISeasonProgress;
|
SeasonProgress: ISeasonProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { IAffiliationMods, IInventoryChanges } from "./purchaseTypes";
|
||||||
|
|
||||||
export const inventoryFields = ["RawUpgrades", "MiscItems", "Consumables", "Recipes"] as const;
|
export const inventoryFields = ["RawUpgrades", "MiscItems", "Consumables", "Recipes"] as const;
|
||||||
export type IInventoryFieldType = (typeof inventoryFields)[number];
|
export type IInventoryFieldType = (typeof inventoryFields)[number];
|
||||||
|
|
||||||
@ -6,8 +8,27 @@ export interface IMissionReward {
|
|||||||
TypeName?: string;
|
TypeName?: string;
|
||||||
UpgradeLevel?: number;
|
UpgradeLevel?: number;
|
||||||
ItemCount: number;
|
ItemCount: number;
|
||||||
|
DailyCooldown?: boolean;
|
||||||
|
Rarity?: number;
|
||||||
TweetText?: string;
|
TweetText?: string;
|
||||||
ProductCategory?: string;
|
ProductCategory?: string;
|
||||||
FromEnemyCache?: boolean;
|
FromEnemyCache?: boolean;
|
||||||
IsStrippedItem?: boolean;
|
IsStrippedItem?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IMissionCredits {
|
||||||
|
MissionCredits: number[];
|
||||||
|
CreditBonus: number[];
|
||||||
|
TotalCredits: number[];
|
||||||
|
DailyMissionBonus?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMissionInventoryUpdateResponse extends Partial<IMissionCredits> {
|
||||||
|
ConquestCompletedMissionsCount?: number;
|
||||||
|
InventoryJson?: string;
|
||||||
|
MissionRewards?: IMissionReward[];
|
||||||
|
InventoryChanges?: IInventoryChanges;
|
||||||
|
FusionPoints?: number;
|
||||||
|
SyndicateXPItemReward?: number;
|
||||||
|
AffiliationMods?: IAffiliationMods[];
|
||||||
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { IColor } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IColor } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import {
|
import {
|
||||||
IApartment,
|
|
||||||
IRoom,
|
IRoom,
|
||||||
IPlacedDecosDatabase,
|
IPlacedDecosDatabase,
|
||||||
ITailorShop,
|
ITailorShop,
|
||||||
ITailorShopDatabase,
|
ITailorShopDatabase,
|
||||||
TBootLocation,
|
TBootLocation,
|
||||||
IApartmentDatabase
|
IApartmentDatabase,
|
||||||
|
IApartmentClient
|
||||||
} from "@/src/types/shipTypes";
|
} from "@/src/types/shipTypes";
|
||||||
import { Document, Model, Types } from "mongoose";
|
import { Document, Model, Types } from "mongoose";
|
||||||
|
|
||||||
@ -21,10 +21,10 @@ export interface IOrbiter {
|
|||||||
BootLocation?: TBootLocation;
|
BootLocation?: TBootLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPersonalRooms {
|
export interface IPersonalRoomsClient {
|
||||||
ShipInteriorColors: IColor;
|
ShipInteriorColors: IColor;
|
||||||
Ship: IOrbiter;
|
Ship: IOrbiter;
|
||||||
Apartment: IApartment;
|
Apartment: IApartmentClient;
|
||||||
TailorShop: ITailorShop;
|
TailorShop: ITailorShop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +103,7 @@ export const slotNames = [
|
|||||||
"WeaponBin",
|
"WeaponBin",
|
||||||
"MechBin",
|
"MechBin",
|
||||||
"PveBonusLoadoutBin",
|
"PveBonusLoadoutBin",
|
||||||
|
"PvpBonusLoadoutBin",
|
||||||
"SentinelBin",
|
"SentinelBin",
|
||||||
"SpaceSuitBin",
|
"SpaceSuitBin",
|
||||||
"SpaceWeaponBin",
|
"SpaceWeaponBin",
|
||||||
|
@ -20,7 +20,10 @@ import {
|
|||||||
IDiscoveredMarker,
|
IDiscoveredMarker,
|
||||||
ILockedWeaponGroupClient,
|
ILockedWeaponGroupClient,
|
||||||
ILoadOutPresets,
|
ILoadOutPresets,
|
||||||
IInvasionProgressClient
|
IInvasionProgressClient,
|
||||||
|
IWeaponSkinClient,
|
||||||
|
IKubrowPetEggClient,
|
||||||
|
INemesisClient
|
||||||
} from "./inventoryTypes/inventoryTypes";
|
} from "./inventoryTypes/inventoryTypes";
|
||||||
import { IGroup } from "./loginTypes";
|
import { IGroup } from "./loginTypes";
|
||||||
|
|
||||||
@ -44,6 +47,7 @@ export type IMissionInventoryUpdateRequest = {
|
|||||||
|
|
||||||
SyndicateId?: string;
|
SyndicateId?: string;
|
||||||
SortieId?: string;
|
SortieId?: string;
|
||||||
|
CalendarProgress?: { challenge: string }[];
|
||||||
SeasonChallengeCompletions?: ISeasonChallenge[];
|
SeasonChallengeCompletions?: ISeasonChallenge[];
|
||||||
AffiliationChanges?: IAffiliationChange[];
|
AffiliationChanges?: IAffiliationChange[];
|
||||||
crossPlaySetting?: string;
|
crossPlaySetting?: string;
|
||||||
@ -71,6 +75,14 @@ export type IMissionInventoryUpdateRequest = {
|
|||||||
PS: string;
|
PS: string;
|
||||||
ActiveDojoColorResearch: string;
|
ActiveDojoColorResearch: string;
|
||||||
RewardInfo?: IRewardInfo;
|
RewardInfo?: IRewardInfo;
|
||||||
|
NemesisKillConvert?: {
|
||||||
|
nemesisName: string;
|
||||||
|
weaponLoc: string;
|
||||||
|
petLoc: "" | "/Lotus/Language/Pets/ZanukaPetName";
|
||||||
|
fingerprint: bigint | number;
|
||||||
|
killed: boolean;
|
||||||
|
};
|
||||||
|
target?: INemesisClient;
|
||||||
ReceivedCeremonyMsg: boolean;
|
ReceivedCeremonyMsg: boolean;
|
||||||
LastCeremonyResetDate: number;
|
LastCeremonyResetDate: number;
|
||||||
MissionPTS: number;
|
MissionPTS: number;
|
||||||
@ -100,6 +112,7 @@ export type IMissionInventoryUpdateRequest = {
|
|||||||
}[];
|
}[];
|
||||||
CollectibleScans?: ICollectibleEntry[];
|
CollectibleScans?: ICollectibleEntry[];
|
||||||
Upgrades?: IUpgradeClient[]; // riven challenge progress
|
Upgrades?: IUpgradeClient[]; // riven challenge progress
|
||||||
|
WeaponSkins?: IWeaponSkinClient[];
|
||||||
StrippedItems?: {
|
StrippedItems?: {
|
||||||
DropTable: string;
|
DropTable: string;
|
||||||
DROP_MOD?: number[];
|
DROP_MOD?: number[];
|
||||||
@ -115,7 +128,9 @@ export type IMissionInventoryUpdateRequest = {
|
|||||||
NumExtraRewards: number;
|
NumExtraRewards: number;
|
||||||
Count: number;
|
Count: number;
|
||||||
}[];
|
}[];
|
||||||
|
KubrowPetEggs?: IKubrowPetEggClient[];
|
||||||
DiscoveredMarkers?: IDiscoveredMarker[];
|
DiscoveredMarkers?: IDiscoveredMarker[];
|
||||||
|
BrandedSuits?: IOid; // sent when captured by g3
|
||||||
LockedWeaponGroup?: ILockedWeaponGroupClient; // sent when captured by zanuka
|
LockedWeaponGroup?: ILockedWeaponGroupClient; // sent when captured by zanuka
|
||||||
UnlockWeapons?: boolean; // sent when recovered weapons from zanuka capture
|
UnlockWeapons?: boolean; // sent when recovered weapons from zanuka capture
|
||||||
IncHarvester?: boolean; // sent when recovered weapons from zanuka capture
|
IncHarvester?: boolean; // sent when recovered weapons from zanuka capture
|
||||||
@ -125,6 +140,16 @@ export type IMissionInventoryUpdateRequest = {
|
|||||||
wagerTier?: number; // the index
|
wagerTier?: number; // the index
|
||||||
creditsFee?: number; // the index
|
creditsFee?: number; // the index
|
||||||
InvasionProgress?: IInvasionProgressClient[];
|
InvasionProgress?: IInvasionProgressClient[];
|
||||||
|
ConquestMissionsCompleted?: number;
|
||||||
|
duviriSuitSelection?: string;
|
||||||
|
duviriPistolSelection?: string;
|
||||||
|
duviriLongGunSelection?: string;
|
||||||
|
duviriMeleeSelection?: string;
|
||||||
|
duviriCaveOffers?: {
|
||||||
|
Seed: number | bigint;
|
||||||
|
Warframes: string[];
|
||||||
|
Weapons: string[];
|
||||||
|
};
|
||||||
} & {
|
} & {
|
||||||
[K in TEquipmentKey]?: IEquipmentClient[];
|
[K in TEquipmentKey]?: IEquipmentClient[];
|
||||||
};
|
};
|
||||||
@ -134,7 +159,7 @@ export interface IRewardInfo {
|
|||||||
invasionId?: string;
|
invasionId?: string;
|
||||||
invasionAllyFaction?: "FC_GRINEER" | "FC_CORPUS";
|
invasionAllyFaction?: "FC_GRINEER" | "FC_CORPUS";
|
||||||
sortieId?: string;
|
sortieId?: string;
|
||||||
sortieTag?: string;
|
sortieTag?: "Mission1" | "Mission2" | "Final";
|
||||||
sortiePrereqs?: string[];
|
sortiePrereqs?: string[];
|
||||||
VaultsCracked?: number; // for Spy missions
|
VaultsCracked?: number; // for Spy missions
|
||||||
rewardTier?: number;
|
rewardTier?: number;
|
||||||
@ -145,12 +170,19 @@ export interface IRewardInfo {
|
|||||||
lostTargetWave?: number;
|
lostTargetWave?: number;
|
||||||
defenseTargetCount?: number;
|
defenseTargetCount?: number;
|
||||||
NemesisAbandonedRewards?: string[];
|
NemesisAbandonedRewards?: string[];
|
||||||
|
NemesisHenchmenKills?: number;
|
||||||
|
NemesisHintProgress?: number;
|
||||||
EOM_AFK?: number;
|
EOM_AFK?: number;
|
||||||
rewardQualifications?: string; // did a Survival for 5 minutes and this was "1"
|
rewardQualifications?: string; // did a Survival for 5 minutes and this was "1"
|
||||||
PurgatoryRewardQualifications?: string;
|
PurgatoryRewardQualifications?: string;
|
||||||
rewardSeed?: number | bigint;
|
rewardSeed?: number | bigint;
|
||||||
periodicMissionTag?: string;
|
periodicMissionTag?: string;
|
||||||
|
ConquestType?: string;
|
||||||
|
ConquestCompleted?: number;
|
||||||
|
ConquestEquipmentSuggestionsFulfilled?: number;
|
||||||
|
ConquestPersonalModifiersActive?: number;
|
||||||
|
ConquestStickersActive?: number;
|
||||||
|
ConquestHardModeActive?: number;
|
||||||
// for bounties, only EOM_AFK and node are given from above, plus:
|
// for bounties, only EOM_AFK and node are given from above, plus:
|
||||||
JobTier?: number;
|
JobTier?: number;
|
||||||
jobId?: string;
|
jobId?: string;
|
||||||
|
@ -6,7 +6,8 @@ import {
|
|||||||
ICrewShipMembersClient,
|
ICrewShipMembersClient,
|
||||||
ICrewShipWeapon,
|
ICrewShipWeapon,
|
||||||
IFlavourItem,
|
IFlavourItem,
|
||||||
ILoadoutConfigClient
|
ILoadoutConfigClient,
|
||||||
|
ILotusCustomization
|
||||||
} from "./inventoryTypes/inventoryTypes";
|
} from "./inventoryTypes/inventoryTypes";
|
||||||
|
|
||||||
export interface ISaveLoadoutRequest {
|
export interface ISaveLoadoutRequest {
|
||||||
@ -43,6 +44,7 @@ export interface ISaveLoadoutRequest {
|
|||||||
EquippedEmotes: string[];
|
EquippedEmotes: string[];
|
||||||
UseAdultOperatorLoadout: boolean;
|
UseAdultOperatorLoadout: boolean;
|
||||||
WeaponSkins: IItemEntry;
|
WeaponSkins: IItemEntry;
|
||||||
|
LotusCustomization: ILotusCustomization;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ISaveLoadoutRequestNoUpgradeVer = Omit<ISaveLoadoutRequest, "UpgradeVer">;
|
export type ISaveLoadoutRequestNoUpgradeVer = Omit<ISaveLoadoutRequest, "UpgradeVer">;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { IOid } from "@/src/types/commonTypes";
|
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
||||||
import { IColor } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IColor } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { ILoadoutClient } from "./saveLoadoutTypes";
|
import { ILoadoutClient } from "./saveLoadoutTypes";
|
||||||
|
|
||||||
export interface IGetShipResponse {
|
export interface IGetShipResponse {
|
||||||
ShipOwnerId: string;
|
ShipOwnerId: string;
|
||||||
Ship: IShip;
|
Ship: IShip;
|
||||||
Apartment: IApartment;
|
Apartment: IApartmentClient;
|
||||||
TailorShop: ITailorShop;
|
TailorShop: ITailorShop;
|
||||||
LoadOutInventory: { LoadOutPresets: ILoadoutClient };
|
LoadOutInventory: { LoadOutPresets: ILoadoutClient };
|
||||||
}
|
}
|
||||||
@ -51,28 +51,42 @@ export interface IRoom {
|
|||||||
PlacedDecos?: IPlacedDecosDatabase[];
|
PlacedDecos?: IPlacedDecosDatabase[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPlants {
|
export interface IPlantClient {
|
||||||
PlantType: string;
|
PlantType: string;
|
||||||
EndTime: IOid;
|
EndTime: IMongoDate;
|
||||||
PlotIndex: number;
|
PlotIndex: number;
|
||||||
}
|
}
|
||||||
export interface IPlanters {
|
|
||||||
|
export interface IPlantDatabase extends Omit<IPlantClient, "EndTime"> {
|
||||||
|
EndTime: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPlanterClient {
|
||||||
Name: string;
|
Name: string;
|
||||||
Plants: IPlants[];
|
Plants: IPlantClient[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IGardening {
|
export interface IPlanterDatabase {
|
||||||
Planters?: IPlanters[];
|
Name: string;
|
||||||
|
Plants: IPlantDatabase[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IApartment {
|
export interface IGardeningClient {
|
||||||
Gardening: IGardening;
|
Planters: IPlanterClient[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IGardeningDatabase {
|
||||||
|
Planters: IPlanterDatabase[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IApartmentClient {
|
||||||
|
Gardening: IGardeningClient;
|
||||||
Rooms: IRoom[];
|
Rooms: IRoom[];
|
||||||
FavouriteLoadouts: IFavouriteLoadout[];
|
FavouriteLoadouts: IFavouriteLoadout[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IApartmentDatabase {
|
export interface IApartmentDatabase {
|
||||||
Gardening: IGardening;
|
Gardening: IGardeningDatabase;
|
||||||
Rooms: IRoom[];
|
Rooms: IRoom[];
|
||||||
FavouriteLoadouts: IFavouriteLoadoutDatabase[];
|
FavouriteLoadouts: IFavouriteLoadoutDatabase[];
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
import { IMongoDate, IOid } from "./commonTypes";
|
import { IMongoDate, IOid } from "./commonTypes";
|
||||||
|
|
||||||
export interface IItemPrice {
|
export interface IItemPrice {
|
||||||
ItemType: string | string[]; // If string[], preprocessing will use RNG to pick one for the current period.
|
ItemType: string;
|
||||||
ItemCount: number;
|
ItemCount: number;
|
||||||
ProductCategory: string;
|
ProductCategory: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IItemPricePreprocessed extends Omit<IItemPrice, "ItemType"> {
|
|
||||||
ItemType: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IItemManifest {
|
export interface IItemManifest {
|
||||||
StoreItem: string;
|
StoreItem: string;
|
||||||
ItemPrices?: IItemPrice[];
|
ItemPrices?: IItemPrice[];
|
||||||
|
RegularPrice?: number[];
|
||||||
|
PremiumPrice?: number[];
|
||||||
Bin: string;
|
Bin: string;
|
||||||
QuantityMultiplier: number;
|
QuantityMultiplier: number;
|
||||||
Expiry: IMongoDate; // Either a date in the distant future or a period in milliseconds for preprocessing.
|
Expiry: IMongoDate; // Either a date in the distant future or a period in milliseconds for preprocessing.
|
||||||
@ -23,10 +21,6 @@ export interface IItemManifest {
|
|||||||
Id: IOid;
|
Id: IOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IItemManifestPreprocessed extends Omit<IItemManifest, "ItemPrices"> {
|
|
||||||
ItemPrices?: IItemPricePreprocessed[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IVendorInfo {
|
export interface IVendorInfo {
|
||||||
_id: IOid;
|
_id: IOid;
|
||||||
TypeName: string;
|
TypeName: string;
|
||||||
@ -38,14 +32,6 @@ export interface IVendorInfo {
|
|||||||
Expiry: IMongoDate; // Either a date in the distant future or a period in milliseconds for preprocessing.
|
Expiry: IMongoDate; // Either a date in the distant future or a period in milliseconds for preprocessing.
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IVendorInfoPreprocessed extends Omit<IVendorInfo, "ItemManifest"> {
|
export interface IVendorManifest {
|
||||||
ItemManifest: IItemManifestPreprocessed[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IRawVendorManifest {
|
|
||||||
VendorInfo: IVendorInfo;
|
VendorInfo: IVendorInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IVendorManifestPreprocessed {
|
|
||||||
VendorInfo: IVendorInfoPreprocessed;
|
|
||||||
}
|
|
||||||
|
@ -10,6 +10,7 @@ export interface IWorldState {
|
|||||||
LiteSorties: ILiteSortie[];
|
LiteSorties: ILiteSortie[];
|
||||||
SyndicateMissions: ISyndicateMissionInfo[];
|
SyndicateMissions: ISyndicateMissionInfo[];
|
||||||
GlobalUpgrades: IGlobalUpgrade[];
|
GlobalUpgrades: IGlobalUpgrade[];
|
||||||
|
ActiveMissions: IFissure[];
|
||||||
NodeOverrides: INodeOverride[];
|
NodeOverrides: INodeOverride[];
|
||||||
EndlessXpChoices: IEndlessXpChoice[];
|
EndlessXpChoices: IEndlessXpChoice[];
|
||||||
SeasonInfo: {
|
SeasonInfo: {
|
||||||
@ -71,6 +72,18 @@ export interface IGlobalUpgrade {
|
|||||||
LocalizeDescTag: string;
|
LocalizeDescTag: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IFissure {
|
||||||
|
_id: IOid;
|
||||||
|
Region: number;
|
||||||
|
Seed: number;
|
||||||
|
Activation: IMongoDate;
|
||||||
|
Expiry: IMongoDate;
|
||||||
|
Node: string;
|
||||||
|
MissionType: string;
|
||||||
|
Modifier: string;
|
||||||
|
Hard?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface INodeOverride {
|
export interface INodeOverride {
|
||||||
_id: IOid;
|
_id: IOid;
|
||||||
Activation?: IMongoDate;
|
Activation?: IMongoDate;
|
||||||
@ -97,6 +110,13 @@ export interface ISortie {
|
|||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ISortieMission {
|
||||||
|
missionType: string;
|
||||||
|
modifierType: string;
|
||||||
|
node: string;
|
||||||
|
tileset: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ILiteSortie {
|
export interface ILiteSortie {
|
||||||
_id: IOid;
|
_id: IOid;
|
||||||
Activation: IMongoDate;
|
Activation: IMongoDate;
|
||||||
@ -126,7 +146,7 @@ export interface ISeasonChallenge {
|
|||||||
export interface ICalendarSeason {
|
export interface ICalendarSeason {
|
||||||
Activation: IMongoDate;
|
Activation: IMongoDate;
|
||||||
Expiry: IMongoDate;
|
Expiry: IMongoDate;
|
||||||
Season: string; // "CST_UNDEFINED" | "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL"
|
Season: "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
|
||||||
Days: ICalendarDay[];
|
Days: ICalendarDay[];
|
||||||
YearIteration: number;
|
YearIteration: number;
|
||||||
Version: number;
|
Version: number;
|
||||||
|
49
static/fixed_responses/allIncarnonList.json
Normal file
49
static/fixed_responses/allIncarnonList.json
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
[
|
||||||
|
"/Lotus/Weapons/ClanTech/Bio/BioWeapon",
|
||||||
|
"/Lotus/Weapons/ClanTech/Energy/EnergyRifle",
|
||||||
|
"/Lotus/Weapons/Corpus/Pistols/CorpusMinigun/CorpusMinigun",
|
||||||
|
"/Lotus/Weapons/Corpus/Pistols/CrpHandRL/CorpusHandRocketLauncher",
|
||||||
|
"/Lotus/Weapons/Grineer/LongGuns/GrineerSawbladeGun/SawBladeGun",
|
||||||
|
"/Lotus/Weapons/Grineer/Melee/GrineerTylAxeAndBoar/RegorAxeShield",
|
||||||
|
"/Lotus/Weapons/Grineer/Pistols/HeatGun/GrnHeatGun",
|
||||||
|
"/Lotus/Weapons/Infested/Pistols/InfVomitGun/InfVomitGunWep",
|
||||||
|
"/Lotus/Weapons/Syndicates/CephalonSuda/Pistols/CSDroidArray",
|
||||||
|
"/Lotus/Weapons/Tenno/Bows/HuntingBow",
|
||||||
|
"/Lotus/Weapons/Tenno/Bows/StalkerBow",
|
||||||
|
"/Lotus/Weapons/Tenno/LongGuns/TnoLeverAction/TnoLeverActionRifle",
|
||||||
|
"/Lotus/Weapons/Tenno/Melee/Axe/DualInfestedAxesWeapon",
|
||||||
|
"/Lotus/Weapons/Tenno/Melee/Dagger/CeramicDagger",
|
||||||
|
"/Lotus/Weapons/Tenno/Melee/Fist/Fist",
|
||||||
|
"/Lotus/Weapons/Tenno/Melee/Hammer/IceHammer/IceHammer",
|
||||||
|
"/Lotus/Weapons/Tenno/Melee/LongSword/LongSword",
|
||||||
|
"/Lotus/Weapons/Tenno/Melee/Maces/PaladinMace/PaladinMaceWeapon",
|
||||||
|
"/Lotus/Weapons/Tenno/Melee/Scythe/StalkerScytheWeapon",
|
||||||
|
"/Lotus/Weapons/Tenno/Melee/Scythe/ParisScythe/ParisScythe",
|
||||||
|
"/Lotus/Weapons/Tenno/Melee/Staff/Staff",
|
||||||
|
"/Lotus/Weapons/Tenno/Melee/Swords/CutlassAndPoignard/TennoCutlass",
|
||||||
|
"/Lotus/Weapons/Tenno/Melee/Swords/TennoSai/TennoSais",
|
||||||
|
"/Lotus/Weapons/Tenno/Pistol/AutoPistol",
|
||||||
|
"/Lotus/Weapons/Tenno/Pistol/BurstPistol",
|
||||||
|
"/Lotus/Weapons/Tenno/Pistol/HandShotGun",
|
||||||
|
"/Lotus/Weapons/Tenno/Pistol/HeavyPistol",
|
||||||
|
"/Lotus/Weapons/Tenno/Pistol/Pistol",
|
||||||
|
"/Lotus/Weapons/Tenno/Pistol/RevolverPistol",
|
||||||
|
"/Lotus/Weapons/Tenno/Pistols/ConclaveLeverPistol/ConclaveLeverPistol",
|
||||||
|
"/Lotus/Weapons/Tenno/Rifle/BoltoRifle",
|
||||||
|
"/Lotus/Weapons/Tenno/Rifle/BurstRifle",
|
||||||
|
"/Lotus/Weapons/Tenno/Rifle/HeavyRifle",
|
||||||
|
"/Lotus/Weapons/Tenno/Rifle/Rifle",
|
||||||
|
"/Lotus/Weapons/Tenno/Rifle/SemiAutoRifle",
|
||||||
|
"/Lotus/Weapons/Tenno/Rifle/TennoAR",
|
||||||
|
"/Lotus/Weapons/Tenno/Shotgun/FullAutoShotgun",
|
||||||
|
"/Lotus/Weapons/Tenno/Shotgun/Shotgun",
|
||||||
|
"/Lotus/Weapons/Tenno/ThrowingWeapons/Kunai",
|
||||||
|
"/Lotus/Weapons/Tenno/ThrowingWeapons/StalkerKunai",
|
||||||
|
"/Lotus/Weapons/Tenno/Zariman/LongGuns/PumpShotgun/ZarimanPumpShotgun",
|
||||||
|
"/Lotus/Weapons/Tenno/Zariman/LongGuns/SemiAutoRifle/ZarimanSemiAutoRifle",
|
||||||
|
"/Lotus/Weapons/Tenno/Zariman/Melee/Dagger/ZarimanDaggerWeapon",
|
||||||
|
"/Lotus/Weapons/Tenno/Zariman/Melee/Tonfas/ZarimanTonfaWeapon",
|
||||||
|
"/Lotus/Weapons/Tenno/Zariman/Pistols/HeavyPistol/ZarimanHeavyPistol",
|
||||||
|
"/Lotus/Weapons/Thanotech/EntFistIncarnon/EntFistIncarnon",
|
||||||
|
"/Lotus/Weapons/Thanotech/EntratiWristGun/EntratiWristGunWeapon"
|
||||||
|
]
|
@ -1097,6 +1097,5 @@
|
|||||||
"/Lotus/Types/LevelObjects/InfestedPumpkinCocoonLamp",
|
"/Lotus/Types/LevelObjects/InfestedPumpkinCocoonLamp",
|
||||||
"/Lotus/Types/LevelObjects/InfestedPumpkinCocoonLampLarge",
|
"/Lotus/Types/LevelObjects/InfestedPumpkinCocoonLampLarge",
|
||||||
"/Lotus/Types/LevelObjects/InfestedPumpkinCocoonLampSmall",
|
"/Lotus/Types/LevelObjects/InfestedPumpkinCocoonLampSmall",
|
||||||
"/Lotus/Types/LevelObjects/InfestedPumpkinExplosiveTotem",
|
"/Lotus/Types/LevelObjects/InfestedPumpkinExplosiveTotem"
|
||||||
"/Lotus/Types/Enemies/Orokin/OrokinMoaBipedAvatar"
|
|
||||||
]
|
]
|
||||||
|
@ -1,106 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": {
|
|
||||||
"$oid": "5f456e01c96976e97d6b8016"
|
|
||||||
},
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Deimos/FishmongerVendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosOrokinFishAPartItem",
|
|
||||||
"PremiumPrice": [9, 9],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 10,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e91b9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishDPartItem",
|
|
||||||
"PremiumPrice": [17, 17],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e91ba"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishCPartItem",
|
|
||||||
"PremiumPrice": [10, 10],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e91bb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishBPartItem",
|
|
||||||
"PremiumPrice": [6, 6],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e91bc"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishAPartItem",
|
|
||||||
"PremiumPrice": [5, 5],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e91bd"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosGenericSharedFishPartItem",
|
|
||||||
"PremiumPrice": [7, 7],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e91be"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"PropertyTextHash": "6DF13A7FB573C25B4B4F989CBEFFC615",
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,101 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": { "$oid": "61ba123467e5d37975aeeb03" },
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementMoon",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
|
|
||||||
"ItemCount": 12,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"RegularPrice": [1, 1],
|
|
||||||
"Bin": "BIN_4",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "604800000" } },
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"LocTagRandSeed": 79554843,
|
|
||||||
"Id": { "$oid": "67bbb592e1534511d6c1c1e2" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementMountain",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
|
|
||||||
"ItemCount": 7,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"RegularPrice": [1, 1],
|
|
||||||
"Bin": "BIN_3",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "604800000" } },
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"LocTagRandSeed": 2413820225,
|
|
||||||
"Id": { "$oid": "67bbb592e1534511d6c1c1e3" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementStorm",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
|
|
||||||
"ItemCount": 3,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"RegularPrice": [1, 1],
|
|
||||||
"Bin": "BIN_2",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "604800000" } },
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"LocTagRandSeed": 3262300883,
|
|
||||||
"Id": { "$oid": "67bbb592e1534511d6c1c1e4" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementShadow",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
|
|
||||||
"ItemCount": 20,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"RegularPrice": [1, 1],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "604800000" } },
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"LocTagRandSeed": 2797325750,
|
|
||||||
"Id": { "$oid": "67bbb592e1534511d6c1c1e5" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementGhost",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
|
|
||||||
"ItemCount": 10,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"RegularPrice": [1, 1],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": { "$date": { "$numberLong": "604800000" } },
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"LocTagRandSeed": 554932310,
|
|
||||||
"Id": { "$oid": "67bbb592e1534511d6c1c1e6" }
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"PropertyTextHash": "255AFE2169BAE4130B4B20D7C55D14FA",
|
|
||||||
"RandomSeedType": "VRST_FLAVOUR_TEXT",
|
|
||||||
"Expiry": { "$date": { "$numberLong": "604800000" } }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,106 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": {
|
|
||||||
"$oid": "59d6e27ebcc718474eb17115"
|
|
||||||
},
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Ostron/FishmongerVendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/DayUncommonFishAPartItem",
|
|
||||||
"PremiumPrice": [14, 14],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 10,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9808"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/BothUncommonFishBPartItem",
|
|
||||||
"PremiumPrice": [12, 12],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 10,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9809"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/DayCommonFishCPartItem",
|
|
||||||
"PremiumPrice": [8, 8],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e980a"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/DayCommonFishBPartItem",
|
|
||||||
"PremiumPrice": [7, 7],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e980b"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/DayCommonFishAPartItem",
|
|
||||||
"PremiumPrice": [10, 10],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e980c"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/BothCommonFishBPartItem",
|
|
||||||
"PremiumPrice": [8, 8],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e980d"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"PropertyTextHash": "CC3B9DAFB38F412998E90A41421A8986",
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,248 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": {
|
|
||||||
"$oid": "5be4a159b144f3cdf1c22efa"
|
|
||||||
},
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Solaris/DebtTokenVendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/Types/StoreItems/Packages/DebtTokenBundles/DebtTokenBundleUncommonD",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemType": "/Lotus/Types/Gameplay/Venus/Resources/VenusCoconutItem",
|
|
||||||
"ItemCount": 5,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/Circuits",
|
|
||||||
"ItemCount": 3664,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"RegularPrice": [87300, 87300],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"LocTagRandSeed": 1881404827,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "670daf92d21f34757a5e73b4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/Types/StoreItems/Packages/DebtTokenBundles/DebtTokenBundleRareC",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/NeuralSensor",
|
|
||||||
"ItemCount": 1,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"RegularPrice": [53300, 53300],
|
|
||||||
"Bin": "BIN_2",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"LocTagRandSeed": 1943984533,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "6710b5029e1a3080a65e73a7"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/Types/StoreItems/Packages/DebtTokenBundles/DebtTokenBundleCommonG",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/Salvage",
|
|
||||||
"ItemCount": 11540,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"RegularPrice": [27300, 27300],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"LocTagRandSeed": 744199559,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "67112582cc115756985e73a4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/Types/StoreItems/Packages/DebtTokenBundles/DebtTokenBundleUncommonB",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemType": "/Lotus/Types/Items/Fish/Solaris/FishParts/CorpusFishThermalLaserItem",
|
|
||||||
"ItemCount": 9,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"RegularPrice": [75800, 75800],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"LocTagRandSeed": 3744711432,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "670de7d28a6ec82cd25e73a2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/Types/StoreItems/Packages/DebtTokenBundles/DebtTokenBundleUncommonB",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/Rubedo",
|
|
||||||
"ItemCount": 3343,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"RegularPrice": [52200, 52200],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"LocTagRandSeed": 1579000687,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "670e58526171148e125e73ad"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/Types/StoreItems/Packages/DebtTokenBundles/DebtTokenBundleCommonA",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemType": "/Lotus/Types/Gameplay/Venus/Resources/CoolantItem",
|
|
||||||
"ItemCount": 9,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ItemType": "/Lotus/Types/Items/Fish/Solaris/FishParts/CorpusFishAnoscopicSensorItem",
|
|
||||||
"ItemCount": 5,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"RegularPrice": [12400, 12400],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"LocTagRandSeed": 3589081466,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "67112582cc115756985e73a5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/Types/StoreItems/Packages/DebtTokenBundles/DebtTokenBundleUncommonC",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemType": "/Lotus/Types/Items/Gems/Solaris/SolarisCommonOreBAlloyItem",
|
|
||||||
"ItemCount": 13,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"RegularPrice": [77500, 77500],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"LocTagRandSeed": 1510234814,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "670f0f21250ad046c35e73ee"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/Types/StoreItems/Packages/DebtTokenBundles/DebtTokenBundleUncommonD",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemType": "/Lotus/Types/Items/Fish/Solaris/FishParts/CorpusFishParralelBiodeItem",
|
|
||||||
"ItemCount": 7,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ItemType": "/Lotus/Types/Items/Gems/Solaris/SolarisCommonGemBCutItem",
|
|
||||||
"ItemCount": 12,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"RegularPrice": [94600, 94600],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"LocTagRandSeed": 4222095721,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "670f63827be40254f95e739d"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/Types/StoreItems/Packages/DebtTokenBundles/DebtTokenBundleCommonJ",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/Nanospores",
|
|
||||||
"ItemCount": 14830,
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"RegularPrice": [25600, 25600],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"LocTagRandSeed": 2694388669,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "67112582cc115756985e73a6"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"PropertyTextHash": "A39621049CA3CA13761028CD21C239EF",
|
|
||||||
"RandomSeedType": "VRST_FLAVOUR_TEXT",
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,106 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": {
|
|
||||||
"$oid": "5b0de8556df82a56ea9bae82"
|
|
||||||
},
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Solaris/FishmongerVendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/CorpusFishThermalLaserItem",
|
|
||||||
"PremiumPrice": [15, 15],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 10,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9515"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/CorpusFishVenedoCaseItem",
|
|
||||||
"PremiumPrice": [8, 8],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9516"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/SolarisFishDissipatorCoilItem",
|
|
||||||
"PremiumPrice": [18, 18],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9517"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/CorpusFishExaBrainItem",
|
|
||||||
"PremiumPrice": [5, 5],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9518"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/CorpusFishAnoscopicSensorItem",
|
|
||||||
"PremiumPrice": [5, 5],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9519"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/GenericFishScrapItem",
|
|
||||||
"PremiumPrice": [5, 5],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e951a"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"PropertyTextHash": "946131D0CF5CDF7C2C03BB967DE0DF49",
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,459 @@
|
|||||||
|
{
|
||||||
|
"VendorInfo": {
|
||||||
|
"_id": {
|
||||||
|
"$oid": "67dadc30e4b6e0e5979c8d56"
|
||||||
|
},
|
||||||
|
"TypeName": "/Lotus/Types/Game/VendorManifests/TheHex/Temple1999VendorManifest",
|
||||||
|
"ItemManifest": [
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TempleBlueprint",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 195,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c18c"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TempleSystemsBlueprint",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 65,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c18d"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TempleChassisBlueprint",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 65,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c18e"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TempleHelmetBlueprint",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 65,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c18f"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/1999EntHybridPistolBlueprint",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 120,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c190"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/WeaponParts/1999EntHybridPistolBarrelBlueprint",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 60,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c191"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/WeaponParts/1999EntHybridPistolReceiverBlueprint",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 60,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c192"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/WeaponParts/1999EntHybridPistolStockBlueprint",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 60,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c193"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumDrumCoreKitA",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 30,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c194"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumDrumCymbalA",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 30,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c195"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumDrumFloorTomA",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 30,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c196"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumDrumSnareA",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 30,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c197"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumEquipmentCaseA",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 30,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c198"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumEquipmentCaseB",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 30,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c199"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumEquipmentCaseC",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 30,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c19a"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumEquipmentCaseD",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 30,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c19b"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumEquipmentCaseE",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 30,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c19c"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumEquipmentCaseF",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 30,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c19d"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumSynthKeyboardA",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 30,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c19e"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Items/PhotoBooth/Vania/PhotoboothTileVaniaObjTempleDefense",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 100,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 1,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowMultipurchase": false,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c19f"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/Kuva",
|
||||||
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemCount": 110,
|
||||||
|
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Bin": "BIN_0",
|
||||||
|
"QuantityMultiplier": 6000,
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PurchaseQuantityLimit": 7,
|
||||||
|
"AllowMultipurchase": true,
|
||||||
|
"Id": {
|
||||||
|
"$oid": "67dadc30641da66dc5c1c1a5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"PropertyTextHash": "20B13D9EB78FEC80EA32D0687F5BA1AE",
|
||||||
|
"RequiredGoalTag": "",
|
||||||
|
"Expiry": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "2051240400000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
175
static/fixed_responses/worldState/sortieTilesets.json
Normal file
175
static/fixed_responses/worldState/sortieTilesets.json
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
{
|
||||||
|
"SettlementNode1": "CorpusShipTileset",
|
||||||
|
"SettlementNode11": "CorpusShipTileset",
|
||||||
|
"SettlementNode12": "CorpusShipTileset",
|
||||||
|
"SettlementNode14": "CorpusShipTileset",
|
||||||
|
"SettlementNode15": "CorpusShipTileset",
|
||||||
|
"SettlementNode2": "CorpusShipTileset",
|
||||||
|
"SettlementNode20": "CorpusShipTileset",
|
||||||
|
"SettlementNode3": "CorpusShipTileset",
|
||||||
|
"SolNode1": "CorpusOutpostTileset",
|
||||||
|
"SolNode10": "CorpusGasCityTileset",
|
||||||
|
"SolNode100": "CorpusGasCityTileset",
|
||||||
|
"SolNode101": "CorpusOutpostTileset",
|
||||||
|
"SolNode102": "CorpusShipTileset",
|
||||||
|
"SolNode103": "GrineerAsteroidTileset",
|
||||||
|
"SolNode104": "CorpusShipTileset",
|
||||||
|
"SolNode105": "GrineerOceanTilesetAnywhere",
|
||||||
|
"SolNode106": "GrineerSettlementTileset",
|
||||||
|
"SolNode107": "CorpusOutpostTileset",
|
||||||
|
"SolNode108": "GrineerAsteroidTileset",
|
||||||
|
"SolNode109": "CorpusOutpostTileset",
|
||||||
|
"SolNode11": "GrineerSettlementTileset",
|
||||||
|
"SolNode113": "GrineerSettlementTileset",
|
||||||
|
"SolNode118": "CorpusShipTileset",
|
||||||
|
"SolNode119": "GrineerAsteroidTileset",
|
||||||
|
"SolNode12": "GrineerAsteroidTileset",
|
||||||
|
"SolNode121": "CorpusGasCityTileset",
|
||||||
|
"SolNode122": "GrineerOceanTileset",
|
||||||
|
"SolNode123": "CorpusShipTileset",
|
||||||
|
"SolNode125": "CorpusGasCityTileset",
|
||||||
|
"SolNode126": "CorpusGasCityTileset",
|
||||||
|
"SolNode127": "CorpusShipTileset",
|
||||||
|
"SolNode128": "CorpusOutpostTileset",
|
||||||
|
"SolNode130": "GrineerAsteroidTileset",
|
||||||
|
"SolNode131": "GrineerShipyardsTileset",
|
||||||
|
"SolNode132": "GrineerShipyardsTileset",
|
||||||
|
"SolNode135": "GrineerGalleonTileset",
|
||||||
|
"SolNode137": "GrineerShipyardsTileset",
|
||||||
|
"SolNode138": "GrineerShipyardsTileset",
|
||||||
|
"SolNode139": "GrineerShipyardsTileset",
|
||||||
|
"SolNode14": "CorpusIcePlanetTilesetCaves",
|
||||||
|
"SolNode140": "GrineerShipyardsTileset",
|
||||||
|
"SolNode141": "GrineerShipyardsTileset",
|
||||||
|
"SolNode144": "GrineerShipyardsTileset",
|
||||||
|
"SolNode146": "GrineerAsteroidTileset",
|
||||||
|
"SolNode147": "GrineerShipyardsTileset",
|
||||||
|
"SolNode149": "GrineerShipyardsTileset",
|
||||||
|
"SolNode15": "GrineerGalleonTileset",
|
||||||
|
"SolNode16": "GrineerSettlementTileset",
|
||||||
|
"SolNode162": "InfestedCorpusShipTileset",
|
||||||
|
"SolNode164": "InfestedCorpusShipTileset",
|
||||||
|
"SolNode166": "InfestedCorpusShipTileset",
|
||||||
|
"SolNode17": "CorpusShipTileset",
|
||||||
|
"SolNode171": "InfestedCorpusShipTileset",
|
||||||
|
"SolNode172": "CorpusShipTileset",
|
||||||
|
"SolNode173": "InfestedCorpusShipTileset",
|
||||||
|
"SolNode175": "InfestedCorpusShipTileset",
|
||||||
|
"SolNode177": "GrineerGalleonTileset",
|
||||||
|
"SolNode18": "GrineerAsteroidTileset",
|
||||||
|
"SolNode181": "GrineerAsteroidTileset",
|
||||||
|
"SolNode184": "GrineerGalleonTileset",
|
||||||
|
"SolNode185": "GrineerGalleonTileset",
|
||||||
|
"SolNode187": "GrineerAsteroidTileset",
|
||||||
|
"SolNode188": "GrineerGalleonTileset",
|
||||||
|
"SolNode189": "GrineerGalleonTileset",
|
||||||
|
"SolNode19": "GrineerAsteroidTileset",
|
||||||
|
"SolNode191": "GrineerShipyardsTileset",
|
||||||
|
"SolNode193": "GrineerAsteroidTileset",
|
||||||
|
"SolNode195": "GrineerGalleonTileset",
|
||||||
|
"SolNode196": "GrineerGalleonTileset",
|
||||||
|
"SolNode2": "CorpusOutpostTileset",
|
||||||
|
"SolNode20": "GrineerGalleonTileset",
|
||||||
|
"SolNode203": "CorpusIcePlanetTileset",
|
||||||
|
"SolNode205": "CorpusIcePlanetTileset",
|
||||||
|
"SolNode209": "CorpusIcePlanetTileset",
|
||||||
|
"SolNode21": "CorpusOutpostTileset",
|
||||||
|
"SolNode210": "CorpusIcePlanetTileset",
|
||||||
|
"SolNode211": "CorpusIcePlanetTileset",
|
||||||
|
"SolNode212": "CorpusIcePlanetTileset",
|
||||||
|
"SolNode214": "CorpusIcePlanetTileset",
|
||||||
|
"SolNode215": "CorpusShipTileset",
|
||||||
|
"SolNode216": "CorpusIcePlanetTileset",
|
||||||
|
"SolNode217": "CorpusIcePlanetTileset",
|
||||||
|
"SolNode22": "CorpusOutpostTileset",
|
||||||
|
"SolNode220": "CorpusIcePlanetTileset",
|
||||||
|
"SolNode223": "GrineerAsteroidTileset",
|
||||||
|
"SolNode224": "GrineerGalleonTileset",
|
||||||
|
"SolNode225": "GrineerGalleonTileset",
|
||||||
|
"SolNode226": "GrineerGalleonTileset",
|
||||||
|
"SolNode228": "EidolonTileset",
|
||||||
|
"SolNode23": "CorpusShipTileset",
|
||||||
|
"SolNode24": "GrineerForestTileset",
|
||||||
|
"SolNode25": "CorpusGasCityTileset",
|
||||||
|
"SolNode26": "GrineerForestTileset",
|
||||||
|
"SolNode30": "GrineerSettlementTileset",
|
||||||
|
"SolNode300": "OrokinMoonTilesetGrineer",
|
||||||
|
"SolNode301": "OrokinMoonTilesetGrineer",
|
||||||
|
"SolNode302": "OrokinMoonTilesetCorpus",
|
||||||
|
"SolNode304": "OrokinMoonTilesetCorpus",
|
||||||
|
"SolNode305": "OrokinMoonTilesetGrineer",
|
||||||
|
"SolNode306": "OrokinMoonTilesetCorpus",
|
||||||
|
"SolNode307": "OrokinMoonTilesetCorpus",
|
||||||
|
"SolNode308": "OrokinMoonTilesetCorpus",
|
||||||
|
"SolNode31": "GrineerGalleonTileset",
|
||||||
|
"SolNode32": "GrineerGalleonTileset",
|
||||||
|
"SolNode36": "GrineerSettlementTileset",
|
||||||
|
"SolNode38": "CorpusOutpostTileset",
|
||||||
|
"SolNode39": "GrineerForestTileset",
|
||||||
|
"SolNode4": "CorpusShipTileset",
|
||||||
|
"SolNode400": "OrokinVoidTileset",
|
||||||
|
"SolNode401": "OrokinVoidTileset",
|
||||||
|
"SolNode402": "OrokinVoidTileset",
|
||||||
|
"SolNode403": "OrokinVoidTileset",
|
||||||
|
"SolNode404": "OrokinVoidTileset",
|
||||||
|
"SolNode405": "OrokinVoidTileset",
|
||||||
|
"SolNode406": "OrokinVoidTileset",
|
||||||
|
"SolNode407": "OrokinVoidTileset",
|
||||||
|
"SolNode408": "OrokinVoidTileset",
|
||||||
|
"SolNode409": "OrokinVoidTileset",
|
||||||
|
"SolNode41": "GrineerSettlementTileset",
|
||||||
|
"SolNode410": "OrokinVoidTileset",
|
||||||
|
"SolNode412": "OrokinVoidTileset",
|
||||||
|
"SolNode42": "GrineerGalleonTileset",
|
||||||
|
"SolNode43": "CorpusOutpostTileset",
|
||||||
|
"SolNode45": "GrineerSettlementTileset",
|
||||||
|
"SolNode46": "GrineerSettlementTileset",
|
||||||
|
"SolNode48": "CorpusOutpostTileset",
|
||||||
|
"SolNode49": "CorpusShipTileset",
|
||||||
|
"SolNode50": "GrineerAsteroidTileset",
|
||||||
|
"SolNode51": "CorpusOutpostTileset",
|
||||||
|
"SolNode53": "CorpusGasCityTileset",
|
||||||
|
"SolNode56": "CorpusShipTileset",
|
||||||
|
"SolNode57": "CorpusOutpostTileset",
|
||||||
|
"SolNode58": "GrineerSettlementTileset",
|
||||||
|
"SolNode59": "GrineerForestTileset",
|
||||||
|
"SolNode6": "CorpusOutpostTileset",
|
||||||
|
"SolNode61": "CorpusShipTileset",
|
||||||
|
"SolNode62": "CorpusIcePlanetTilesetCaves",
|
||||||
|
"SolNode64": "GrineerOceanTileset",
|
||||||
|
"SolNode66": "CorpusOutpostTileset",
|
||||||
|
"SolNode67": "GrineerAsteroidTileset",
|
||||||
|
"SolNode68": "GrineerGalleonTileset",
|
||||||
|
"SolNode70": "GrineerGalleonTileset",
|
||||||
|
"SolNode706": "OrokinDerelictTileset",
|
||||||
|
"SolNode707": "OrokinDerelictTileset",
|
||||||
|
"SolNode708": "OrokinDerelictTileset",
|
||||||
|
"SolNode709": "OrokinDerelictTileset",
|
||||||
|
"SolNode710": "OrokinDerelictTileset",
|
||||||
|
"SolNode711": "OrokinDerelictTileset",
|
||||||
|
"SolNode712": "OrokinDerelictTileset",
|
||||||
|
"SolNode713": "OrokinDerelictTileset",
|
||||||
|
"SolNode72": "CorpusOutpostTileset",
|
||||||
|
"SolNode73": "CorpusGasCityTileset",
|
||||||
|
"SolNode74": "CorpusGasCityTileset",
|
||||||
|
"SolNode741": "GrineerFortressTileset",
|
||||||
|
"SolNode742": "GrineerFortressTileset",
|
||||||
|
"SolNode743": "GrineerFortressTileset",
|
||||||
|
"SolNode744": "GrineerFortressTileset",
|
||||||
|
"SolNode745": "GrineerFortressTileset",
|
||||||
|
"SolNode746": "GrineerFortressTileset",
|
||||||
|
"SolNode747": "GrineerFortressTileset",
|
||||||
|
"SolNode748": "GrineerFortressTileset",
|
||||||
|
"SolNode75": "GrineerForestTileset",
|
||||||
|
"SolNode76": "CorpusShipTileset",
|
||||||
|
"SolNode78": "CorpusShipTileset",
|
||||||
|
"SolNode79": "GrineerForestTileset",
|
||||||
|
"SolNode81": "CorpusShipTileset",
|
||||||
|
"SolNode82": "GrineerGalleonTileset",
|
||||||
|
"SolNode84": "CorpusIcePlanetTilesetCaves",
|
||||||
|
"SolNode88": "CorpusShipTileset",
|
||||||
|
"SolNode93": "GrineerAsteroidTileset",
|
||||||
|
"SolNode96": "GrineerGalleonTileset",
|
||||||
|
"SolNode97": "CorpusGasCityTileset",
|
||||||
|
"SolNode99": "GrineerSettlementTileset"
|
||||||
|
}
|
157
static/fixed_responses/worldState/syndicateMissions.json
Normal file
157
static/fixed_responses/worldState/syndicateMissions.json
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
[
|
||||||
|
"SettlementNode1",
|
||||||
|
"SettlementNode11",
|
||||||
|
"SettlementNode12",
|
||||||
|
"SettlementNode14",
|
||||||
|
"SettlementNode15",
|
||||||
|
"SettlementNode2",
|
||||||
|
"SettlementNode3",
|
||||||
|
"SolNode1",
|
||||||
|
"SolNode10",
|
||||||
|
"SolNode100",
|
||||||
|
"SolNode101",
|
||||||
|
"SolNode102",
|
||||||
|
"SolNode103",
|
||||||
|
"SolNode106",
|
||||||
|
"SolNode107",
|
||||||
|
"SolNode109",
|
||||||
|
"SolNode11",
|
||||||
|
"SolNode113",
|
||||||
|
"SolNode118",
|
||||||
|
"SolNode119",
|
||||||
|
"SolNode12",
|
||||||
|
"SolNode121",
|
||||||
|
"SolNode122",
|
||||||
|
"SolNode123",
|
||||||
|
"SolNode125",
|
||||||
|
"SolNode126",
|
||||||
|
"SolNode128",
|
||||||
|
"SolNode130",
|
||||||
|
"SolNode131",
|
||||||
|
"SolNode132",
|
||||||
|
"SolNode135",
|
||||||
|
"SolNode137",
|
||||||
|
"SolNode138",
|
||||||
|
"SolNode139",
|
||||||
|
"SolNode14",
|
||||||
|
"SolNode140",
|
||||||
|
"SolNode141",
|
||||||
|
"SolNode146",
|
||||||
|
"SolNode147",
|
||||||
|
"SolNode149",
|
||||||
|
"SolNode15",
|
||||||
|
"SolNode153",
|
||||||
|
"SolNode16",
|
||||||
|
"SolNode162",
|
||||||
|
"SolNode164",
|
||||||
|
"SolNode166",
|
||||||
|
"SolNode167",
|
||||||
|
"SolNode17",
|
||||||
|
"SolNode171",
|
||||||
|
"SolNode172",
|
||||||
|
"SolNode173",
|
||||||
|
"SolNode175",
|
||||||
|
"SolNode177",
|
||||||
|
"SolNode18",
|
||||||
|
"SolNode181",
|
||||||
|
"SolNode184",
|
||||||
|
"SolNode185",
|
||||||
|
"SolNode187",
|
||||||
|
"SolNode188",
|
||||||
|
"SolNode189",
|
||||||
|
"SolNode19",
|
||||||
|
"SolNode191",
|
||||||
|
"SolNode195",
|
||||||
|
"SolNode196",
|
||||||
|
"SolNode2",
|
||||||
|
"SolNode20",
|
||||||
|
"SolNode203",
|
||||||
|
"SolNode204",
|
||||||
|
"SolNode205",
|
||||||
|
"SolNode209",
|
||||||
|
"SolNode21",
|
||||||
|
"SolNode211",
|
||||||
|
"SolNode212",
|
||||||
|
"SolNode214",
|
||||||
|
"SolNode215",
|
||||||
|
"SolNode216",
|
||||||
|
"SolNode217",
|
||||||
|
"SolNode22",
|
||||||
|
"SolNode220",
|
||||||
|
"SolNode223",
|
||||||
|
"SolNode224",
|
||||||
|
"SolNode225",
|
||||||
|
"SolNode226",
|
||||||
|
"SolNode23",
|
||||||
|
"SolNode25",
|
||||||
|
"SolNode26",
|
||||||
|
"SolNode27",
|
||||||
|
"SolNode30",
|
||||||
|
"SolNode31",
|
||||||
|
"SolNode36",
|
||||||
|
"SolNode38",
|
||||||
|
"SolNode39",
|
||||||
|
"SolNode4",
|
||||||
|
"SolNode400",
|
||||||
|
"SolNode401",
|
||||||
|
"SolNode402",
|
||||||
|
"SolNode403",
|
||||||
|
"SolNode404",
|
||||||
|
"SolNode405",
|
||||||
|
"SolNode406",
|
||||||
|
"SolNode407",
|
||||||
|
"SolNode408",
|
||||||
|
"SolNode409",
|
||||||
|
"SolNode41",
|
||||||
|
"SolNode410",
|
||||||
|
"SolNode412",
|
||||||
|
"SolNode42",
|
||||||
|
"SolNode43",
|
||||||
|
"SolNode45",
|
||||||
|
"SolNode46",
|
||||||
|
"SolNode48",
|
||||||
|
"SolNode49",
|
||||||
|
"SolNode50",
|
||||||
|
"SolNode56",
|
||||||
|
"SolNode57",
|
||||||
|
"SolNode58",
|
||||||
|
"SolNode59",
|
||||||
|
"SolNode6",
|
||||||
|
"SolNode61",
|
||||||
|
"SolNode62",
|
||||||
|
"SolNode63",
|
||||||
|
"SolNode64",
|
||||||
|
"SolNode66",
|
||||||
|
"SolNode67",
|
||||||
|
"SolNode68",
|
||||||
|
"SolNode70",
|
||||||
|
"SolNode706",
|
||||||
|
"SolNode707",
|
||||||
|
"SolNode708",
|
||||||
|
"SolNode709",
|
||||||
|
"SolNode710",
|
||||||
|
"SolNode711",
|
||||||
|
"SolNode72",
|
||||||
|
"SolNode73",
|
||||||
|
"SolNode74",
|
||||||
|
"SolNode741",
|
||||||
|
"SolNode742",
|
||||||
|
"SolNode743",
|
||||||
|
"SolNode744",
|
||||||
|
"SolNode745",
|
||||||
|
"SolNode746",
|
||||||
|
"SolNode748",
|
||||||
|
"SolNode75",
|
||||||
|
"SolNode76",
|
||||||
|
"SolNode78",
|
||||||
|
"SolNode79",
|
||||||
|
"SolNode81",
|
||||||
|
"SolNode82",
|
||||||
|
"SolNode84",
|
||||||
|
"SolNode85",
|
||||||
|
"SolNode88",
|
||||||
|
"SolNode89",
|
||||||
|
"SolNode93",
|
||||||
|
"SolNode96",
|
||||||
|
"SolNode97"
|
||||||
|
]
|
@ -401,6 +401,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="card mb-3" style="height: 400px;">
|
||||||
|
<h5 class="card-header" data-loc="inventory_evolutionProgress"></h5>
|
||||||
|
<div class="card-body overflow-auto">
|
||||||
|
<form class="input-group mb-3" onsubmit="doAcquireEvolution();return false;">
|
||||||
|
<input class="form-control" id="acquire-type-EvolutionProgress" list="datalist-EvolutionProgress" />
|
||||||
|
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
||||||
|
</form>
|
||||||
|
<table class="table table-hover w-100">
|
||||||
|
<tbody id="EvolutionProgress-list"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="card mb-3">
|
<div class="card mb-3">
|
||||||
<h5 class="card-header" data-loc="general_bulkActions"></h5>
|
<h5 class="card-header" data-loc="general_bulkActions"></h5>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -411,6 +427,7 @@
|
|||||||
<button class="btn btn-primary" onclick="addMissingEquipment(['SpaceGuns', 'SpaceMelee']);" data-loc="inventory_bulkAddSpaceWeapons"></button>
|
<button class="btn btn-primary" onclick="addMissingEquipment(['SpaceGuns', 'SpaceMelee']);" data-loc="inventory_bulkAddSpaceWeapons"></button>
|
||||||
<button class="btn btn-primary" onclick="addMissingEquipment(['Sentinels']);" data-loc="inventory_bulkAddSentinels"></button>
|
<button class="btn btn-primary" onclick="addMissingEquipment(['Sentinels']);" data-loc="inventory_bulkAddSentinels"></button>
|
||||||
<button class="btn btn-primary" onclick="addMissingEquipment(['SentinelWeapons']);" data-loc="inventory_bulkAddSentinelWeapons"></button>
|
<button class="btn btn-primary" onclick="addMissingEquipment(['SentinelWeapons']);" data-loc="inventory_bulkAddSentinelWeapons"></button>
|
||||||
|
<button class="btn btn-primary" onclick="addMissingEvolutionProgress();" data-loc="inventory_bulkAddEvolutionProgress"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-2 d-flex flex-wrap gap-2">
|
<div class="mb-2 d-flex flex-wrap gap-2">
|
||||||
<button class="btn btn-success" onclick="maxRankAllEquipment(['Suits']);" data-loc="inventory_bulkRankUpSuits"></button>
|
<button class="btn btn-success" onclick="maxRankAllEquipment(['Suits']);" data-loc="inventory_bulkRankUpSuits"></button>
|
||||||
@ -419,6 +436,7 @@
|
|||||||
<button class="btn btn-success" onclick="maxRankAllEquipment(['SpaceGuns', 'SpaceMelee']);" data-loc="inventory_bulkRankUpSpaceWeapons"></button>
|
<button class="btn btn-success" onclick="maxRankAllEquipment(['SpaceGuns', 'SpaceMelee']);" data-loc="inventory_bulkRankUpSpaceWeapons"></button>
|
||||||
<button class="btn btn-success" onclick="maxRankAllEquipment(['Sentinels']);" data-loc="inventory_bulkRankUpSentinels"></button>
|
<button class="btn btn-success" onclick="maxRankAllEquipment(['Sentinels']);" data-loc="inventory_bulkRankUpSentinels"></button>
|
||||||
<button class="btn btn-success" onclick="maxRankAllEquipment(['SentinelWeapons']);" data-loc="inventory_bulkRankUpSentinelWeapons"></button>
|
<button class="btn btn-success" onclick="maxRankAllEquipment(['SentinelWeapons']);" data-loc="inventory_bulkRankUpSentinelWeapons"></button>
|
||||||
|
<button class="btn btn-success" onclick="maxRankAllEvolutions();" data-loc="inventory_bulkRankUpEvolutionProgress"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -492,8 +510,9 @@
|
|||||||
<div class="card mb-3">
|
<div class="card mb-3">
|
||||||
<h5 class="card-header" data-loc="general_bulkActions"></h5>
|
<h5 class="card-header" data-loc="general_bulkActions"></h5>
|
||||||
<div class="card-body d-flex flex-wrap gap-2">
|
<div class="card-body d-flex flex-wrap gap-2">
|
||||||
<button class="btn btn-primary" onclick="doAddAllMods();" data-loc="mods_bulkAddMods"></button>
|
<button class="btn btn-primary" onclick="doAddAllMods();" data-loc="mods_addMissingUnrankedMods"></button>
|
||||||
<button class="btn btn-danger" onclick="doRemoveUnrankedMods();" data-loc="mods_removeUnranked"></button>
|
<button class="btn btn-danger" onclick="doRemoveUnrankedMods();" data-loc="mods_removeUnranked"></button>
|
||||||
|
<button class="btn btn-primary" onclick="doAddMissingMaxRankMods();" data-loc="mods_addMissingMaxRankMods"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -575,6 +594,10 @@
|
|||||||
<input class="form-check-input" type="checkbox" id="infiniteHelminthMaterials" />
|
<input class="form-check-input" type="checkbox" id="infiniteHelminthMaterials" />
|
||||||
<label class="form-check-label" for="infiniteHelminthMaterials" data-loc="cheats_infiniteHelminthMaterials"></label>
|
<label class="form-check-label" for="infiniteHelminthMaterials" data-loc="cheats_infiniteHelminthMaterials"></label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="dontSubtractConsumables" />
|
||||||
|
<label class="form-check-label" for="dontSubtractConsumables" data-loc="cheats_dontSubtractConsumables"></label>
|
||||||
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="unlockAllShipFeatures" />
|
<input class="form-check-input" type="checkbox" id="unlockAllShipFeatures" />
|
||||||
<label class="form-check-label" for="unlockAllShipFeatures" data-loc="cheats_unlockAllShipFeatures"></label>
|
<label class="form-check-label" for="unlockAllShipFeatures" data-loc="cheats_unlockAllShipFeatures"></label>
|
||||||
@ -651,6 +674,10 @@
|
|||||||
<input class="form-check-input" type="checkbox" id="noResourceExtractorDronesDamage" />
|
<input class="form-check-input" type="checkbox" id="noResourceExtractorDronesDamage" />
|
||||||
<label class="form-check-label" for="noResourceExtractorDronesDamage" data-loc="cheats_noResourceExtractorDronesDamage"></label>
|
<label class="form-check-label" for="noResourceExtractorDronesDamage" data-loc="cheats_noResourceExtractorDronesDamage"></label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="skipClanKeyCrafting" />
|
||||||
|
<label class="form-check-label" for="skipClanKeyCrafting" data-loc="cheats_skipClanKeyCrafting"></label>
|
||||||
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<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>
|
||||||
@ -733,6 +760,7 @@
|
|||||||
</datalist>
|
</datalist>
|
||||||
<datalist id="datalist-archonCrystalUpgrades"></datalist>
|
<datalist id="datalist-archonCrystalUpgrades"></datalist>
|
||||||
<datalist id="datalist-OperatorAmps"></datalist>
|
<datalist id="datalist-OperatorAmps"></datalist>
|
||||||
|
<datalist id="datalist-EvolutionProgress"></datalist>
|
||||||
<datalist id="datalist-ModularParts"></datalist>
|
<datalist id="datalist-ModularParts"></datalist>
|
||||||
<datalist id="datalist-ModularParts-HB_DECK"></datalist>
|
<datalist id="datalist-ModularParts-HB_DECK"></datalist>
|
||||||
<datalist id="datalist-ModularParts-HB_ENGINE"></datalist>
|
<datalist id="datalist-ModularParts-HB_ENGINE"></datalist>
|
||||||
|
@ -13,6 +13,7 @@ function doLogin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loginFromLocalStorage() {
|
function loginFromLocalStorage() {
|
||||||
|
const isRegister = registerSubmit;
|
||||||
doLoginRequest(
|
doLoginRequest(
|
||||||
data => {
|
data => {
|
||||||
if (single.getCurrentPath() == "/webui/") {
|
if (single.getCurrentPath() == "/webui/") {
|
||||||
@ -28,7 +29,7 @@ function loginFromLocalStorage() {
|
|||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
logout();
|
logout();
|
||||||
alert("Login failed");
|
alert(isRegister ? "Registration failed. Account already exists?" : "Login failed");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -44,7 +45,7 @@ function doLoginRequest(succ_cb, fail_cb) {
|
|||||||
s: "W0RFXVN0ZXZlIGxpa2VzIGJpZyBidXR0cw==", // signature of some kind
|
s: "W0RFXVN0ZXZlIGxpa2VzIGJpZyBidXR0cw==", // signature of some kind
|
||||||
lang: "en",
|
lang: "en",
|
||||||
date: 1501230947855458660, // ???
|
date: 1501230947855458660, // ???
|
||||||
ClientType: registerSubmit ? "" : "webui",
|
ClientType: registerSubmit ? "webui-register" : "webui",
|
||||||
PS: "W0RFXVN0ZXZlIGxpa2VzIGJpZyBidXR0cw==" // anti-cheat data
|
PS: "W0RFXVN0ZXZlIGxpa2VzIGJpZyBidXR0cw==" // anti-cheat data
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@ -77,18 +78,22 @@ function logout() {
|
|||||||
function renameAccount() {
|
function renameAccount() {
|
||||||
const newname = window.prompt(loc("code_changeNameConfirm"));
|
const newname = window.prompt(loc("code_changeNameConfirm"));
|
||||||
if (newname) {
|
if (newname) {
|
||||||
fetch("/custom/renameAccount?" + window.authz + "&newname=" + newname).then(() => {
|
revalidateAuthz(() => {
|
||||||
$(".displayname").text(newname);
|
fetch("/custom/renameAccount?" + window.authz + "&newname=" + newname).then(() => {
|
||||||
updateLocElements();
|
$(".displayname").text(newname);
|
||||||
|
updateLocElements();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteAccount() {
|
function deleteAccount() {
|
||||||
if (window.confirm(loc("code_deleteAccountConfirm"))) {
|
if (window.confirm(loc("code_deleteAccountConfirm"))) {
|
||||||
fetch("/custom/deleteAccount?" + window.authz).then(() => {
|
revalidateAuthz(() => {
|
||||||
logout();
|
fetch("/custom/deleteAccount?" + window.authz).then(() => {
|
||||||
single.loadRoute("/webui/"); // Show login screen
|
logout();
|
||||||
|
single.loadRoute("/webui/"); // Show login screen
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,6 +187,16 @@ const webUiModularWeapons = [
|
|||||||
"/Lotus/Types/Friendly/Pets/CreaturePets/MedjayPredatorKubrowPetPowerSuit"
|
"/Lotus/Types/Friendly/Pets/CreaturePets/MedjayPredatorKubrowPetPowerSuit"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const permanentEvolutionWeapons = new Set([
|
||||||
|
"/Lotus/Weapons/Tenno/Zariman/LongGuns/PumpShotgun/ZarimanPumpShotgun",
|
||||||
|
"/Lotus/Weapons/Tenno/Zariman/LongGuns/SemiAutoRifle/ZarimanSemiAutoRifle",
|
||||||
|
"/Lotus/Weapons/Tenno/Zariman/Melee/Dagger/ZarimanDaggerWeapon",
|
||||||
|
"/Lotus/Weapons/Tenno/Zariman/Melee/Tonfas/ZarimanTonfaWeapon",
|
||||||
|
"/Lotus/Weapons/Tenno/Zariman/Pistols/HeavyPistol/ZarimanHeavyPistol",
|
||||||
|
"/Lotus/Weapons/Thanotech/EntFistIncarnon/EntFistIncarnon",
|
||||||
|
"/Lotus/Weapons/Thanotech/EntratiWristGun/EntratiWristGunWeapon"
|
||||||
|
]);
|
||||||
|
|
||||||
let uniqueLevelCaps = {};
|
let uniqueLevelCaps = {};
|
||||||
function fetchItemList() {
|
function fetchItemList() {
|
||||||
window.itemListPromise = new Promise(resolve => {
|
window.itemListPromise = new Promise(resolve => {
|
||||||
@ -360,6 +375,7 @@ function fetchItemList() {
|
|||||||
}
|
}
|
||||||
fetchItemList();
|
fetchItemList();
|
||||||
|
|
||||||
|
// Assumes that caller revalidates authz
|
||||||
function updateInventory() {
|
function updateInventory() {
|
||||||
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
|
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
|
||||||
req.done(data => {
|
req.done(data => {
|
||||||
@ -472,25 +488,27 @@ function updateInventory() {
|
|||||||
a.href = "#";
|
a.href = "#";
|
||||||
a.onclick = function (event) {
|
a.onclick = function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (item.XP < maxXP) {
|
revalidateAuthz(() => {
|
||||||
addGearExp(category, item.ItemId.$oid, maxXP - item.XP);
|
if (item.XP < maxXP) {
|
||||||
}
|
addGearExp(category, item.ItemId.$oid, maxXP - item.XP);
|
||||||
if ("exalted" in itemMap[item.ItemType]) {
|
}
|
||||||
for (const exaltedType of itemMap[item.ItemType].exalted) {
|
if ("exalted" in itemMap[item.ItemType]) {
|
||||||
const exaltedItem = data.SpecialItems.find(x => x.ItemType == exaltedType);
|
for (const exaltedType of itemMap[item.ItemType].exalted) {
|
||||||
if (exaltedItem) {
|
const exaltedItem = data.SpecialItems.find(x => x.ItemType == exaltedType);
|
||||||
const exaltedCap =
|
if (exaltedItem) {
|
||||||
itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000;
|
const exaltedCap =
|
||||||
if (exaltedItem.XP < exaltedCap) {
|
itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000;
|
||||||
addGearExp(
|
if (exaltedItem.XP < exaltedCap) {
|
||||||
"SpecialItems",
|
addGearExp(
|
||||||
exaltedItem.ItemId.$oid,
|
"SpecialItems",
|
||||||
exaltedCap - exaltedItem.XP
|
exaltedItem.ItemId.$oid,
|
||||||
);
|
exaltedCap - exaltedItem.XP
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
};
|
};
|
||||||
a.title = loc("code_maxRank");
|
a.title = loc("code_maxRank");
|
||||||
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>`;
|
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>`;
|
||||||
@ -562,6 +580,82 @@ function updateInventory() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById("EvolutionProgress-list").innerHTML = "";
|
||||||
|
data.EvolutionProgress?.forEach(item => {
|
||||||
|
const datalist = document.getElementById("datalist-EvolutionProgress");
|
||||||
|
const optionToRemove = datalist.querySelector(`option[data-key="${item.ItemType}"]`);
|
||||||
|
if (optionToRemove) {
|
||||||
|
datalist.removeChild(optionToRemove);
|
||||||
|
}
|
||||||
|
const tr = document.createElement("tr");
|
||||||
|
tr.setAttribute("data-item-type", item.ItemType);
|
||||||
|
{
|
||||||
|
const td = document.createElement("td");
|
||||||
|
td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType;
|
||||||
|
if (item.Rank != null) {
|
||||||
|
td.textContent += " | " + loc("code_rank") + ": [" + item.Rank + "/5]";
|
||||||
|
}
|
||||||
|
tr.appendChild(td);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const td = document.createElement("td");
|
||||||
|
td.classList = "text-end text-nowrap";
|
||||||
|
if (item.Rank < 5) {
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = "#";
|
||||||
|
a.onclick = function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
setEvolutionProgress([{ ItemType: item.ItemType, Rank: 5 }]);
|
||||||
|
};
|
||||||
|
a.title = loc("code_maxRank");
|
||||||
|
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>`;
|
||||||
|
|
||||||
|
td.appendChild(a);
|
||||||
|
}
|
||||||
|
if ((permanentEvolutionWeapons.has(item.ItemType) && item.Rank > 0) || item.Rank > 1) {
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = "#";
|
||||||
|
a.onclick = function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
setEvolutionProgress([{ ItemType: item.ItemType, Rank: item.Rank - 1 }]);
|
||||||
|
};
|
||||||
|
a.title = loc("code_rankDown");
|
||||||
|
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"/></svg>`;
|
||||||
|
|
||||||
|
td.appendChild(a);
|
||||||
|
}
|
||||||
|
if (item.Rank < 5) {
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = "#";
|
||||||
|
a.onclick = function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
setEvolutionProgress([{ ItemType: item.ItemType, Rank: item.Rank + 1 }]);
|
||||||
|
};
|
||||||
|
a.title = loc("code_rankUp");
|
||||||
|
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z"/></svg>`;
|
||||||
|
|
||||||
|
td.appendChild(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.appendChild(td);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("EvolutionProgress-list").appendChild(tr);
|
||||||
|
});
|
||||||
|
|
||||||
|
const datalistEvolutionProgress = document.querySelectorAll("#datalist-EvolutionProgress option");
|
||||||
|
const formEvolutionProgress = document.querySelector('form[onsubmit*="doAcquireEvolution()"]');
|
||||||
|
const giveAllQEvolutionProgress = document.querySelector(
|
||||||
|
'button[onclick*="addMissingEvolutionProgress()"]'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (datalistEvolutionProgress.length === 0) {
|
||||||
|
formEvolutionProgress.classList.add("disabled");
|
||||||
|
formEvolutionProgress.querySelector("input").disabled = true;
|
||||||
|
formEvolutionProgress.querySelector("button").disabled = true;
|
||||||
|
giveAllQEvolutionProgress.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Populate quests route
|
// Populate quests route
|
||||||
document.getElementById("QuestKeys-list").innerHTML = "";
|
document.getElementById("QuestKeys-list").innerHTML = "";
|
||||||
data.QuestKeys.forEach(item => {
|
data.QuestKeys.forEach(item => {
|
||||||
@ -673,18 +767,18 @@ function updateInventory() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const datalistQuestKeys = document.querySelectorAll("#datalist-QuestKeys option");
|
const datalistQuestKeys = document.querySelectorAll("#datalist-QuestKeys option");
|
||||||
const form = document.querySelector("form[onsubmit*=\"doAcquireEquipment('QuestKeys')\"]");
|
const formQuestKeys = document.querySelector("form[onsubmit*=\"doAcquireEquipment('QuestKeys')\"]");
|
||||||
const giveAllQuestButton = document.querySelector("button[onclick*=\"doBulkQuestUpdate('giveAll')\"]");
|
const giveAllQuestButton = document.querySelector("button[onclick*=\"doBulkQuestUpdate('giveAll')\"]");
|
||||||
|
|
||||||
if (datalistQuestKeys.length === 0) {
|
if (datalistQuestKeys.length === 0) {
|
||||||
form.classList.add("disabled");
|
formQuestKeys.classList.add("disabled");
|
||||||
form.querySelector("input").disabled = true;
|
formQuestKeys.querySelector("input").disabled = true;
|
||||||
form.querySelector("button").disabled = true;
|
formQuestKeys.querySelector("button").disabled = true;
|
||||||
giveAllQuestButton.disabled = true;
|
giveAllQuestButton.disabled = true;
|
||||||
} else {
|
} else {
|
||||||
form.classList.remove("disabled");
|
formQuestKeys.classList.remove("disabled");
|
||||||
form.querySelector("input").disabled = false;
|
formQuestKeys.querySelector("input").disabled = false;
|
||||||
form.querySelector("button").disabled = false;
|
formQuestKeys.querySelector("button").disabled = false;
|
||||||
giveAllQuestButton.disabled = false;
|
giveAllQuestButton.disabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1079,6 +1173,16 @@ function doAcquireModularEquipment(category, WeaponType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function doAcquireEvolution() {
|
||||||
|
const uniqueName = getKey(document.getElementById("acquire-type-EvolutionProgress"));
|
||||||
|
if (!uniqueName) {
|
||||||
|
$("#acquire-type-EvolutionProgress").addClass("is-invalid").focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setEvolutionProgress([{ ItemType: uniqueName, Rank: permanentEvolutionWeapons.has(uniqueName) ? 0 : 1 }]);
|
||||||
|
}
|
||||||
|
|
||||||
$("input[list]").on("input", function () {
|
$("input[list]").on("input", function () {
|
||||||
$(this).removeClass("is-invalid");
|
$(this).removeClass("is-invalid");
|
||||||
});
|
});
|
||||||
@ -1116,54 +1220,34 @@ function addMissingEquipment(categories) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function maxRankAllEquipment(categories) {
|
function addMissingEvolutionProgress() {
|
||||||
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
|
const requests = [];
|
||||||
|
document.querySelectorAll("#datalist-EvolutionProgress option").forEach(elm => {
|
||||||
|
const uniqueName = elm.getAttribute("data-key");
|
||||||
|
requests.push({ ItemType: uniqueName, Rank: permanentEvolutionWeapons.has(uniqueName) ? 0 : 1 });
|
||||||
|
});
|
||||||
|
if (requests.length != 0 && window.confirm(loc("code_addItemsConfirm").split("|COUNT|").join(requests.length))) {
|
||||||
|
setEvolutionProgress(requests);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
req.done(data => {
|
function maxRankAllEvolutions() {
|
||||||
window.itemListPromise.then(itemMap => {
|
revalidateAuthz(() => {
|
||||||
const batchData = {};
|
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
|
||||||
|
req.done(data => {
|
||||||
|
const requests = [];
|
||||||
|
|
||||||
categories.forEach(category => {
|
data.EvolutionProgress.forEach(item => {
|
||||||
data[category].forEach(item => {
|
if (item.Rank < 5) {
|
||||||
const maxXP =
|
requests.push({
|
||||||
category === "Suits" ||
|
ItemType: item.ItemType,
|
||||||
category === "SpaceSuits" ||
|
Rank: 5
|
||||||
category === "Sentinels" ||
|
});
|
||||||
category === "Hoverboards"
|
}
|
||||||
? 1_600_000
|
|
||||||
: 800_000;
|
|
||||||
|
|
||||||
if (item.XP < maxXP) {
|
|
||||||
if (!batchData[category]) {
|
|
||||||
batchData[category] = [];
|
|
||||||
}
|
|
||||||
batchData[category].push({
|
|
||||||
ItemId: { $oid: item.ItemId.$oid },
|
|
||||||
XP: maxXP
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (category === "Suits") {
|
|
||||||
if ("exalted" in itemMap[item.ItemType]) {
|
|
||||||
for (const exaltedType of itemMap[item.ItemType].exalted) {
|
|
||||||
const exaltedItem = data["SpecialItems"].find(x => x.ItemType == exaltedType);
|
|
||||||
if (exaltedItem) {
|
|
||||||
const exaltedCap = itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000;
|
|
||||||
if (exaltedItem.XP < exaltedCap) {
|
|
||||||
batchData["SpecialItems"] ??= [];
|
|
||||||
batchData["SpecialItems"].push({
|
|
||||||
ItemId: { $oid: exaltedItem.ItemId.$oid },
|
|
||||||
XP: exaltedCap
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Object.keys(batchData).length > 0) {
|
if (Object.keys(requests).length > 0) {
|
||||||
return sendBatchGearExp(batchData);
|
return setEvolutionProgress(requests);
|
||||||
}
|
}
|
||||||
|
|
||||||
toast(loc("code_noEquipmentToRankUp"));
|
toast(loc("code_noEquipmentToRankUp"));
|
||||||
@ -1171,6 +1255,64 @@ function maxRankAllEquipment(categories) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function maxRankAllEquipment(categories) {
|
||||||
|
revalidateAuthz(() => {
|
||||||
|
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
|
||||||
|
req.done(data => {
|
||||||
|
window.itemListPromise.then(itemMap => {
|
||||||
|
const batchData = {};
|
||||||
|
|
||||||
|
categories.forEach(category => {
|
||||||
|
data[category].forEach(item => {
|
||||||
|
const maxXP =
|
||||||
|
category === "Suits" ||
|
||||||
|
category === "SpaceSuits" ||
|
||||||
|
category === "Sentinels" ||
|
||||||
|
category === "Hoverboards"
|
||||||
|
? 1_600_000
|
||||||
|
: 800_000;
|
||||||
|
|
||||||
|
if (item.XP < maxXP) {
|
||||||
|
if (!batchData[category]) {
|
||||||
|
batchData[category] = [];
|
||||||
|
}
|
||||||
|
batchData[category].push({
|
||||||
|
ItemId: { $oid: item.ItemId.$oid },
|
||||||
|
XP: maxXP
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (category === "Suits") {
|
||||||
|
if ("exalted" in itemMap[item.ItemType]) {
|
||||||
|
for (const exaltedType of itemMap[item.ItemType].exalted) {
|
||||||
|
const exaltedItem = data["SpecialItems"].find(x => x.ItemType == exaltedType);
|
||||||
|
if (exaltedItem) {
|
||||||
|
const exaltedCap =
|
||||||
|
itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000;
|
||||||
|
if (exaltedItem.XP < exaltedCap) {
|
||||||
|
batchData["SpecialItems"] ??= [];
|
||||||
|
batchData["SpecialItems"].push({
|
||||||
|
ItemId: { $oid: exaltedItem.ItemId.$oid },
|
||||||
|
XP: exaltedCap
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Object.keys(batchData).length > 0) {
|
||||||
|
return sendBatchGearExp(batchData);
|
||||||
|
}
|
||||||
|
|
||||||
|
toast(loc("code_noEquipmentToRankUp"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assumes that caller revalidates authz
|
||||||
function addGearExp(category, oid, xp) {
|
function addGearExp(category, oid, xp) {
|
||||||
const data = {};
|
const data = {};
|
||||||
data[category] = [
|
data[category] = [
|
||||||
@ -1179,16 +1321,14 @@ function addGearExp(category, oid, xp) {
|
|||||||
XP: xp
|
XP: xp
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
revalidateAuthz(() => {
|
$.post({
|
||||||
$.post({
|
url: "/custom/addXp?" + window.authz,
|
||||||
url: "/custom/addXp?" + window.authz,
|
contentType: "application/json",
|
||||||
contentType: "application/json",
|
data: JSON.stringify(data)
|
||||||
data: JSON.stringify(data)
|
}).done(function () {
|
||||||
}).done(function () {
|
if (category != "SpecialItems") {
|
||||||
if (category != "SpecialItems") {
|
updateInventory();
|
||||||
updateInventory();
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1303,6 +1443,19 @@ function maturePet(oid, revert) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setEvolutionProgress(requests) {
|
||||||
|
revalidateAuthz(() => {
|
||||||
|
const req = $.post({
|
||||||
|
url: "/custom/setEvolutionProgress?" + window.authz,
|
||||||
|
contentType: "application/json",
|
||||||
|
data: JSON.stringify(requests)
|
||||||
|
});
|
||||||
|
req.done(() => {
|
||||||
|
updateInventory();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function doAcquireMiscItems() {
|
function doAcquireMiscItems() {
|
||||||
const uniqueName = getKey(document.getElementById("miscitem-type"));
|
const uniqueName = getKey(document.getElementById("miscitem-type"));
|
||||||
if (!uniqueName) {
|
if (!uniqueName) {
|
||||||
@ -1450,32 +1603,34 @@ function doAcquireMod() {
|
|||||||
const uiConfigs = [...$("#server-settings input[id]")].map(x => x.id);
|
const uiConfigs = [...$("#server-settings input[id]")].map(x => x.id);
|
||||||
|
|
||||||
function doChangeSettings() {
|
function doChangeSettings() {
|
||||||
fetch("/custom/config?" + window.authz)
|
revalidateAuthz(() => {
|
||||||
.then(response => response.json())
|
fetch("/custom/config?" + window.authz)
|
||||||
.then(json => {
|
.then(response => response.json())
|
||||||
for (const i of uiConfigs) {
|
.then(json => {
|
||||||
var x = document.getElementById(i);
|
for (const i of uiConfigs) {
|
||||||
if (x != null) {
|
var x = document.getElementById(i);
|
||||||
if (x.type == "checkbox") {
|
if (x != null) {
|
||||||
if (x.checked === true) {
|
if (x.type == "checkbox") {
|
||||||
json[i] = true;
|
if (x.checked === true) {
|
||||||
} else {
|
json[i] = true;
|
||||||
json[i] = false;
|
} else {
|
||||||
|
json[i] = false;
|
||||||
|
}
|
||||||
|
} else if (x.type == "number") {
|
||||||
|
json[i] = parseInt(x.value);
|
||||||
}
|
}
|
||||||
} else if (x.type == "number") {
|
|
||||||
json[i] = parseInt(x.value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
$.post({
|
||||||
$.post({
|
url: "/custom/config?" + window.authz,
|
||||||
url: "/custom/config?" + window.authz,
|
contentType: "text/plain",
|
||||||
contentType: "text/plain",
|
data: JSON.stringify(json, null, 2)
|
||||||
data: JSON.stringify(json, null, 2)
|
}).then(() => {
|
||||||
}).then(() => {
|
// A few cheats affect the inventory response which in turn may change what values we need to show
|
||||||
// A few cheats affect the inventory response which in turn may change what values we need to show
|
updateInventory();
|
||||||
updateInventory();
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cheats route
|
// Cheats route
|
||||||
@ -1647,6 +1802,14 @@ function doRemoveUnrankedMods() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function doAddMissingMaxRankMods() {
|
||||||
|
revalidateAuthz(() => {
|
||||||
|
fetch("/custom/addMissingMaxRankMods?" + window.authz).then(() => {
|
||||||
|
updateInventory();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Powersuit Route
|
// Powersuit Route
|
||||||
|
|
||||||
single.getRoute("#powersuit-route").on("beforeload", function () {
|
single.getRoute("#powersuit-route").on("beforeload", function () {
|
||||||
@ -1720,33 +1883,39 @@ function doChangeSupportedSyndicate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function doAddCurrency(currency) {
|
function doAddCurrency(currency) {
|
||||||
$.post({
|
revalidateAuthz(() => {
|
||||||
url: "/custom/addCurrency?" + window.authz,
|
$.post({
|
||||||
contentType: "application/json",
|
url: "/custom/addCurrency?" + window.authz,
|
||||||
data: JSON.stringify({
|
contentType: "application/json",
|
||||||
currency,
|
data: JSON.stringify({
|
||||||
delta: document.getElementById(currency + "-delta").valueAsNumber
|
currency,
|
||||||
})
|
delta: document.getElementById(currency + "-delta").valueAsNumber
|
||||||
}).then(function () {
|
})
|
||||||
updateInventory();
|
}).then(function () {
|
||||||
|
updateInventory();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function doQuestUpdate(operation, itemType) {
|
function doQuestUpdate(operation, itemType) {
|
||||||
$.post({
|
revalidateAuthz(() => {
|
||||||
url: "/custom/manageQuests?" + window.authz + "&operation=" + operation + "&itemType=" + itemType,
|
$.post({
|
||||||
contentType: "application/json"
|
url: "/custom/manageQuests?" + window.authz + "&operation=" + operation + "&itemType=" + itemType,
|
||||||
}).then(function () {
|
contentType: "application/json"
|
||||||
updateInventory();
|
}).then(function () {
|
||||||
|
updateInventory();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function doBulkQuestUpdate(operation) {
|
function doBulkQuestUpdate(operation) {
|
||||||
$.post({
|
revalidateAuthz(() => {
|
||||||
url: "/custom/manageQuests?" + window.authz + "&operation=" + operation,
|
$.post({
|
||||||
contentType: "application/json"
|
url: "/custom/manageQuests?" + window.authz + "&operation=" + operation,
|
||||||
}).then(function () {
|
contentType: "application/json"
|
||||||
updateInventory();
|
}).then(function () {
|
||||||
|
updateInventory();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,8 @@ dict = {
|
|||||||
code_rerollsNumber: `Anzahl der Umrollversuche`,
|
code_rerollsNumber: `Anzahl der Umrollversuche`,
|
||||||
code_viewStats: `Statistiken anzeigen`,
|
code_viewStats: `Statistiken anzeigen`,
|
||||||
code_rank: `Rang`,
|
code_rank: `Rang`,
|
||||||
|
code_rankUp: `Rang erhöhen`,
|
||||||
|
code_rankDown: `Rang verringern`,
|
||||||
code_count: `Anzahl`,
|
code_count: `Anzahl`,
|
||||||
code_focusAllUnlocked: `Alle Fokus-Schulen sind bereits freigeschaltet.`,
|
code_focusAllUnlocked: `Alle Fokus-Schulen sind bereits freigeschaltet.`,
|
||||||
code_focusUnlocked: `|COUNT| neue Fokus-Schulen freigeschaltet! Ein Inventar-Update wird benötigt, damit die Änderungen im Spiel sichtbar werden. Die Sternenkarte zu besuchen, sollte der einfachste Weg sein, dies auszulösen.`,
|
code_focusUnlocked: `|COUNT| neue Fokus-Schulen freigeschaltet! Ein Inventar-Update wird benötigt, damit die Änderungen im Spiel sichtbar werden. Die Sternenkarte zu besuchen, sollte der einfachste Weg sein, dies auszulösen.`,
|
||||||
@ -60,7 +62,7 @@ dict = {
|
|||||||
login_emailLabel: `E-Mail-Adresse`,
|
login_emailLabel: `E-Mail-Adresse`,
|
||||||
login_passwordLabel: `Passwort`,
|
login_passwordLabel: `Passwort`,
|
||||||
login_loginButton: `Anmelden`,
|
login_loginButton: `Anmelden`,
|
||||||
login_registerButton: `[UNTRANSLATED] Register`,
|
login_registerButton: `Registrieren`,
|
||||||
navbar_logout: `Abmelden`,
|
navbar_logout: `Abmelden`,
|
||||||
navbar_renameAccount: `Account umbenennen`,
|
navbar_renameAccount: `Account umbenennen`,
|
||||||
navbar_deleteAccount: `Account löschen`,
|
navbar_deleteAccount: `Account löschen`,
|
||||||
@ -82,20 +84,23 @@ dict = {
|
|||||||
inventory_sentinelWeapons: `Wächter-Waffen`,
|
inventory_sentinelWeapons: `Wächter-Waffen`,
|
||||||
inventory_operatorAmps: `Verstärker`,
|
inventory_operatorAmps: `Verstärker`,
|
||||||
inventory_hoverboards: `K-Drives`,
|
inventory_hoverboards: `K-Drives`,
|
||||||
inventory_moaPets: `Moa`,
|
inventory_moaPets: `Moas`,
|
||||||
inventory_kubrowPets: `Bestien`,
|
inventory_kubrowPets: `Bestien`,
|
||||||
|
inventory_evolutionProgress: `Incarnon-Entwicklungsfortschritte`,
|
||||||
inventory_bulkAddSuits: `Fehlende Warframes hinzufügen`,
|
inventory_bulkAddSuits: `Fehlende Warframes hinzufügen`,
|
||||||
inventory_bulkAddWeapons: `Fehlende Waffen hinzufügen`,
|
inventory_bulkAddWeapons: `Fehlende Waffen hinzufügen`,
|
||||||
inventory_bulkAddSpaceSuits: `Fehlende Archwings hinzufügen`,
|
inventory_bulkAddSpaceSuits: `Fehlende Archwings hinzufügen`,
|
||||||
inventory_bulkAddSpaceWeapons: `Fehlende Archwing-Waffen hinzufügen`,
|
inventory_bulkAddSpaceWeapons: `Fehlende Archwing-Waffen hinzufügen`,
|
||||||
inventory_bulkAddSentinels: `Fehlende Wächter hinzufügen`,
|
inventory_bulkAddSentinels: `Fehlende Wächter hinzufügen`,
|
||||||
inventory_bulkAddSentinelWeapons: `Fehlende Wächter-Waffen hinzufügen`,
|
inventory_bulkAddSentinelWeapons: `Fehlende Wächter-Waffen hinzufügen`,
|
||||||
|
inventory_bulkAddEvolutionProgress: `Fehlende Incarnon-Entwicklungsfortschritte hinzufügen`,
|
||||||
inventory_bulkRankUpSuits: `Alle Warframes auf Max. Rang`,
|
inventory_bulkRankUpSuits: `Alle Warframes auf Max. Rang`,
|
||||||
inventory_bulkRankUpWeapons: `Alle Waffen auf Max. Rang`,
|
inventory_bulkRankUpWeapons: `Alle Waffen auf Max. Rang`,
|
||||||
inventory_bulkRankUpSpaceSuits: `Alle Archwings auf Max. Rang`,
|
inventory_bulkRankUpSpaceSuits: `Alle Archwings auf Max. Rang`,
|
||||||
inventory_bulkRankUpSpaceWeapons: `Alle Archwing-Waffen auf Max. Rang`,
|
inventory_bulkRankUpSpaceWeapons: `Alle Archwing-Waffen auf Max. Rang`,
|
||||||
inventory_bulkRankUpSentinels: `Alle Wächter auf Max. Rang`,
|
inventory_bulkRankUpSentinels: `Alle Wächter auf Max. Rang`,
|
||||||
inventory_bulkRankUpSentinelWeapons: `Alle Wächter-Waffen auf Max. Rang`,
|
inventory_bulkRankUpSentinelWeapons: `Alle Wächter-Waffen auf Max. Rang`,
|
||||||
|
inventory_bulkRankUpEvolutionProgress: `Alle Incarnon-Entwicklungsfortschritte auf Max. Rang`,
|
||||||
|
|
||||||
quests_list: `Quests`,
|
quests_list: `Quests`,
|
||||||
quests_completeAll: `Alle Quests abschließen`,
|
quests_completeAll: `Alle Quests abschließen`,
|
||||||
@ -115,8 +120,9 @@ dict = {
|
|||||||
mods_fingerprintHelp: `Benötigst du Hilfe mit dem Fingerabdruck?`,
|
mods_fingerprintHelp: `Benötigst du Hilfe mit dem Fingerabdruck?`,
|
||||||
mods_rivens: `Rivens`,
|
mods_rivens: `Rivens`,
|
||||||
mods_mods: `Mods`,
|
mods_mods: `Mods`,
|
||||||
mods_bulkAddMods: `Fehlende Mods hinzufügen`,
|
mods_addMissingUnrankedMods: `Fehlende Mods ohne Rang hinzufügen`,
|
||||||
mods_removeUnranked: `[UNTRANSLATED] Remove Unranked Mods`,
|
mods_removeUnranked: `Mods ohne Rang entfernen`,
|
||||||
|
mods_addMissingMaxRankMods: `Fehlende Mods mit Max. Rang hinzufügen`,
|
||||||
cheats_administratorRequirement: `Du musst Administrator sein, um diese Funktion nutzen zu können. Um Administrator zu werden, füge <code>|DISPLAYNAME|</code> zu <code>administratorNames</code> in der config.json hinzu.`,
|
cheats_administratorRequirement: `Du musst Administrator sein, um diese Funktion nutzen zu können. Um Administrator zu werden, füge <code>|DISPLAYNAME|</code> zu <code>administratorNames</code> in der config.json hinzu.`,
|
||||||
cheats_server: `Server`,
|
cheats_server: `Server`,
|
||||||
cheats_skipTutorial: `Tutorial überspringen`,
|
cheats_skipTutorial: `Tutorial überspringen`,
|
||||||
@ -128,6 +134,7 @@ dict = {
|
|||||||
cheats_infiniteEndo: `Unendlich Endo`,
|
cheats_infiniteEndo: `Unendlich Endo`,
|
||||||
cheats_infiniteRegalAya: `Unendlich Reines Aya`,
|
cheats_infiniteRegalAya: `Unendlich Reines Aya`,
|
||||||
cheats_infiniteHelminthMaterials: `Unendlich Helminth-Materialien`,
|
cheats_infiniteHelminthMaterials: `Unendlich Helminth-Materialien`,
|
||||||
|
cheats_dontSubtractConsumables: `Verbrauchsgegenstände (Ausrüstung) nicht verbrauchen`,
|
||||||
cheats_unlockAllShipFeatures: `Alle Schiffs-Funktionen freischalten`,
|
cheats_unlockAllShipFeatures: `Alle Schiffs-Funktionen freischalten`,
|
||||||
cheats_unlockAllShipDecorations: `Alle Schiffsdekorationen freischalten`,
|
cheats_unlockAllShipDecorations: `Alle Schiffsdekorationen freischalten`,
|
||||||
cheats_unlockAllFlavourItems: `Alle <abbr title=\"Animationssets, Glyphen, Farbpaletten usw.\">Sammlerstücke</abbr> freischalten`,
|
cheats_unlockAllFlavourItems: `Alle <abbr title=\"Animationssets, Glyphen, Farbpaletten usw.\">Sammlerstücke</abbr> freischalten`,
|
||||||
@ -147,6 +154,7 @@ dict = {
|
|||||||
cheats_noKimCooldowns: `Keine Wartezeit bei KIM`,
|
cheats_noKimCooldowns: `Keine Wartezeit bei KIM`,
|
||||||
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_noDojoRoomBuildStage: `Kein Dojo-Raum-Bauvorgang`,
|
cheats_noDojoRoomBuildStage: `Kein Dojo-Raum-Bauvorgang`,
|
||||||
cheats_noDojoDecoBuildStage: `Kein Dojo-Deko-Bauvorgang`,
|
cheats_noDojoDecoBuildStage: `Kein Dojo-Deko-Bauvorgang`,
|
||||||
cheats_fastDojoRoomDestruction: `Schnelle Dojo-Raum-Zerstörung`,
|
cheats_fastDojoRoomDestruction: `Schnelle Dojo-Raum-Zerstörung`,
|
||||||
|
@ -33,6 +33,8 @@ dict = {
|
|||||||
code_rerollsNumber: `Number of rerolls`,
|
code_rerollsNumber: `Number of rerolls`,
|
||||||
code_viewStats: `View Stats`,
|
code_viewStats: `View Stats`,
|
||||||
code_rank: `Rank`,
|
code_rank: `Rank`,
|
||||||
|
code_rankUp: `Rank up`,
|
||||||
|
code_rankDown: `Rank down`,
|
||||||
code_count: `Count`,
|
code_count: `Count`,
|
||||||
code_focusAllUnlocked: `All focus schools are already unlocked.`,
|
code_focusAllUnlocked: `All focus schools are already unlocked.`,
|
||||||
code_focusUnlocked: `Unlocked |COUNT| new focus schools! An inventory update will be needed for the changes to be reflected in-game. Visiting the navigation should be the easiest way to trigger that.`,
|
code_focusUnlocked: `Unlocked |COUNT| new focus schools! An inventory update will be needed for the changes to be reflected in-game. Visiting the navigation should be the easiest way to trigger that.`,
|
||||||
@ -81,20 +83,23 @@ dict = {
|
|||||||
inventory_sentinelWeapons: `Sentinel Weapons`,
|
inventory_sentinelWeapons: `Sentinel Weapons`,
|
||||||
inventory_operatorAmps: `Amps`,
|
inventory_operatorAmps: `Amps`,
|
||||||
inventory_hoverboards: `K-Drives`,
|
inventory_hoverboards: `K-Drives`,
|
||||||
inventory_moaPets: `Moa`,
|
inventory_moaPets: `Moas`,
|
||||||
inventory_kubrowPets: `Beasts`,
|
inventory_kubrowPets: `Beasts`,
|
||||||
|
inventory_evolutionProgress: `Incarnon Evolution Progress`,
|
||||||
inventory_bulkAddSuits: `Add Missing Warframes`,
|
inventory_bulkAddSuits: `Add Missing Warframes`,
|
||||||
inventory_bulkAddWeapons: `Add Missing Weapons`,
|
inventory_bulkAddWeapons: `Add Missing Weapons`,
|
||||||
inventory_bulkAddSpaceSuits: `Add Missing Archwings`,
|
inventory_bulkAddSpaceSuits: `Add Missing Archwings`,
|
||||||
inventory_bulkAddSpaceWeapons: `Add Missing Archwing Weapons`,
|
inventory_bulkAddSpaceWeapons: `Add Missing Archwing Weapons`,
|
||||||
inventory_bulkAddSentinels: `Add Missing Sentinels`,
|
inventory_bulkAddSentinels: `Add Missing Sentinels`,
|
||||||
inventory_bulkAddSentinelWeapons: `Add Missing Sentinel Weapons`,
|
inventory_bulkAddSentinelWeapons: `Add Missing Sentinel Weapons`,
|
||||||
|
inventory_bulkAddEvolutionProgress: `Add Missing Incarnon Evolution Progress`,
|
||||||
inventory_bulkRankUpSuits: `Max Rank All Warframes`,
|
inventory_bulkRankUpSuits: `Max Rank All Warframes`,
|
||||||
inventory_bulkRankUpWeapons: `Max Rank All Weapons`,
|
inventory_bulkRankUpWeapons: `Max Rank All Weapons`,
|
||||||
inventory_bulkRankUpSpaceSuits: `Max Rank All Archwings`,
|
inventory_bulkRankUpSpaceSuits: `Max Rank All Archwings`,
|
||||||
inventory_bulkRankUpSpaceWeapons: `Max Rank All Archwing Weapons`,
|
inventory_bulkRankUpSpaceWeapons: `Max Rank All Archwing Weapons`,
|
||||||
inventory_bulkRankUpSentinels: `Max Rank All Sentinels`,
|
inventory_bulkRankUpSentinels: `Max Rank All Sentinels`,
|
||||||
inventory_bulkRankUpSentinelWeapons: `Max Rank All Sentinel Weapons`,
|
inventory_bulkRankUpSentinelWeapons: `Max Rank All Sentinel Weapons`,
|
||||||
|
inventory_bulkRankUpEvolutionProgress: `Max Rank All Incarnon Evolution Progress`,
|
||||||
|
|
||||||
quests_list: `Quests`,
|
quests_list: `Quests`,
|
||||||
quests_completeAll: `Complete All Quests`,
|
quests_completeAll: `Complete All Quests`,
|
||||||
@ -114,8 +119,9 @@ dict = {
|
|||||||
mods_fingerprintHelp: `Need help with the fingerprint?`,
|
mods_fingerprintHelp: `Need help with the fingerprint?`,
|
||||||
mods_rivens: `Rivens`,
|
mods_rivens: `Rivens`,
|
||||||
mods_mods: `Mods`,
|
mods_mods: `Mods`,
|
||||||
mods_bulkAddMods: `Add Missing Mods`,
|
mods_addMissingUnrankedMods: `Add Missing Unranked Mods`,
|
||||||
mods_removeUnranked: `Remove Unranked Mods`,
|
mods_removeUnranked: `Remove Unranked Mods`,
|
||||||
|
mods_addMissingMaxRankMods: `Add Missing Max Rank Mods`,
|
||||||
cheats_administratorRequirement: `You must be an administrator to use this feature. To become an administrator, add <code>|DISPLAYNAME|</code> to <code>administratorNames</code> in the config.json.`,
|
cheats_administratorRequirement: `You must be an administrator to use this feature. To become an administrator, add <code>|DISPLAYNAME|</code> to <code>administratorNames</code> in the config.json.`,
|
||||||
cheats_server: `Server`,
|
cheats_server: `Server`,
|
||||||
cheats_skipTutorial: `Skip Tutorial`,
|
cheats_skipTutorial: `Skip Tutorial`,
|
||||||
@ -127,6 +133,7 @@ dict = {
|
|||||||
cheats_infiniteEndo: `Infinite Endo`,
|
cheats_infiniteEndo: `Infinite Endo`,
|
||||||
cheats_infiniteRegalAya: `Infinite Regal Aya`,
|
cheats_infiniteRegalAya: `Infinite Regal Aya`,
|
||||||
cheats_infiniteHelminthMaterials: `Infinite Helminth Materials`,
|
cheats_infiniteHelminthMaterials: `Infinite Helminth Materials`,
|
||||||
|
cheats_dontSubtractConsumables: `Don't Subtract Consumables`,
|
||||||
cheats_unlockAllShipFeatures: `Unlock All Ship Features`,
|
cheats_unlockAllShipFeatures: `Unlock All Ship Features`,
|
||||||
cheats_unlockAllShipDecorations: `Unlock All Ship Decorations`,
|
cheats_unlockAllShipDecorations: `Unlock All Ship Decorations`,
|
||||||
cheats_unlockAllFlavourItems: `Unlock All <abbr title=\"Animation Sets, Glyphs, Palettes, etc.\">Flavor Items</abbr>`,
|
cheats_unlockAllFlavourItems: `Unlock All <abbr title=\"Animation Sets, Glyphs, Palettes, etc.\">Flavor Items</abbr>`,
|
||||||
@ -146,6 +153,7 @@ dict = {
|
|||||||
cheats_noKimCooldowns: `No KIM Cooldowns`,
|
cheats_noKimCooldowns: `No KIM Cooldowns`,
|
||||||
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_noDojoRoomBuildStage: `No Dojo Room Build Stage`,
|
cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`,
|
||||||
cheats_noDojoDecoBuildStage: `No Dojo Deco Build Stage`,
|
cheats_noDojoDecoBuildStage: `No Dojo Deco Build Stage`,
|
||||||
cheats_fastDojoRoomDestruction: `Fast Dojo Room Destruction`,
|
cheats_fastDojoRoomDestruction: `Fast Dojo Room Destruction`,
|
||||||
|
@ -34,6 +34,8 @@ dict = {
|
|||||||
code_rerollsNumber: `Cantidad de reintentos`,
|
code_rerollsNumber: `Cantidad de reintentos`,
|
||||||
code_viewStats: `Ver estadísticas`,
|
code_viewStats: `Ver estadísticas`,
|
||||||
code_rank: `Rango`,
|
code_rank: `Rango`,
|
||||||
|
code_rankUp: `Subir de rango`,
|
||||||
|
code_rankDown: `Bajar de rango`,
|
||||||
code_count: `Cantidad`,
|
code_count: `Cantidad`,
|
||||||
code_focusAllUnlocked: `Todas las escuelas de enfoque ya están desbloqueadas.`,
|
code_focusAllUnlocked: `Todas las escuelas de enfoque ya están desbloqueadas.`,
|
||||||
code_focusUnlocked: `¡Desbloqueadas |COUNT| nuevas escuelas de enfoque! Se necesita una actualización del inventario para reflejar los cambios en el juego. Visitar la navegación debería ser la forma más sencilla de activarlo.`,
|
code_focusUnlocked: `¡Desbloqueadas |COUNT| nuevas escuelas de enfoque! Se necesita una actualización del inventario para reflejar los cambios en el juego. Visitar la navegación debería ser la forma más sencilla de activarlo.`,
|
||||||
@ -60,7 +62,7 @@ dict = {
|
|||||||
login_emailLabel: `Dirección de correo electrónico`,
|
login_emailLabel: `Dirección de correo electrónico`,
|
||||||
login_passwordLabel: `Contraseña`,
|
login_passwordLabel: `Contraseña`,
|
||||||
login_loginButton: `Iniciar sesión`,
|
login_loginButton: `Iniciar sesión`,
|
||||||
login_registerButton: `[UNTRANSLATED] Register`,
|
login_registerButton: `Registrarse`,
|
||||||
navbar_logout: `Cerrar sesión`,
|
navbar_logout: `Cerrar sesión`,
|
||||||
navbar_renameAccount: `Renombrar cuenta`,
|
navbar_renameAccount: `Renombrar cuenta`,
|
||||||
navbar_deleteAccount: `Eliminar cuenta`,
|
navbar_deleteAccount: `Eliminar cuenta`,
|
||||||
@ -82,20 +84,23 @@ dict = {
|
|||||||
inventory_sentinelWeapons: `Armas de centinela`,
|
inventory_sentinelWeapons: `Armas de centinela`,
|
||||||
inventory_operatorAmps: `Amps`,
|
inventory_operatorAmps: `Amps`,
|
||||||
inventory_hoverboards: `K-Drives`,
|
inventory_hoverboards: `K-Drives`,
|
||||||
inventory_moaPets: `Moa`,
|
inventory_moaPets: `Moas`,
|
||||||
inventory_kubrowPets: `Bestias`,
|
inventory_kubrowPets: `Bestias`,
|
||||||
|
inventory_evolutionProgress: `Progreso de evolución Incarnon`,
|
||||||
inventory_bulkAddSuits: `Agregar Warframes faltantes`,
|
inventory_bulkAddSuits: `Agregar Warframes faltantes`,
|
||||||
inventory_bulkAddWeapons: `Agregar armas faltantes`,
|
inventory_bulkAddWeapons: `Agregar armas faltantes`,
|
||||||
inventory_bulkAddSpaceSuits: `Agregar Archwings faltantes`,
|
inventory_bulkAddSpaceSuits: `Agregar Archwings faltantes`,
|
||||||
inventory_bulkAddSpaceWeapons: `Agregar armas Archwing faltantes`,
|
inventory_bulkAddSpaceWeapons: `Agregar armas Archwing faltantes`,
|
||||||
inventory_bulkAddSentinels: `Agregar centinelas faltantes`,
|
inventory_bulkAddSentinels: `Agregar centinelas faltantes`,
|
||||||
inventory_bulkAddSentinelWeapons: `Agregar armas de centinela faltantes`,
|
inventory_bulkAddSentinelWeapons: `Agregar armas de centinela faltantes`,
|
||||||
|
inventory_bulkAddEvolutionProgress: `Completar el progreso de evolución Incarnon faltante`,
|
||||||
inventory_bulkRankUpSuits: `Maximizar rango de todos los Warframes`,
|
inventory_bulkRankUpSuits: `Maximizar rango de todos los Warframes`,
|
||||||
inventory_bulkRankUpWeapons: `Maximizar rango de todas las armas`,
|
inventory_bulkRankUpWeapons: `Maximizar rango de todas las armas`,
|
||||||
inventory_bulkRankUpSpaceSuits: `Maximizar rango de todos los Archwings`,
|
inventory_bulkRankUpSpaceSuits: `Maximizar rango de todos los Archwings`,
|
||||||
inventory_bulkRankUpSpaceWeapons: `Maximizar rango de todas las armas Archwing`,
|
inventory_bulkRankUpSpaceWeapons: `Maximizar rango de todas las armas Archwing`,
|
||||||
inventory_bulkRankUpSentinels: `Maximizar rango de todos los centinelas`,
|
inventory_bulkRankUpSentinels: `Maximizar rango de todos los centinelas`,
|
||||||
inventory_bulkRankUpSentinelWeapons: `Maximizar rango de todas las armas de centinela`,
|
inventory_bulkRankUpSentinelWeapons: `Maximizar rango de todas las armas de centinela`,
|
||||||
|
inventory_bulkRankUpEvolutionProgress: `Maximizar todo el progreso de evolución Incarnon`,
|
||||||
|
|
||||||
quests_list: `Misiones`,
|
quests_list: `Misiones`,
|
||||||
quests_completeAll: `Completar todas las misiones`,
|
quests_completeAll: `Completar todas las misiones`,
|
||||||
@ -115,8 +120,9 @@ dict = {
|
|||||||
mods_fingerprintHelp: `¿Necesitas ayuda con la huella digital?`,
|
mods_fingerprintHelp: `¿Necesitas ayuda con la huella digital?`,
|
||||||
mods_rivens: `Agrietados`,
|
mods_rivens: `Agrietados`,
|
||||||
mods_mods: `Mods`,
|
mods_mods: `Mods`,
|
||||||
mods_bulkAddMods: `Agregar mods faltantes`,
|
mods_addMissingUnrankedMods: `Agregar mods sin rango faltantes`,
|
||||||
mods_removeUnranked: `[UNTRANSLATED] Remove Unranked Mods`,
|
mods_removeUnranked: `Quitar mods sin rango`,
|
||||||
|
mods_addMissingMaxRankMods: `Agregar mods de rango máximo faltantes`,
|
||||||
cheats_administratorRequirement: `Debes ser administrador para usar esta función. Para convertirte en administrador, agrega <code>|DISPLAYNAME|</code> a <code>administratorNames</code> en el archivo config.json.`,
|
cheats_administratorRequirement: `Debes ser administrador para usar esta función. Para convertirte en administrador, agrega <code>|DISPLAYNAME|</code> a <code>administratorNames</code> en el archivo config.json.`,
|
||||||
cheats_server: `Servidor`,
|
cheats_server: `Servidor`,
|
||||||
cheats_skipTutorial: `Omitir tutorial`,
|
cheats_skipTutorial: `Omitir tutorial`,
|
||||||
@ -128,6 +134,7 @@ dict = {
|
|||||||
cheats_infiniteEndo: `Endo infinito`,
|
cheats_infiniteEndo: `Endo infinito`,
|
||||||
cheats_infiniteRegalAya: `Aya Real infinita`,
|
cheats_infiniteRegalAya: `Aya Real infinita`,
|
||||||
cheats_infiniteHelminthMaterials: `Materiales Helminto infinitos`,
|
cheats_infiniteHelminthMaterials: `Materiales Helminto infinitos`,
|
||||||
|
cheats_dontSubtractConsumables: `No restar consumibles`,
|
||||||
cheats_unlockAllShipFeatures: `Desbloquear todas las funciones de nave`,
|
cheats_unlockAllShipFeatures: `Desbloquear todas las funciones de nave`,
|
||||||
cheats_unlockAllShipDecorations: `Desbloquear todas las decoraciones de nave`,
|
cheats_unlockAllShipDecorations: `Desbloquear todas las decoraciones de nave`,
|
||||||
cheats_unlockAllFlavourItems: `Desbloquear todos los <abbr title="Conjuntos de animaciones, glifos, paletas, etc.">ítems estéticos</abbr>`,
|
cheats_unlockAllFlavourItems: `Desbloquear todos los <abbr title="Conjuntos de animaciones, glifos, paletas, etc.">ítems estéticos</abbr>`,
|
||||||
@ -147,6 +154,7 @@ dict = {
|
|||||||
cheats_noKimCooldowns: `Sin tiempo de espera para conversaciones KIM`,
|
cheats_noKimCooldowns: `Sin tiempo de espera para conversaciones KIM`,
|
||||||
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_noDojoRoomBuildStage: `Sin etapa de construcción de sala del dojo`,
|
cheats_noDojoRoomBuildStage: `Sin etapa de construcción de sala del dojo`,
|
||||||
cheats_noDojoDecoBuildStage: `Sin etapa de construcción de decoraciones del dojo`,
|
cheats_noDojoDecoBuildStage: `Sin etapa de construcción de decoraciones del dojo`,
|
||||||
cheats_fastDojoRoomDestruction: `Destrucción rápida de salas del dojo`,
|
cheats_fastDojoRoomDestruction: `Destrucción rápida de salas del dojo`,
|
||||||
|
@ -34,6 +34,8 @@ dict = {
|
|||||||
code_rerollsNumber: `Nombre de rerolls`,
|
code_rerollsNumber: `Nombre de rerolls`,
|
||||||
code_viewStats: `Voir les stats`,
|
code_viewStats: `Voir les stats`,
|
||||||
code_rank: `Rang`,
|
code_rank: `Rang`,
|
||||||
|
code_rankUp: `[UNTRANSLATED] Rank up`,
|
||||||
|
code_rankDown: `[UNTRANSLATED] Rank down`,
|
||||||
code_count: `Quantité`,
|
code_count: `Quantité`,
|
||||||
code_focusAllUnlocked: `Les écoles de Focus sont déjà déverrouillées.`,
|
code_focusAllUnlocked: `Les écoles de Focus sont déjà déverrouillées.`,
|
||||||
code_focusUnlocked: `|COUNT| écoles de Focus déverrouillées ! Synchronisation de l'inventaire nécessaire.`,
|
code_focusUnlocked: `|COUNT| écoles de Focus déverrouillées ! Synchronisation de l'inventaire nécessaire.`,
|
||||||
@ -82,20 +84,23 @@ dict = {
|
|||||||
inventory_sentinelWeapons: `Armes de sentinelles`,
|
inventory_sentinelWeapons: `Armes de sentinelles`,
|
||||||
inventory_operatorAmps: `Amplificateurs`,
|
inventory_operatorAmps: `Amplificateurs`,
|
||||||
inventory_hoverboards: `K-Drives`,
|
inventory_hoverboards: `K-Drives`,
|
||||||
inventory_moaPets: `Moa`,
|
inventory_moaPets: `Moas`,
|
||||||
inventory_kubrowPets: `Bêtes`,
|
inventory_kubrowPets: `Bêtes`,
|
||||||
|
inventory_evolutionProgress: `[UNTRANSLATED] Incarnon Evolution Progress`,
|
||||||
inventory_bulkAddSuits: `Ajouter les Warframes manquantes`,
|
inventory_bulkAddSuits: `Ajouter les Warframes manquantes`,
|
||||||
inventory_bulkAddWeapons: `Ajouter les armes manquantes`,
|
inventory_bulkAddWeapons: `Ajouter les armes manquantes`,
|
||||||
inventory_bulkAddSpaceSuits: `Ajouter les Archwings manquants`,
|
inventory_bulkAddSpaceSuits: `Ajouter les Archwings manquants`,
|
||||||
inventory_bulkAddSpaceWeapons: `Ajouter les armes d'Archwing manquantes`,
|
inventory_bulkAddSpaceWeapons: `Ajouter les armes d'Archwing manquantes`,
|
||||||
inventory_bulkAddSentinels: `Ajouter les Sentinelles manquantes`,
|
inventory_bulkAddSentinels: `Ajouter les Sentinelles manquantes`,
|
||||||
inventory_bulkAddSentinelWeapons: `Ajouter les armes de Sentinelles manquantes`,
|
inventory_bulkAddSentinelWeapons: `Ajouter les armes de Sentinelles manquantes`,
|
||||||
|
inventory_bulkAddEvolutionProgress: `[UNTRANSLATED] Add Missing Incarnon Evolution Progress`,
|
||||||
inventory_bulkRankUpSuits: `Toutes les Warframes rang max`,
|
inventory_bulkRankUpSuits: `Toutes les Warframes rang max`,
|
||||||
inventory_bulkRankUpWeapons: `Toutes les armes rang max`,
|
inventory_bulkRankUpWeapons: `Toutes les armes rang max`,
|
||||||
inventory_bulkRankUpSpaceSuits: `Tous les Archwings rang max`,
|
inventory_bulkRankUpSpaceSuits: `Tous les Archwings rang max`,
|
||||||
inventory_bulkRankUpSpaceWeapons: `Toutes les armes d'Archwing rang max`,
|
inventory_bulkRankUpSpaceWeapons: `Toutes les armes d'Archwing rang max`,
|
||||||
inventory_bulkRankUpSentinels: `Toutes les Sentinelles rang max`,
|
inventory_bulkRankUpSentinels: `Toutes les Sentinelles rang max`,
|
||||||
inventory_bulkRankUpSentinelWeapons: `Toutes les armes de Sentinelles rang max`,
|
inventory_bulkRankUpSentinelWeapons: `Toutes les armes de Sentinelles rang max`,
|
||||||
|
inventory_bulkRankUpEvolutionProgress: `[UNTRANSLATED] Max Rank All Incarnon Evolution Progress`,
|
||||||
|
|
||||||
quests_list: `Quêtes`,
|
quests_list: `Quêtes`,
|
||||||
quests_completeAll: `Compléter toutes les quêtes`,
|
quests_completeAll: `Compléter toutes les quêtes`,
|
||||||
@ -115,8 +120,9 @@ dict = {
|
|||||||
mods_fingerprintHelp: `Besoin d'aide pour l'empreinte ?`,
|
mods_fingerprintHelp: `Besoin d'aide pour l'empreinte ?`,
|
||||||
mods_rivens: `Rivens`,
|
mods_rivens: `Rivens`,
|
||||||
mods_mods: `Mods`,
|
mods_mods: `Mods`,
|
||||||
mods_bulkAddMods: `Ajouter les mods manquants`,
|
mods_addMissingUnrankedMods: `[UNTRANSLATED] Add Missing Unranked Mods`,
|
||||||
mods_removeUnranked: `[UNTRANSLATED] Remove Unranked Mods`,
|
mods_removeUnranked: `[UNTRANSLATED] Remove Unranked Mods`,
|
||||||
|
mods_addMissingMaxRankMods: `[UNTRANSLATED] Add Missing Max Rank Mods`,
|
||||||
cheats_administratorRequirement: `Rôle d'administrateur requis pour cette fonctionnalité. Ajoutez <code>|DISPLAYNAME|</code> à la ligne <code>administratorNames</code> dans le fichier config.json.`,
|
cheats_administratorRequirement: `Rôle d'administrateur requis pour cette fonctionnalité. Ajoutez <code>|DISPLAYNAME|</code> à la ligne <code>administratorNames</code> dans le fichier config.json.`,
|
||||||
cheats_server: `Serveur`,
|
cheats_server: `Serveur`,
|
||||||
cheats_skipTutorial: `Passer le tutoriel`,
|
cheats_skipTutorial: `Passer le tutoriel`,
|
||||||
@ -128,6 +134,7 @@ dict = {
|
|||||||
cheats_infiniteEndo: `Endo infini`,
|
cheats_infiniteEndo: `Endo infini`,
|
||||||
cheats_infiniteRegalAya: `Aya Raffiné infini`,
|
cheats_infiniteRegalAya: `Aya Raffiné infini`,
|
||||||
cheats_infiniteHelminthMaterials: `Ressources d'Helminth infinies`,
|
cheats_infiniteHelminthMaterials: `Ressources d'Helminth infinies`,
|
||||||
|
cheats_dontSubtractConsumables: `[UNTRANSLATED] Don't Subtract Consumables`,
|
||||||
cheats_unlockAllShipFeatures: `Débloquer tous les segments du vaisseau`,
|
cheats_unlockAllShipFeatures: `Débloquer tous les segments du vaisseau`,
|
||||||
cheats_unlockAllShipDecorations: `Débloquer toutes les décorations du vaisseau`,
|
cheats_unlockAllShipDecorations: `Débloquer toutes les décorations du vaisseau`,
|
||||||
cheats_unlockAllFlavourItems: `Débloquer tous les <abbr title=\"Animations, Glyphes, Palettes, etc.\">Flavor Items</abbr>`,
|
cheats_unlockAllFlavourItems: `Débloquer tous les <abbr title=\"Animations, Glyphes, Palettes, etc.\">Flavor Items</abbr>`,
|
||||||
@ -147,6 +154,7 @@ dict = {
|
|||||||
cheats_noKimCooldowns: `Aucun cooldown sur le KIM`,
|
cheats_noKimCooldowns: `Aucun cooldown sur le KIM`,
|
||||||
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_noDojoRoomBuildStage: `Aucune attente (construction des salles)`,
|
cheats_noDojoRoomBuildStage: `Aucune attente (construction des salles)`,
|
||||||
cheats_noDojoDecoBuildStage: `Aucune attente (construction des décorations)`,
|
cheats_noDojoDecoBuildStage: `Aucune attente (construction des décorations)`,
|
||||||
cheats_fastDojoRoomDestruction: `Destruction de salle instantanée (Dojo)`,
|
cheats_fastDojoRoomDestruction: `Destruction de salle instantanée (Dojo)`,
|
||||||
|
@ -34,6 +34,8 @@ dict = {
|
|||||||
code_rerollsNumber: `Количество циклов`,
|
code_rerollsNumber: `Количество циклов`,
|
||||||
code_viewStats: `Просмотр характеристики`,
|
code_viewStats: `Просмотр характеристики`,
|
||||||
code_rank: `Ранг`,
|
code_rank: `Ранг`,
|
||||||
|
code_rankUp: `Повысить Ранг`,
|
||||||
|
code_rankDown: `Понизить Ранг`,
|
||||||
code_count: `Количество`,
|
code_count: `Количество`,
|
||||||
code_focusAllUnlocked: `Все школы фокуса уже разблокированы.`,
|
code_focusAllUnlocked: `Все школы фокуса уже разблокированы.`,
|
||||||
code_focusUnlocked: `Разблокировано |COUNT| новых школ фокуса! Для отображения изменений в игре потребуется обновление инвентаря. Посещение навигации — самый простой способ этого добиться.`,
|
code_focusUnlocked: `Разблокировано |COUNT| новых школ фокуса! Для отображения изменений в игре потребуется обновление инвентаря. Посещение навигации — самый простой способ этого добиться.`,
|
||||||
@ -84,18 +86,21 @@ dict = {
|
|||||||
inventory_hoverboards: `К-Драйвы`,
|
inventory_hoverboards: `К-Драйвы`,
|
||||||
inventory_moaPets: `МОА`,
|
inventory_moaPets: `МОА`,
|
||||||
inventory_kubrowPets: `Звери`,
|
inventory_kubrowPets: `Звери`,
|
||||||
|
inventory_evolutionProgress: `Прогресс эволюции Инкарнонов`,
|
||||||
inventory_bulkAddSuits: `Добавить отсутствующие варфреймы`,
|
inventory_bulkAddSuits: `Добавить отсутствующие варфреймы`,
|
||||||
inventory_bulkAddWeapons: `Добавить отсутствующее оружие`,
|
inventory_bulkAddWeapons: `Добавить отсутствующее оружие`,
|
||||||
inventory_bulkAddSpaceSuits: `Добавить отсутствующие арчвинги`,
|
inventory_bulkAddSpaceSuits: `Добавить отсутствующие арчвинги`,
|
||||||
inventory_bulkAddSpaceWeapons: `Добавить отсутствующее оружие арчвингов`,
|
inventory_bulkAddSpaceWeapons: `Добавить отсутствующее оружие арчвингов`,
|
||||||
inventory_bulkAddSentinels: `Добавить отсутствующих стражей`,
|
inventory_bulkAddSentinels: `Добавить отсутствующих стражей`,
|
||||||
inventory_bulkAddSentinelWeapons: `Добавить отсутствующее оружие стражей`,
|
inventory_bulkAddSentinelWeapons: `Добавить отсутствующее оружие стражей`,
|
||||||
|
inventory_bulkAddEvolutionProgress: `Добавить отсуствующий прогресс эволюции Инкарнонов`,
|
||||||
inventory_bulkRankUpSuits: `Максимальный ранг всех варфреймов`,
|
inventory_bulkRankUpSuits: `Максимальный ранг всех варфреймов`,
|
||||||
inventory_bulkRankUpWeapons: `Максимальный ранг всего оружия`,
|
inventory_bulkRankUpWeapons: `Максимальный ранг всего оружия`,
|
||||||
inventory_bulkRankUpSpaceSuits: `Максимальный ранг всех арчвингов`,
|
inventory_bulkRankUpSpaceSuits: `Максимальный ранг всех арчвингов`,
|
||||||
inventory_bulkRankUpSpaceWeapons: `Максимальный ранг всего оружия арчвингов`,
|
inventory_bulkRankUpSpaceWeapons: `Максимальный ранг всего оружия арчвингов`,
|
||||||
inventory_bulkRankUpSentinels: `Максимальный ранг всех стражей`,
|
inventory_bulkRankUpSentinels: `Максимальный ранг всех стражей`,
|
||||||
inventory_bulkRankUpSentinelWeapons: `Максимальный ранг всего оружия стражей`,
|
inventory_bulkRankUpSentinelWeapons: `Максимальный ранг всего оружия стражей`,
|
||||||
|
inventory_bulkRankUpEvolutionProgress: `Максимальный ранг всех эволюций Инкарнонов`,
|
||||||
|
|
||||||
quests_list: `Квесты`,
|
quests_list: `Квесты`,
|
||||||
quests_completeAll: `Завершить все квесты`,
|
quests_completeAll: `Завершить все квесты`,
|
||||||
@ -115,8 +120,9 @@ dict = {
|
|||||||
mods_fingerprintHelp: `Нужна помощь с отпечатком?`,
|
mods_fingerprintHelp: `Нужна помощь с отпечатком?`,
|
||||||
mods_rivens: `Моды Разлома`,
|
mods_rivens: `Моды Разлома`,
|
||||||
mods_mods: `Моды`,
|
mods_mods: `Моды`,
|
||||||
mods_bulkAddMods: `Добавить отсутствующие моды`,
|
mods_addMissingUnrankedMods: `[UNTRANSLATED] Add Missing Unranked Mods`,
|
||||||
mods_removeUnranked: `[UNTRANSLATED] Remove Unranked Mods`,
|
mods_removeUnranked: `[UNTRANSLATED] Remove Unranked Mods`,
|
||||||
|
mods_addMissingMaxRankMods: `[UNTRANSLATED] Add Missing Max Rank Mods`,
|
||||||
cheats_administratorRequirement: `Вы должны быть администратором для использования этой функции. Чтобы стать администратором, добавьте <code>\"|DISPLAYNAME|\"</code> в <code>administratorNames</code> в config.json.`,
|
cheats_administratorRequirement: `Вы должны быть администратором для использования этой функции. Чтобы стать администратором, добавьте <code>\"|DISPLAYNAME|\"</code> в <code>administratorNames</code> в config.json.`,
|
||||||
cheats_server: `Сервер`,
|
cheats_server: `Сервер`,
|
||||||
cheats_skipTutorial: `Пропустить обучение`,
|
cheats_skipTutorial: `Пропустить обучение`,
|
||||||
@ -128,6 +134,7 @@ dict = {
|
|||||||
cheats_infiniteEndo: `Бесконечное эндо`,
|
cheats_infiniteEndo: `Бесконечное эндо`,
|
||||||
cheats_infiniteRegalAya: `Бесконечная Королевская Айя`,
|
cheats_infiniteRegalAya: `Бесконечная Королевская Айя`,
|
||||||
cheats_infiniteHelminthMaterials: `Бесконечные Выделения Гельминта`,
|
cheats_infiniteHelminthMaterials: `Бесконечные Выделения Гельминта`,
|
||||||
|
cheats_dontSubtractConsumables: `[UNTRANSLATED] Don't Subtract Consumables`,
|
||||||
cheats_unlockAllShipFeatures: `Разблокировать все функции корабля`,
|
cheats_unlockAllShipFeatures: `Разблокировать все функции корабля`,
|
||||||
cheats_unlockAllShipDecorations: `Разблокировать все украшения корабля`,
|
cheats_unlockAllShipDecorations: `Разблокировать все украшения корабля`,
|
||||||
cheats_unlockAllFlavourItems: `Разблокировать все <abbr title=\"Наборы анимаций, глифы, палитры и т. д.\">уникальные предметы</abbr>`,
|
cheats_unlockAllFlavourItems: `Разблокировать все <abbr title=\"Наборы анимаций, глифы, палитры и т. д.\">уникальные предметы</abbr>`,
|
||||||
@ -147,6 +154,7 @@ dict = {
|
|||||||
cheats_noKimCooldowns: `Чаты KIM без кулдауна`,
|
cheats_noKimCooldowns: `Чаты KIM без кулдауна`,
|
||||||
cheats_instantResourceExtractorDrones: `Мгновенные Экстракторы Ресурсов`,
|
cheats_instantResourceExtractorDrones: `Мгновенные Экстракторы Ресурсов`,
|
||||||
cheats_noResourceExtractorDronesDamage: `Без урона по дронам-сборщикам`,
|
cheats_noResourceExtractorDronesDamage: `Без урона по дронам-сборщикам`,
|
||||||
|
cheats_skipClanKeyCrafting: `[UNTRANSLATED] Skip Clan Key Crafting`,
|
||||||
cheats_noDojoRoomBuildStage: `Мгновенное Строительтво Комнат Додзё`,
|
cheats_noDojoRoomBuildStage: `Мгновенное Строительтво Комнат Додзё`,
|
||||||
cheats_noDojoDecoBuildStage: `Мгновенное Строительтво Декораций Додзё`,
|
cheats_noDojoDecoBuildStage: `Мгновенное Строительтво Декораций Додзё`,
|
||||||
cheats_fastDojoRoomDestruction: `Мгновенные Уничтожение Комнат Додзё`,
|
cheats_fastDojoRoomDestruction: `Мгновенные Уничтожение Комнат Додзё`,
|
||||||
|
@ -34,6 +34,8 @@ dict = {
|
|||||||
code_rerollsNumber: `洗卡次数`,
|
code_rerollsNumber: `洗卡次数`,
|
||||||
code_viewStats: `查看属性`,
|
code_viewStats: `查看属性`,
|
||||||
code_rank: `等级`,
|
code_rank: `等级`,
|
||||||
|
code_rankUp: `[UNTRANSLATED] Rank up`,
|
||||||
|
code_rankDown: `[UNTRANSLATED] Rank down`,
|
||||||
code_count: `数量`,
|
code_count: `数量`,
|
||||||
code_focusAllUnlocked: `所有专精学派均已解锁。`,
|
code_focusAllUnlocked: `所有专精学派均已解锁。`,
|
||||||
code_focusUnlocked: `已解锁 |COUNT| 个新专精学派!需要游戏内仓库更新才能生效,您可以通过访问星图来触发仓库更新。`,
|
code_focusUnlocked: `已解锁 |COUNT| 个新专精学派!需要游戏内仓库更新才能生效,您可以通过访问星图来触发仓库更新。`,
|
||||||
@ -84,18 +86,21 @@ dict = {
|
|||||||
inventory_hoverboards: `K式悬浮板`,
|
inventory_hoverboards: `K式悬浮板`,
|
||||||
inventory_moaPets: `恐鸟`,
|
inventory_moaPets: `恐鸟`,
|
||||||
inventory_kubrowPets: `[UNTRANSLATED] Beasts`,
|
inventory_kubrowPets: `[UNTRANSLATED] Beasts`,
|
||||||
|
inventory_evolutionProgress: `[UNTRANSLATED] Incarnon Evolution Progress`,
|
||||||
inventory_bulkAddSuits: `添加缺失战甲`,
|
inventory_bulkAddSuits: `添加缺失战甲`,
|
||||||
inventory_bulkAddWeapons: `添加缺失武器`,
|
inventory_bulkAddWeapons: `添加缺失武器`,
|
||||||
inventory_bulkAddSpaceSuits: `添加缺失Archwing`,
|
inventory_bulkAddSpaceSuits: `添加缺失Archwing`,
|
||||||
inventory_bulkAddSpaceWeapons: `添加缺失Archwing武器`,
|
inventory_bulkAddSpaceWeapons: `添加缺失Archwing武器`,
|
||||||
inventory_bulkAddSentinels: `添加缺失守护`,
|
inventory_bulkAddSentinels: `添加缺失守护`,
|
||||||
inventory_bulkAddSentinelWeapons: `添加缺失守护武器`,
|
inventory_bulkAddSentinelWeapons: `添加缺失守护武器`,
|
||||||
|
inventory_bulkAddEvolutionProgress: `[UNTRANSLATED] Add Missing Incarnon Evolution Progress`,
|
||||||
inventory_bulkRankUpSuits: `所有战甲升满级`,
|
inventory_bulkRankUpSuits: `所有战甲升满级`,
|
||||||
inventory_bulkRankUpWeapons: `所有武器升满级`,
|
inventory_bulkRankUpWeapons: `所有武器升满级`,
|
||||||
inventory_bulkRankUpSpaceSuits: `所有Archwing升满级`,
|
inventory_bulkRankUpSpaceSuits: `所有Archwing升满级`,
|
||||||
inventory_bulkRankUpSpaceWeapons: `所有Archwing武器升满级`,
|
inventory_bulkRankUpSpaceWeapons: `所有Archwing武器升满级`,
|
||||||
inventory_bulkRankUpSentinels: `所有守护升满级`,
|
inventory_bulkRankUpSentinels: `所有守护升满级`,
|
||||||
inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`,
|
inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`,
|
||||||
|
inventory_bulkRankUpEvolutionProgress: `[UNTRANSLATED] Max Rank All Incarnon Evolution Progress`,
|
||||||
|
|
||||||
quests_list: `任务`,
|
quests_list: `任务`,
|
||||||
quests_completeAll: `完成所有任务`,
|
quests_completeAll: `完成所有任务`,
|
||||||
@ -115,8 +120,9 @@ dict = {
|
|||||||
mods_fingerprintHelp: `需要印记相关的帮助?`,
|
mods_fingerprintHelp: `需要印记相关的帮助?`,
|
||||||
mods_rivens: `裂罅MOD`,
|
mods_rivens: `裂罅MOD`,
|
||||||
mods_mods: `Mods`,
|
mods_mods: `Mods`,
|
||||||
mods_bulkAddMods: `添加缺失MOD`,
|
mods_addMissingUnrankedMods: `[UNTRANSLATED] Add Missing Unranked Mods`,
|
||||||
mods_removeUnranked: `[UNTRANSLATED] Remove Unranked Mods`,
|
mods_removeUnranked: `[UNTRANSLATED] Remove Unranked Mods`,
|
||||||
|
mods_addMissingMaxRankMods: `[UNTRANSLATED] Add Missing Max Rank Mods`,
|
||||||
cheats_administratorRequirement: `您必须是管理员才能使用此功能。要成为管理员,请将 <code>|DISPLAYNAME|</code> 添加到 config.json 的 <code>administratorNames</code> 中。`,
|
cheats_administratorRequirement: `您必须是管理员才能使用此功能。要成为管理员,请将 <code>|DISPLAYNAME|</code> 添加到 config.json 的 <code>administratorNames</code> 中。`,
|
||||||
cheats_server: `服务器`,
|
cheats_server: `服务器`,
|
||||||
cheats_skipTutorial: `跳过教程`,
|
cheats_skipTutorial: `跳过教程`,
|
||||||
@ -128,6 +134,7 @@ dict = {
|
|||||||
cheats_infiniteEndo: `无限内融核心`,
|
cheats_infiniteEndo: `无限内融核心`,
|
||||||
cheats_infiniteRegalAya: `无限御品阿耶`,
|
cheats_infiniteRegalAya: `无限御品阿耶`,
|
||||||
cheats_infiniteHelminthMaterials: `无限Helminth材料`,
|
cheats_infiniteHelminthMaterials: `无限Helminth材料`,
|
||||||
|
cheats_dontSubtractConsumables: `[UNTRANSLATED] Don't Subtract Consumables`,
|
||||||
cheats_unlockAllShipFeatures: `解锁所有飞船功能`,
|
cheats_unlockAllShipFeatures: `解锁所有飞船功能`,
|
||||||
cheats_unlockAllShipDecorations: `解锁所有飞船装饰`,
|
cheats_unlockAllShipDecorations: `解锁所有飞船装饰`,
|
||||||
cheats_unlockAllFlavourItems: `解锁所有<abbr title=\"动画组合、图标、调色板等\">装饰物品</abbr>`,
|
cheats_unlockAllFlavourItems: `解锁所有<abbr title=\"动画组合、图标、调色板等\">装饰物品</abbr>`,
|
||||||
@ -147,6 +154,7 @@ dict = {
|
|||||||
cheats_noKimCooldowns: `[UNTRANSLATED] No KIM Cooldowns`,
|
cheats_noKimCooldowns: `[UNTRANSLATED] No KIM Cooldowns`,
|
||||||
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_noDojoRoomBuildStage: `无视道场房间建造阶段`,
|
cheats_noDojoRoomBuildStage: `无视道场房间建造阶段`,
|
||||||
cheats_noDojoDecoBuildStage: `[UNTRANSLATED] No Dojo Deco Build Stage`,
|
cheats_noDojoDecoBuildStage: `[UNTRANSLATED] No Dojo Deco Build Stage`,
|
||||||
cheats_fastDojoRoomDestruction: `快速拆除道场房间`,
|
cheats_fastDojoRoomDestruction: `快速拆除道场房间`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user