forked from OpenWF/SpaceNinjaServer
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
4e57bcd1ae | |||
e2fe406017 | |||
c53dc2fd02 | |||
cfa3586f64 | |||
238af294fe | |||
1914fd8f10 | |||
ec4af075b5 | |||
355a70d366 | |||
cad82cf7de | |||
ff3a9b382c | |||
18fbd51efb | |||
f7b4b4f089 | |||
83743831c9 |
@ -21,6 +21,13 @@ app.use((req, _res, next) => {
|
|||||||
if (req.headers["content-encoding"] == "ezip" || req.headers["content-encoding"] == "e") {
|
if (req.headers["content-encoding"] == "ezip" || req.headers["content-encoding"] == "e") {
|
||||||
req.headers["content-encoding"] = undefined;
|
req.headers["content-encoding"] = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// U18 uses application/x-www-form-urlencoded even tho the data is JSON which Express doesn't like.
|
||||||
|
// U17 sets no Content-Type at all, which Express also doesn't like.
|
||||||
|
if (!req.headers["content-type"] || req.headers["content-type"] == "application/x-www-form-urlencoded") {
|
||||||
|
req.headers["content-type"] = "application/octet-stream";
|
||||||
|
}
|
||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -82,9 +82,12 @@ export const loginController: RequestHandler = async (request, response) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (account.Nonce && account.ClientType != "webui" && !account.Dropped && !loginRequest.kick) {
|
if (account.Nonce && account.ClientType != "webui" && !account.Dropped && !loginRequest.kick) {
|
||||||
response.status(400).json({ error: "nonce still set" });
|
// U17 seems to handle "nonce still set" like a login failure.
|
||||||
|
if (version_compare(buildLabel, "2015.12.05.18.07") >= 0) {
|
||||||
|
response.status(400).send({ error: "nonce still set" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
account.ClientType = loginRequest.ClientType;
|
account.ClientType = loginRequest.ClientType;
|
||||||
account.Nonce = nonce;
|
account.Nonce = nonce;
|
||||||
@ -103,13 +106,16 @@ const createLoginResponse = (myAddress: string, account: IDatabaseAccountJson, b
|
|||||||
CountryCode: account.CountryCode,
|
CountryCode: account.CountryCode,
|
||||||
AmazonAuthToken: account.AmazonAuthToken,
|
AmazonAuthToken: account.AmazonAuthToken,
|
||||||
AmazonRefreshToken: account.AmazonRefreshToken,
|
AmazonRefreshToken: account.AmazonRefreshToken,
|
||||||
ConsentNeeded: account.ConsentNeeded,
|
|
||||||
TrackedSettings: account.TrackedSettings,
|
|
||||||
Nonce: account.Nonce,
|
Nonce: account.Nonce,
|
||||||
IRC: config.myIrcAddresses ?? [myAddress],
|
IRC: config.myIrcAddresses ?? [myAddress],
|
||||||
NRS: config.NRS,
|
NRS: config.NRS,
|
||||||
BuildLabel: buildLabel
|
BuildLabel: buildLabel
|
||||||
};
|
};
|
||||||
|
if (version_compare(buildLabel, "2018.11.08.14.45") >= 0) {
|
||||||
|
// U24 and up
|
||||||
|
resp.ConsentNeeded = account.ConsentNeeded;
|
||||||
|
resp.TrackedSettings = account.TrackedSettings;
|
||||||
|
}
|
||||||
if (version_compare(buildLabel, "2019.08.29.20.01") >= 0) {
|
if (version_compare(buildLabel, "2019.08.29.20.01") >= 0) {
|
||||||
// U25.7 and up
|
// U25.7 and up
|
||||||
resp.ForceLogoutVersion = account.ForceLogoutVersion;
|
resp.ForceLogoutVersion = account.ForceLogoutVersion;
|
||||||
|
25
src/controllers/api/questControlController.ts
Normal file
25
src/controllers/api/questControlController.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
// Basic shim handling action=sync to login on U21
|
||||||
|
export const questControlController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId);
|
||||||
|
const quests: IQuestState[] = [];
|
||||||
|
for (const quest of inventory.QuestKeys) {
|
||||||
|
quests.push({
|
||||||
|
quest: quest.ItemType,
|
||||||
|
state: 3 // COMPLETE
|
||||||
|
});
|
||||||
|
}
|
||||||
|
res.json({
|
||||||
|
QuestState: quests
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IQuestState {
|
||||||
|
quest: string;
|
||||||
|
state: number;
|
||||||
|
task?: string;
|
||||||
|
}
|
@ -18,16 +18,15 @@ import {
|
|||||||
ITypeXPItem
|
ITypeXPItem
|
||||||
} from "@/src/types/inventoryTypes/inventoryTypes";
|
} from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { catBreadHash } from "@/src/helpers/stringHelpers";
|
import { catBreadHash, getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { ExportCustoms, ExportDojoRecipes } from "warframe-public-export-plus";
|
import { ExportCustoms, ExportDojoRecipes } from "warframe-public-export-plus";
|
||||||
import { IStatsClient } from "@/src/types/statTypes";
|
import { IStatsClient } from "@/src/types/statTypes";
|
||||||
import { toStoreItem } from "@/src/services/itemDataService";
|
import { toStoreItem } from "@/src/services/itemDataService";
|
||||||
|
import { FlattenMaps } from "mongoose";
|
||||||
|
|
||||||
export const getProfileViewingDataController: RequestHandler = async (req, res) => {
|
const getProfileViewingDataByPlayerIdImpl = async (playerId: string): Promise<IProfileViewingData | undefined> => {
|
||||||
if (req.query.playerId) {
|
const account = await Account.findById(playerId, "DisplayName");
|
||||||
const account = await Account.findById(req.query.playerId as string, "DisplayName");
|
|
||||||
if (!account) {
|
if (!account) {
|
||||||
res.status(409).send("Could not find requested account");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const inventory = (await Inventory.findOne({ accountOwnerId: account._id }))!;
|
const inventory = (await Inventory.findOne({ accountOwnerId: account._id }))!;
|
||||||
@ -67,13 +66,23 @@ export const getProfileViewingDataController: RequestHandler = async (req, res)
|
|||||||
delete stats.__v;
|
delete stats.__v;
|
||||||
delete stats.accountOwnerId;
|
delete stats.accountOwnerId;
|
||||||
|
|
||||||
res.json({
|
return {
|
||||||
Results: [result],
|
Results: [result],
|
||||||
TechProjects: [],
|
TechProjects: [],
|
||||||
XpComponents: [],
|
XpComponents: [],
|
||||||
//XpCacheExpiryDate, some IMongoDate in the future, no clue what it's for
|
//XpCacheExpiryDate, some IMongoDate in the future, no clue what it's for
|
||||||
Stats: stats
|
Stats: stats
|
||||||
});
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getProfileViewingDataGetController: RequestHandler = async (req, res) => {
|
||||||
|
if (req.query.playerId) {
|
||||||
|
const data = await getProfileViewingDataByPlayerIdImpl(req.query.playerId as string);
|
||||||
|
if (data) {
|
||||||
|
res.json(data);
|
||||||
|
} else {
|
||||||
|
res.status(409).send("Could not find requested account");
|
||||||
|
}
|
||||||
} else if (req.query.guildId) {
|
} else if (req.query.guildId) {
|
||||||
const guild = await Guild.findById(req.query.guildId, "Name Tier XP Class Emblem TechProjects ClaimedXP");
|
const guild = await Guild.findById(req.query.guildId, "Name Tier XP Class Emblem TechProjects ClaimedXP");
|
||||||
if (!guild) {
|
if (!guild) {
|
||||||
@ -170,6 +179,28 @@ export const getProfileViewingDataController: RequestHandler = async (req, res)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// For old versions, this was an authenticated POST request.
|
||||||
|
interface IGetProfileViewingDataRequest {
|
||||||
|
AccountId: string;
|
||||||
|
}
|
||||||
|
export const getProfileViewingDataPostController: RequestHandler = async (req, res) => {
|
||||||
|
const payload = getJSONfromString<IGetProfileViewingDataRequest>(String(req.body));
|
||||||
|
const data = await getProfileViewingDataByPlayerIdImpl(payload.AccountId);
|
||||||
|
if (data) {
|
||||||
|
res.json(data);
|
||||||
|
} else {
|
||||||
|
res.status(409).send("Could not find requested account");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IProfileViewingData {
|
||||||
|
Results: IPlayerProfileViewingDataResult[];
|
||||||
|
TechProjects: [];
|
||||||
|
XpComponents: [];
|
||||||
|
//XpCacheExpiryDate, some IMongoDate in the future, no clue what it's for
|
||||||
|
Stats: FlattenMaps<Partial<TStatsDatabaseDocument>>;
|
||||||
|
}
|
||||||
|
|
||||||
interface IPlayerProfileViewingDataResult extends Partial<IDailyAffiliations> {
|
interface IPlayerProfileViewingDataResult extends Partial<IDailyAffiliations> {
|
||||||
AccountId: IOid;
|
AccountId: IOid;
|
||||||
DisplayName: string;
|
DisplayName: string;
|
||||||
|
@ -59,6 +59,7 @@ import { getGuildDojoController } from "@/src/controllers/api/getGuildDojoContro
|
|||||||
import { getGuildLogController } from "@/src/controllers/api/getGuildLogController";
|
import { getGuildLogController } from "@/src/controllers/api/getGuildLogController";
|
||||||
import { getIgnoredUsersController } from "@/src/controllers/api/getIgnoredUsersController";
|
import { getIgnoredUsersController } from "@/src/controllers/api/getIgnoredUsersController";
|
||||||
import { getNewRewardSeedController } from "@/src/controllers/api/getNewRewardSeedController";
|
import { getNewRewardSeedController } from "@/src/controllers/api/getNewRewardSeedController";
|
||||||
|
import { getProfileViewingDataPostController } from "@/src/controllers/dynamic/getProfileViewingDataController";
|
||||||
import { getShipController } from "@/src/controllers/api/getShipController";
|
import { getShipController } from "@/src/controllers/api/getShipController";
|
||||||
import { getVendorInfoController } from "@/src/controllers/api/getVendorInfoController";
|
import { getVendorInfoController } from "@/src/controllers/api/getVendorInfoController";
|
||||||
import { getVoidProjectionRewardsController } from "@/src/controllers/api/getVoidProjectionRewardsController";
|
import { getVoidProjectionRewardsController } from "@/src/controllers/api/getVoidProjectionRewardsController";
|
||||||
@ -96,6 +97,7 @@ import { playerSkillsController } from "@/src/controllers/api/playerSkillsContro
|
|||||||
import { postGuildAdvertisementController } from "@/src/controllers/api/postGuildAdvertisementController";
|
import { postGuildAdvertisementController } from "@/src/controllers/api/postGuildAdvertisementController";
|
||||||
import { projectionManagerController } from "@/src/controllers/api/projectionManagerController";
|
import { projectionManagerController } from "@/src/controllers/api/projectionManagerController";
|
||||||
import { purchaseController } from "@/src/controllers/api/purchaseController";
|
import { purchaseController } from "@/src/controllers/api/purchaseController";
|
||||||
|
import { questControlController } from "@/src/controllers/api/questControlController";
|
||||||
import { queueDojoComponentDestructionController } from "@/src/controllers/api/queueDojoComponentDestructionController";
|
import { queueDojoComponentDestructionController } from "@/src/controllers/api/queueDojoComponentDestructionController";
|
||||||
import { redeemPromoCodeController } from "@/src/controllers/api/redeemPromoCodeController";
|
import { redeemPromoCodeController } from "@/src/controllers/api/redeemPromoCodeController";
|
||||||
import { releasePetController } from "@/src/controllers/api/releasePetController";
|
import { releasePetController } from "@/src/controllers/api/releasePetController";
|
||||||
@ -184,6 +186,7 @@ apiRouter.get("/getVendorInfo.php", getVendorInfoController);
|
|||||||
apiRouter.get("/hub", hubController);
|
apiRouter.get("/hub", hubController);
|
||||||
apiRouter.get("/hubInstances", hubInstancesController);
|
apiRouter.get("/hubInstances", hubInstancesController);
|
||||||
apiRouter.get("/inbox.php", inboxController);
|
apiRouter.get("/inbox.php", inboxController);
|
||||||
|
apiRouter.get("/getMessages.php", inboxController); // unsure if this is correct, but needed for U17
|
||||||
apiRouter.get("/inventory.php", inventoryController);
|
apiRouter.get("/inventory.php", inventoryController);
|
||||||
apiRouter.get("/loginRewards.php", loginRewardsController);
|
apiRouter.get("/loginRewards.php", loginRewardsController);
|
||||||
apiRouter.get("/logout.php", logoutController);
|
apiRouter.get("/logout.php", logoutController);
|
||||||
@ -191,6 +194,7 @@ apiRouter.get("/marketRecommendations.php", marketRecommendationsController);
|
|||||||
apiRouter.get("/marketSearchRecommendations.php", marketRecommendationsController);
|
apiRouter.get("/marketSearchRecommendations.php", marketRecommendationsController);
|
||||||
apiRouter.get("/modularWeaponSale.php", modularWeaponSaleController);
|
apiRouter.get("/modularWeaponSale.php", modularWeaponSaleController);
|
||||||
apiRouter.get("/playedParkourTutorial.php", playedParkourTutorialController);
|
apiRouter.get("/playedParkourTutorial.php", playedParkourTutorialController);
|
||||||
|
apiRouter.get("/questControl.php", questControlController);
|
||||||
apiRouter.get("/queueDojoComponentDestruction.php", queueDojoComponentDestructionController);
|
apiRouter.get("/queueDojoComponentDestruction.php", queueDojoComponentDestructionController);
|
||||||
apiRouter.get("/removeFromAlliance.php", removeFromAllianceController);
|
apiRouter.get("/removeFromAlliance.php", removeFromAllianceController);
|
||||||
apiRouter.get("/setActiveQuest.php", setActiveQuestController);
|
apiRouter.get("/setActiveQuest.php", setActiveQuestController);
|
||||||
@ -247,6 +251,7 @@ 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);
|
||||||
apiRouter.post("/getGuildDojo.php", getGuildDojoController);
|
apiRouter.post("/getGuildDojo.php", getGuildDojoController);
|
||||||
|
apiRouter.post("/getProfileViewingData.php", getProfileViewingDataPostController);
|
||||||
apiRouter.post("/getVoidProjectionRewards.php", getVoidProjectionRewardsController);
|
apiRouter.post("/getVoidProjectionRewards.php", getVoidProjectionRewardsController);
|
||||||
apiRouter.post("/gifting.php", giftingController);
|
apiRouter.post("/gifting.php", giftingController);
|
||||||
apiRouter.post("/gildWeapon.php", gildWeaponController);
|
apiRouter.post("/gildWeapon.php", gildWeaponController);
|
||||||
@ -274,6 +279,7 @@ apiRouter.post("/playerSkills.php", playerSkillsController);
|
|||||||
apiRouter.post("/postGuildAdvertisement.php", postGuildAdvertisementController);
|
apiRouter.post("/postGuildAdvertisement.php", postGuildAdvertisementController);
|
||||||
apiRouter.post("/projectionManager.php", projectionManagerController);
|
apiRouter.post("/projectionManager.php", projectionManagerController);
|
||||||
apiRouter.post("/purchase.php", purchaseController);
|
apiRouter.post("/purchase.php", purchaseController);
|
||||||
|
apiRouter.post("/questControl.php", questControlController); // U17
|
||||||
apiRouter.post("/redeemPromoCode.php", redeemPromoCodeController);
|
apiRouter.post("/redeemPromoCode.php", redeemPromoCodeController);
|
||||||
apiRouter.post("/releasePet.php", releasePetController);
|
apiRouter.post("/releasePet.php", releasePetController);
|
||||||
apiRouter.post("/removeFromGuild.php", removeFromGuildController);
|
apiRouter.post("/removeFromGuild.php", removeFromGuildController);
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
import { aggregateSessionsController } from "@/src/controllers/dynamic/aggregateSessionsController";
|
import { aggregateSessionsController } from "@/src/controllers/dynamic/aggregateSessionsController";
|
||||||
import { getGuildAdsController } from "@/src/controllers/dynamic/getGuildAdsController";
|
import { getGuildAdsController } from "@/src/controllers/dynamic/getGuildAdsController";
|
||||||
import { getProfileViewingDataController } from "@/src/controllers/dynamic/getProfileViewingDataController";
|
import { getProfileViewingDataGetController } from "@/src/controllers/dynamic/getProfileViewingDataController";
|
||||||
import { worldStateController } from "@/src/controllers/dynamic/worldStateController";
|
import { worldStateController } from "@/src/controllers/dynamic/worldStateController";
|
||||||
|
|
||||||
const dynamicController = express.Router();
|
const dynamicController = express.Router();
|
||||||
|
|
||||||
dynamicController.get("/aggregateSessions.php", aggregateSessionsController);
|
dynamicController.get("/aggregateSessions.php", aggregateSessionsController);
|
||||||
dynamicController.get("/getGuildAds.php", getGuildAdsController);
|
dynamicController.get("/getGuildAds.php", getGuildAdsController);
|
||||||
dynamicController.get("/getProfileViewingData.php", getProfileViewingDataController);
|
dynamicController.get("/getProfileViewingData.php", getProfileViewingDataGetController);
|
||||||
dynamicController.get("/worldState.php", worldStateController);
|
dynamicController.get("/worldState.php", worldStateController);
|
||||||
|
|
||||||
export { dynamicController };
|
export { dynamicController };
|
||||||
|
@ -175,6 +175,9 @@ export const getDojoClient = async (
|
|||||||
}
|
}
|
||||||
if (dojoComponent.CompletionTime) {
|
if (dojoComponent.CompletionTime) {
|
||||||
clientComponent.CompletionTime = toMongoDate(dojoComponent.CompletionTime);
|
clientComponent.CompletionTime = toMongoDate(dojoComponent.CompletionTime);
|
||||||
|
clientComponent.TimeRemaining = Math.trunc(
|
||||||
|
(dojoComponent.CompletionTime.getTime() - Date.now()) / 1000
|
||||||
|
);
|
||||||
if (dojoComponent.CompletionLogPending && Date.now() >= dojoComponent.CompletionTime.getTime()) {
|
if (dojoComponent.CompletionLogPending && Date.now() >= dojoComponent.CompletionTime.getTime()) {
|
||||||
const entry = guild.RoomChanges?.find(x => x.componentId.equals(dojoComponent._id));
|
const entry = guild.RoomChanges?.find(x => x.componentId.equals(dojoComponent._id));
|
||||||
if (entry) {
|
if (entry) {
|
||||||
@ -210,6 +213,9 @@ export const getDojoClient = async (
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
clientComponent.DestructionTime = toMongoDate(dojoComponent.DestructionTime);
|
clientComponent.DestructionTime = toMongoDate(dojoComponent.DestructionTime);
|
||||||
|
clientComponent.DestructionTimeRemaining = Math.trunc(
|
||||||
|
(dojoComponent.DestructionTime.getTime() - Date.now()) / 1000
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
clientComponent.RegularCredits = dojoComponent.RegularCredits;
|
clientComponent.RegularCredits = dojoComponent.RegularCredits;
|
||||||
@ -245,6 +251,7 @@ export const getDojoClient = async (
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
clientDeco.CompletionTime = toMongoDate(deco.CompletionTime);
|
clientDeco.CompletionTime = toMongoDate(deco.CompletionTime);
|
||||||
|
clientDeco.TimeRemaining = Math.trunc((deco.CompletionTime.getTime() - Date.now()) / 1000);
|
||||||
} else {
|
} else {
|
||||||
clientDeco.RegularCredits = deco.RegularCredits;
|
clientDeco.RegularCredits = deco.RegularCredits;
|
||||||
clientDeco.MiscItems = deco.MiscItems;
|
clientDeco.MiscItems = deco.MiscItems;
|
||||||
|
@ -789,6 +789,10 @@ export const addItem = async (
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "NeutralCreatures": {
|
case "NeutralCreatures": {
|
||||||
|
if (inventory.Horses.length != 0) {
|
||||||
|
logger.warn("refusing to add Horse because account already has one");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
const horseIndex = inventory.Horses.push({ ItemType: typeName });
|
const horseIndex = inventory.Horses.push({ ItemType: typeName });
|
||||||
return {
|
return {
|
||||||
Horses: [inventory.Horses[horseIndex - 1].toJSON<IEquipmentClient>()]
|
Horses: [inventory.Horses[horseIndex - 1].toJSON<IEquipmentClient>()]
|
||||||
|
@ -1449,7 +1449,11 @@ function getRandomMissionDrops(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
rewardManifests = [job.rewards];
|
rewardManifests = [job.rewards];
|
||||||
|
if (job.xpAmounts.length > 1) {
|
||||||
rotations = [RewardInfo.JobStage! % (job.xpAmounts.length - 1)];
|
rotations = [RewardInfo.JobStage! % (job.xpAmounts.length - 1)];
|
||||||
|
} else {
|
||||||
|
rotations = [0];
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
RewardInfo.Q &&
|
RewardInfo.Q &&
|
||||||
(RewardInfo.JobStage === job.xpAmounts.length - 1 || job.isVault) &&
|
(RewardInfo.JobStage === job.xpAmounts.length - 1 || job.isVault) &&
|
||||||
|
@ -193,6 +193,12 @@ const pushSyndicateMissions = (
|
|||||||
idSuffix: string,
|
idSuffix: string,
|
||||||
syndicateTag: string
|
syndicateTag: string
|
||||||
): void => {
|
): void => {
|
||||||
|
const dayStart = getSortieTime(day);
|
||||||
|
if (Date.now() >= dayStart) {
|
||||||
|
return; // The client does not seem to respect activation.
|
||||||
|
}
|
||||||
|
const dayEnd = getSortieTime(day + 1);
|
||||||
|
|
||||||
const nodeOptions: string[] = [...syndicateMissions];
|
const nodeOptions: string[] = [...syndicateMissions];
|
||||||
|
|
||||||
const rng = new CRng(seed);
|
const rng = new CRng(seed);
|
||||||
@ -203,8 +209,6 @@ const pushSyndicateMissions = (
|
|||||||
nodeOptions.splice(index, 1);
|
nodeOptions.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dayStart = getSortieTime(day);
|
|
||||||
const dayEnd = getSortieTime(day + 1);
|
|
||||||
worldState.SyndicateMissions.push({
|
worldState.SyndicateMissions.push({
|
||||||
_id: { $oid: ((dayStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + idSuffix },
|
_id: { $oid: ((dayStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + idSuffix },
|
||||||
Activation: { $date: { $numberLong: dayStart.toString() } },
|
Activation: { $date: { $numberLong: dayStart.toString() } },
|
||||||
@ -291,11 +295,9 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => {
|
|||||||
"SORTIE_MODIFIER_VIRAL",
|
"SORTIE_MODIFIER_VIRAL",
|
||||||
"SORTIE_MODIFIER_ELECTRICITY",
|
"SORTIE_MODIFIER_ELECTRICITY",
|
||||||
"SORTIE_MODIFIER_RADIATION",
|
"SORTIE_MODIFIER_RADIATION",
|
||||||
"SORTIE_MODIFIER_GAS",
|
|
||||||
"SORTIE_MODIFIER_FIRE",
|
"SORTIE_MODIFIER_FIRE",
|
||||||
"SORTIE_MODIFIER_EXPLOSION",
|
"SORTIE_MODIFIER_EXPLOSION",
|
||||||
"SORTIE_MODIFIER_FREEZE",
|
"SORTIE_MODIFIER_FREEZE",
|
||||||
"SORTIE_MODIFIER_TOXIN",
|
|
||||||
"SORTIE_MODIFIER_POISON",
|
"SORTIE_MODIFIER_POISON",
|
||||||
"SORTIE_MODIFIER_SECONDARY_ONLY",
|
"SORTIE_MODIFIER_SECONDARY_ONLY",
|
||||||
"SORTIE_MODIFIER_SHOTGUN_ONLY",
|
"SORTIE_MODIFIER_SHOTGUN_ONLY",
|
||||||
@ -742,6 +744,10 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
// Omit void fissures for versions prior to Dante Unbound to avoid script errors.
|
// Omit void fissures for versions prior to Dante Unbound to avoid script errors.
|
||||||
if (buildLabel && version_compare(buildLabel, "2024.03.24.20.00") < 0) {
|
if (buildLabel && version_compare(buildLabel, "2024.03.24.20.00") < 0) {
|
||||||
worldState.ActiveMissions = [];
|
worldState.ActiveMissions = [];
|
||||||
|
if (version_compare(buildLabel, "2017.10.12.17.04") < 0) {
|
||||||
|
// Old versions seem to really get hung up on not being able to load these.
|
||||||
|
worldState.PVPChallengeInstances = [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.worldState?.starDays) {
|
if (config.worldState?.starDays) {
|
||||||
@ -762,6 +768,8 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Nightwave Challenges
|
// Nightwave Challenges
|
||||||
|
// Current nightwave season was introduced in 38.0.8 so omitting challenges before that to avoid UI bugs and even crashes on really old versions.
|
||||||
|
if (!buildLabel || version_compare(buildLabel, "2025.02.05.11.19") >= 0) {
|
||||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(day - 2));
|
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(day - 2));
|
||||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(day - 1));
|
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(day - 1));
|
||||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(day - 0));
|
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(day - 0));
|
||||||
@ -772,6 +780,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
if (isBeforeNextExpectedWorldStateRefresh(weekEnd)) {
|
if (isBeforeNextExpectedWorldStateRefresh(weekEnd)) {
|
||||||
pushWeeklyActs(worldState, week + 1);
|
pushWeeklyActs(worldState, week + 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Elite Sanctuary Onslaught cycling every week
|
// Elite Sanctuary Onslaught cycling every week
|
||||||
worldState.NodeOverrides.find(x => x.Node == "SolNode802")!.Seed = new CRng(week).randomInt(0, 0xffff);
|
worldState.NodeOverrides.find(x => x.Node == "SolNode802")!.Seed = new CRng(week).randomInt(0, 0xffff);
|
||||||
@ -901,7 +910,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
Jobs: [
|
Jobs: [
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(venusJobs),
|
jobType: rng.randomElement(venusJobs),
|
||||||
rewards: `Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierATable${table}Rewards`,
|
rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierATable${table}Rewards`,
|
||||||
masteryReq: 0,
|
masteryReq: 0,
|
||||||
minEnemyLevel: 5,
|
minEnemyLevel: 5,
|
||||||
maxEnemyLevel: 15,
|
maxEnemyLevel: 15,
|
||||||
@ -909,7 +918,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(venusJobs),
|
jobType: rng.randomElement(venusJobs),
|
||||||
rewards: `Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierBTable${table}Rewards`,
|
rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierBTable${table}Rewards`,
|
||||||
masteryReq: 1,
|
masteryReq: 1,
|
||||||
minEnemyLevel: 10,
|
minEnemyLevel: 10,
|
||||||
maxEnemyLevel: 30,
|
maxEnemyLevel: 30,
|
||||||
@ -917,7 +926,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(venusJobs),
|
jobType: rng.randomElement(venusJobs),
|
||||||
rewards: `Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierCTable${table}Rewards`,
|
rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierCTable${table}Rewards`,
|
||||||
masteryReq: 2,
|
masteryReq: 2,
|
||||||
minEnemyLevel: 20,
|
minEnemyLevel: 20,
|
||||||
maxEnemyLevel: 40,
|
maxEnemyLevel: 40,
|
||||||
@ -925,7 +934,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(venusJobs),
|
jobType: rng.randomElement(venusJobs),
|
||||||
rewards: `Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierDTable${table}Rewards`,
|
rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierDTable${table}Rewards`,
|
||||||
masteryReq: 3,
|
masteryReq: 3,
|
||||||
minEnemyLevel: 30,
|
minEnemyLevel: 30,
|
||||||
maxEnemyLevel: 50,
|
maxEnemyLevel: 50,
|
||||||
@ -933,7 +942,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(venusJobs),
|
jobType: rng.randomElement(venusJobs),
|
||||||
rewards: `Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierETable${table}Rewards`,
|
rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierETable${table}Rewards`,
|
||||||
masteryReq: 5,
|
masteryReq: 5,
|
||||||
minEnemyLevel: 40,
|
minEnemyLevel: 40,
|
||||||
maxEnemyLevel: 60,
|
maxEnemyLevel: 60,
|
||||||
@ -941,7 +950,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(venusJobs),
|
jobType: rng.randomElement(venusJobs),
|
||||||
rewards: `Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierETable${table}Rewards`,
|
rewards: `/Lotus/Types/Game/MissionDecks/VenusJobMissionRewards/VenusTierETable${table}Rewards`,
|
||||||
masteryReq: 10,
|
masteryReq: 10,
|
||||||
minEnemyLevel: 100,
|
minEnemyLevel: 100,
|
||||||
maxEnemyLevel: 100,
|
maxEnemyLevel: 100,
|
||||||
|
@ -173,9 +173,11 @@ export interface IDojoComponentClient {
|
|||||||
Message?: string;
|
Message?: string;
|
||||||
RegularCredits?: number; // "Collecting Materials" state: Number of credits that were donated.
|
RegularCredits?: number; // "Collecting Materials" state: Number of credits that were donated.
|
||||||
MiscItems?: IMiscItem[]; // "Collecting Materials" state: Resources that were donated.
|
MiscItems?: IMiscItem[]; // "Collecting Materials" state: Resources that were donated.
|
||||||
CompletionTime?: IMongoDate;
|
CompletionTime?: IMongoDate; // new versions
|
||||||
|
TimeRemaining?: number; // old versions
|
||||||
RushPlatinum?: number;
|
RushPlatinum?: number;
|
||||||
DestructionTime?: IMongoDate;
|
DestructionTime?: IMongoDate; // new versions
|
||||||
|
DestructionTimeRemaining?: number; // old versions
|
||||||
Decos?: IDojoDecoClient[];
|
Decos?: IDojoDecoClient[];
|
||||||
DecoCapacity?: number;
|
DecoCapacity?: number;
|
||||||
PaintBot?: IOid;
|
PaintBot?: IOid;
|
||||||
@ -212,7 +214,8 @@ export interface IDojoDecoClient {
|
|||||||
Sockets?: number;
|
Sockets?: number;
|
||||||
RegularCredits?: number;
|
RegularCredits?: number;
|
||||||
MiscItems?: IMiscItem[];
|
MiscItems?: IMiscItem[];
|
||||||
CompletionTime?: IMongoDate;
|
CompletionTime?: IMongoDate; // new versions
|
||||||
|
TimeRemaining?: number; // old versions
|
||||||
RushPlatinum?: number;
|
RushPlatinum?: number;
|
||||||
PictureFrameInfo?: IPictureFrameInfo;
|
PictureFrameInfo?: IPictureFrameInfo;
|
||||||
Pending?: boolean;
|
Pending?: boolean;
|
||||||
|
@ -8,8 +8,8 @@ export interface IAccountAndLoginResponseCommons {
|
|||||||
ForceLogoutVersion?: number;
|
ForceLogoutVersion?: number;
|
||||||
AmazonAuthToken?: string;
|
AmazonAuthToken?: string;
|
||||||
AmazonRefreshToken?: string;
|
AmazonRefreshToken?: string;
|
||||||
ConsentNeeded: boolean;
|
ConsentNeeded?: boolean;
|
||||||
TrackedSettings: string[];
|
TrackedSettings?: string[];
|
||||||
Nonce: number;
|
Nonce: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ export interface IWorldState {
|
|||||||
GlobalUpgrades: IGlobalUpgrade[];
|
GlobalUpgrades: IGlobalUpgrade[];
|
||||||
ActiveMissions: IFissure[];
|
ActiveMissions: IFissure[];
|
||||||
NodeOverrides: INodeOverride[];
|
NodeOverrides: INodeOverride[];
|
||||||
|
PVPChallengeInstances: IPVPChallengeInstance[];
|
||||||
EndlessXpChoices: IEndlessXpChoice[];
|
EndlessXpChoices: IEndlessXpChoice[];
|
||||||
SeasonInfo: {
|
SeasonInfo: {
|
||||||
Activation: IMongoDate;
|
Activation: IMongoDate;
|
||||||
@ -130,6 +131,21 @@ export interface ILiteSortie {
|
|||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IPVPChallengeInstance {
|
||||||
|
_id: IOid;
|
||||||
|
challengeTypeRefID: string;
|
||||||
|
startDate: IMongoDate;
|
||||||
|
endDate: IMongoDate;
|
||||||
|
params: {
|
||||||
|
n: string; // "ScriptParamValue";
|
||||||
|
v: number;
|
||||||
|
}[];
|
||||||
|
isGenerated: boolean;
|
||||||
|
PVPMode: string;
|
||||||
|
subChallenges: IOid[];
|
||||||
|
Category: string; // "PVPChallengeTypeCategory_WEEKLY" | "PVPChallengeTypeCategory_WEEKLY_ROOT" | "PVPChallengeTypeCategory_DAILY";
|
||||||
|
}
|
||||||
|
|
||||||
export interface IEndlessXpChoice {
|
export interface IEndlessXpChoice {
|
||||||
Category: string;
|
Category: string;
|
||||||
Choices: string[];
|
Choices: string[];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user