返回提交历史
Modified
src/controllers/custom/unlockAllScansController.ts
+13
-2
Modified
src/models/inventoryModels/inventoryModel.ts
+2
-0
Modified
src/services/importService.ts
+4
-1
Modified
src/services/inventoryService.ts
+40
-0
Modified
src/services/missionInventoryUpdateService.ts
+5
-0
Modified
src/types/inventoryTypes/inventoryTypes.ts
+2
-1
XFEstudio/XFESpaceNinjaServer
feat: thousand-year fish (#3949)
Closes #3933 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3949 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
cba2c9fd
代码差异
6 个文件
+66
-4
@@ -3,7 +3,12 @@ import allScans from "../../../static/fixed_responses/allScans.json" with { type
3
3
import { ExportCodex, ExportEnemies } from "warframe-public-export-plus";
4
4
import { getAccountIdForRequest } from "../../services/loginService.ts";
5
5
import { getStats } from "../../services/statsService.ts";
6
import { addShipDecorations, getInventory, updateIncentiveStates } from "../../services/inventoryService.ts";
6
import {
7
addShipDecorations,
8
getInventory,
9
giveThousandYearFishDeco,
10
updateIncentiveStates
11
} from "../../services/inventoryService.ts";
7
12
import { getShipDecoByNameTag } from "../../services/itemDataService.ts";
8
13
import { broadcastInventoryUpdate } from "../../services/wsService.ts";
9
14
@@ -11,7 +16,10 @@ export const unlockAllScansController: RequestHandler = async (req, res) => {
11
16
const accountId = await getAccountIdForRequest(req);
12
17
const [stats, inventory] = await Promise.all([
13
18
getStats(accountId),
14
getInventory(accountId, "ChallengeProgress CollectibleSeries LoreFragmentScans ShipDecorations")
19
getInventory(
20
accountId,
21
"ChallengeProgress CollectibleSeries LoreFragmentScans ShipDecorations receivedThousandYearFishDeco accountOwnerId"
22
)
15
23
]);
16
24
17
25
// Unlock all enemy & object scans
@@ -158,6 +166,9 @@ export const unlockAllScansController: RequestHandler = async (req, res) => {
158
166
ItemType
159
167
});
160
168
}
169
if (!inventory.receivedThousandYearFishDeco) {
170
await giveThousandYearFishDeco(inventory); // needs accountOwnerId
171
}
161
172
162
173
await Promise.all([stats.save(), inventory.save()]);
163
174
res.end();
@@ -1753,6 +1753,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
1753
1753
Ships: { type: [Schema.Types.ObjectId], ref: "Ships" },
1754
1754
// /Lotus/Types/Items/ShipDecos/
1755
1755
ShipDecorations: [typeCountSchema],
1756
receivedThousandYearFishDeco: Boolean,
1756
1757
1757
1758
//Railjack/Components(https://warframe.fandom.com/wiki/Railjack/Components)
1758
1759
CrewShipRawSalvage: [typeCountSchema],
@@ -2037,6 +2038,7 @@ inventorySchema.set("toJSON", {
2037
2038
delete returnedObject.NemesisTaxedCredits;
2038
2039
delete returnedObject.duviriSeedRefresh;
2039
2040
delete returnedObject.HybridFusionTreasures;
2041
delete returnedObject.receivedThousandYearFishDeco;
2040
2042
2041
2043
const inventoryDatabase = returnedObject as Partial<IInventoryDatabase>;
2042
2044
const inventoryResponse = returnedObject as IInventoryClient;
@@ -88,7 +88,7 @@ import type {
88
88
import { fromMongoDate, fromOid } from "../helpers/inventoryHelpers.ts";
89
89
import { getRecipe } from "./itemDataService.ts";
90
90
import { logger } from "../utils/logger.ts";
91
import { migrateFusionTreasures } from "./inventoryService.ts";
91
import { isEligibleForThousandYearFishDeco, migrateFusionTreasures } from "./inventoryService.ts";
92
92
93
93
const convertOptionalDate = (value: IMongoDateWithLegacySupport | undefined): Date | undefined => {
94
94
return value ? fromMongoDate(value) : undefined;
@@ -506,6 +506,9 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
506
506
}
507
507
if (client.LoreFragmentScans !== undefined) {
508
508
db.LoreFragmentScans = client.LoreFragmentScans;
509
if (!db.receivedThousandYearFishDeco && isEligibleForThousandYearFishDeco(db)) {
510
db.receivedThousandYearFishDeco = true;
511
}
509
512
}
510
513
for (const key of ["PendingSpectreLoadouts", "SpectreLoadouts"] as const) {
511
514
if (client[key] !== undefined) {
@@ -3099,6 +3099,46 @@ export const updateEntratiVault = (inventory: TInventoryDatabaseDocument): void
3099
3099
}
3100
3100
};
3101
3101
3102
export const isEligibleForThousandYearFishDeco = (inventory: TInventoryDatabaseDocument): boolean => {
3103
const lfsTypes = new Set<string>(inventory.LoreFragmentScans.map(x => x.ItemType));
3104
return (
3105
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentA") &&
3106
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentB") &&
3107
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentC") &&
3108
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentD") &&
3109
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentE") &&
3110
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentF") &&
3111
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentG") &&
3112
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentH") &&
3113
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentI") &&
3114
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentJ") &&
3115
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentK") &&
3116
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentL") &&
3117
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentM") &&
3118
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentN") &&
3119
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentO") &&
3120
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentP") &&
3121
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentQ") &&
3122
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentR") &&
3123
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentS") &&
3124
lfsTypes.has("/Lotus/Types/Lore/Fragments/EidolonFragments/EidolonFragmentT")
3125
);
3126
};
3127
3128
export const giveThousandYearFishDeco = async (inventory: TInventoryDatabaseDocument): Promise<void> => {
3129
inventory.receivedThousandYearFishDeco = true;
3130
await createMessage(inventory.accountOwnerId, [
3131
{
3132
sndr: "/Lotus/Language/Npcs/Onkko",
3133
icon: "/Lotus/Interface/Icons/Npcs/Ostron/Onkko.png",
3134
sub: "/Lotus/Language/Messages/EidolonCollectibleRewardTitle",
3135
msg: "/Lotus/Language/Messages/EidolonCollectibleRewardBody",
3136
att: ["/Lotus/Types/Items/ShipDecos/LisetPropOstStoneFish"],
3137
highPriority: true
3138
}
3139
]);
3140
};
3141
3102
3142
export const ensureUserHasFounderHonoria = async (inventory: TInventoryDatabaseDocument): Promise<void> => {
3103
3143
if (!inventory.FlavourItems.some(x => x.ItemType == "/Lotus/Types/Items/Titles/FounderLvl1Title")) {
3104
3144
const eligibleItems = [
@@ -47,6 +47,8 @@ import {
47
47
getDialogue,
48
48
giveNemesisPetRecipe,
49
49
giveNemesisWeaponRecipe,
50
giveThousandYearFishDeco,
51
isEligibleForThousandYearFishDeco,
50
52
updateCurrency,
51
53
updateEntratiVault,
52
54
updateIncentiveStates,
@@ -476,6 +478,9 @@ export const addMissionInventoryUpdates = async (
476
478
}
477
479
case "LoreFragmentScans":
478
480
addLoreFragmentScans(inventory, value);
481
if (!inventory.receivedThousandYearFishDeco && isEligibleForThousandYearFishDeco(inventory)) {
482
await giveThousandYearFishDeco(inventory);
483
}
479
484
break;
480
485
case "LibraryScans":
481
486
value.forEach(scan => {
@@ -167,6 +167,8 @@ export interface IInventoryDatabase
167
167
DeathSquadPoints?: number;
168
168
NemesisTaxedCredits?: number;
169
169
duviriSeedRefresh?: Date;
170
HybridFusionTreasures: IHybridFusionTreasure[]; // SNS-specific in-database format to support both modern & legacy clients
171
receivedThousandYearFishDeco?: true; // placed decos are not in inventory, hence this boolean
170
172
171
173
Created: Date;
172
174
CurrentLoadOutIds: Types.ObjectId[];
@@ -211,7 +213,6 @@ export interface IInventoryDatabase
211
213
ChallengeInstanceStates?: IChallengeInstanceStateDatabase[];
212
214
PeriodicMissionCompletions: IPeriodicMissionCompletionDatabase[];
213
215
FusionTreasures?: IFusionTreasure[];
214
HybridFusionTreasures: IHybridFusionTreasure[]; // SNS-specific in-database format to support both modern & legacy clients
215
216
}
216
217
217
218
export interface IQuestKeyDatabase {