Compare commits
11 Commits
24d778371f
...
630d7471f2
Author | SHA1 | Date | |
---|---|---|---|
630d7471f2 | |||
eac1c11c46 | |||
8f07f8faea | |||
f242d9f873 | |||
9a034b1c8a | |||
122950034e | |||
636d3100f3 | |||
444c92f0c6 | |||
653798b987 | |||
7a88f6f486 | |||
82b203e00b |
17
AGENTS.md
Normal file
17
AGENTS.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
## In General
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
Use `npm i` or `npm ci` to install all dependencies.
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
Use `npm run verify` to verify that your changes pass TypeScript's checks.
|
||||||
|
|
||||||
|
### Formatting
|
||||||
|
|
||||||
|
Use `npm run prettier` to ensure your formatting matches the expected format. Failing to do so will cause CI failure.
|
||||||
|
|
||||||
|
## WebUI Specific
|
||||||
|
|
||||||
|
The translation system is designed around additions being made to `static/webui/translations/en.js`. They are copied over for translation via `npm run update-translations`. DO NOT produce non-English strings; we want them to be translated by humans who can understand the full context.
|
@ -59,6 +59,10 @@
|
|||||||
"unlockAllSimarisResearchEntries": false,
|
"unlockAllSimarisResearchEntries": false,
|
||||||
"spoofMasteryRank": -1,
|
"spoofMasteryRank": -1,
|
||||||
"nightwaveStandingMultiplier": 1,
|
"nightwaveStandingMultiplier": 1,
|
||||||
|
"unfaithfulBugFixes": {
|
||||||
|
"ignore1999LastRegionPlayed": false,
|
||||||
|
"fixXtraCheeseTimer": false
|
||||||
|
},
|
||||||
"worldState": {
|
"worldState": {
|
||||||
"creditBoost": false,
|
"creditBoost": false,
|
||||||
"affinityBoost": false,
|
"affinityBoost": false,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { getCalendarProgress, getInventory } from "@/src/services/inventoryService";
|
import { checkCalendarChallengeCompletion, getCalendarProgress, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||||
import { getWorldState } from "@/src/services/worldStateService";
|
import { getWorldState } from "@/src/services/worldStateService";
|
||||||
@ -12,27 +12,23 @@ export const completeCalendarEventController: RequestHandler = async (req, res)
|
|||||||
const calendarProgress = getCalendarProgress(inventory);
|
const calendarProgress = getCalendarProgress(inventory);
|
||||||
const currentSeason = getWorldState().KnownCalendarSeasons[0];
|
const currentSeason = getWorldState().KnownCalendarSeasons[0];
|
||||||
let inventoryChanges: IInventoryChanges = {};
|
let inventoryChanges: IInventoryChanges = {};
|
||||||
let dayIndex = 0;
|
const dayIndex = calendarProgress.SeasonProgress.LastCompletedDayIdx + 1;
|
||||||
for (const day of currentSeason.Days) {
|
const day = currentSeason.Days[dayIndex];
|
||||||
if (day.events.length == 0 || day.events[0].type != "CET_CHALLENGE") {
|
|
||||||
if (dayIndex == calendarProgress.SeasonProgress.LastCompletedDayIdx) {
|
|
||||||
if (day.events.length != 0) {
|
if (day.events.length != 0) {
|
||||||
|
if (day.events[0].type == "CET_CHALLENGE") {
|
||||||
|
throw new Error(`completeCalendarEvent should not be used for challenges`);
|
||||||
|
}
|
||||||
const selection = day.events[parseInt(req.query.CompletedEventIdx as string)];
|
const selection = day.events[parseInt(req.query.CompletedEventIdx as string)];
|
||||||
if (selection.type == "CET_REWARD") {
|
if (selection.type == "CET_REWARD") {
|
||||||
inventoryChanges = (await handleStoreItemAcquisition(selection.reward!, inventory))
|
inventoryChanges = (await handleStoreItemAcquisition(selection.reward!, inventory)).InventoryChanges;
|
||||||
.InventoryChanges;
|
|
||||||
} else if (selection.type == "CET_UPGRADE") {
|
} else if (selection.type == "CET_UPGRADE") {
|
||||||
calendarProgress.YearProgress.Upgrades.push(selection.upgrade!);
|
calendarProgress.YearProgress.Upgrades.push(selection.upgrade!);
|
||||||
} else if (selection.type != "CET_PLOT") {
|
} else if (selection.type != "CET_PLOT") {
|
||||||
throw new Error(`unexpected selection type: ${selection.type}`);
|
throw new Error(`unexpected selection type: ${selection.type}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
calendarProgress.SeasonProgress.LastCompletedDayIdx = dayIndex;
|
||||||
}
|
checkCalendarChallengeCompletion(calendarProgress, currentSeason);
|
||||||
++dayIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
calendarProgress.SeasonProgress.LastCompletedDayIdx++;
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
InventoryChanges: inventoryChanges,
|
InventoryChanges: inventoryChanges,
|
||||||
|
@ -8,16 +8,15 @@ import {
|
|||||||
getKnifeUpgrade,
|
getKnifeUpgrade,
|
||||||
getNemesisManifest,
|
getNemesisManifest,
|
||||||
getNemesisPasscode,
|
getNemesisPasscode,
|
||||||
getNemesisPasscodeModTypes,
|
|
||||||
GUESS_CORRECT,
|
GUESS_CORRECT,
|
||||||
GUESS_INCORRECT,
|
GUESS_INCORRECT,
|
||||||
GUESS_NEUTRAL,
|
GUESS_NEUTRAL,
|
||||||
GUESS_NONE,
|
GUESS_NONE,
|
||||||
GUESS_WILDCARD,
|
GUESS_WILDCARD,
|
||||||
IKnifeResponse
|
IKnifeResponse,
|
||||||
|
parseUpgrade
|
||||||
} from "@/src/helpers/nemesisHelpers";
|
} from "@/src/helpers/nemesisHelpers";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
|
||||||
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
||||||
import { freeUpSlot, getInventory } from "@/src/services/inventoryService";
|
import { freeUpSlot, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountForRequest } from "@/src/services/loginService";
|
import { getAccountForRequest } from "@/src/services/loginService";
|
||||||
@ -215,7 +214,19 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
inventory.Nemesis!.Weakened = true;
|
inventory.Nemesis!.Weakened = true;
|
||||||
await consumePasscodeModCharges(inventory, response);
|
|
||||||
|
// Subtract a charge from all requiem mods installed on parazon
|
||||||
|
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!;
|
||||||
|
for (let i = 3; i != 6; ++i) {
|
||||||
|
//logger.debug(`subtracting a charge from ${dataknifeUpgrades[i]}`);
|
||||||
|
const upgrade = parseUpgrade(inventory, dataknifeUpgrades[i]);
|
||||||
|
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Guess was incorrect, increase rank
|
// Guess was incorrect, increase rank
|
||||||
@ -380,18 +391,3 @@ interface IKnife {
|
|||||||
AttachedUpgrades: IUpgradeClient[];
|
AttachedUpgrades: IUpgradeClient[];
|
||||||
HiddenWhenHolstered: boolean;
|
HiddenWhenHolstered: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const consumePasscodeModCharges = async (
|
|
||||||
inventory: TInventoryDatabaseDocument,
|
|
||||||
response: IKnifeResponse
|
|
||||||
): Promise<void> => {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
@ -13,7 +13,7 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
|
|||||||
|
|
||||||
const inventory = await getInventory(
|
const inventory = await getInventory(
|
||||||
account._id.toString(),
|
account._id.toString(),
|
||||||
"ChallengesFixVersion ChallengeProgress SeasonChallengeHistory Affiliations"
|
"ChallengesFixVersion ChallengeProgress SeasonChallengeHistory Affiliations CalendarProgress"
|
||||||
);
|
);
|
||||||
let affiliationMods: IAffiliationMods[] = [];
|
let affiliationMods: IAffiliationMods[] = [];
|
||||||
if (challenges.ChallengeProgress) {
|
if (challenges.ChallengeProgress) {
|
||||||
|
@ -237,7 +237,7 @@ export const getNemesisPasscode = (nemesis: { fp: bigint; Faction: TNemesisFacti
|
|||||||
return passcode;
|
return passcode;
|
||||||
};
|
};
|
||||||
|
|
||||||
const requiemMods: readonly string[] = [
|
/*const requiemMods: readonly string[] = [
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalOneMod",
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalOneMod",
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalTwoMod",
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalTwoMod",
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalThreeMod",
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalThreeMod",
|
||||||
@ -246,7 +246,7 @@ const requiemMods: readonly string[] = [
|
|||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalSixMod",
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalSixMod",
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalSevenMod",
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalSevenMod",
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalEightMod"
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalEightMod"
|
||||||
];
|
];*/
|
||||||
|
|
||||||
export const antivirusMods: readonly string[] = [
|
export const antivirusMods: readonly string[] = [
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusOneMod",
|
"/Lotus/Upgrades/Mods/Immortal/AntivirusOneMod",
|
||||||
@ -259,12 +259,12 @@ export const antivirusMods: readonly string[] = [
|
|||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusEightMod"
|
"/Lotus/Upgrades/Mods/Immortal/AntivirusEightMod"
|
||||||
];
|
];
|
||||||
|
|
||||||
export const getNemesisPasscodeModTypes = (nemesis: { fp: bigint; Faction: TNemesisFaction }): string[] => {
|
/*export const getNemesisPasscodeModTypes = (nemesis: { fp: bigint; Faction: TNemesisFaction }): string[] => {
|
||||||
const passcode = getNemesisPasscode(nemesis);
|
const passcode = getNemesisPasscode(nemesis);
|
||||||
return nemesis.Faction == "FC_INFESTATION"
|
return nemesis.Faction == "FC_INFESTATION"
|
||||||
? passcode.map(i => antivirusMods[i])
|
? passcode.map(i => antivirusMods[i])
|
||||||
: passcode.map(i => requiemMods[i]);
|
: passcode.map(i => requiemMods[i]);
|
||||||
};
|
};*/
|
||||||
|
|
||||||
// Symbols; 0-7 are the normal requiem mods.
|
// Symbols; 0-7 are the normal requiem mods.
|
||||||
export const GUESS_NONE = 8;
|
export const GUESS_NONE = 8;
|
||||||
@ -343,6 +343,27 @@ export const getKnifeUpgrade = (
|
|||||||
throw new Error(`${type} does not seem to be installed on parazon?!`);
|
throw new Error(`${type} does not seem to be installed on parazon?!`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const parseUpgrade = (
|
||||||
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
str: string
|
||||||
|
): { ItemId: IOid; ItemType: string } => {
|
||||||
|
if (str.length == 24) {
|
||||||
|
const upgrade = inventory.Upgrades.id(str);
|
||||||
|
if (upgrade) {
|
||||||
|
return {
|
||||||
|
ItemId: { $oid: str },
|
||||||
|
ItemType: upgrade.ItemType
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw new Error(`Could not resolve oid ${str}`);
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
ItemId: { $oid: "000000000000000000000000" },
|
||||||
|
ItemType: str
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const consumeModCharge = (
|
export const consumeModCharge = (
|
||||||
response: IKnifeResponse,
|
response: IKnifeResponse,
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
@ -66,6 +66,10 @@ export interface IConfig {
|
|||||||
unlockAllSimarisResearchEntries?: boolean;
|
unlockAllSimarisResearchEntries?: boolean;
|
||||||
spoofMasteryRank?: number;
|
spoofMasteryRank?: number;
|
||||||
nightwaveStandingMultiplier?: number;
|
nightwaveStandingMultiplier?: number;
|
||||||
|
unfaithfulBugFixes?: {
|
||||||
|
ignore1999LastRegionPlayed?: boolean;
|
||||||
|
fixXtraCheeseTimer?: boolean;
|
||||||
|
};
|
||||||
worldState?: {
|
worldState?: {
|
||||||
creditBoost?: boolean;
|
creditBoost?: boolean;
|
||||||
affinityBoost?: boolean;
|
affinityBoost?: boolean;
|
||||||
|
@ -84,9 +84,11 @@ import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from ".
|
|||||||
import { createMessage } from "./inboxService";
|
import { createMessage } from "./inboxService";
|
||||||
import { getMaxStanding, getMinStanding } from "@/src/helpers/syndicateStandingHelper";
|
import { getMaxStanding, getMinStanding } from "@/src/helpers/syndicateStandingHelper";
|
||||||
import { getNightwaveSyndicateTag, getWorldState } from "./worldStateService";
|
import { getNightwaveSyndicateTag, getWorldState } from "./worldStateService";
|
||||||
|
import { ICalendarSeason } from "@/src/types/worldStateTypes";
|
||||||
import { generateNemesisProfile, INemesisProfile } from "../helpers/nemesisHelpers";
|
import { generateNemesisProfile, INemesisProfile } from "../helpers/nemesisHelpers";
|
||||||
import { TAccountDocument } from "./loginService";
|
import { TAccountDocument } from "./loginService";
|
||||||
import { unixTimesInMs } from "../constants/timeConstants";
|
import { unixTimesInMs } from "../constants/timeConstants";
|
||||||
|
import { addString } from "../helpers/stringHelpers";
|
||||||
|
|
||||||
export const createInventory = async (
|
export const createInventory = async (
|
||||||
accountOwnerId: Types.ObjectId,
|
accountOwnerId: Types.ObjectId,
|
||||||
@ -1783,6 +1785,10 @@ export const addChallenges = (
|
|||||||
} else {
|
} else {
|
||||||
inventory.ChallengeProgress.push({ Name, Progress });
|
inventory.ChallengeProgress.push({ Name, Progress });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Name.startsWith("Calendar")) {
|
||||||
|
addString(getCalendarProgress(inventory).SeasonProgress.ActivatedChallenges, Name);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const affiliationMods: IAffiliationMods[] = [];
|
const affiliationMods: IAffiliationMods[] = [];
|
||||||
@ -2029,6 +2035,20 @@ export const getCalendarProgress = (inventory: TInventoryDatabaseDocument): ICal
|
|||||||
return inventory.CalendarProgress;
|
return inventory.CalendarProgress;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const checkCalendarChallengeCompletion = (
|
||||||
|
calendarProgress: ICalendarProgress,
|
||||||
|
currentSeason: ICalendarSeason
|
||||||
|
): void => {
|
||||||
|
const dayIndex = calendarProgress.SeasonProgress.LastCompletedDayIdx + 1;
|
||||||
|
if (calendarProgress.SeasonProgress.LastCompletedChallengeDayIdx >= dayIndex) {
|
||||||
|
const day = currentSeason.Days[dayIndex];
|
||||||
|
if (day.events.length != 0 && day.events[0].type == "CET_CHALLENGE") {
|
||||||
|
//logger.debug(`already completed the challenge, skipping ahead`);
|
||||||
|
calendarProgress.SeasonProgress.LastCompletedDayIdx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const giveNemesisWeaponRecipe = (
|
export const giveNemesisWeaponRecipe = (
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
weaponType: string,
|
weaponType: string,
|
||||||
|
@ -33,6 +33,7 @@ import {
|
|||||||
addSkin,
|
addSkin,
|
||||||
addStanding,
|
addStanding,
|
||||||
applyClientEquipmentUpdates,
|
applyClientEquipmentUpdates,
|
||||||
|
checkCalendarChallengeCompletion,
|
||||||
combineInventoryChanges,
|
combineInventoryChanges,
|
||||||
generateRewardSeed,
|
generateRewardSeed,
|
||||||
getCalendarProgress,
|
getCalendarProgress,
|
||||||
@ -67,7 +68,15 @@ import {
|
|||||||
} from "@/src/helpers/nemesisHelpers";
|
} from "@/src/helpers/nemesisHelpers";
|
||||||
import { Loadout } from "../models/inventoryModels/loadoutModel";
|
import { Loadout } from "../models/inventoryModels/loadoutModel";
|
||||||
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
|
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
|
||||||
import { getLiteSortie, getSortie, idToBountyCycle, idToDay, idToWeek, pushClassicBounties } from "./worldStateService";
|
import {
|
||||||
|
getLiteSortie,
|
||||||
|
getSortie,
|
||||||
|
getWorldState,
|
||||||
|
idToBountyCycle,
|
||||||
|
idToDay,
|
||||||
|
idToWeek,
|
||||||
|
pushClassicBounties
|
||||||
|
} from "./worldStateService";
|
||||||
import { config } from "./configService";
|
import { config } from "./configService";
|
||||||
import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
|
import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
|
||||||
import { ISyndicateMissionInfo } from "../types/worldStateTypes";
|
import { ISyndicateMissionInfo } from "../types/worldStateTypes";
|
||||||
@ -259,7 +268,9 @@ export const addMissionInventoryUpdates = async (
|
|||||||
addMissionComplete(inventory, value);
|
addMissionComplete(inventory, value);
|
||||||
break;
|
break;
|
||||||
case "LastRegionPlayed":
|
case "LastRegionPlayed":
|
||||||
|
if (!(config.unfaithfulBugFixes?.ignore1999LastRegionPlayed && value === "1999MapName")) {
|
||||||
inventory.LastRegionPlayed = value;
|
inventory.LastRegionPlayed = value;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "RawUpgrades":
|
case "RawUpgrades":
|
||||||
addMods(inventory, value);
|
addMods(inventory, value);
|
||||||
@ -620,12 +631,11 @@ export const addMissionInventoryUpdates = async (
|
|||||||
}
|
}
|
||||||
case "CalendarProgress": {
|
case "CalendarProgress": {
|
||||||
const calendarProgress = getCalendarProgress(inventory);
|
const calendarProgress = getCalendarProgress(inventory);
|
||||||
for (const progress of value) {
|
const currentSeason = getWorldState().KnownCalendarSeasons[0];
|
||||||
const challengeName = progress.challenge.substring(progress.challenge.lastIndexOf("/") + 1);
|
calendarProgress.SeasonProgress.LastCompletedChallengeDayIdx = currentSeason.Days.findIndex(
|
||||||
calendarProgress.SeasonProgress.LastCompletedDayIdx++;
|
x => x.events[0].challenge == value[value.length - 1].challenge
|
||||||
calendarProgress.SeasonProgress.LastCompletedChallengeDayIdx++;
|
);
|
||||||
calendarProgress.SeasonProgress.ActivatedChallenges.push(challengeName);
|
checkCalendarChallengeCompletion(calendarProgress, currentSeason);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "duviriCaveOffers": {
|
case "duviriCaveOffers": {
|
||||||
@ -1629,7 +1639,19 @@ function getRandomMissionDrops(
|
|||||||
}
|
}
|
||||||
rewardManifests = [job.rewards];
|
rewardManifests = [job.rewards];
|
||||||
if (job.xpAmounts.length > 1) {
|
if (job.xpAmounts.length > 1) {
|
||||||
rotations = [RewardInfo.JobStage! % (job.xpAmounts.length - 1)];
|
const curentStage = RewardInfo.JobStage! + 1;
|
||||||
|
const totalStage = job.xpAmounts.length;
|
||||||
|
let tableIndex = 1; // Stage 2, Stage 3 of 4, and Stage 3 of 5
|
||||||
|
|
||||||
|
if (curentStage == 1) {
|
||||||
|
tableIndex = 0;
|
||||||
|
} else if (curentStage == totalStage) {
|
||||||
|
tableIndex = 3;
|
||||||
|
} else if (totalStage == 5 && curentStage == 4) {
|
||||||
|
tableIndex = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
rotations = [tableIndex];
|
||||||
} else {
|
} else {
|
||||||
rotations = [0];
|
rotations = [0];
|
||||||
}
|
}
|
||||||
@ -1638,11 +1660,7 @@ function getRandomMissionDrops(
|
|||||||
(RewardInfo.JobStage === job.xpAmounts.length - 1 || job.isVault) &&
|
(RewardInfo.JobStage === job.xpAmounts.length - 1 || job.isVault) &&
|
||||||
!isEndlessJob
|
!isEndlessJob
|
||||||
) {
|
) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
rotations.push(3);
|
||||||
if (ExportRewards[job.rewards]) {
|
|
||||||
rewardManifests.push(job.rewards);
|
|
||||||
rotations.push(ExportRewards[job.rewards].length - 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import { Account } from "../models/loginModel";
|
|||||||
import { createAccount, createNonce, getUsernameFromEmail, isCorrectPassword } from "./loginService";
|
import { createAccount, createNonce, getUsernameFromEmail, isCorrectPassword } from "./loginService";
|
||||||
import { IDatabaseAccountJson } from "../types/loginTypes";
|
import { IDatabaseAccountJson } from "../types/loginTypes";
|
||||||
import { HydratedDocument } from "mongoose";
|
import { HydratedDocument } from "mongoose";
|
||||||
import { Agent, WebSocket } from "undici";
|
import { Agent, WebSocket as UnidiciWebSocket } from "undici";
|
||||||
|
|
||||||
let httpServer: http.Server | undefined;
|
let httpServer: http.Server | undefined;
|
||||||
let httpsServer: https.Server | undefined;
|
let httpsServer: https.Server | undefined;
|
||||||
@ -46,13 +46,9 @@ export const startWebServer = (): void => {
|
|||||||
"Access the WebUI in your browser at http://localhost" + (httpPort == 80 ? "" : ":" + httpPort)
|
"Access the WebUI in your browser at http://localhost" + (httpPort == 80 ? "" : ":" + httpPort)
|
||||||
);
|
);
|
||||||
|
|
||||||
// https://github.com/oven-sh/bun/issues/20547
|
|
||||||
if (!process.versions.bun) {
|
|
||||||
void runWsSelfTest("wss", httpsPort).then(ok => {
|
void runWsSelfTest("wss", httpsPort).then(ok => {
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
logger.warn(
|
logger.warn(`WSS self-test failed. The server may not actually be reachable at port ${httpsPort}.`);
|
||||||
`WSS self-test failed. The server may not actually be reachable at port ${httpsPort}.`
|
|
||||||
);
|
|
||||||
if (process.platform == "win32") {
|
if (process.platform == "win32") {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`You can check who actually has that port via powershell: Get-Process -Id (Get-NetTCPConnection -LocalPort ${httpsPort}).OwningProcess`
|
`You can check who actually has that port via powershell: Get-Process -Id (Get-NetTCPConnection -LocalPort ${httpsPort}).OwningProcess`
|
||||||
@ -60,21 +56,35 @@ export const startWebServer = (): void => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const runWsSelfTest = (protocol: "ws" | "wss", port: number): Promise<boolean> => {
|
const runWsSelfTest = (protocol: "ws" | "wss", port: number): Promise<boolean> => {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const agent = new Agent({ connect: { rejectUnauthorized: false } });
|
// https://github.com/oven-sh/bun/issues/20547
|
||||||
const client = new WebSocket(`${protocol}://localhost:${port}/custom/selftest`, { dispatcher: agent });
|
if (process.versions.bun) {
|
||||||
|
const client = new WebSocket(`${protocol}://localhost:${port}/custom/selftest`, {
|
||||||
|
tls: { rejectUnauthorized: false }
|
||||||
|
} as unknown as string);
|
||||||
client.onmessage = (e): void => {
|
client.onmessage = (e): void => {
|
||||||
resolve(e.data == "SpaceNinjaServer");
|
resolve(e.data == "SpaceNinjaServer");
|
||||||
};
|
};
|
||||||
client.onerror = client.onclose = (): void => {
|
client.onerror = client.onclose = (): void => {
|
||||||
resolve(false);
|
resolve(false);
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
const agent = new Agent({ connect: { rejectUnauthorized: false } });
|
||||||
|
const client = new UnidiciWebSocket(`${protocol}://localhost:${port}/custom/selftest`, {
|
||||||
|
dispatcher: agent
|
||||||
|
});
|
||||||
|
client.onmessage = (e): void => {
|
||||||
|
resolve(e.data == "SpaceNinjaServer");
|
||||||
|
};
|
||||||
|
client.onerror = client.onclose = (): void => {
|
||||||
|
resolve(false);
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1327,6 +1327,17 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
const cheeseInterval = hourInSeconds * 8;
|
const cheeseInterval = hourInSeconds * 8;
|
||||||
const cheeseDuration = hourInSeconds * 2;
|
const cheeseDuration = hourInSeconds * 2;
|
||||||
const cheeseIndex = Math.trunc(timeSecs / cheeseInterval);
|
const cheeseIndex = Math.trunc(timeSecs / cheeseInterval);
|
||||||
|
let cheeseStart = cheeseIndex * cheeseInterval;
|
||||||
|
let cheeseEnd = cheeseStart + cheeseDuration;
|
||||||
|
let cheeseNext = (cheeseIndex + 1) * cheeseInterval;
|
||||||
|
// Live servers only update the start time once it happens, which makes the
|
||||||
|
// client show a negative countdown during off-hours. Optionally adjust the
|
||||||
|
// times so the next activation is always in the future.
|
||||||
|
if (config.unfaithfulBugFixes?.fixXtraCheeseTimer && timeSecs >= cheeseEnd) {
|
||||||
|
cheeseStart = cheeseNext;
|
||||||
|
cheeseEnd = cheeseStart + cheeseDuration;
|
||||||
|
cheeseNext += cheeseInterval;
|
||||||
|
}
|
||||||
const tmp: ITmp = {
|
const tmp: ITmp = {
|
||||||
cavabegin: "1690761600",
|
cavabegin: "1690761600",
|
||||||
PurchasePlatformLockEnabled: true,
|
PurchasePlatformLockEnabled: true,
|
||||||
@ -1351,9 +1362,9 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
ennnd: true,
|
ennnd: true,
|
||||||
mbrt: true,
|
mbrt: true,
|
||||||
fbst: {
|
fbst: {
|
||||||
a: cheeseIndex * cheeseInterval, // This has a bug where the client shows a negative time for "Xtra cheese starts in ..." until it refreshes the world state. This is because we're only providing the new activation as soon as that time/date is reached. However, this is 100% faithful to live.
|
a: cheeseStart,
|
||||||
e: cheeseIndex * cheeseInterval + cheeseDuration,
|
e: cheeseEnd,
|
||||||
n: (cheeseIndex + 1) * cheeseInterval
|
n: cheeseNext
|
||||||
},
|
},
|
||||||
sfn: [550, 553, 554, 555][halfHour % 4]
|
sfn: [550, 553, 554, 555][halfHour % 4]
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user