forked from OpenWF/SpaceNinjaServer
Compare commits
3 Commits
2a7767ef4a
...
8104e2fc27
| Author | SHA1 | Date | |
|---|---|---|---|
| 8104e2fc27 | |||
| 18fafc38b5 | |||
| 98a46e51de |
@ -1,11 +1,20 @@
|
|||||||
import type { RequestHandler } from "express";
|
import type { RequestHandler } from "express";
|
||||||
import { updateShipFeature } from "../../services/personalRoomsService.ts";
|
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
||||||
import type { IUnlockShipFeatureRequest } from "../../types/requestTypes.ts";
|
import { getInventory } from "../../services/inventoryService.ts";
|
||||||
import { parseString } from "../../helpers/general.ts";
|
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
||||||
|
import { unlockShipFeature } from "../../services/personalRoomsService.ts";
|
||||||
|
|
||||||
export const unlockShipFeatureController: RequestHandler = async (req, res) => {
|
export const unlockShipFeatureController: RequestHandler = async (req, res) => {
|
||||||
const accountId = parseString(req.query.accountId);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const shipFeatureRequest = JSON.parse((req.body as string).toString()) as IUnlockShipFeatureRequest;
|
const inventory = await getInventory(accountId, "MiscItems accountOwnerId");
|
||||||
await updateShipFeature(accountId, shipFeatureRequest.Feature);
|
const request = getJSONfromString<IUnlockShipFeatureRequest>(String(req.body));
|
||||||
|
|
||||||
|
await unlockShipFeature(inventory, request.Feature);
|
||||||
|
await inventory.save();
|
||||||
res.send([]);
|
res.send([]);
|
||||||
};
|
};
|
||||||
|
interface IUnlockShipFeatureRequest {
|
||||||
|
Feature: string;
|
||||||
|
KeyChain: string;
|
||||||
|
ChainStage: number;
|
||||||
|
}
|
||||||
|
|||||||
@ -388,7 +388,7 @@ export const addItem = async (
|
|||||||
};
|
};
|
||||||
} else if (ExportResources[typeName].productCategory == "CrewShips") {
|
} else if (ExportResources[typeName].productCategory == "CrewShips") {
|
||||||
return {
|
return {
|
||||||
...addCrewShip(inventory, typeName),
|
...(await addCrewShip(inventory, typeName)),
|
||||||
// fix to unlock railjack modding, item bellow supposed to be obtained from archwing quest
|
// fix to unlock railjack modding, item bellow supposed to be obtained from archwing quest
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
...(!inventory.CrewShipHarnesses?.length
|
...(!inventory.CrewShipHarnesses?.length
|
||||||
@ -1543,17 +1543,31 @@ export const addCrewShipSalvagedWeaponSkin = (
|
|||||||
return inventoryChanges;
|
return inventoryChanges;
|
||||||
};
|
};
|
||||||
|
|
||||||
const addCrewShip = (
|
const addCrewShip = async (
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
typeName: string,
|
typeName: string,
|
||||||
inventoryChanges: IInventoryChanges = {}
|
inventoryChanges: IInventoryChanges = {}
|
||||||
): IInventoryChanges => {
|
): Promise<IInventoryChanges> => {
|
||||||
if (inventory.CrewShips.length != 0) {
|
if (inventory.CrewShips.length != 0) {
|
||||||
logger.warn("refusing to add CrewShip because account already has one");
|
logger.warn("refusing to add CrewShip because account already has one");
|
||||||
} else {
|
} else {
|
||||||
const index = inventory.CrewShips.push({ ItemType: typeName }) - 1;
|
const index = inventory.CrewShips.push({ ItemType: typeName }) - 1;
|
||||||
inventoryChanges.CrewShips ??= [];
|
inventoryChanges.CrewShips ??= [];
|
||||||
inventoryChanges.CrewShips.push(inventory.CrewShips[index].toJSON<IEquipmentClient>());
|
inventoryChanges.CrewShips.push(inventory.CrewShips[index].toJSON<IEquipmentClient>());
|
||||||
|
const railjackQuest = inventory.QuestKeys.find(
|
||||||
|
qk => qk.ItemType === "/Lotus/Types/Keys/RailJackBuildQuest/RailjackBuildQuestKeyChain"
|
||||||
|
);
|
||||||
|
if (!railjackQuest || !railjackQuest.Completed) {
|
||||||
|
const questChanges = await completeQuest(
|
||||||
|
inventory,
|
||||||
|
"/Lotus/Types/Keys/RailJackBuildQuest/RailjackBuildQuestKeyChain",
|
||||||
|
false
|
||||||
|
);
|
||||||
|
if (questChanges) {
|
||||||
|
inventoryChanges.QuestKeys ??= [];
|
||||||
|
inventoryChanges.QuestKeys.push(questChanges);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return inventoryChanges;
|
return inventoryChanges;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -243,7 +243,7 @@ export const addMissionInventoryUpdates = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (inventoryUpdates.MissionStatus == "GS_SUCCESS" && inventoryUpdates.RewardInfo.jobId) {
|
if (inventoryUpdates.RewardInfo.jobId) {
|
||||||
// e.g. for Profit-Taker Phase 1:
|
// e.g. for Profit-Taker Phase 1:
|
||||||
// JobTier: -6,
|
// JobTier: -6,
|
||||||
// jobId: '/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyOne_-6_SolarisUnitedHub1_663a71c80000000000000025_EudicoHeists',
|
// jobId: '/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyOne_-6_SolarisUnitedHub1_663a71c80000000000000025_EudicoHeists',
|
||||||
@ -251,7 +251,10 @@ export const addMissionInventoryUpdates = async (
|
|||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const [bounty, tier, hub, id, tag] = inventoryUpdates.RewardInfo.jobId.split("_");
|
const [bounty, tier, hub, id, tag] = inventoryUpdates.RewardInfo.jobId.split("_");
|
||||||
if (tag == "EudicoHeists") {
|
if (
|
||||||
|
(tag == "EudicoHeists" && inventoryUpdates.MissionStatus == "GS_SUCCESS") ||
|
||||||
|
(tag == "NokkoColony" && inventoryUpdates.RewardInfo.JobStage == 4)
|
||||||
|
) {
|
||||||
inventory.CompletedJobChains ??= [];
|
inventory.CompletedJobChains ??= [];
|
||||||
let chain = inventory.CompletedJobChains.find(x => x.LocationTag == tag);
|
let chain = inventory.CompletedJobChains.find(x => x.LocationTag == tag);
|
||||||
if (!chain) {
|
if (!chain) {
|
||||||
@ -1126,7 +1129,8 @@ export const addMissionRewards = async (
|
|||||||
RegularCredits: creditDrops,
|
RegularCredits: creditDrops,
|
||||||
VoidTearParticipantsCurrWave: voidTearWave,
|
VoidTearParticipantsCurrWave: voidTearWave,
|
||||||
StrippedItems: strippedItems,
|
StrippedItems: strippedItems,
|
||||||
AffiliationChanges: AffiliationMods
|
AffiliationChanges: AffiliationMods,
|
||||||
|
InvasionProgress: invasionProgress
|
||||||
}: IMissionInventoryUpdateRequest,
|
}: IMissionInventoryUpdateRequest,
|
||||||
firstCompletion: boolean
|
firstCompletion: boolean
|
||||||
): Promise<AddMissionRewardsReturnType> => {
|
): Promise<AddMissionRewardsReturnType> => {
|
||||||
@ -1176,6 +1180,19 @@ export const addMissionRewards = async (
|
|||||||
|
|
||||||
//inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display
|
//inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display
|
||||||
|
|
||||||
|
if (invasionProgress) {
|
||||||
|
for (const clientProgress of invasionProgress) {
|
||||||
|
const dbProgress = inventory.QualifyingInvasions.find(x => x.invasionId.equals(clientProgress._id.$oid));
|
||||||
|
if (dbProgress) {
|
||||||
|
const run =
|
||||||
|
(clientProgress.AttackerScore > clientProgress.DefenderScore
|
||||||
|
? dbProgress.AttackerScore
|
||||||
|
: dbProgress.DefenderScore) - 1;
|
||||||
|
missionCompletionCredits += 1000 * Math.min(run, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (rewardInfo.goalId) {
|
if (rewardInfo.goalId) {
|
||||||
const goal = getWorldState().Goals.find(x => x._id.$oid == rewardInfo.goalId);
|
const goal = getWorldState().Goals.find(x => x._id.$oid == rewardInfo.goalId);
|
||||||
if (goal) {
|
if (goal) {
|
||||||
@ -1500,7 +1517,7 @@ export const addMissionRewards = async (
|
|||||||
syndicateEntry = Goals.find(m => m._id.$oid === syndicateMissionId);
|
syndicateEntry = Goals.find(m => m._id.$oid === syndicateMissionId);
|
||||||
if (syndicateEntry) syndicateEntry.Tag = syndicateEntry.JobAffiliationTag!;
|
if (syndicateEntry) syndicateEntry.Tag = syndicateEntry.JobAffiliationTag!;
|
||||||
}
|
}
|
||||||
if (syndicateEntry && syndicateEntry.Jobs) {
|
if (syndicateEntry && syndicateEntry.Jobs && !jobType.startsWith("/Lotus/Types/Gameplay/NokkoColony/Jobs")) {
|
||||||
let currentJob = syndicateEntry.Jobs[rewardInfo.JobTier!];
|
let currentJob = syndicateEntry.Jobs[rewardInfo.JobTier!];
|
||||||
if (
|
if (
|
||||||
[
|
[
|
||||||
@ -2008,6 +2025,17 @@ function getRandomMissionDrops(
|
|||||||
xpAmounts: [1000]
|
xpAmounts: [1000]
|
||||||
};
|
};
|
||||||
RewardInfo.Q = false; // Just in case
|
RewardInfo.Q = false; // Just in case
|
||||||
|
} else if (jobType.startsWith("/Lotus/Types/Gameplay/NokkoColony/Jobs/NokkoJob")) {
|
||||||
|
job = {
|
||||||
|
rewards: jobType.replace(
|
||||||
|
"/Lotus/Types/Gameplay/NokkoColony/Jobs/NokkoJob",
|
||||||
|
"Lotus/Types/Game/MissionDecks/NokkoColonyRewards/NokkoColonyRewards"
|
||||||
|
),
|
||||||
|
masteryReq: 0,
|
||||||
|
minEnemyLevel: 30,
|
||||||
|
maxEnemyLevel: 40,
|
||||||
|
xpAmounts: [0, 0, 0, 0, 0]
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
const tierMap = {
|
const tierMap = {
|
||||||
Two: "B",
|
Two: "B",
|
||||||
@ -2051,14 +2079,18 @@ function getRandomMissionDrops(
|
|||||||
} else if (totalStage == 5 && curentStage == 4) {
|
} else if (totalStage == 5 && curentStage == 4) {
|
||||||
tableIndex = 2;
|
tableIndex = 2;
|
||||||
}
|
}
|
||||||
|
if (jobType.startsWith("/Lotus/Types/Gameplay/NokkoColony/Jobs/NokkoJob")) {
|
||||||
rotations = [tableIndex];
|
if (RewardInfo.JobStage === job.xpAmounts.length - 1) rotations = [0, 1, 2];
|
||||||
|
} else {
|
||||||
|
rotations = [tableIndex];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
rotations = [0];
|
rotations = [0];
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
RewardInfo.Q &&
|
RewardInfo.Q &&
|
||||||
(RewardInfo.JobStage === job.xpAmounts.length - 1 || jobType.endsWith("VaultBounty")) &&
|
(RewardInfo.JobStage === job.xpAmounts.length - 1 || jobType.endsWith("VaultBounty")) &&
|
||||||
|
!jobType.startsWith("/Lotus/Types/Gameplay/NokkoColony/Jobs/NokkoJob") &&
|
||||||
!isEndlessJob
|
!isEndlessJob
|
||||||
) {
|
) {
|
||||||
rotations.push(ExportRewards[job.rewards].length - 1);
|
rotations.push(ExportRewards[job.rewards].length - 1);
|
||||||
@ -2149,22 +2181,24 @@ function getRandomMissionDrops(
|
|||||||
logger.warn(`RewardSeed mismatch:`, { client: RewardInfo.rewardSeed, database: inventory.RewardSeed });
|
logger.warn(`RewardSeed mismatch:`, { client: RewardInfo.rewardSeed, database: inventory.RewardSeed });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const rng = new SRng(BigInt(RewardInfo.rewardSeed ?? generateRewardSeed()) ^ 0xffffffffffffffffn);
|
if (rotations.length > 1) {
|
||||||
rewardManifests.forEach(name => {
|
const rng = new SRng(BigInt(RewardInfo.rewardSeed ?? generateRewardSeed()) ^ 0xffffffffffffffffn);
|
||||||
const table = ExportRewards[name];
|
rewardManifests.forEach(name => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
const table = ExportRewards[name];
|
||||||
if (!table) {
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
logger.error(`unknown droptable: ${name}`);
|
if (!table) {
|
||||||
return;
|
logger.error(`unknown droptable: ${name}`);
|
||||||
}
|
return;
|
||||||
for (const rotation of rotations) {
|
|
||||||
const rotationRewards = table[rotation];
|
|
||||||
const drop = getRandomRewardByChance(rotationRewards, rng);
|
|
||||||
if (drop) {
|
|
||||||
drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount });
|
|
||||||
}
|
}
|
||||||
}
|
for (const rotation of rotations) {
|
||||||
});
|
const rotationRewards = table[rotation];
|
||||||
|
const drop = getRandomRewardByChance(rotationRewards, rng);
|
||||||
|
if (drop) {
|
||||||
|
drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Railjack Abandoned Cache Rewards, Rotation A (Mandatory Objectives)
|
// Railjack Abandoned Cache Rewards, Rotation A (Mandatory Objectives)
|
||||||
if (RewardInfo.POICompletions) {
|
if (RewardInfo.POICompletions) {
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import { PersonalRooms } from "../models/personalRoomsModel.ts";
|
import { PersonalRooms } from "../models/personalRoomsModel.ts";
|
||||||
import { addItem, getInventory } from "./inventoryService.ts";
|
import { addItem } from "./inventoryService.ts";
|
||||||
import type { IGardeningDatabase, TPersonalRoomsDatabaseDocument } from "../types/personalRoomsTypes.ts";
|
import type { IGardeningDatabase, TPersonalRoomsDatabaseDocument } from "../types/personalRoomsTypes.ts";
|
||||||
import { getRandomElement } from "./rngService.ts";
|
import { getRandomElement } from "./rngService.ts";
|
||||||
|
import type { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel.ts";
|
||||||
|
import { logger } from "../utils/logger.ts";
|
||||||
|
|
||||||
export const getPersonalRooms = async (
|
export const getPersonalRooms = async (
|
||||||
accountId: string,
|
accountId: string,
|
||||||
@ -15,19 +17,17 @@ export const getPersonalRooms = async (
|
|||||||
return personalRooms;
|
return personalRooms;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateShipFeature = async (accountId: string, shipFeature: string): Promise<void> => {
|
export const unlockShipFeature = async (inventory: TInventoryDatabaseDocument, shipFeature: string): Promise<void> => {
|
||||||
const personalRooms = await getPersonalRooms(accountId);
|
const personalRooms = await getPersonalRooms(inventory.accountOwnerId.toString());
|
||||||
|
|
||||||
if (personalRooms.Ship.Features.includes(shipFeature)) {
|
if (personalRooms.Ship.Features.includes(shipFeature)) {
|
||||||
throw new Error(`ship feature ${shipFeature} already unlocked`);
|
logger.warn(`ship feature ${shipFeature} already unlocked`);
|
||||||
|
} else {
|
||||||
|
personalRooms.Ship.Features.push(shipFeature);
|
||||||
|
await personalRooms.save();
|
||||||
}
|
}
|
||||||
|
const miscItem = inventory.MiscItems.find(x => x.ItemType === shipFeature);
|
||||||
personalRooms.Ship.Features.push(shipFeature);
|
if (miscItem && miscItem.ItemCount > 0) await addItem(inventory, shipFeature, miscItem.ItemCount * -1);
|
||||||
await personalRooms.save();
|
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
await addItem(inventory, shipFeature, -1);
|
|
||||||
await inventory.save();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createGarden = (): IGardeningDatabase => {
|
export const createGarden = (): IGardeningDatabase => {
|
||||||
|
|||||||
@ -120,7 +120,7 @@ export const completeQuest = async (
|
|||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
questKey: string,
|
questKey: string,
|
||||||
sendMessages: boolean = false
|
sendMessages: boolean = false
|
||||||
): Promise<void> => {
|
): Promise<void | IQuestKeyClient> => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
const chainStages = ExportKeys[questKey]?.chainStages;
|
const chainStages = ExportKeys[questKey]?.chainStages;
|
||||||
|
|
||||||
@ -176,6 +176,8 @@ export const completeQuest = async (
|
|||||||
existingQuestKey.CompletionDate = new Date();
|
existingQuestKey.CompletionDate = new Date();
|
||||||
await handleQuestCompletion(inventory, questKey, undefined, run > 0);
|
await handleQuestCompletion(inventory, questKey, undefined, run > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return existingQuestKey.toJSON<IQuestKeyClient>();
|
||||||
};
|
};
|
||||||
|
|
||||||
const getQuestCompletionItems = (questKey: string): ITypeCount[] | undefined => {
|
const getQuestCompletionItems = (questKey: string): ITypeCount[] | undefined => {
|
||||||
|
|||||||
@ -9,7 +9,8 @@ import type {
|
|||||||
TEquipmentKey,
|
TEquipmentKey,
|
||||||
ICrewMemberClient,
|
ICrewMemberClient,
|
||||||
IKubrowPetPrintClient,
|
IKubrowPetPrintClient,
|
||||||
IUpgradeClient
|
IUpgradeClient,
|
||||||
|
IQuestKeyClient
|
||||||
} from "./inventoryTypes/inventoryTypes.ts";
|
} from "./inventoryTypes/inventoryTypes.ts";
|
||||||
|
|
||||||
export enum PurchaseSource {
|
export enum PurchaseSource {
|
||||||
@ -83,6 +84,7 @@ export type IInventoryChanges = {
|
|||||||
CrewMembers?: ICrewMemberClient[];
|
CrewMembers?: ICrewMemberClient[];
|
||||||
KubrowPetPrints?: IKubrowPetPrintClient[];
|
KubrowPetPrints?: IKubrowPetPrintClient[];
|
||||||
Upgrades?: IUpgradeClient[]; // TOVERIFY
|
Upgrades?: IUpgradeClient[]; // TOVERIFY
|
||||||
|
QuestKeys?: IQuestKeyClient[];
|
||||||
} & Record<
|
} & Record<
|
||||||
Exclude<
|
Exclude<
|
||||||
string,
|
string,
|
||||||
|
|||||||
@ -234,11 +234,6 @@ export interface IUpgradeOperation {
|
|||||||
PolarizeValue: ArtifactPolarity;
|
PolarizeValue: ArtifactPolarity;
|
||||||
PolarityRemap: IPolarity[];
|
PolarityRemap: IPolarity[];
|
||||||
}
|
}
|
||||||
export interface IUnlockShipFeatureRequest {
|
|
||||||
Feature: string;
|
|
||||||
KeyChain: string;
|
|
||||||
ChainStage: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IVoidTearParticipantInfo {
|
export interface IVoidTearParticipantInfo {
|
||||||
AccountId: string;
|
AccountId: string;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user