返回提交历史
Modified
src/controllers/api/claimCompletedRecipeController.ts
+1
-1
Modified
src/controllers/api/guildTechController.ts
+2
-4
Modified
src/controllers/custom/addItemsController.ts
+1
-1
Modified
src/services/inventoryService.ts
+49
-44
Modified
src/services/purchaseService.ts
+11
-13
Modified
src/types/purchaseTypes.ts
+39
-25
XFEstudio/XFESpaceNinjaServer
fix: consume a slot when item is crafted instead of bought via plat (#1029)
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1029
a5c45bb6
代码差异
6 个文件
+103
-88
@@ -91,7 +91,7 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
91
91
}
92
92
InventoryChanges = {
93
93
...InventoryChanges,
94
...(await addItem(inventory, recipe.resultType, recipe.num)).InventoryChanges
94
...(await addItem(inventory, recipe.resultType, recipe.num, false)).InventoryChanges
95
95
};
96
96
await inventory.save();
97
97
res.json({ InventoryChanges });
@@ -54,10 +54,8 @@ export const guildTechController: RequestHandler = async (req, res) => {
54
54
}
55
55
}
56
56
addMiscItems(inventory, miscItemChanges);
57
const inventoryChanges: IInventoryChanges = {
58
...updateCurrency(inventory, contributions.RegularCredits, false),
59
MiscItems: miscItemChanges
60
};
57
const inventoryChanges: IInventoryChanges = updateCurrency(inventory, contributions.RegularCredits, false);
58
inventoryChanges.MiscItems = miscItemChanges;
61
59
62
60
if (techProject.ReqCredits == 0 && !techProject.ReqItems.find(x => x.ItemCount > 0)) {
63
61
// This research is now fully funded.
@@ -7,7 +7,7 @@ export const addItemsController: RequestHandler = async (req, res) => {
7
7
const requests = req.body as IAddItemRequest[];
8
8
const inventory = await getInventory(accountId);
9
9
for (const request of requests) {
10
await addItem(inventory, request.ItemType, request.ItemCount);
10
await addItem(inventory, request.ItemType, request.ItemCount, true);
11
11
}
12
12
await inventory.save();
13
13
res.end();
@@ -5,7 +5,7 @@ import {
5
5
} from "@/src/models/inventoryModels/inventoryModel";
6
6
import { config } from "@/src/services/configService";
7
7
import { HydratedDocument, Types } from "mongoose";
8
import { SlotNames, IInventoryChanges, IBinChanges, ICurrencyChanges } from "@/src/types/purchaseTypes";
8
import { SlotNames, IInventoryChanges, IBinChanges, slotNames } from "@/src/types/purchaseTypes";
9
9
import {
10
10
IChallengeProgress,
11
11
IConsumable,
@@ -126,13 +126,17 @@ export const combineInventoryChanges = (InventoryChanges: IInventoryChanges, del
126
126
for (const item of right) {
127
127
left.push(item);
128
128
}
129
} else if (typeof delta[key] == "object") {
130
console.assert(key.substring(-3) == "Bin");
131
console.assert(key != "InfestedFoundry");
132
const left = InventoryChanges[key] as IBinChanges;
133
const right = delta[key] as IBinChanges;
134
left.count += right.count;
135
left.platinum += right.platinum;
129
} else if (slotNames.indexOf(key as SlotNames) != -1) {
130
const left = InventoryChanges[key as SlotNames]!;
131
const right = delta[key as SlotNames]!;
132
if (right.count) {
133
left.count ??= 0;
134
left.count += right.count;
135
}
136
if (right.platinum) {
137
left.platinum ??= 0;
138
left.platinum += right.platinum;
139
}
136
140
left.Slots += right.Slots;
137
141
if (right.Extra) {
138
142
left.Extra ??= 0;
@@ -159,10 +163,32 @@ export const getInventory = async (
159
163
return inventory;
160
164
};
161
165
166
const occupySlot = (
167
inventory: TInventoryDatabaseDocument,
168
bin: InventorySlot,
169
premiumPurchase: boolean
170
): IInventoryChanges => {
171
const slotChanges = {
172
Slots: 0,
173
Extra: 0
174
};
175
if (premiumPurchase) {
176
slotChanges.Extra += 1;
177
} else {
178
// { count: 1, platinum: 0, Slots: -1 }
179
slotChanges.Slots -= 1;
180
}
181
updateSlots(inventory, bin, slotChanges.Slots, slotChanges.Extra);
182
const inventoryChanges: IInventoryChanges = {};
183
inventoryChanges[bin] = slotChanges satisfies IBinChanges;
184
return inventoryChanges;
185
};
186
162
187
export const addItem = async (
163
188
inventory: TInventoryDatabaseDocument,
164
189
typeName: string,
165
quantity: number = 1
190
quantity: number = 1,
191
premiumPurchase: boolean = false
166
192
): Promise<{ InventoryChanges: IInventoryChanges }> => {
167
193
// Bundles are technically StoreItems but a) they don't have a normal counterpart, and b) they are used in non-StoreItem contexts, e.g. email attachments.
168
194
if (typeName in ExportBundles) {
@@ -302,14 +328,13 @@ export const addItem = async (
302
328
const inventoryChanges = addEquipment(inventory, weapon.productCategory, typeName);
303
329
if (weapon.additionalItems) {
304
330
for (const item of weapon.additionalItems) {
305
combineInventoryChanges(inventoryChanges, await addItem(inventory, item, 1));
331
combineInventoryChanges(inventoryChanges, (await addItem(inventory, item, 1)).InventoryChanges);
306
332
}
307
333
}
308
updateSlots(inventory, InventorySlot.WEAPONS, 0, 1);
309
334
return {
310
335
InventoryChanges: {
311
336
...inventoryChanges,
312
WeaponBin: { count: 1, platinum: 0, Slots: -1 }
337
...occupySlot(inventory, InventorySlot.WEAPONS, premiumPurchase)
313
338
}
314
339
};
315
340
} else {
@@ -378,44 +403,26 @@ export const addItem = async (
378
403
case "Powersuits":
379
404
switch (typeName.substr(1).split("/")[2]) {
380
405
default: {
381
const inventoryChanges = addPowerSuit(inventory, typeName);
382
updateSlots(inventory, InventorySlot.SUITS, 0, 1);
383
406
return {
384
407
InventoryChanges: {
385
...inventoryChanges,
386
SuitBin: {
387
count: 1,
388
platinum: 0,
389
Slots: -1
390
}
408
...addPowerSuit(inventory, typeName),
409
...occupySlot(inventory, InventorySlot.SUITS, premiumPurchase)
391
410
}
392
411
};
393
412
}
394
413
case "Archwing": {
395
const inventoryChanges = addSpaceSuit(inventory, typeName);
396
updateSlots(inventory, InventorySlot.SPACESUITS, 0, 1);
397
414
return {
398
415
InventoryChanges: {
399
...inventoryChanges,
400
SpaceSuitBin: {
401
count: 1,
402
platinum: 0,
403
Slots: -1
404
}
416
...addSpaceSuit(inventory, typeName),
417
...occupySlot(inventory, InventorySlot.SPACESUITS, premiumPurchase)
405
418
}
406
419
};
407
420
}
408
421
case "EntratiMech": {
409
const inventoryChanges = addMechSuit(inventory, typeName);
410
updateSlots(inventory, InventorySlot.MECHSUITS, 0, 1);
411
422
return {
412
423
InventoryChanges: {
413
...inventoryChanges,
414
MechBin: {
415
count: 1,
416
platinum: 0,
417
Slots: -1
418
}
424
...addMechSuit(inventory, typeName),
425
...occupySlot(inventory, InventorySlot.MECHSUITS, premiumPurchase)
419
426
}
420
427
};
421
428
}
@@ -446,12 +453,10 @@ export const addItem = async (
446
453
case "Types":
447
454
switch (typeName.substr(1).split("/")[2]) {
448
455
case "Sentinels": {
449
const inventoryChanges = addSentinel(inventory, typeName);
450
updateSlots(inventory, InventorySlot.SENTINELS, 0, 1);
451
456
return {
452
457
InventoryChanges: {
453
...inventoryChanges,
454
SentinelBin: { count: 1, platinum: 0, Slots: -1 }
458
...addSentinel(inventory, typeName),
459
...occupySlot(inventory, InventorySlot.SENTINELS, premiumPurchase)
455
460
}
456
461
};
457
462
}
@@ -531,9 +536,9 @@ export const addItems = async (
531
536
let inventoryDelta;
532
537
for (const item of items) {
533
538
if (typeof item === "string") {
534
inventoryDelta = await addItem(inventory, item);
539
inventoryDelta = await addItem(inventory, item, 1, true);
535
540
} else {
536
inventoryDelta = await addItem(inventory, item.ItemType, item.ItemCount);
541
inventoryDelta = await addItem(inventory, item.ItemType, item.ItemCount, true);
537
542
}
538
543
combineInventoryChanges(inventoryChanges, inventoryDelta.InventoryChanges);
539
544
}
@@ -682,8 +687,8 @@ export const updateCurrency = (
682
687
inventory: TInventoryDatabaseDocument,
683
688
price: number,
684
689
usePremium: boolean
685
): ICurrencyChanges => {
686
const currencyChanges: ICurrencyChanges = {};
690
): IInventoryChanges => {
691
const currencyChanges: IInventoryChanges = {};
687
692
if (price != 0 && isCurrencyTracked(usePremium)) {
688
693
if (usePremium) {
689
694
if (inventory.PremiumCreditsFree > 0) {
@@ -164,7 +164,7 @@ export const handlePurchase = async (
164
164
addMiscItems(inventory, [invItem]);
165
165
166
166
purchaseResponse.InventoryChanges.MiscItems ??= [];
167
(purchaseResponse.InventoryChanges.MiscItems as IMiscItem[]).push(invItem);
167
purchaseResponse.InventoryChanges.MiscItems.push(invItem);
168
168
} else if (!config.infiniteRegalAya) {
169
169
inventory.PrimeTokens -= offer.PrimePrice! * purchaseRequest.PurchaseParams.Quantity;
170
170
}
@@ -191,11 +191,11 @@ const handleItemPrices = (
191
191
addMiscItems(inventory, [invItem]);
192
192
193
193
inventoryChanges.MiscItems ??= [];
194
const change = (inventoryChanges.MiscItems as IMiscItem[]).find(x => x.ItemType == item.ItemType);
194
const change = inventoryChanges.MiscItems.find(x => x.ItemType == item.ItemType);
195
195
if (change) {
196
196
change.ItemCount += invItem.ItemCount;
197
197
} else {
198
(inventoryChanges.MiscItems as IMiscItem[]).push(invItem);
198
inventoryChanges.MiscItems.push(invItem);
199
199
}
200
200
}
201
201
};
@@ -251,7 +251,7 @@ export const handleStoreItemAcquisition = async (
251
251
}
252
252
switch (storeCategory) {
253
253
default: {
254
purchaseResponse = await addItem(inventory, internalName, quantity);
254
purchaseResponse = await addItem(inventory, internalName, quantity, true);
255
255
break;
256
256
}
257
257
case "Types":
@@ -300,16 +300,14 @@ const handleSlotPurchase = (
300
300
301
301
logger.debug(`added ${slotsPurchased} slot ${slotName}`);
302
302
303
return {
304
InventoryChanges: {
305
[slotName]: {
306
count: 0,
307
platinum: 1,
308
Slots: slotsPurchased,
309
Extra: slotsPurchased
310
}
311
}
303
const inventoryChanges: IInventoryChanges = {};
304
inventoryChanges[slotName] = {
305
count: 0,
306
platinum: 1,
307
Slots: slotsPurchased,
308
Extra: slotsPurchased
312
309
};
310
return { InventoryChanges: inventoryChanges };
313
311
};
314
312
315
313
const handleBoosterPackPurchase = async (
@@ -1,5 +1,5 @@
1
1
import { IEquipmentClient } from "./inventoryTypes/commonInventoryTypes";
2
import { IDroneClient, IInfestedFoundryClient, TEquipmentKey } from "./inventoryTypes/inventoryTypes";
2
import { IDroneClient, IInfestedFoundryClient, IMiscItem, TEquipmentKey } from "./inventoryTypes/inventoryTypes";
3
3
4
4
export interface IPurchaseRequest {
5
5
PurchaseParams: IPurchaseParams;
@@ -22,20 +22,31 @@ export interface IPurchaseParams {
22
22
IsWeekly?: boolean; // for Source 7
23
23
}
24
24
25
export interface ICurrencyChanges {
26
RegularCredits?: number;
27
PremiumCredits?: number;
28
PremiumCreditsFree?: number;
29
}
30
31
25
export type IInventoryChanges = {
32
26
[_ in SlotNames]?: IBinChanges;
33
27
} & {
34
28
[_ in TEquipmentKey]?: IEquipmentClient[];
35
} & ICurrencyChanges & {
36
InfestedFoundry?: IInfestedFoundryClient;
37
Drones?: IDroneClient[];
38
} & Record<string, IBinChanges | number | object[] | IInfestedFoundryClient>;
29
} & {
30
RegularCredits?: number;
31
PremiumCredits?: number;
32
PremiumCreditsFree?: number;
33
InfestedFoundry?: IInfestedFoundryClient;
34
Drones?: IDroneClient[];
35
MiscItems?: IMiscItem[];
36
} & Record<
37
Exclude<
38
string,
39
| SlotNames
40
| TEquipmentKey
41
| "RegularCredits"
42
| "PremiumCredits"
43
| "PremiumCreditsFree"
44
| "InfestedFoundry"
45
| "Drones"
46
| "MiscItems"
47
>,
48
number | object[]
49
>;
39
50
40
51
export interface IAffiliationMods {
41
52
Tag: string;
@@ -51,8 +62,8 @@ export interface IPurchaseResponse {
51
62
}
52
63
53
64
export type IBinChanges = {
54
count: number;
55
platinum: number;
65
count?: number;
66
platinum?: number;
56
67
Slots: number;
57
68
Extra?: number;
58
69
};
@@ -69,18 +80,21 @@ export type SlotPurchaseName =
69
80
| "TwoCrewShipSalvageSlotItem"
70
81
| "CrewMemberSlotItem";
71
82
72
export type SlotNames =
73
| "SuitBin"
74
| "WeaponBin"
75
| "MechBin"
76
| "PveBonusLoadoutBin"
77
| "SentinelBin"
78
| "SpaceSuitBin"
79
| "SpaceWeaponBin"
80
| "OperatorAmpBin"
81
| "RandomModBin"
82
| "CrewShipSalvageBin"
83
| "CrewMemberBin";
83
export const slotNames = [
84
"SuitBin",
85
"WeaponBin",
86
"MechBin",
87
"PveBonusLoadoutBin",
88
"SentinelBin",
89
"SpaceSuitBin",
90
"SpaceWeaponBin",
91
"OperatorAmpBin",
92
"RandomModBin",
93
"CrewShipSalvageBin",
94
"CrewMemberBin"
95
] as const;
96
97
export type SlotNames = (typeof slotNames)[number];
84
98
85
99
export type SlotPurchase = {
86
100
[P in SlotPurchaseName]: { name: SlotNames; slotsPerPurchase: number };