forked from OpenWF/SpaceNinjaServer
Compare commits
14 Commits
8b0ba0b84a
...
218df461e1
Author | SHA1 | Date | |
---|---|---|---|
218df461e1 | |||
86d871537b | |||
11f2ffe64d | |||
8fd7152c41 | |||
0f3d9f6c2c | |||
c2a633b549 | |||
7040d422a2 | |||
ba1380ec4c | |||
26f37f58e5 | |||
e59bdcdfbc | |||
c1ca303310 | |||
8afb515231 | |||
5eecf11b1a | |||
37ac10acd2 |
28
src/controllers/api/crewMembersController.ts
Normal file
28
src/controllers/api/crewMembersController.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { ICrewMemberClient } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
|
export const crewMembersController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId, "CrewMembers");
|
||||||
|
const data = getJSONfromString<ICrewMembersRequest>(String(req.body));
|
||||||
|
const dbCrewMember = inventory.CrewMembers.id(data.crewMember.ItemId.$oid)!;
|
||||||
|
dbCrewMember.AssignedRole = data.crewMember.AssignedRole;
|
||||||
|
dbCrewMember.SkillEfficiency = data.crewMember.SkillEfficiency;
|
||||||
|
dbCrewMember.WeaponConfigIdx = data.crewMember.WeaponConfigIdx;
|
||||||
|
dbCrewMember.WeaponId = new Types.ObjectId(data.crewMember.WeaponId.$oid);
|
||||||
|
dbCrewMember.Configs = data.crewMember.Configs;
|
||||||
|
dbCrewMember.SecondInCommand = data.crewMember.SecondInCommand;
|
||||||
|
await inventory.save();
|
||||||
|
res.json({
|
||||||
|
crewMemberId: data.crewMember.ItemId.$oid,
|
||||||
|
NemesisFingerprint: data.crewMember.NemesisFingerprint
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ICrewMembersRequest {
|
||||||
|
crewMember: ICrewMemberClient;
|
||||||
|
}
|
@ -12,6 +12,7 @@ import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { getRandomInt } from "@/src/services/rngService";
|
import { getRandomInt } from "@/src/services/rngService";
|
||||||
import { IFingerprintStat } from "@/src/helpers/rivenHelper";
|
import { IFingerprintStat } from "@/src/helpers/rivenHelper";
|
||||||
|
import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
|
|
||||||
export const crewShipIdentifySalvageController: RequestHandler = async (req, res) => {
|
export const crewShipIdentifySalvageController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -42,22 +43,33 @@ export const crewShipIdentifySalvageController: RequestHandler = async (req, res
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const meta = ExportRailjackWeapons[payload.ItemType];
|
const meta = ExportRailjackWeapons[payload.ItemType];
|
||||||
const upgradeType = meta.defaultUpgrades![0].ItemType;
|
let defaultOverwrites: Partial<IEquipmentDatabase> | undefined;
|
||||||
const upgradeMeta = ExportUpgrades[upgradeType];
|
if (meta.defaultUpgrades?.[0]) {
|
||||||
const buffs: IFingerprintStat[] = [];
|
const upgradeType = meta.defaultUpgrades[0].ItemType;
|
||||||
for (const buff of upgradeMeta.upgradeEntries!) {
|
const upgradeMeta = ExportUpgrades[upgradeType];
|
||||||
buffs.push({
|
const buffs: IFingerprintStat[] = [];
|
||||||
Tag: buff.tag,
|
for (const buff of upgradeMeta.upgradeEntries!) {
|
||||||
Value: Math.trunc(Math.random() * 0x40000000)
|
buffs.push({
|
||||||
});
|
Tag: buff.tag,
|
||||||
|
Value: Math.trunc(Math.random() * 0x40000000)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
defaultOverwrites = {
|
||||||
|
UpgradeType: upgradeType,
|
||||||
|
UpgradeFingerprint: JSON.stringify({
|
||||||
|
compat: payload.ItemType,
|
||||||
|
buffs
|
||||||
|
} satisfies IInnateDamageFingerprint)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
addEquipment(inventory, "CrewShipSalvagedWeapons", payload.ItemType, undefined, inventoryChanges, {
|
addEquipment(
|
||||||
UpgradeType: upgradeType,
|
inventory,
|
||||||
UpgradeFingerprint: JSON.stringify({
|
"CrewShipSalvagedWeapons",
|
||||||
compat: payload.ItemType,
|
payload.ItemType,
|
||||||
buffs
|
undefined,
|
||||||
} satisfies IInnateDamageFingerprint)
|
inventoryChanges,
|
||||||
});
|
defaultOverwrites
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
inventoryChanges.CrewShipRawSalvage = [
|
inventoryChanges.CrewShipRawSalvage = [
|
||||||
|
@ -360,6 +360,22 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
res.json({
|
res.json({
|
||||||
inventoryChanges: inventoryChanges
|
inventoryChanges: inventoryChanges
|
||||||
});
|
});
|
||||||
|
} else if (data.Action == "InstantFinish") {
|
||||||
|
if (data.TechProductCategory != "CrewShipWeapons" && data.TechProductCategory != "CrewShipWeaponSkins") {
|
||||||
|
throw new Error(`unexpected TechProductCategory: ${data.TechProductCategory}`);
|
||||||
|
}
|
||||||
|
const inventoryChanges = finishComponentRepair(inventory, data.TechProductCategory, data.CategoryItemId!);
|
||||||
|
inventoryChanges.MiscItems = [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/InstantSalvageRepairItem",
|
||||||
|
ItemCount: -1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
addMiscItems(inventory, inventoryChanges.MiscItems);
|
||||||
|
await inventory.save();
|
||||||
|
res.json({
|
||||||
|
inventoryChanges: inventoryChanges
|
||||||
|
});
|
||||||
} 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(`unhandled guildTech request`);
|
throw new Error(`unhandled guildTech request`);
|
||||||
@ -372,7 +388,7 @@ type TGuildTechRequest =
|
|||||||
| IGuildTechContributeRequest;
|
| IGuildTechContributeRequest;
|
||||||
|
|
||||||
interface IGuildTechBasicRequest {
|
interface IGuildTechBasicRequest {
|
||||||
Action: "Start" | "Fabricate" | "Pause" | "Unpause" | "Cancel" | "Rush";
|
Action: "Start" | "Fabricate" | "Pause" | "Unpause" | "Cancel" | "Rush" | "InstantFinish";
|
||||||
Mode: "Guild" | "Personal";
|
Mode: "Guild" | "Personal";
|
||||||
RecipeType: string;
|
RecipeType: string;
|
||||||
TechProductCategory?: string;
|
TechProductCategory?: string;
|
||||||
@ -406,11 +422,19 @@ const claimSalvagedComponent = (inventory: TInventoryDatabaseDocument, itemId: s
|
|||||||
inventory.PersonalTechProjects.splice(personalTechProjectIndex, 1);
|
inventory.PersonalTechProjects.splice(personalTechProjectIndex, 1);
|
||||||
|
|
||||||
const category = personalTechProject.ProductCategory! as "CrewShipWeapons" | "CrewShipWeaponSkins";
|
const category = personalTechProject.ProductCategory! as "CrewShipWeapons" | "CrewShipWeaponSkins";
|
||||||
|
return finishComponentRepair(inventory, category, itemId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const finishComponentRepair = (
|
||||||
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
category: "CrewShipWeapons" | "CrewShipWeaponSkins",
|
||||||
|
itemId: string
|
||||||
|
): IInventoryChanges => {
|
||||||
const salvageCategory = getSalvageCategory(category);
|
const salvageCategory = getSalvageCategory(category);
|
||||||
|
|
||||||
// find salved part & delete it
|
// find salved part & delete it
|
||||||
const salvageIndex = inventory[salvageCategory].findIndex(x => x._id.equals(itemId));
|
const salvageIndex = inventory[salvageCategory].findIndex(x => x._id.equals(itemId));
|
||||||
const salvageItem = inventory[category][salvageIndex];
|
const salvageItem = inventory[salvageCategory][salvageIndex];
|
||||||
inventory[salvageCategory].splice(salvageIndex, 1);
|
inventory[salvageCategory].splice(salvageIndex, 1);
|
||||||
|
|
||||||
// add final item
|
// add final item
|
||||||
|
@ -94,7 +94,8 @@ import {
|
|||||||
ICrewMemberClient,
|
ICrewMemberClient,
|
||||||
ISortieRewardAttenuation,
|
ISortieRewardAttenuation,
|
||||||
IInvasionProgressDatabase,
|
IInvasionProgressDatabase,
|
||||||
IInvasionProgressClient
|
IInvasionProgressClient,
|
||||||
|
IAccolades
|
||||||
} from "../../types/inventoryTypes/inventoryTypes";
|
} from "../../types/inventoryTypes/inventoryTypes";
|
||||||
import { IOid } from "../../types/commonTypes";
|
import { IOid } from "../../types/commonTypes";
|
||||||
import {
|
import {
|
||||||
@ -1059,6 +1060,13 @@ pendingRecipeSchema.set("toJSON", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const accoladesSchema = new Schema<IAccolades>(
|
||||||
|
{
|
||||||
|
Heirloom: Boolean
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
||||||
|
|
||||||
const infestedFoundrySchema = new Schema<IInfestedFoundryDatabase>(
|
const infestedFoundrySchema = new Schema<IInfestedFoundryDatabase>(
|
||||||
{
|
{
|
||||||
Name: String,
|
Name: String,
|
||||||
@ -1466,6 +1474,16 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
//Mastery Rank next availability
|
//Mastery Rank next availability
|
||||||
TrainingDate: { type: Date, default: new Date(0) },
|
TrainingDate: { type: Date, default: new Date(0) },
|
||||||
|
|
||||||
|
//Accolades
|
||||||
|
Staff: Boolean,
|
||||||
|
Founder: Number,
|
||||||
|
Guide: Number,
|
||||||
|
Moderator: Boolean,
|
||||||
|
Partner: Boolean,
|
||||||
|
Accolades: accoladesSchema,
|
||||||
|
//Not an accolade but unlocks an extra chat
|
||||||
|
Counselor: Boolean,
|
||||||
|
|
||||||
//you saw last played Region when you opened the star map
|
//you saw last played Region when you opened the star map
|
||||||
LastRegionPlayed: String,
|
LastRegionPlayed: String,
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import { contributeToVaultController } from "@/src/controllers/api/contributeToV
|
|||||||
import { createAllianceController } from "@/src/controllers/api/createAllianceController";
|
import { createAllianceController } from "@/src/controllers/api/createAllianceController";
|
||||||
import { createGuildController } from "@/src/controllers/api/createGuildController";
|
import { createGuildController } from "@/src/controllers/api/createGuildController";
|
||||||
import { creditsController } from "@/src/controllers/api/creditsController";
|
import { creditsController } from "@/src/controllers/api/creditsController";
|
||||||
|
import { crewMembersController } from "@/src/controllers/api/crewMembersController";
|
||||||
import { crewShipIdentifySalvageController } from "@/src/controllers/api/crewShipIdentifySalvageController";
|
import { crewShipIdentifySalvageController } from "@/src/controllers/api/crewShipIdentifySalvageController";
|
||||||
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
|
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
|
||||||
import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
|
import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
|
||||||
@ -222,6 +223,7 @@ apiRouter.post("/contributeToDojoComponent.php", contributeToDojoComponentContro
|
|||||||
apiRouter.post("/contributeToVault.php", contributeToVaultController);
|
apiRouter.post("/contributeToVault.php", contributeToVaultController);
|
||||||
apiRouter.post("/createAlliance.php", createAllianceController);
|
apiRouter.post("/createAlliance.php", createAllianceController);
|
||||||
apiRouter.post("/createGuild.php", createGuildController);
|
apiRouter.post("/createGuild.php", createGuildController);
|
||||||
|
apiRouter.post("/crewMembers.php", crewMembersController);
|
||||||
apiRouter.post("/crewShipIdentifySalvage.php", crewShipIdentifySalvageController);
|
apiRouter.post("/crewShipIdentifySalvage.php", crewShipIdentifySalvageController);
|
||||||
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
|
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
|
||||||
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
|
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
|
||||||
|
@ -230,17 +230,23 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
replaceSlots(db[key], client[key]);
|
replaceSlots(db[key], client[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// boolean
|
||||||
for (const key of [
|
for (const key of [
|
||||||
"UseAdultOperatorLoadout",
|
"UseAdultOperatorLoadout",
|
||||||
"HasOwnedVoidProjectionsPreviously",
|
"HasOwnedVoidProjectionsPreviously",
|
||||||
"ReceivedStartingGear",
|
"ReceivedStartingGear",
|
||||||
"ArchwingEnabled",
|
"ArchwingEnabled",
|
||||||
"PlayedParkourTutorial"
|
"PlayedParkourTutorial",
|
||||||
|
"Staff",
|
||||||
|
"Moderator",
|
||||||
|
"Partner",
|
||||||
|
"Counselor"
|
||||||
] as const) {
|
] as const) {
|
||||||
if (client[key] !== undefined) {
|
if (client[key] !== undefined) {
|
||||||
db[key] = client[key];
|
db[key] = client[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// number
|
||||||
for (const key of [
|
for (const key of [
|
||||||
"PlayerLevel",
|
"PlayerLevel",
|
||||||
"RegularCredits",
|
"RegularCredits",
|
||||||
@ -250,12 +256,15 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
"PrimeTokens",
|
"PrimeTokens",
|
||||||
"TradesRemaining",
|
"TradesRemaining",
|
||||||
"GiftsRemaining",
|
"GiftsRemaining",
|
||||||
"ChallengesFixVersion"
|
"ChallengesFixVersion",
|
||||||
|
"Founder",
|
||||||
|
"Guide"
|
||||||
] as const) {
|
] as const) {
|
||||||
if (client[key] !== undefined) {
|
if (client[key] !== undefined) {
|
||||||
db[key] = client[key];
|
db[key] = client[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// string
|
||||||
for (const key of [
|
for (const key of [
|
||||||
"ThemeStyle",
|
"ThemeStyle",
|
||||||
"ThemeBackground",
|
"ThemeBackground",
|
||||||
@ -270,6 +279,7 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
db[key] = client[key];
|
db[key] = client[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// string[]
|
||||||
for (const key of [
|
for (const key of [
|
||||||
"EquippedGear",
|
"EquippedGear",
|
||||||
"EquippedEmotes",
|
"EquippedEmotes",
|
||||||
@ -380,6 +390,9 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (client.Accolades !== undefined) {
|
||||||
|
db.Accolades = client.Accolades;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const convertLoadOutConfig = (client: ILoadoutConfigClient): ILoadoutConfigDatabase => {
|
const convertLoadOutConfig = (client: ILoadoutConfigClient): ILoadoutConfigDatabase => {
|
||||||
|
@ -53,7 +53,7 @@ import conservationAnimals from "@/static/fixed_responses/conservationAnimals.js
|
|||||||
import { getInfNodes } from "@/src/helpers/nemesisHelpers";
|
import { getInfNodes } 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 { getWorldState } from "./worldStateService";
|
import { getLiteSortie, getWorldState, idToWeek } from "./worldStateService";
|
||||||
import { config } from "./configService";
|
import { config } from "./configService";
|
||||||
|
|
||||||
const getRotations = (rewardInfo: IRewardInfo, tierOverride?: number): number[] => {
|
const getRotations = (rewardInfo: IRewardInfo, tierOverride?: number): number[] => {
|
||||||
@ -71,7 +71,12 @@ const getRotations = (rewardInfo: IRewardInfo, tierOverride?: number): number[]
|
|||||||
return [rewardInfo.rewardTier];
|
return [rewardInfo.rewardTier];
|
||||||
}
|
}
|
||||||
|
|
||||||
const rotationCount = rewardInfo.rewardQualifications?.length || 0;
|
// Aborting a railjack mission should not give any rewards (https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1741)
|
||||||
|
if (rewardInfo.rewardQualifications === undefined) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const rotationCount = rewardInfo.rewardQualifications.length || 0;
|
||||||
if (rotationCount === 0) return [0];
|
if (rotationCount === 0) return [0];
|
||||||
|
|
||||||
const rotationPattern =
|
const rotationPattern =
|
||||||
@ -132,11 +137,13 @@ export const addMissionInventoryUpdates = async (
|
|||||||
// Somewhat heuristically detect G3 capture:
|
// Somewhat heuristically detect G3 capture:
|
||||||
// - https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1365
|
// - https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1365
|
||||||
// - https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1694
|
// - https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1694
|
||||||
|
// - https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1724
|
||||||
if (
|
if (
|
||||||
inventoryUpdates.MissionFailed &&
|
inventoryUpdates.MissionFailed &&
|
||||||
inventoryUpdates.MissionStatus == "GS_FAILURE" &&
|
inventoryUpdates.MissionStatus == "GS_FAILURE" &&
|
||||||
inventoryUpdates.ObjectiveReached &&
|
inventoryUpdates.ObjectiveReached &&
|
||||||
!inventoryUpdates.LockedWeaponGroup &&
|
!inventoryUpdates.LockedWeaponGroup &&
|
||||||
|
!inventory.LockedWeaponGroup &&
|
||||||
!inventoryUpdates.LevelKeyName
|
!inventoryUpdates.LevelKeyName
|
||||||
) {
|
) {
|
||||||
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "NORMAL"))!;
|
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "NORMAL"))!;
|
||||||
@ -988,11 +995,7 @@ function getRandomMissionDrops(
|
|||||||
if (sortieId == "Lite") {
|
if (sortieId == "Lite") {
|
||||||
sortieId = arr[2];
|
sortieId = arr[2];
|
||||||
|
|
||||||
// TODO: Some way to get from sortieId to reward to make this faster + more reliable at week rollover.
|
const boss = getLiteSortie(idToWeek(sortieId)).Boss;
|
||||||
const boss = getWorldState().LiteSorties[0].Boss as
|
|
||||||
| "SORTIE_BOSS_AMAR"
|
|
||||||
| "SORTIE_BOSS_NIRA"
|
|
||||||
| "SORTIE_BOSS_BOREAL";
|
|
||||||
let crystalType = {
|
let crystalType = {
|
||||||
SORTIE_BOSS_AMAR: "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalAmar",
|
SORTIE_BOSS_AMAR: "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalAmar",
|
||||||
SORTIE_BOSS_NIRA: "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalNira",
|
SORTIE_BOSS_NIRA: "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalNira",
|
||||||
|
@ -216,6 +216,27 @@ const handleQuestCompletion = async (
|
|||||||
setupKahlSyndicate(inventory);
|
setupKahlSyndicate(inventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Whispers in the Walls is unlocked once The New + Heart of Deimos are completed.
|
||||||
|
if (
|
||||||
|
(questKey == "/Lotus/Types/Keys/NewWarQuest/NewWarQuestKeyChain" &&
|
||||||
|
inventory.QuestKeys.find(
|
||||||
|
x => x.ItemType == "/Lotus/Types/Keys/InfestedMicroplanetQuest/InfestedMicroplanetQuestKeyChain"
|
||||||
|
)?.Completed) ||
|
||||||
|
(questKey == "/Lotus/Types/Keys/InfestedMicroplanetQuest/InfestedMicroplanetQuestKeyChain" &&
|
||||||
|
inventory.QuestKeys.find(x => x.ItemType == "/Lotus/Types/Keys/NewWarQuest/NewWarQuestKeyChain")?.Completed)
|
||||||
|
) {
|
||||||
|
await createMessage(inventory.accountOwnerId, [
|
||||||
|
{
|
||||||
|
sndr: "/Lotus/Language/Bosses/Loid",
|
||||||
|
msg: "/Lotus/Language/EntratiLab/EntratiQuest/WiTWQuestRecievedInboxBody",
|
||||||
|
att: ["/Lotus/Types/Keys/EntratiLab/EntratiQuestKeyChain"],
|
||||||
|
sub: "/Lotus/Language/EntratiLab/EntratiQuest/WiTWQuestRecievedInboxTitle",
|
||||||
|
icon: "/Lotus/Interface/Icons/Npcs/Entrati/Loid.png",
|
||||||
|
highPriority: true
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
const questCompletionItems = getQuestCompletionItems(questKey);
|
const questCompletionItems = getQuestCompletionItems(questKey);
|
||||||
logger.debug(`quest completion items`, questCompletionItems);
|
logger.debug(`quest completion items`, questCompletionItems);
|
||||||
if (questCompletionItems) {
|
if (questCompletionItems) {
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import fs from "fs";
|
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
||||||
import path from "path";
|
|
||||||
import { repoDir } from "@/src/helpers/pathHelper";
|
|
||||||
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 {
|
||||||
@ -9,44 +7,68 @@ import {
|
|||||||
IVendorInfo,
|
IVendorInfo,
|
||||||
IVendorManifestPreprocessed
|
IVendorManifestPreprocessed
|
||||||
} from "@/src/types/vendorTypes";
|
} from "@/src/types/vendorTypes";
|
||||||
import { JSONParse } from "json-with-bigint";
|
|
||||||
import { ExportVendors } from "warframe-public-export-plus";
|
import { ExportVendors } from "warframe-public-export-plus";
|
||||||
import { unixTimesInMs } from "../constants/timeConstants";
|
|
||||||
|
|
||||||
const getVendorManifestJson = (name: string): IRawVendorManifest => {
|
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
|
||||||
return JSONParse(fs.readFileSync(path.join(repoDir, `static/fixed_responses/getVendorInfo/${name}.json`), "utf-8"));
|
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 DeimosHivemindCommisionsManifestPetVendor from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestPetVendor.json";
|
||||||
|
import DeimosHivemindCommisionsManifestProspector from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestProspector.json";
|
||||||
|
import DeimosHivemindCommisionsManifestTokenVendor from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestTokenVendor.json";
|
||||||
|
import DeimosHivemindCommisionsManifestWeaponsmith from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestWeaponsmith.json";
|
||||||
|
import DeimosHivemindTokenVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosHivemindTokenVendorManifest.json";
|
||||||
|
import DeimosPetVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosPetVendorManifest.json";
|
||||||
|
import DeimosProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosProspectorVendorManifest.json";
|
||||||
|
import DuviriAcrithisVendorManifest from "@/static/fixed_responses/getVendorInfo/DuviriAcrithisVendorManifest.json";
|
||||||
|
import EntratiLabsEntratiLabsCommisionsManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabsCommisionsManifest.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 HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json";
|
||||||
|
import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.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 OstronProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronProspectorVendorManifest.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 SolarisFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisFishmongerVendorManifest.json";
|
||||||
|
import SolarisProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisProspectorVendorManifest.json";
|
||||||
|
import TeshinHardModeVendorManifest from "@/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json";
|
||||||
|
import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVendorInfo/ZarimanCommisionsManifestArchimedean.json";
|
||||||
|
|
||||||
const rawVendorManifests: IRawVendorManifest[] = [
|
const rawVendorManifests: IRawVendorManifest[] = [
|
||||||
getVendorManifestJson("ArchimedeanVendorManifest"),
|
ArchimedeanVendorManifest,
|
||||||
getVendorManifestJson("DeimosEntratiFragmentVendorProductsManifest"),
|
DeimosEntratiFragmentVendorProductsManifest,
|
||||||
getVendorManifestJson("DeimosFishmongerVendorManifest"),
|
DeimosFishmongerVendorManifest,
|
||||||
getVendorManifestJson("DeimosHivemindCommisionsManifestFishmonger"),
|
DeimosHivemindCommisionsManifestFishmonger,
|
||||||
getVendorManifestJson("DeimosHivemindCommisionsManifestPetVendor"),
|
DeimosHivemindCommisionsManifestPetVendor,
|
||||||
getVendorManifestJson("DeimosHivemindCommisionsManifestProspector"),
|
DeimosHivemindCommisionsManifestProspector,
|
||||||
getVendorManifestJson("DeimosHivemindCommisionsManifestTokenVendor"),
|
DeimosHivemindCommisionsManifestTokenVendor,
|
||||||
getVendorManifestJson("DeimosHivemindCommisionsManifestWeaponsmith"),
|
DeimosHivemindCommisionsManifestWeaponsmith,
|
||||||
getVendorManifestJson("DeimosHivemindTokenVendorManifest"),
|
DeimosHivemindTokenVendorManifest,
|
||||||
getVendorManifestJson("DeimosPetVendorManifest"),
|
DeimosPetVendorManifest,
|
||||||
getVendorManifestJson("DeimosProspectorVendorManifest"),
|
DeimosProspectorVendorManifest,
|
||||||
getVendorManifestJson("DuviriAcrithisVendorManifest"),
|
DuviriAcrithisVendorManifest,
|
||||||
getVendorManifestJson("EntratiLabsEntratiLabsCommisionsManifest"),
|
EntratiLabsEntratiLabsCommisionsManifest,
|
||||||
getVendorManifestJson("EntratiLabsEntratiLabVendorManifest"),
|
EntratiLabsEntratiLabVendorManifest,
|
||||||
getVendorManifestJson("GuildAdvertisementVendorManifest"), // uses preprocessing
|
GuildAdvertisementVendorManifest, // uses preprocessing
|
||||||
getVendorManifestJson("HubsIronwakeDondaVendorManifest"), // uses preprocessing
|
HubsIronwakeDondaVendorManifest, // uses preprocessing
|
||||||
getVendorManifestJson("HubsRailjackCrewMemberVendorManifest"),
|
HubsRailjackCrewMemberVendorManifest,
|
||||||
getVendorManifestJson("MaskSalesmanManifest"),
|
MaskSalesmanManifest,
|
||||||
getVendorManifestJson("Nova1999ConquestShopManifest"),
|
Nova1999ConquestShopManifest,
|
||||||
getVendorManifestJson("OstronFishmongerVendorManifest"),
|
OstronFishmongerVendorManifest,
|
||||||
getVendorManifestJson("OstronPetVendorManifest"),
|
OstronPetVendorManifest,
|
||||||
getVendorManifestJson("OstronProspectorVendorManifest"),
|
OstronProspectorVendorManifest,
|
||||||
getVendorManifestJson("RadioLegionIntermission12VendorManifest"),
|
RadioLegionIntermission12VendorManifest,
|
||||||
getVendorManifestJson("SolarisDebtTokenVendorManifest"),
|
SolarisDebtTokenVendorManifest,
|
||||||
getVendorManifestJson("SolarisDebtTokenVendorRepossessionsManifest"),
|
SolarisDebtTokenVendorRepossessionsManifest,
|
||||||
getVendorManifestJson("SolarisFishmongerVendorManifest"),
|
SolarisFishmongerVendorManifest,
|
||||||
getVendorManifestJson("SolarisProspectorVendorManifest"),
|
SolarisProspectorVendorManifest,
|
||||||
getVendorManifestJson("TeshinHardModeVendorManifest"), // uses preprocessing
|
TeshinHardModeVendorManifest, // uses preprocessing
|
||||||
getVendorManifestJson("ZarimanCommisionsManifestArchimedean")
|
ZarimanCommisionsManifestArchimedean
|
||||||
];
|
];
|
||||||
|
|
||||||
interface IGeneratableVendorInfo extends Omit<IVendorInfo, "ItemManifest" | "Expiry"> {
|
interface IGeneratableVendorInfo extends Omit<IVendorInfo, "ItemManifest" | "Expiry"> {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { Stats, TStatsDatabaseDocument } from "@/src/models/statsModel";
|
import { Stats, TStatsDatabaseDocument } from "@/src/models/statsModel";
|
||||||
import {
|
import {
|
||||||
IEnemy,
|
|
||||||
IStatsAdd,
|
IStatsAdd,
|
||||||
IStatsMax,
|
IStatsMax,
|
||||||
IStatsSet,
|
IStatsSet,
|
||||||
@ -137,34 +136,34 @@ export const updateStats = async (accountOwnerId: string, payload: IStatsUpdate)
|
|||||||
case "HEADSHOT":
|
case "HEADSHOT":
|
||||||
case "KILL_ASSIST": {
|
case "KILL_ASSIST": {
|
||||||
playerStats.Enemies ??= [];
|
playerStats.Enemies ??= [];
|
||||||
const enemyStatKey = {
|
const enemyStatKey = (
|
||||||
KILL_ENEMY: "kills",
|
{
|
||||||
EXECUTE_ENEMY: "executions",
|
KILL_ENEMY: "kills",
|
||||||
HEADSHOT: "headshots",
|
EXECUTE_ENEMY: "executions",
|
||||||
KILL_ASSIST: "assists"
|
HEADSHOT: "headshots",
|
||||||
}[category] as "kills" | "executions" | "headshots" | "assists";
|
KILL_ASSIST: "assists"
|
||||||
|
} as const
|
||||||
|
)[category];
|
||||||
|
|
||||||
for (const [type, count] of Object.entries(data as IUploadEntry)) {
|
for (const [type, count] of Object.entries(data as IUploadEntry)) {
|
||||||
const enemy = playerStats.Enemies.find(element => element.type === type);
|
let enemy = playerStats.Enemies.find(element => element.type === type);
|
||||||
if (enemy) {
|
if (!enemy) {
|
||||||
if (category === "KILL_ENEMY") {
|
enemy = { type: type };
|
||||||
enemy.kills ??= 0;
|
playerStats.Enemies.push(enemy);
|
||||||
const captureCount = (actionData as IStatsAdd)["CAPTURE_ENEMY"]?.[type];
|
}
|
||||||
if (captureCount) {
|
if (category === "KILL_ENEMY") {
|
||||||
enemy.kills += Math.max(count - captureCount, 0);
|
enemy.kills ??= 0;
|
||||||
enemy.captures ??= 0;
|
const captureCount = (actionData as IStatsAdd)["CAPTURE_ENEMY"]?.[type];
|
||||||
enemy.captures += captureCount;
|
if (captureCount) {
|
||||||
} else {
|
enemy.kills += Math.max(count - captureCount, 0);
|
||||||
enemy.kills += count;
|
enemy.captures ??= 0;
|
||||||
}
|
enemy.captures += captureCount;
|
||||||
} else {
|
} else {
|
||||||
enemy[enemyStatKey] ??= 0;
|
enemy.kills += count;
|
||||||
enemy[enemyStatKey] += count;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const newEnemy: IEnemy = { type: type };
|
enemy[enemyStatKey] ??= 0;
|
||||||
newEnemy[enemyStatKey] = count;
|
enemy[enemyStatKey] += count;
|
||||||
playerStats.Enemies.push(newEnemy);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -4,7 +4,14 @@ 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 } from "warframe-public-export-plus";
|
||||||
import { ICalendarDay, ICalendarSeason, ISeasonChallenge, ISortie, IWorldState } from "../types/worldStateTypes";
|
import {
|
||||||
|
ICalendarDay,
|
||||||
|
ICalendarSeason,
|
||||||
|
ILiteSortie,
|
||||||
|
ISeasonChallenge,
|
||||||
|
ISortie,
|
||||||
|
IWorldState
|
||||||
|
} from "../types/worldStateTypes";
|
||||||
|
|
||||||
const sortieBosses = [
|
const sortieBosses = [
|
||||||
"SORTIE_BOSS_HYENA",
|
"SORTIE_BOSS_HYENA",
|
||||||
@ -348,6 +355,34 @@ const getSeasonWeeklyHardChallenge = (week: number, id: number): ISeasonChalleng
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const pushWeeklyActs = (worldState: IWorldState, week: number): void => {
|
||||||
|
const weekStart = EPOCH + week * 604800000;
|
||||||
|
const weekEnd = weekStart + 604800000;
|
||||||
|
|
||||||
|
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyChallenge(week, 0));
|
||||||
|
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyChallenge(week, 1));
|
||||||
|
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyHardChallenge(week, 2));
|
||||||
|
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyHardChallenge(week, 3));
|
||||||
|
worldState.SeasonInfo.ActiveChallenges.push({
|
||||||
|
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 0).toString().padStart(8, "0") },
|
||||||
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
|
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentCompleteMissions" + (week - 12)
|
||||||
|
});
|
||||||
|
worldState.SeasonInfo.ActiveChallenges.push({
|
||||||
|
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 1).toString().padStart(8, "0") },
|
||||||
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
|
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEximus" + (week - 12)
|
||||||
|
});
|
||||||
|
worldState.SeasonInfo.ActiveChallenges.push({
|
||||||
|
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 2).toString().padStart(8, "0") },
|
||||||
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
|
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEnemies" + (week - 12)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const birthdays: number[] = [
|
const birthdays: number[] = [
|
||||||
1, // Kaya
|
1, // Kaya
|
||||||
45, // Lettie
|
45, // Lettie
|
||||||
@ -604,29 +639,10 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
if (isBeforeNextExpectedWorldStateRefresh(EPOCH + (day + 1) * 86400000)) {
|
if (isBeforeNextExpectedWorldStateRefresh(EPOCH + (day + 1) * 86400000)) {
|
||||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(day + 1));
|
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(day + 1));
|
||||||
}
|
}
|
||||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyChallenge(week, 0));
|
pushWeeklyActs(worldState, week);
|
||||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyChallenge(week, 1));
|
if (isBeforeNextExpectedWorldStateRefresh(weekEnd)) {
|
||||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyHardChallenge(week, 2));
|
pushWeeklyActs(worldState, week + 1);
|
||||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyHardChallenge(week, 3));
|
}
|
||||||
worldState.SeasonInfo.ActiveChallenges.push({
|
|
||||||
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 0).toString().padStart(8, "0") },
|
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
|
||||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentCompleteMissions" + (week - 12)
|
|
||||||
});
|
|
||||||
worldState.SeasonInfo.ActiveChallenges.push({
|
|
||||||
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 1).toString().padStart(8, "0") },
|
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
|
||||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEximus" + (week - 12)
|
|
||||||
});
|
|
||||||
worldState.SeasonInfo.ActiveChallenges.push({
|
|
||||||
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 2).toString().padStart(8, "0") },
|
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
|
||||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEnemies" + (week - 12)
|
|
||||||
});
|
|
||||||
// TODO: Provide upcoming weekly acts if rollover is imminent
|
|
||||||
|
|
||||||
// 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 = week; // unfaithful
|
||||||
@ -941,65 +957,9 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
pushSortieIfRelevant(worldState.Sorties, day);
|
pushSortieIfRelevant(worldState.Sorties, day);
|
||||||
|
|
||||||
// Archon Hunt cycling every week
|
// Archon Hunt cycling every week
|
||||||
// TODO: Handle imminent rollover
|
worldState.LiteSorties.push(getLiteSortie(week));
|
||||||
{
|
if (isBeforeNextExpectedWorldStateRefresh(weekEnd)) {
|
||||||
const boss = ["SORTIE_BOSS_AMAR", "SORTIE_BOSS_NIRA", "SORTIE_BOSS_BOREAL"][week % 3];
|
worldState.LiteSorties.push(getLiteSortie(week + 1));
|
||||||
const showdownNode = ["SolNode99", "SolNode53", "SolNode24"][week % 3];
|
|
||||||
const systemIndex = [3, 4, 2][week % 3]; // Mars, Jupiter, Earth
|
|
||||||
|
|
||||||
const nodes: string[] = [];
|
|
||||||
for (const [key, value] of Object.entries(ExportRegions)) {
|
|
||||||
if (
|
|
||||||
value.systemIndex === systemIndex &&
|
|
||||||
value.factionIndex !== undefined &&
|
|
||||||
value.factionIndex < 2 &&
|
|
||||||
value.name.indexOf("Archwing") == -1 &&
|
|
||||||
value.missionIndex != 0 // Exclude MT_ASSASSINATION
|
|
||||||
) {
|
|
||||||
nodes.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const rng = new CRng(week);
|
|
||||||
const firstNodeIndex = rng.randomInt(0, nodes.length - 1);
|
|
||||||
const firstNode = nodes[firstNodeIndex];
|
|
||||||
nodes.splice(firstNodeIndex, 1);
|
|
||||||
worldState.LiteSorties.push({
|
|
||||||
_id: {
|
|
||||||
$oid: Math.trunc(weekStart / 1000).toString(16) + "5e23a244740a190c"
|
|
||||||
},
|
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
|
||||||
Reward: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards",
|
|
||||||
Seed: week,
|
|
||||||
Boss: boss,
|
|
||||||
Missions: [
|
|
||||||
{
|
|
||||||
missionType: rng.randomElement([
|
|
||||||
"MT_INTEL",
|
|
||||||
"MT_MOBILE_DEFENSE",
|
|
||||||
"MT_EXTERMINATION",
|
|
||||||
"MT_SABOTAGE",
|
|
||||||
"MT_RESCUE"
|
|
||||||
]),
|
|
||||||
node: firstNode
|
|
||||||
},
|
|
||||||
{
|
|
||||||
missionType: rng.randomElement([
|
|
||||||
"MT_DEFENSE",
|
|
||||||
"MT_TERRITORY",
|
|
||||||
"MT_ARTIFACT",
|
|
||||||
"MT_EXCAVATE",
|
|
||||||
"MT_SURVIVAL"
|
|
||||||
]),
|
|
||||||
node: rng.randomElement(nodes)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
missionType: "MT_ASSASSINATION",
|
|
||||||
node: showdownNode
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Circuit choices cycling every week
|
// Circuit choices cycling every week
|
||||||
@ -1071,3 +1031,70 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
|
|
||||||
return worldState;
|
return worldState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const idToWeek = (id: string): number => {
|
||||||
|
return (parseInt(id.substring(0, 8), 16) * 1000 - EPOCH) / 604800000;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getLiteSortie = (week: number): ILiteSortie => {
|
||||||
|
const boss = (["SORTIE_BOSS_AMAR", "SORTIE_BOSS_NIRA", "SORTIE_BOSS_BOREAL"] as const)[week % 3];
|
||||||
|
const showdownNode = ["SolNode99", "SolNode53", "SolNode24"][week % 3];
|
||||||
|
const systemIndex = [3, 4, 2][week % 3]; // Mars, Jupiter, Earth
|
||||||
|
|
||||||
|
const nodes: string[] = [];
|
||||||
|
for (const [key, value] of Object.entries(ExportRegions)) {
|
||||||
|
if (
|
||||||
|
value.systemIndex === systemIndex &&
|
||||||
|
value.factionIndex !== undefined &&
|
||||||
|
value.factionIndex < 2 &&
|
||||||
|
value.name.indexOf("Archwing") == -1 &&
|
||||||
|
value.missionIndex != 0 // Exclude MT_ASSASSINATION
|
||||||
|
) {
|
||||||
|
nodes.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const rng = new CRng(week);
|
||||||
|
const firstNodeIndex = rng.randomInt(0, nodes.length - 1);
|
||||||
|
const firstNode = nodes[firstNodeIndex];
|
||||||
|
nodes.splice(firstNodeIndex, 1);
|
||||||
|
|
||||||
|
const weekStart = EPOCH + week * 604800000;
|
||||||
|
const weekEnd = weekStart + 604800000;
|
||||||
|
return {
|
||||||
|
_id: {
|
||||||
|
$oid: Math.trunc(weekStart / 1000).toString(16) + "5e23a244740a190c"
|
||||||
|
},
|
||||||
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
|
Reward: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards",
|
||||||
|
Seed: week,
|
||||||
|
Boss: boss,
|
||||||
|
Missions: [
|
||||||
|
{
|
||||||
|
missionType: rng.randomElement([
|
||||||
|
"MT_INTEL",
|
||||||
|
"MT_MOBILE_DEFENSE",
|
||||||
|
"MT_EXTERMINATION",
|
||||||
|
"MT_SABOTAGE",
|
||||||
|
"MT_RESCUE"
|
||||||
|
]),
|
||||||
|
node: firstNode
|
||||||
|
},
|
||||||
|
{
|
||||||
|
missionType: rng.randomElement([
|
||||||
|
"MT_DEFENSE",
|
||||||
|
"MT_TERRITORY",
|
||||||
|
"MT_ARTIFACT",
|
||||||
|
"MT_EXCAVATE",
|
||||||
|
"MT_SURVIVAL"
|
||||||
|
]),
|
||||||
|
node: rng.randomElement(nodes)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
missionType: "MT_ASSASSINATION",
|
||||||
|
node: showdownNode
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -250,9 +250,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
Guide?: number;
|
Guide?: number;
|
||||||
Moderator?: boolean;
|
Moderator?: boolean;
|
||||||
Partner?: boolean;
|
Partner?: boolean;
|
||||||
Accolades?: {
|
Accolades?: IAccolades;
|
||||||
Heirloom?: boolean;
|
|
||||||
};
|
|
||||||
Counselor?: boolean;
|
Counselor?: boolean;
|
||||||
Upgrades: IUpgradeClient[];
|
Upgrades: IUpgradeClient[];
|
||||||
EquippedGear: string[];
|
EquippedGear: string[];
|
||||||
@ -489,7 +487,7 @@ export interface ICrewMemberClient {
|
|||||||
XP: number;
|
XP: number;
|
||||||
PowersuitType: string;
|
PowersuitType: string;
|
||||||
Configs: IItemConfig[];
|
Configs: IItemConfig[];
|
||||||
SecondInCommand: boolean;
|
SecondInCommand: boolean; // on call
|
||||||
ItemId: IOid;
|
ItemId: IOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -914,6 +912,10 @@ export interface IPendingRecipeClient
|
|||||||
CompletionDate: IMongoDate;
|
CompletionDate: IMongoDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IAccolades {
|
||||||
|
Heirloom?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IPendingTrade {
|
export interface IPendingTrade {
|
||||||
State: number;
|
State: number;
|
||||||
SelfReady: boolean;
|
SelfReady: boolean;
|
||||||
|
@ -32,7 +32,7 @@ export interface IVendorInfo {
|
|||||||
TypeName: string;
|
TypeName: string;
|
||||||
ItemManifest: IItemManifest[];
|
ItemManifest: IItemManifest[];
|
||||||
PropertyTextHash?: string;
|
PropertyTextHash?: string;
|
||||||
RandomSeedType?: "VRST_WEAPON";
|
RandomSeedType?: string;
|
||||||
RequiredGoalTag?: string;
|
RequiredGoalTag?: string;
|
||||||
WeaponUpgradeValueAttenuationExponent?: number;
|
WeaponUpgradeValueAttenuationExponent?: 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.
|
||||||
|
@ -103,7 +103,7 @@ export interface ILiteSortie {
|
|||||||
Expiry: IMongoDate;
|
Expiry: IMongoDate;
|
||||||
Reward: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards";
|
Reward: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards";
|
||||||
Seed: number;
|
Seed: number;
|
||||||
Boss: string; // "SORTIE_BOSS_AMAR" | "SORTIE_BOSS_NIRA" | "SORTIE_BOSS_BOREAL"
|
Boss: "SORTIE_BOSS_AMAR" | "SORTIE_BOSS_NIRA" | "SORTIE_BOSS_BOREAL";
|
||||||
Missions: {
|
Missions: {
|
||||||
missionType: string;
|
missionType: string;
|
||||||
node: string;
|
node: string;
|
||||||
|
@ -1097,5 +1097,6 @@
|
|||||||
"/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"
|
||||||
]
|
]
|
||||||
|
@ -487,6 +487,7 @@ function updateInventory() {
|
|||||||
a.href = "#";
|
a.href = "#";
|
||||||
a.onclick = function (event) {
|
a.onclick = function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
document.getElementById(category + "-list").removeChild(tr);
|
||||||
disposeOfGear(category, item.ItemId.$oid);
|
disposeOfGear(category, item.ItemId.$oid);
|
||||||
};
|
};
|
||||||
a.title = loc("code_remove");
|
a.title = loc("code_remove");
|
||||||
@ -683,6 +684,7 @@ function updateInventory() {
|
|||||||
a.href = "#";
|
a.href = "#";
|
||||||
a.onclick = function (event) {
|
a.onclick = function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
document.getElementById("riven-list").removeChild(tr);
|
||||||
disposeOfGear("Upgrades", item.ItemId.$oid);
|
disposeOfGear("Upgrades", item.ItemId.$oid);
|
||||||
};
|
};
|
||||||
a.title = loc("code_remove");
|
a.title = loc("code_remove");
|
||||||
@ -723,6 +725,7 @@ function updateInventory() {
|
|||||||
a.href = "#";
|
a.href = "#";
|
||||||
a.onclick = function (event) {
|
a.onclick = function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
document.getElementById("mods-list").removeChild(tr);
|
||||||
disposeOfGear("Upgrades", item.ItemId.$oid);
|
disposeOfGear("Upgrades", item.ItemId.$oid);
|
||||||
};
|
};
|
||||||
a.title = loc("code_remove");
|
a.title = loc("code_remove");
|
||||||
@ -765,6 +768,7 @@ function updateInventory() {
|
|||||||
a.href = "#";
|
a.href = "#";
|
||||||
a.onclick = function (event) {
|
a.onclick = function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
document.getElementById("mods-list").removeChild(tr);
|
||||||
disposeOfItems("Upgrades", item.ItemType, item.ItemCount);
|
disposeOfItems("Upgrades", item.ItemType, item.ItemCount);
|
||||||
};
|
};
|
||||||
a.title = loc("code_remove");
|
a.title = loc("code_remove");
|
||||||
@ -1097,8 +1101,6 @@ function disposeOfGear(category, oid) {
|
|||||||
url: "/api/sell.php?" + window.authz,
|
url: "/api/sell.php?" + window.authz,
|
||||||
contentType: "text/plain",
|
contentType: "text/plain",
|
||||||
data: JSON.stringify(data)
|
data: JSON.stringify(data)
|
||||||
}).done(function () {
|
|
||||||
updateInventory();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1120,8 +1122,6 @@ function disposeOfItems(category, type, count) {
|
|||||||
url: "/api/sell.php?" + window.authz,
|
url: "/api/sell.php?" + window.authz,
|
||||||
contentType: "text/plain",
|
contentType: "text/plain",
|
||||||
data: JSON.stringify(data)
|
data: JSON.stringify(data)
|
||||||
}).done(function () {
|
|
||||||
updateInventory();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1260,21 +1260,28 @@ function doAcquireMod() {
|
|||||||
$("#mod-to-acquire").addClass("is-invalid").focus();
|
$("#mod-to-acquire").addClass("is-invalid").focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
revalidateAuthz(() => {
|
const count = parseInt($("#mod-count").val());
|
||||||
$.post({
|
if (count != 0) {
|
||||||
url: "/custom/addItems?" + window.authz,
|
revalidateAuthz(() => {
|
||||||
contentType: "application/json",
|
$.post({
|
||||||
data: JSON.stringify([
|
url: "/custom/addItems?" + window.authz,
|
||||||
{
|
contentType: "application/json",
|
||||||
ItemType: uniqueName,
|
data: JSON.stringify([
|
||||||
ItemCount: parseInt($("#mod-count").val())
|
{
|
||||||
|
ItemType: uniqueName,
|
||||||
|
ItemCount: count
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}).done(function () {
|
||||||
|
if (count > 0) {
|
||||||
|
toast(loc("code_succAdded"));
|
||||||
|
} else {
|
||||||
|
toast(loc("code_succRemoved"));
|
||||||
}
|
}
|
||||||
])
|
updateInventory();
|
||||||
}).done(function () {
|
});
|
||||||
document.getElementById("mod-to-acquire").value = "";
|
|
||||||
updateInventory();
|
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const uiConfigs = [...$("#server-settings input[id]")].map(x => x.id);
|
const uiConfigs = [...$("#server-settings input[id]")].map(x => x.id);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user