返回提交历史
Modified
config.json
+1
-1
Added
src/controllers/api/artifactsController.ts
+23
-0
Modified
src/controllers/api/missionInventoryUpdateController.ts
+36
-9
Modified
src/models/inventoryModel.ts
+32
-4
Modified
src/routes/api.ts
+2
-0
Modified
src/services/inventoryService.ts
+131
-26
Added
src/services/missionInventoryUpdateService .ts
+249
-0
Modified
src/types/genericUpdate.ts
+1
-1
Modified
src/types/inventoryTypes/inventoryTypes.ts
+5
-8
Modified
src/types/missionInventoryUpdateType.ts
+38
-1
Modified
src/types/session.ts
+1
-0
Modified
static/data/items.ts
+43
-1
Added
static/json/missions-drop-table.json
+1
-0
Added
static/json/scripts/missions-drop-table-get-script.js
+30
-0
XFEstudio/SpaceNinjaServer
MissionInventoryUpdate(not completed), Mod upgrade, Booster purchase (#49)
Co-authored-by: OrdisPrime <134585663+OrdisPrime@users.noreply.github.com> Co-authored-by: Ângelo Tadeucci <angelo_tadeucci@hotmail.com.br>
01cfecd9
代码差异
14 个文件
+593
-51
@@ -8,4 +8,4 @@
8
8
"skipTutorial": true,
9
9
"testMission": true,
10
10
"testQuestKey": true
11
}
11
}
@@ -0,0 +1,23 @@
1
import { upgradeMod } from "@/src/services/inventoryService";
2
import { RequestHandler } from "express";
3
4
// eslint-disable-next-line @typescript-eslint/no-misused-promises
5
const artifactsController: RequestHandler = async (req, res) => {
6
const [data] = String(req.body).split("\n");
7
const id = req.query.accountId as string;
8
9
// TODO - salt check
10
11
try {
12
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
13
const parsedData = JSON.parse(data);
14
15
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
16
const upgradeModId = await upgradeMod(parsedData, id);
17
res.send(upgradeModId);
18
} catch (err) {
19
console.error("Error parsing JSON data:", err);
20
}
21
};
22
23
export { artifactsController };
@@ -1,7 +1,9 @@
1
1
import { RequestHandler } from "express";
2
2
import { missionInventoryUpdate } from "@/src/services/inventoryService";
3
import { combineRewardAndLootInventory, getRewards } from "@/src/services/missionInventoryUpdateService ";
3
4
import { IMissionInventoryUpdate } from "@/src/types/missionInventoryUpdateType";
4
5
/*
6
**** INPUT ****
5
7
- [ ] crossPlaySetting
6
8
- [ ] rewardsMultiplier
7
9
- [ ] ActiveBoosters
@@ -27,7 +29,7 @@ import { IMissionInventoryUpdate } from "@/src/types/missionInventoryUpdateType"
27
29
- [ ] SeasonChallengeHistory
28
30
- [ ] PS (Passive anti-cheat data which includes your username, module list, process list, and system name.)
29
31
- [ ] ActiveDojoColorResearch
30
- [ ] RewardInfo
32
- [x] RewardInfo
31
33
- [ ] ReceivedCeremonyMsg
32
34
- [ ] LastCeremonyResetDate
33
35
- [ ] MissionPTS (Used to validate the mission/alive time above.)
@@ -42,20 +44,45 @@ import { IMissionInventoryUpdate } from "@/src/types/missionInventoryUpdateType"
42
44
43
45
// eslint-disable-next-line @typescript-eslint/no-misused-promises
44
46
const missionInventoryUpdateController: RequestHandler = async (req, res) => {
45
const id = req.query.accountId as string;
46
47
47
const [data] = String(req.body).split("\n");
48
const id = req.query.accountId as string;
48
49
49
50
try {
50
const parsedData = JSON.parse(data) as IMissionInventoryUpdate;
51
if (typeof parsedData !== "object") throw new Error("Invalid data format");
52
await missionInventoryUpdate(parsedData, id);
51
const lootInventory = JSON.parse(data) as IMissionInventoryUpdate;
52
if (typeof lootInventory !== "object" || lootInventory === null) {
53
throw new Error("Invalid data format");
54
}
55
56
const { InventoryChanges, MissionRewards } = getRewards(lootInventory.RewardInfo);
57
58
const { combinedInventoryChanges, TotalCredits, CreditsBonus, MissionCredits, FusionPoints } =
59
combineRewardAndLootInventory(InventoryChanges, lootInventory);
60
61
// eslint-disable-next-line @typescript-eslint/no-unused-vars
62
const InventoryJson = JSON.stringify(await missionInventoryUpdate(combinedInventoryChanges, id));
63
res.json({
64
// InventoryJson, // this part will reset game data and missions will be locked
65
MissionRewards,
66
InventoryChanges,
67
TotalCredits,
68
CreditsBonus,
69
MissionCredits,
70
...(FusionPoints !== undefined && { FusionPoints })
71
});
53
72
} catch (err) {
54
73
console.error("Error parsing JSON data:", err);
55
74
}
56
57
// TODO - Return the updated inventory the way the game does it.
58
res.json({});
59
75
};
60
76
77
/*
78
**** OUTPUT ****
79
- [x] InventoryJson
80
- [x] MissionRewards
81
- [x] TotalCredits
82
- [x] CreditsBonus
83
- [x] MissionCredits
84
- [x] InventoryChanges
85
- [x] FusionPoints
86
*/
87
61
88
export { missionInventoryUpdateController };
@@ -7,7 +7,7 @@ import {
7
7
IBooster
8
8
} from "../types/inventoryTypes/inventoryTypes";
9
9
import { IOid } from "../types/commonTypes";
10
import { ISuitDatabase, ISuitDocument } from "@/src/types/inventoryTypes/SuitTypes";
10
import { ISuitDatabase } from "@/src/types/inventoryTypes/SuitTypes";
11
11
import { IWeaponDatabase } from "@/src/types/inventoryTypes/weaponTypes";
12
12
13
13
const abilityOverrideSchema = new Schema({
@@ -77,6 +77,34 @@ const BoosterSchema = new Schema({
77
77
ItemType: String
78
78
});
79
79
80
const RawUpgrades = new Schema({
81
ItemType: String,
82
ItemCount: Number
83
});
84
85
RawUpgrades.set("toJSON", {
86
transform(_document, returnedObject) {
87
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
88
returnedObject.LastAdded = { $oid: returnedObject._id.toString() } satisfies IOid;
89
delete returnedObject._id;
90
delete returnedObject.__v;
91
}
92
});
93
94
const Upgrade = new Schema({
95
UpgradeFingerprint: String,
96
ItemType: String
97
});
98
99
Upgrade.set("toJSON", {
100
transform(_document, returnedObject) {
101
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
102
returnedObject.ItemId = { $oid: returnedObject._id.toString() } satisfies IOid;
103
delete returnedObject._id;
104
delete returnedObject.__v;
105
}
106
});
107
80
108
WeaponSchema.set("toJSON", {
81
109
transform(_document, returnedObject) {
82
110
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
@@ -187,7 +215,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
187
215
MiscItems: [Schema.Types.Mixed],
188
216
ChallengesFixVersion: Number,
189
217
ChallengeProgress: [Schema.Types.Mixed],
190
RawUpgrades: [Schema.Types.Mixed],
218
RawUpgrades: [RawUpgrades],
191
219
ReceivedStartingGear: Boolean,
192
220
Suits: [suitSchema],
193
221
LongGuns: [WeaponSchema],
@@ -209,7 +237,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>({
209
237
PendingRecipes: [Schema.Types.Mixed],
210
238
TrainingDate: Schema.Types.Mixed,
211
239
PlayerLevel: Number,
212
Upgrades: [Schema.Types.Mixed],
240
Upgrades: [Upgrade],
213
241
EquippedGear: [String],
214
242
DeathMarks: [String],
215
243
FusionTreasures: [Schema.Types.Mixed],
@@ -350,7 +378,7 @@ type InventoryDocumentProps = {
350
378
Boosters: Types.DocumentArray<IBooster>;
351
379
};
352
380
353
type InventoryModelType = Model<IInventoryDatabase, {}, InventoryDocumentProps>;
381
type InventoryModelType = Model<IInventoryDatabase, object, InventoryDocumentProps>;
354
382
355
383
const Inventory = model<IInventoryDatabase, InventoryModelType>("Inventory", inventorySchema);
356
384
@@ -29,6 +29,7 @@ import { updateSessionGetController, updateSessionPostController } from "@/src/c
29
29
import { viewController } from "@/src/controllers/api/viewController";
30
30
import { joinSessionController } from "@/src/controllers/api/joinSessionController";
31
31
import { saveLoadoutController } from "@/src/controllers/api/saveLoadout";
32
import { artifactsController } from "../controllers/api/artifactsController";
32
33
33
34
import express from "express";
34
35
@@ -58,6 +59,7 @@ apiRouter.get("/deleteSession.php", deleteSessionController);
58
59
apiRouter.get("/logout.php", logoutController);
59
60
60
61
// post
62
apiRouter.post("/artifacts.php", artifactsController);
61
63
apiRouter.post("/findSessions.php", findSessionsController);
62
64
// eslint-disable-next-line @typescript-eslint/no-misused-promises
63
65
apiRouter.post("/purchase.php", purchaseController);
@@ -7,15 +7,14 @@ import { SlotType } from "@/src/types/purchaseTypes";
7
7
import { IWeaponResponse } from "@/src/types/inventoryTypes/weaponTypes";
8
8
import {
9
9
IChallengeProgress,
10
IConsumable,
11
ICrewShipSalvagedWeaponSkin,
10
12
IFlavourItem,
11
IInventoryDatabaseDocument
13
IInventoryDatabaseDocument,
14
IMiscItem,
15
IRawUpgrade
12
16
} from "@/src/types/inventoryTypes/inventoryTypes";
13
import {
14
IMissionInventoryUpdate,
15
IMissionInventoryUpdateCard,
16
IMissionInventoryUpdateGear,
17
IMissionInventoryUpdateItem
18
} from "../types/missionInventoryUpdateType";
17
import { IMissionInventoryUpdate, IMissionInventoryUpdateGear } from "../types/missionInventoryUpdateType";
19
18
import { IGenericUpdate } from "../types/genericUpdate";
20
19
21
20
const createInventory = async (accountOwnerId: Types.ObjectId) => {
@@ -146,7 +145,7 @@ const addGearExpByCategory = (
146
145
const category = inventory[categoryName];
147
146
148
147
gearArray?.forEach(({ ItemId, XP }) => {
149
const itemIndex = category.findIndex(i => i._id?.equals(ItemId.$oid));
148
const itemIndex = category.findIndex(item => item._id?.equals(ItemId.$oid));
150
149
const item = category[itemIndex];
151
150
152
151
if (itemIndex !== -1 && item.XP != undefined) {
@@ -156,21 +155,61 @@ const addGearExpByCategory = (
156
155
});
157
156
};
158
157
159
const addItemsByCategory = (
160
inventory: IInventoryDatabaseDocument,
161
itemsArray: (IMissionInventoryUpdateItem | IMissionInventoryUpdateCard)[] | undefined,
162
categoryName: "RawUpgrades" | "MiscItems"
163
) => {
164
const category = inventory[categoryName];
158
const addMiscItems = (inventory: IInventoryDatabaseDocument, itemsArray: IMiscItem[] | undefined) => {
159
const { MiscItems } = inventory;
160
161
itemsArray?.forEach(({ ItemCount, ItemType }) => {
162
const itemIndex = MiscItems.findIndex(miscItem => miscItem.ItemType === ItemType);
163
164
if (itemIndex !== -1) {
165
MiscItems[itemIndex].ItemCount += ItemCount;
166
inventory.markModified(`MiscItems.${itemIndex}.ItemCount`);
167
} else {
168
MiscItems.push({ ItemCount, ItemType });
169
}
170
});
171
};
172
173
const addConsumables = (inventory: IInventoryDatabaseDocument, itemsArray: IConsumable[] | undefined) => {
174
const { Consumables } = inventory;
165
175
166
176
itemsArray?.forEach(({ ItemCount, ItemType }) => {
167
const itemIndex = category.findIndex(i => i.ItemType === ItemType);
177
const itemIndex = Consumables.findIndex(i => i.ItemType === ItemType);
178
179
if (itemIndex !== -1) {
180
Consumables[itemIndex].ItemCount += ItemCount;
181
inventory.markModified(`Consumables.${itemIndex}.ItemCount`);
182
} else {
183
Consumables.push({ ItemCount, ItemType });
184
}
185
});
186
};
187
188
const addRecipes = (inventory: IInventoryDatabaseDocument, itemsArray: IConsumable[] | undefined) => {
189
const { Recipes } = inventory;
190
191
itemsArray?.forEach(({ ItemCount, ItemType }) => {
192
const itemIndex = Recipes.findIndex(i => i.ItemType === ItemType);
193
194
if (itemIndex !== -1) {
195
Recipes[itemIndex].ItemCount += ItemCount;
196
inventory.markModified(`Recipes.${itemIndex}.ItemCount`);
197
} else {
198
Recipes.push({ ItemCount, ItemType });
199
}
200
});
201
};
202
203
const addMods = (inventory: IInventoryDatabaseDocument, itemsArray: IRawUpgrade[] | undefined) => {
204
const { RawUpgrades } = inventory;
205
itemsArray?.forEach(({ ItemType, ItemCount }) => {
206
const itemIndex = RawUpgrades.findIndex(i => i.ItemType === ItemType);
168
207
169
208
if (itemIndex !== -1) {
170
category[itemIndex].ItemCount += ItemCount;
171
inventory.markModified(`${categoryName}.${itemIndex}.ItemCount`);
209
RawUpgrades[itemIndex].ItemCount += ItemCount;
210
inventory.markModified(`RawUpgrades.${itemIndex}.ItemCount`);
172
211
} else {
173
category.push({ ItemCount, ItemType });
212
RawUpgrades.push({ ItemCount, ItemType });
174
213
}
175
214
});
176
215
};
@@ -193,20 +232,28 @@ const addChallenges = (inventory: IInventoryDatabaseDocument, itemsArray: IChall
193
232
const gearKeys = ["Suits", "Pistols", "LongGuns", "Melee"] as const;
194
233
type GearKeysType = (typeof gearKeys)[number];
195
234
196
export const missionInventoryUpdate = async (data: IMissionInventoryUpdate, accountId: string): Promise<void> => {
197
const { RawUpgrades, MiscItems, RegularCredits, ChallengeProgress } = data;
235
export const missionInventoryUpdate = async (data: IMissionInventoryUpdate, accountId: string) => {
236
const { RawUpgrades, MiscItems, RegularCredits, ChallengeProgress, FusionPoints, Consumables, Recipes } = data;
198
237
const inventory = await getInventory(accountId);
199
238
239
// credits
240
inventory.RegularCredits += RegularCredits || 0;
241
242
// endo
243
inventory.FusionPoints += FusionPoints || 0;
244
200
245
// Gear XP
201
246
gearKeys.forEach((key: GearKeysType) => addGearExpByCategory(inventory, data[key], key));
202
247
203
// Other
204
// TODO: Ensure mods have a valid fusion level and items have a valid quantity, preferably inside of the functions themselves.
205
addItemsByCategory(inventory, RawUpgrades, "RawUpgrades");
206
addItemsByCategory(inventory, MiscItems, "MiscItems");
248
// other
249
addMods(inventory, RawUpgrades);
250
addMiscItems(inventory, MiscItems);
251
addConsumables(inventory, Consumables);
252
addRecipes(inventory, Recipes);
207
253
addChallenges(inventory, ChallengeProgress);
208
254
209
await inventory.save();
255
const changedInventory = await inventory.save();
256
return changedInventory.toJSON();
210
257
};
211
258
212
259
export const addBooster = async (ItemType: string, time: number, accountId: string): Promise<void> => {
@@ -215,7 +262,7 @@ export const addBooster = async (ItemType: string, time: number, accountId: stri
215
262
const inventory = await getInventory(accountId);
216
263
const { Boosters } = inventory;
217
264
218
const itemIndex = Boosters.findIndex(i => i.ItemType === ItemType);
265
const itemIndex = Boosters.findIndex(booster => booster.ItemType === ItemType);
219
266
220
267
if (itemIndex !== -1) {
221
268
const existingBooster = Boosters[itemIndex];
@@ -228,4 +275,62 @@ export const addBooster = async (ItemType: string, time: number, accountId: stri
228
275
await inventory.save();
229
276
};
230
277
278
export const upgradeMod = async (
279
{
280
Upgrade,
281
LevelDiff,
282
Cost,
283
FusionPointCost
284
}: { Upgrade: ICrewShipSalvagedWeaponSkin; LevelDiff: number; Cost: number; FusionPointCost: number },
285
accountId: string
286
): Promise<string | undefined> => {
287
try {
288
const inventory = await getInventory(accountId);
289
const { Upgrades, RawUpgrades } = inventory;
290
const { ItemType, UpgradeFingerprint, ItemId } = Upgrade;
291
292
const safeUpgradeFingerprint = UpgradeFingerprint || '{"lvl":0}';
293
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
294
const parsedUpgradeFingerprint = JSON.parse(safeUpgradeFingerprint);
295
parsedUpgradeFingerprint.lvl += LevelDiff;
296
const stringifiedUpgradeFingerprint = JSON.stringify(parsedUpgradeFingerprint);
297
298
let itemIndex = Upgrades.findIndex(upgrade => upgrade._id?.equals(ItemId!.$oid));
299
300
if (itemIndex !== -1) {
301
Upgrades[itemIndex].UpgradeFingerprint = stringifiedUpgradeFingerprint;
302
inventory.markModified(`Upgrades.${itemIndex}.UpgradeFingerprint`);
303
} else {
304
itemIndex =
305
Upgrades.push({
306
UpgradeFingerprint: stringifiedUpgradeFingerprint,
307
ItemType
308
}) - 1;
309
310
const rawItemIndex = RawUpgrades.findIndex(rawUpgrade => rawUpgrade.ItemType === ItemType);
311
RawUpgrades[rawItemIndex].ItemCount--;
312
if (RawUpgrades[rawItemIndex].ItemCount > 0) {
313
inventory.markModified(`RawUpgrades.${rawItemIndex}.UpgradeFingerprint`);
314
} else {
315
RawUpgrades.splice(rawItemIndex, 1);
316
}
317
}
318
319
inventory.RegularCredits -= Cost;
320
inventory.FusionPoints -= FusionPointCost;
321
322
const changedInventory = await inventory.save();
323
const itemId = changedInventory.toJSON().Upgrades[itemIndex]?.ItemId?.$oid;
324
325
if (!itemId) {
326
throw new Error("Item Id not found in upgradeMod");
327
}
328
329
return itemId;
330
} catch (error) {
331
console.error("Error in upgradeMod:", error);
332
throw error;
333
}
334
};
335
231
336
export { createInventory, addPowerSuit };
@@ -0,0 +1,249 @@
1
import {
2
IMissionInventoryUpdate,
3
IMissionInventoryUpdateRewardInfo,
4
IMissionRewardResponse,
5
IReward,
6
IInventoryFieldType,
7
inventoryFields
8
} from "@/src/types/missionInventoryUpdateType";
9
10
import missionsDropTable from "@/static/json/missions-drop-table.json";
11
import { modNames, relicNames, miscNames, resourceNames, gearNames, blueprintNames } from "@/static/data/items";
12
13
// need reverse engineer rewardSeed, otherwise ingame displayed rotation reward will be different than added to db or displayed on mission end
14
const getRewards = (
15
rewardInfo: IMissionInventoryUpdateRewardInfo | undefined
16
): { InventoryChanges: IMissionInventoryUpdate; MissionRewards: IMissionRewardResponse[] } => {
17
if (!rewardInfo) {
18
return { InventoryChanges: {}, MissionRewards: [] };
19
}
20
21
const rewards = (missionsDropTable as { [key: string]: IReward[] })[rewardInfo.node];
22
if (!rewards) {
23
return { InventoryChanges: {}, MissionRewards: [] };
24
}
25
26
const rotationCount = rewardInfo.rewardQualifications?.length || 0;
27
const rotations = getRotations(rotationCount);
28
const drops: IReward[] = [];
29
for (const rotation of rotations) {
30
const rotationRewards = rewards.filter(reward => reward.rotation === rotation);
31
32
// Separate guaranteed and chance drops
33
const guaranteedDrops: IReward[] = [];
34
const chanceDrops: IReward[] = [];
35
for (const reward of rotationRewards) {
36
if (reward.chance === 100) {
37
guaranteedDrops.push(reward);
38
} else {
39
chanceDrops.push(reward);
40
}
41
}
42
43
const randomDrop = getRandomRewardByChance(chanceDrops);
44
if (randomDrop) {
45
guaranteedDrops.push(randomDrop);
46
}
47
48
drops.push(...guaranteedDrops);
49
}
50
51
// const testDrops = [
52
// { chance: 7.69, name: "Lith W3 Relic", rotation: "B" },
53
// { chance: 7.69, name: "Lith W3 Relic", rotation: "B" },
54
// { chance: 10.82, name: "2X Orokin Cell", rotation: "C" },
55
// { chance: 10.82, name: "Arrow Mutation", rotation: "C" },
56
// { chance: 10.82, name: "200 Endo", rotation: "C" },
57
// { chance: 10.82, name: "2,000,000 Credits Cache", rotation: "C" },
58
// { chance: 7.69, name: "Health Restore (Large)", rotation: "C" },
59
// { chance: 7.69, name: "Vapor Specter Blueprint", rotation: "C" }
60
// ];
61
// console.log("Mission rewards:", testDrops);
62
// return formatRewardsToInventoryType(testDrops);
63
64
console.log("Mission rewards:", drops);
65
return formatRewardsToInventoryType(drops);
66
};
67
68
const combineRewardAndLootInventory = (
69
rewardInventory: IMissionInventoryUpdate,
70
lootInventory: IMissionInventoryUpdate
71
) => {
72
const missionCredits = lootInventory.RegularCredits || 0;
73
const creditsBonus = rewardInventory.RegularCredits || 0;
74
const totalCredits = missionCredits + creditsBonus;
75
const FusionPoints = (lootInventory.FusionPoints || 0) + (rewardInventory.FusionPoints || 0) || undefined;
76
77
lootInventory.RegularCredits = totalCredits;
78
if (FusionPoints) {
79
lootInventory.FusionPoints = FusionPoints;
80
}
81
inventoryFields.forEach((field: IInventoryFieldType) => {
82
if (rewardInventory[field] && !lootInventory[field]) {
83
lootInventory[field] = [];
84
}
85
rewardInventory[field]?.forEach(item => lootInventory[field]!.push(item));
86
});
87
88
return {
89
combinedInventoryChanges: lootInventory,
90
TotalCredits: [totalCredits, totalCredits],
91
CreditsBonus: [creditsBonus, creditsBonus],
92
MissionCredits: [missionCredits, missionCredits],
93
...(FusionPoints !== undefined && { FusionPoints })
94
};
95
};
96
97
const getRotations = (rotationCount: number): (string | undefined)[] => {
98
if (rotationCount === 0) return [undefined];
99
100
const rotationPattern = ["A", "A", "B", "C"];
101
let rotationIndex = 0;
102
const rotatedValues = [];
103
104
for (let i = 1; i <= rotationCount; i++) {
105
rotatedValues.push(rotationPattern[rotationIndex]);
106
rotationIndex = (rotationIndex + 1) % 3;
107
}
108
109
return rotatedValues;
110
};
111
112
const getRandomRewardByChance = (data: IReward[] | undefined): IReward | undefined => {
113
if (!data || data.length == 0) return;
114
115
const totalChance = data.reduce((sum, item) => sum + item.chance, 0);
116
const randomValue = Math.random() * totalChance;
117
118
let cumulativeChance = 0;
119
for (const item of data) {
120
cumulativeChance += item.chance;
121
if (randomValue <= cumulativeChance) {
122
return item;
123
}
124
}
125
126
return;
127
};
128
129
const formatRewardsToInventoryType = (
130
rewards: IReward[]
131
): { InventoryChanges: IMissionInventoryUpdate; MissionRewards: IMissionRewardResponse[] } => {
132
const InventoryChanges: IMissionInventoryUpdate = {};
133
const MissionRewards: IMissionRewardResponse[] = [];
134
for (const reward of rewards) {
135
if (itemCheck(InventoryChanges, MissionRewards, reward.name)) {
136
continue;
137
}
138
139
if (reward.name.includes(" Endo")) {
140
if (!InventoryChanges.FusionPoints) {
141
InventoryChanges.FusionPoints = 0;
142
}
143
InventoryChanges.FusionPoints += getCountFromName(reward.name);
144
} else if (reward.name.includes(" Credits Cache") || reward.name.includes("Return: ")) {
145
if (!InventoryChanges.RegularCredits) {
146
InventoryChanges.RegularCredits = 0;
147
}
148
InventoryChanges.RegularCredits += getCountFromName(reward.name);
149
}
150
}
151
return { InventoryChanges, MissionRewards };
152
};
153
154
const itemCheck = (
155
InventoryChanges: IMissionInventoryUpdate,
156
MissionRewards: IMissionRewardResponse[],
157
name: string
158
) => {
159
const rewardCheck = {
160
RawUpgrades: modNames[name],
161
Consumables: gearNames[name],
162
MiscItems:
163
miscNames[name] ||
164
miscNames[name.replace(/\d+X\s*/, "")] ||
165
resourceNames[name] ||
166
resourceNames[name.replace(/\d+X\s*/, "")] ||
167
relicNames[name.replace("Relic", "Intact")] ||
168
relicNames[name.replace("Relic (Radiant)", "Radiant")],
169
Recipes: blueprintNames[name]
170
};
171
for (const key of Object.keys(rewardCheck) as IInventoryFieldType[]) {
172
if (rewardCheck[key]) {
173
addRewardResponse(InventoryChanges, MissionRewards, name, rewardCheck[key]!, key);
174
return true;
175
}
176
}
177
return false;
178
};
179
180
const getCountFromName = (name: string) => {
181
const regex = /(^(?:\d{1,3}(?:,\d{3})*(?:\.\d+)?)(\s|X))|(\s(?:\d{1,3}(?:,\d{3})*(?:\.\d+)?)$)/;
182
const countMatches = name.match(regex);
183
return countMatches ? parseInt(countMatches[0].replace(/,/g, ""), 10) : 1;
184
};
185
186
const addRewardResponse = (
187
InventoryChanges: IMissionInventoryUpdate,
188
MissionRewards: IMissionRewardResponse[],
189
ItemName: string,
190
ItemType: string,
191
InventoryCategory: IInventoryFieldType
192
) => {
193
if (!ItemType) return;
194
195
if (!InventoryChanges[InventoryCategory]) {
196
InventoryChanges[InventoryCategory] = [];
197
}
198
199
const ItemCount = getCountFromName(ItemName);
200
const TweetText = `${ItemName}`;
201
202
const existReward = InventoryChanges[InventoryCategory]!.find(item => item.ItemType === ItemType);
203
if (existReward) {
204
existReward.ItemCount += ItemCount;
205
const missionReward = MissionRewards.find(missionReward => missionReward.TypeName === ItemType);
206
if (missionReward) {
207
missionReward.ItemCount += ItemCount;
208
}
209
} else {
210
InventoryChanges[InventoryCategory]!.push({ ItemType, ItemCount });
211
MissionRewards.push({
212
ItemCount,
213
TweetText,
214
ProductCategory: InventoryCategory,
215
StoreItem: ItemType.replace("/Lotus/", "/Lotus/StoreItems/"),
216
TypeName: ItemType
217
});
218
}
219
};
220
221
// eslint-disable-next-line @typescript-eslint/no-unused-vars
222
const _missionRewardsCheckAllNamings = () => {
223
let tempRewards: IReward[] = [];
224
Object.values(missionsDropTable as { [key: string]: IReward[] }).forEach(rewards => {
225
rewards.forEach(reward => {
226
tempRewards.push(reward);
227
});
228
});
229
tempRewards = tempRewards
230
.filter(reward => !modNames[reward.name])
231
.filter(reward => !miscNames[reward.name])
232
.filter(reward => !miscNames[reward.name.replace(/\d+X\s*/, "")])
233
.filter(reward => !resourceNames[reward.name])
234
.filter(reward => !resourceNames[reward.name.replace(/\d+X\s*/, "")])
235
.filter(reward => !gearNames[reward.name])
236
.filter(reward => {
237
return (
238
!relicNames[reward.name.replace("Relic", "Intact")] &&
239
!relicNames[reward.name.replace("Relic (Radiant)", "Radiant")]
240
);
241
})
242
.filter(reward => !blueprintNames[reward.name])
243
.filter(reward => !reward.name.includes(" Endo"))
244
.filter(reward => !reward.name.includes(" Credits Cache") && !reward.name.includes("Return: "));
245
console.log(tempRewards);
246
};
247
// _missionRewardsCheckAllNamings();
248
249
export { getRewards, combineRewardAndLootInventory };
@@ -1,4 +1,4 @@
1
1
export interface IGenericUpdate {
2
2
NodeIntrosCompleted: string | string[];
3
3
// AffiliationMods: any[];
4
}
4
}
@@ -1,3 +1,4 @@
1
/* eslint-disable @typescript-eslint/no-explicit-any */
1
2
import { Document, Types } from "mongoose";
2
3
import { IOid } from "../commonTypes";
3
4
import { IAbilityOverride, IColor, FocusSchool, IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
@@ -33,7 +34,7 @@ export interface IInventoryResponse {
33
34
DailyFocus: number;
34
35
GiftsRemaining: number;
35
36
HandlerPoints: number;
36
MiscItems: IConsumable[];
37
MiscItems: IMiscItem[];
37
38
ChallengesFixVersion: number;
38
39
ChallengeProgress: IChallengeProgress[];
39
40
RawUpgrades: IRawUpgrade[];
@@ -319,7 +320,8 @@ export interface ICrewShipSalvageBinClass {
319
320
export interface ICrewShipSalvagedWeaponSkin {
320
321
ItemType: string;
321
322
UpgradeFingerprint?: string;
322
ItemId: IOid;
323
ItemId?: IOid;
324
_id?: Types.ObjectId;
323
325
}
324
326
325
327
export interface ICrewShipWeapon {
@@ -375,11 +377,6 @@ export interface IFlavourItem {
375
377
ItemType: string;
376
378
}
377
379
378
export interface IRawUpgrade {
379
ItemCount: number;
380
ItemType: string;
381
}
382
383
380
export interface IMiscItem {
384
381
ItemCount: number;
385
382
ItemType: string;
@@ -933,9 +930,9 @@ export interface IProgress {
933
930
}
934
931
935
932
export interface IRawUpgrade {
933
ItemType: string;
936
934
ItemCount: number;
937
935
LastAdded?: IOid;
938
ItemType: string;
939
936
}
940
937
941
938
export interface IScoop {
@@ -1,6 +1,9 @@
1
/* eslint-disable @typescript-eslint/no-explicit-any */
1
2
import { IOid } from "./commonTypes";
2
3
import { IDate } from "./inventoryTypes/inventoryTypes";
3
4
5
export const inventoryFields = ["RawUpgrades", "MiscItems", "Consumables", "Recipes"] as const;
6
export type IInventoryFieldType = (typeof inventoryFields)[number];
4
7
export interface IMissionInventoryUpdateGear {
5
8
ItemType: string;
6
9
ItemName: string;
@@ -43,6 +46,21 @@ export interface IMissionInventoryUpdateChallange {
43
46
Completed: any[];
44
47
}
45
48
49
export interface IMissionInventoryUpdateRewardInfo {
50
node: string;
51
rewardTier?: number;
52
nightmareMode?: boolean;
53
useVaultManifest?: boolean;
54
EnemyCachesFound?: number;
55
toxinOk?: boolean;
56
lostTargetWave?: number;
57
defenseTargetCount?: number;
58
EOM_AFK?: number;
59
rewardQualifications?: string;
60
PurgatoryRewardQualifications?: string;
61
rewardSeed?: number;
62
}
63
46
64
export interface IMissionInventoryUpdate {
47
65
rewardsMultiplier?: number;
48
66
ActiveBoosters?: any[];
@@ -50,8 +68,27 @@ export interface IMissionInventoryUpdate {
50
68
Pistols?: IMissionInventoryUpdateGear[];
51
69
Suits?: IMissionInventoryUpdateGear[];
52
70
Melee?: IMissionInventoryUpdateGear[];
53
RawUpgrades?: IMissionInventoryUpdateCard[];
71
RawUpgrades?: IMissionInventoryUpdateItem[];
54
72
MiscItems?: IMissionInventoryUpdateItem[];
73
Consumables?: IMissionInventoryUpdateItem[];
74
Recipes?: IMissionInventoryUpdateItem[];
55
75
RegularCredits?: number;
56
76
ChallengeProgress?: IMissionInventoryUpdateChallange[];
77
RewardInfo?: IMissionInventoryUpdateRewardInfo;
78
FusionPoints?: number;
79
}
80
81
export interface IMissionRewardResponse {
82
StoreItem?: string;
83
TypeName: string;
84
UpgradeLevel?: number;
85
ItemCount: number;
86
TweetText: string;
87
ProductCategory: string;
88
}
89
90
export interface IReward {
91
name: string;
92
chance: number;
93
rotation?: string;
57
94
}
@@ -1,3 +1,4 @@
1
/* eslint-disable @typescript-eslint/no-explicit-any */
1
2
export interface ISession {
2
3
sessionId: string;
3
4
creatorId: string;
@@ -1,4 +1,4 @@
1
import Items, { Item, Weapon } from "warframe-items";
1
import Items, { Category, Item, Warframe, Weapon } from "warframe-items";
2
2
3
3
type MinWeapon = Omit<Weapon, "patchlogs">;
4
4
type MinItem = Omit<Item, "patchlogs">;
@@ -16,3 +16,45 @@ export const items: MinItem[] = new Items({ category: ["All"] }).map(item => {
16
16
delete next.patchlogs;
17
17
return next;
18
18
});
19
20
const getNamesObj = (category: Category) =>
21
new Items({ category: [category] }).reduce((acc, item) => {
22
acc[item.name!.replace("'S", "'s")] = item.uniqueName!;
23
return acc;
24
}, {} as ImportAssertions);
25
26
export const modNames = getNamesObj("Mods");
27
export const resourceNames = getNamesObj("Resources");
28
export const miscNames = getNamesObj("Misc");
29
export const relicNames = getNamesObj("Relics");
30
export const skinNames = getNamesObj("Skins");
31
export const arcaneNames = getNamesObj("Arcanes");
32
export const gearNames = getNamesObj("Gear");
33
34
export const craftNames: ImportAssertions = Object.fromEntries(
35
(
36
new Items({
37
category: [
38
"Warframes",
39
"Gear",
40
"Melee",
41
"Primary",
42
"Secondary",
43
"Sentinels",
44
"Misc",
45
"Arch-Gun",
46
"Arch-Melee"
47
]
48
}) as Warframe[]
49
)
50
.flatMap(item => item.components || [])
51
.filter(item => item.drops && item.drops[0])
52
.map(item => [item.drops![0].type, item.uniqueName])
53
);
54
craftNames["Forma Blueprint"] = "/Lotus/Types/Recipes/Components/FormaBlueprint";
55
56
export const blueprintNames: ImportAssertions = Object.fromEntries(
57
Object.keys(craftNames)
58
.filter(name => name.includes("Blueprint"))
59
.map(name => [name, craftNames[name]])
60
);