返回提交历史
Modified
package-lock.json
+4
-4
Modified
package.json
+1
-1
Modified
src/controllers/api/entratiLabConquestModeController.ts
+2
-0
Modified
src/controllers/api/missionInventoryUpdateController.ts
+12
-4
Modified
src/services/missionInventoryUpdateService.ts
+198
-9
Modified
src/types/missionTypes.ts
+19
-0
Modified
src/types/requestTypes.ts
+7
-1
XFEstudio/XFESpaceNinjaServer
feat: conquest progression & rewards (#1791)
Closes #1570 Co-authored-by: Jānis <janisslsm@noreply.localhost> Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1791 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
15aaa28a
代码差异
7 个文件
+243
-19
@@ -18,7 +18,7 @@
18
18
"morgan": "^1.10.0",
19
19
"ncp": "^2.0.0",
20
20
"typescript": "^5.5",
21
"warframe-public-export-plus": "^0.5.56",
21
"warframe-public-export-plus": "^0.5.57",
22
22
"warframe-riven-info": "^0.1.2",
23
23
"winston": "^3.17.0",
24
24
"winston-daily-rotate-file": "^5.0.0"
@@ -3789,9 +3789,9 @@
3789
3789
}
3790
3790
},
3791
3791
"node_modules/warframe-public-export-plus": {
3792
"version": "0.5.56",
3793
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.56.tgz",
3794
"integrity": "sha512-px+J7tUm6fkSzwKkvL73ySQReDq9oM1UrHSLM3vbYGBvELM892iBgPYG45okIhScCSdwmmXTiWZTf4x/I4qiNQ=="
3792
"version": "0.5.57",
3793
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.57.tgz",
3794
"integrity": "sha512-CKbg7/2hSDH7I7yYSWwkrP4N2rEAEK1vNEuehj+RD9vMvl1c4u6klHLMwdh+ULxXiW4djWIlNIhs5bi/fm58Mg=="
3795
3795
},
3796
3796
"node_modules/warframe-riven-info": {
3797
3797
"version": "0.1.2",
@@ -25,7 +25,7 @@
25
25
"morgan": "^1.10.0",
26
26
"ncp": "^2.0.0",
27
27
"typescript": "^5.5",
28
"warframe-public-export-plus": "^0.5.56",
28
"warframe-public-export-plus": "^0.5.57",
29
29
"warframe-riven-info": "^0.1.2",
30
30
"winston": "^3.17.0",
31
31
"winston-daily-rotate-file": "^5.0.0"
@@ -21,10 +21,12 @@ export const entratiLabConquestModeController: RequestHandler = async (req, res)
21
21
inventory.EntratiVaultCountResetDate = new Date(weekEnd);
22
22
if (inventory.EntratiLabConquestUnlocked) {
23
23
inventory.EntratiLabConquestUnlocked = 0;
24
inventory.EntratiLabConquestCacheScoreMission = 0;
24
25
inventory.EntratiLabConquestActiveFrameVariants = [];
25
26
}
26
27
if (inventory.EchoesHexConquestUnlocked) {
27
28
inventory.EchoesHexConquestUnlocked = 0;
29
inventory.EchoesHexConquestCacheScoreMission = 0;
28
30
inventory.EchoesHexConquestActiveFrameVariants = [];
29
31
inventory.EchoesHexConquestActiveStickers = [];
30
32
}
@@ -6,6 +6,7 @@ import { addMissionInventoryUpdates, addMissionRewards } from "@/src/services/mi
6
6
import { getInventory } from "@/src/services/inventoryService";
7
7
import { getInventoryResponse } from "./inventoryController";
8
8
import { logger } from "@/src/utils/logger";
9
import { IMissionInventoryUpdateResponse } from "@/src/types/missionTypes";
9
10
10
11
/*
11
12
**** INPUT ****
@@ -71,8 +72,14 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
71
72
return;
72
73
}
73
74
74
const { MissionRewards, inventoryChanges, credits, AffiliationMods, SyndicateXPItemReward } =
75
await addMissionRewards(inventory, missionReport, firstCompletion);
75
const {
76
MissionRewards,
77
inventoryChanges,
78
credits,
79
AffiliationMods,
80
SyndicateXPItemReward,
81
ConquestCompletedMissionsCount
82
} = await addMissionRewards(inventory, missionReport, firstCompletion);
76
83
77
84
await inventory.save();
78
85
const inventoryResponse = await getInventoryResponse(inventory, true);
@@ -86,8 +93,9 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
86
93
...inventoryUpdates,
87
94
//FusionPoints: inventoryChanges?.FusionPoints, // This in combination with InventoryJson or InventoryChanges seems to just double the number of endo shown, so unsure when this is needed.
88
95
SyndicateXPItemReward,
89
AffiliationMods
90
});
96
AffiliationMods,
97
ConquestCompletedMissionsCount
98
} satisfies IMissionInventoryUpdateResponse);
91
99
};
92
100
93
101
/*
@@ -43,7 +43,7 @@ import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/invento
43
43
import { getEntriesUnsafe } from "@/src/utils/ts-utils";
44
44
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
45
45
import { handleStoreItemAcquisition } from "./purchaseService";
46
import { IMissionReward } from "../types/missionTypes";
46
import { IMissionCredits, IMissionReward } from "../types/missionTypes";
47
47
import { crackRelic } from "@/src/helpers/relicHelper";
48
48
import { createMessage } from "./inboxService";
49
49
import kuriaMessage50 from "@/static/fixed_responses/kuriaMessages/fiftyPercent.json";
@@ -586,8 +586,140 @@ interface AddMissionRewardsReturnType {
586
586
credits?: IMissionCredits;
587
587
AffiliationMods?: IAffiliationMods[];
588
588
SyndicateXPItemReward?: number;
589
ConquestCompletedMissionsCount?: number;
589
590
}
590
591
592
interface IConquestReward {
593
at: number;
594
pool: IRngResult[];
595
}
596
597
const labConquestRewards: IConquestReward[] = [
598
{
599
at: 5,
600
pool: ExportRewards[
601
"/Lotus/Types/Game/MissionDecks/EntratiLabConquestRewards/EntratiLabConquestSilverRewards"
602
][0] as IRngResult[]
603
},
604
{
605
at: 10,
606
pool: ExportRewards[
607
"/Lotus/Types/Game/MissionDecks/EntratiLabConquestRewards/EntratiLabConquestSilverRewards"
608
][0] as IRngResult[]
609
},
610
{
611
at: 15,
612
pool: [
613
{
614
type: "/Lotus/StoreItems/Types/Gameplay/EntratiLab/Resources/EntratiLanthornBundle",
615
itemCount: 3,
616
probability: 1
617
}
618
]
619
},
620
{
621
at: 20,
622
pool: ExportRewards[
623
"/Lotus/Types/Game/MissionDecks/EntratiLabConquestRewards/EntratiLabConquestGoldRewards"
624
][0] as IRngResult[]
625
},
626
{
627
at: 28,
628
pool: [
629
{
630
type: "/Lotus/StoreItems/Types/Items/MiscItems/DistillPoints",
631
itemCount: 20,
632
probability: 1
633
}
634
]
635
},
636
{
637
at: 31,
638
pool: ExportRewards[
639
"/Lotus/Types/Game/MissionDecks/EntratiLabConquestRewards/EntratiLabConquestGoldRewards"
640
][0] as IRngResult[]
641
},
642
{
643
at: 34,
644
pool: ExportRewards[
645
"/Lotus/Types/Game/MissionDecks/EntratiLabConquestRewards/EntratiLabConquestArcaneRewards"
646
][0] as IRngResult[]
647
},
648
{
649
at: 37,
650
pool: [
651
{
652
type: "/Lotus/StoreItems/Types/Items/MiscItems/DistillPoints",
653
itemCount: 50,
654
probability: 1
655
}
656
]
657
}
658
];
659
660
const hexConquestRewards: IConquestReward[] = [
661
{
662
at: 5,
663
pool: ExportRewards[
664
"/Lotus/Types/Game/MissionDecks/1999ConquestRewards/1999ConquestSilverRewards"
665
][0] as IRngResult[]
666
},
667
{
668
at: 10,
669
pool: ExportRewards[
670
"/Lotus/Types/Game/MissionDecks/1999ConquestRewards/1999ConquestSilverRewards"
671
][0] as IRngResult[]
672
},
673
{
674
at: 15,
675
pool: [
676
{
677
type: "/Lotus/StoreItems/Types/BoosterPacks/1999StickersPackEchoesArchimedea",
678
itemCount: 1,
679
probability: 1
680
}
681
]
682
},
683
{
684
at: 20,
685
pool: ExportRewards[
686
"/Lotus/Types/Game/MissionDecks/1999ConquestRewards/1999ConquestGoldRewards"
687
][0] as IRngResult[]
688
},
689
{
690
at: 28,
691
pool: [
692
{
693
type: "/Lotus/StoreItems/Types/Items/MiscItems/1999ConquestBucks",
694
itemCount: 6,
695
probability: 1
696
}
697
]
698
},
699
{
700
at: 31,
701
pool: ExportRewards[
702
"/Lotus/Types/Game/MissionDecks/1999ConquestRewards/1999ConquestGoldRewards"
703
][0] as IRngResult[]
704
},
705
{
706
at: 34,
707
pool: ExportRewards[
708
"/Lotus/Types/Game/MissionDecks/1999ConquestRewards/1999ConquestArcaneRewards"
709
][0] as IRngResult[]
710
},
711
{
712
at: 37,
713
pool: [
714
{
715
type: "/Lotus/StoreItems/Types/Items/MiscItems/1999ConquestBucks",
716
itemCount: 9,
717
probability: 1
718
}
719
]
720
}
721
];
722
591
723
//TODO: return type of partial missioninventoryupdate response
592
724
export const addMissionRewards = async (
593
725
inventory: TInventoryDatabaseDocument,
@@ -620,6 +752,7 @@ export const addMissionRewards = async (
620
752
const inventoryChanges: IInventoryChanges = {};
621
753
const AffiliationMods: IAffiliationMods[] = [];
622
754
let SyndicateXPItemReward;
755
let ConquestCompletedMissionsCount;
623
756
624
757
let missionCompletionCredits = 0;
625
758
//inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display
@@ -691,6 +824,62 @@ export const addMissionRewards = async (
691
824
});
692
825
}
693
826
827
if (rewardInfo.ConquestCompleted !== undefined) {
828
let score = 1;
829
if (rewardInfo.ConquestHardModeActive === 1) score += 3;
830
831
if (rewardInfo.ConquestPersonalModifiersActive !== undefined)
832
score += rewardInfo.ConquestPersonalModifiersActive;
833
if (rewardInfo.ConquestEquipmentSuggestionsFulfilled !== undefined)
834
score += rewardInfo.ConquestEquipmentSuggestionsFulfilled;
835
836
score *= rewardInfo.ConquestCompleted + 1;
837
838
if (rewardInfo.ConquestCompleted == 2 && rewardInfo.ConquestHardModeActive === 1) score += 1;
839
840
logger.debug(`completed conquest mission ${rewardInfo.ConquestCompleted + 1} for a score of ${score}`);
841
842
const conquestType = rewardInfo.ConquestType;
843
const conquestNode =
844
conquestType == "HexConquest" ? "EchoesHexConquestHardModeUnlocked" : "EntratiLabConquestHardModeUnlocked";
845
if (score >= 25 && inventory.NodeIntrosCompleted.indexOf(conquestNode) == -1)
846
inventory.NodeIntrosCompleted.push(conquestNode);
847
848
if (conquestType == "HexConquest") {
849
inventory.EchoesHexConquestCacheScoreMission ??= 0;
850
if (score > inventory.EchoesHexConquestCacheScoreMission) {
851
for (const reward of hexConquestRewards) {
852
if (score >= reward.at && inventory.EchoesHexConquestCacheScoreMission < reward.at) {
853
const rolled = getRandomReward(reward.pool)!;
854
logger.debug(`rolled hex conquest reward for reaching ${reward.at} points`, rolled);
855
MissionRewards.push({
856
StoreItem: rolled.type,
857
ItemCount: rolled.itemCount
858
});
859
}
860
}
861
inventory.EchoesHexConquestCacheScoreMission = score;
862
}
863
} else {
864
inventory.EntratiLabConquestCacheScoreMission ??= 0;
865
if (score > inventory.EntratiLabConquestCacheScoreMission) {
866
for (const reward of labConquestRewards) {
867
if (score >= reward.at && inventory.EntratiLabConquestCacheScoreMission < reward.at) {
868
const rolled = getRandomReward(reward.pool)!;
869
logger.debug(`rolled lab conquest reward for reaching ${reward.at} points`, rolled);
870
MissionRewards.push({
871
StoreItem: rolled.type,
872
ItemCount: rolled.itemCount
873
});
874
}
875
}
876
inventory.EntratiLabConquestCacheScoreMission = score;
877
}
878
}
879
880
ConquestCompletedMissionsCount = rewardInfo.ConquestCompleted == 2 ? 0 : rewardInfo.ConquestCompleted + 1;
881
}
882
694
883
for (const reward of MissionRewards) {
695
884
const inventoryChange = await handleStoreItemAcquisition(
696
885
reward.StoreItem,
@@ -882,16 +1071,16 @@ export const addMissionRewards = async (
882
1071
}
883
1072
}
884
1073
885
return { inventoryChanges, MissionRewards, credits, AffiliationMods, SyndicateXPItemReward };
1074
return {
1075
inventoryChanges,
1076
MissionRewards,
1077
credits,
1078
AffiliationMods,
1079
SyndicateXPItemReward,
1080
ConquestCompletedMissionsCount
1081
};
886
1082
};
887
1083
888
interface IMissionCredits {
889
MissionCredits: number[];
890
CreditBonus: number[];
891
TotalCredits: number[];
892
DailyMissionBonus?: boolean;
893
}
894
895
1084
//creditBonus is not entirely accurate.
896
1085
//TODO: consider ActiveBoosters
897
1086
export const addCredits = (
@@ -1,3 +1,5 @@
1
import { IAffiliationMods, IInventoryChanges } from "./purchaseTypes";
2
1
3
export const inventoryFields = ["RawUpgrades", "MiscItems", "Consumables", "Recipes"] as const;
2
4
export type IInventoryFieldType = (typeof inventoryFields)[number];
3
5
@@ -11,3 +13,20 @@ export interface IMissionReward {
11
13
FromEnemyCache?: boolean;
12
14
IsStrippedItem?: boolean;
13
15
}
16
17
export interface IMissionCredits {
18
MissionCredits: number[];
19
CreditBonus: number[];
20
TotalCredits: number[];
21
DailyMissionBonus?: boolean;
22
}
23
24
export interface IMissionInventoryUpdateResponse extends Partial<IMissionCredits> {
25
ConquestCompletedMissionsCount?: number;
26
InventoryJson?: string;
27
MissionRewards?: IMissionReward[];
28
InventoryChanges?: IInventoryChanges;
29
FusionPoints?: number;
30
SyndicateXPItemReward?: number;
31
AffiliationMods?: IAffiliationMods[];
32
}
@@ -125,6 +125,7 @@ export type IMissionInventoryUpdateRequest = {
125
125
wagerTier?: number; // the index
126
126
creditsFee?: number; // the index
127
127
InvasionProgress?: IInvasionProgressClient[];
128
ConquestMissionsCompleted?: number;
128
129
} & {
129
130
[K in TEquipmentKey]?: IEquipmentClient[];
130
131
};
@@ -150,7 +151,12 @@ export interface IRewardInfo {
150
151
PurgatoryRewardQualifications?: string;
151
152
rewardSeed?: number | bigint;
152
153
periodicMissionTag?: string;
153
154
ConquestType?: string;
155
ConquestCompleted?: number;
156
ConquestEquipmentSuggestionsFulfilled?: number;
157
ConquestPersonalModifiersActive?: number;
158
ConquestStickersActive?: number;
159
ConquestHardModeActive?: number;
154
160
// for bounties, only EOM_AFK and node are given from above, plus:
155
161
JobTier?: number;
156
162
jobId?: string;