返回提交历史
Modified
src/controllers/api/inventoryController.ts
+23
-33
Modified
src/models/inventoryModels/inventoryModel.ts
+6
-0
Added
src/services/invasionService.ts
+29
-0
Modified
src/services/missionInventoryUpdateService.ts
+26
-0
Modified
src/types/inventoryTypes/inventoryTypes.ts
+4
-2
XFEstudio/XFESpaceNinjaServer
feat: invasion death squad inbox messages (#3186)
Closes #3083 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3186 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
ba92dcae
代码差异
5 个文件
+88
-35
@@ -219,44 +219,34 @@ export const inventoryController: RequestHandler = async (request, response) =>
219
219
if (qi.AttackerScore >= 3) {
220
220
factionSidedWith = invasion.Faction;
221
221
battlePay = invasion.AttackerReward.countedItems;
222
logger.debug(`invasion pay from ${factionSidedWith}`, { battlePay });
223
222
} else if (qi.DefenderScore >= 3) {
224
223
factionSidedWith = invasion.DefenderFaction;
225
224
battlePay = invasion.DefenderReward.countedItems;
226
logger.debug(`invasion pay from ${factionSidedWith}`, { battlePay });
227
225
}
228
if (factionSidedWith) {
229
if (battlePay) {
230
// Decoupling rewards from the inbox message because it may delete itself without being read
231
for (const item of battlePay) {
232
await addItem(inventory, item.ItemType, item.ItemCount);
233
}
234
await createMessage(account._id, [
235
{
236
sndr:
237
factionSidedWith == "FC_GRINEER"
238
? "/Lotus/Language/Menu/GrineerInvasionLeader"
239
: "/Lotus/Language/Menu/CorpusInvasionLeader",
240
msg: `/Lotus/Language/G1Quests/${factionSidedWith}_InvasionThankyouMessageBody`,
241
sub: `/Lotus/Language/G1Quests/${factionSidedWith}_InvasionThankyouMessageSubject`,
242
countedAtt: battlePay,
243
attVisualOnly: true,
244
icon:
245
factionSidedWith == "FC_GRINEER"
246
? "/Lotus/Interface/Icons/Npcs/EliteRifleLancerAvatar.png" // Source: https://www.reddit.com/r/Warframe/comments/1aj4usx/battle_pay_worth_10_plat/, https://www.youtube.com/watch?v=XhNZ6ai6BOY
247
: "/Lotus/Interface/Icons/Npcs/CrewmanNormal.png", // My best source for this is https://www.youtube.com/watch?v=rxrCCFm73XE around 1:37
248
// TOVERIFY: highPriority?
249
endDate: new Date(Date.now() + 86400_000) // TOVERIFY: This type of inbox message seems to automatically delete itself. We'll just delete it after 24 hours, but it's not clear if this is correct.
250
}
251
]);
252
}
253
if (invasion.Faction != "FC_INFESTATION") {
254
// Sided with grineer -> opposed corpus -> send zanuka (harvester)
255
// Sided with corpus -> opposed grineer -> send g3 (death squad)
256
inventory[factionSidedWith != "FC_GRINEER" ? "DeathSquadable" : "Harvestable"] = true;
257
// TOVERIFY: Should this happen earlier?
258
// TOVERIFY: Should this send an (ephemeral) email?
226
if (factionSidedWith && battlePay) {
227
logger.debug(`invasion pay from ${factionSidedWith}`, { battlePay });
228
// Decoupling rewards from the inbox message because it may delete itself without being read
229
for (const item of battlePay) {
230
await addItem(inventory, item.ItemType, item.ItemCount);
259
231
}
232
await createMessage(account._id, [
233
{
234
sndr:
235
factionSidedWith == "FC_GRINEER"
236
? "/Lotus/Language/Menu/GrineerInvasionLeader"
237
: "/Lotus/Language/Menu/CorpusInvasionLeader",
238
msg: `/Lotus/Language/G1Quests/${factionSidedWith}_InvasionThankyouMessageBody`,
239
sub: `/Lotus/Language/G1Quests/${factionSidedWith}_InvasionThankyouMessageSubject`,
240
countedAtt: battlePay,
241
attVisualOnly: true,
242
icon:
243
factionSidedWith == "FC_GRINEER"
244
? "/Lotus/Interface/Icons/Npcs/EliteRifleLancerAvatar.png" // Source: https://www.reddit.com/r/Warframe/comments/1aj4usx/battle_pay_worth_10_plat/, https://www.youtube.com/watch?v=XhNZ6ai6BOY
245
: "/Lotus/Interface/Icons/Npcs/CrewmanNormal.png", // My best source for this is https://www.youtube.com/watch?v=rxrCCFm73XE around 1:37
246
// TOVERIFY: highPriority?
247
endDate: new Date(Date.now() + 86400_000) // TOVERIFY: This type of inbox message seems to automatically delete itself. We'll just delete it after 24 hours, but it's not clear if this is correct.
248
}
249
]);
260
250
}
261
251
logger.debug(`removing QualifyingInvasions entry for completed invasion: ${qi.invasionId.toString()}`);
262
252
inventory.QualifyingInvasions.splice(i, 1);
@@ -1909,6 +1909,10 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
1909
1909
//Grustag three
1910
1910
DeathSquadable: Boolean,
1911
1911
1912
// Server-only tracking fields for when to give zanuka or G3 death marks
1913
HarvesterPoints: Number,
1914
DeathSquadPoints: Number,
1915
1912
1916
EndlessXP: { type: [endlessXpProgressSchema], default: undefined },
1913
1917
1914
1918
DescentRewards: { type: [descentCategoryRewardSchema], default: undefined },
@@ -1952,6 +1956,8 @@ inventorySchema.set("toJSON", {
1952
1956
delete returnedObject.__v;
1953
1957
delete returnedObject.accountOwnerId;
1954
1958
delete returnedObject.MissionRelicRewards;
1959
delete returnedObject.HarvesterPoints;
1960
delete returnedObject.DeathSquadPoints;
1955
1961
1956
1962
const inventoryDatabase = returnedObject as Partial<IInventoryDatabase>;
1957
1963
const inventoryResponse = returnedObject as IInventoryClient;
@@ -0,0 +1,29 @@
1
interface IDeathSquadInfo {
2
booleanKey: "DeathSquadable" | "Harvestable";
3
numberKey: "DeathSquadPoints" | "HarvesterPoints";
4
inboxSender: string;
5
inboxIcon: string;
6
inboxTitle: string;
7
inboxMessage: string;
8
inboxMessageRepeat: string;
9
}
10
11
export const grineerDeathSquadInfo: IDeathSquadInfo = {
12
booleanKey: "DeathSquadable",
13
numberKey: "DeathSquadPoints",
14
inboxSender: "/Lotus/Language/Bosses/BossCouncilorVayHek",
15
inboxIcon: "/Lotus/Interface/Icons/Npcs/VayHekPortrait.png",
16
inboxTitle: "/Lotus/Language/G1Quests/DeathSquadTitle",
17
inboxMessage: "/Lotus/Language/G1Quests/DeathSquadMessage",
18
inboxMessageRepeat: "/Lotus/Language/G1Quests/DeathSquadMessageRepeat"
19
};
20
21
export const corpusDeathSquadInfo: IDeathSquadInfo = {
22
booleanKey: "Harvestable",
23
numberKey: "HarvesterPoints",
24
inboxSender: "/Lotus/Language/Bosses/BossAladV",
25
inboxIcon: "/Lotus/Interface/Icons/Npcs/AladVPortrait_d.png",
26
inboxTitle: "/Lotus/Language/G1Quests/HarvesterTitle",
27
inboxMessage: "/Lotus/Language/G1Quests/HarvesterkMessage",
28
inboxMessageRepeat: "/Lotus/Language/G1Quests/HarvesterkMessageRepeat"
29
};
@@ -73,6 +73,7 @@ import {
73
73
} from "../helpers/nemesisHelpers.ts";
74
74
import { Loadout } from "../models/inventoryModels/loadoutModel.ts";
75
75
import {
76
getInvasionByOid,
76
77
getLiteSortie,
77
78
getSortie,
78
79
getWorldState,
@@ -92,6 +93,7 @@ import { Guild } from "../models/guildModel.ts";
92
93
import { handleGuildGoalProgress } from "./guildService.ts";
93
94
import { importLoadOutConfig } from "./importService.ts";
94
95
import gameToBuildVersion from "../constants/gameToBuildVersion.ts";
96
import { corpusDeathSquadInfo, grineerDeathSquadInfo } from "./invasionService.ts";
95
97
96
98
const getRotations = (rewardInfo: IRewardInfo, tierOverride?: number): number[] => {
97
99
// For Spy missions, e.g. 3 vaults cracked = A, B, C
@@ -826,6 +828,30 @@ export const addMissionInventoryUpdates = async (
826
828
DefenderScore: clientProgress.DefenderScore
827
829
});
828
830
}
831
const invasion = getInvasionByOid(clientProgress._id.$oid)!;
832
const factionSidedWith = clientProgress.AttackerScore ? invasion.Faction : invasion.DefenderFaction;
833
if (invasion.Faction != "FC_INFESTATION") {
834
const info = factionSidedWith != "FC_GRINEER" ? grineerDeathSquadInfo : corpusDeathSquadInfo;
835
if (!inventory[info.booleanKey]) {
836
const numberKey = info.numberKey;
837
inventory[numberKey] ??= 0;
838
inventory[numberKey] += clientProgress.AttackerScore + clientProgress.DefenderScore;
839
if (inventory[numberKey] >= 5) {
840
inventory[numberKey] = 0;
841
const isRepeatMark = inventory[info.booleanKey] !== undefined;
842
inventory[info.booleanKey] = true;
843
await createMessage(inventory.accountOwnerId, [
844
{
845
sndr: info.inboxSender,
846
msg: isRepeatMark ? info.inboxMessageRepeat : info.inboxMessage,
847
sub: info.inboxTitle,
848
icon: info.inboxIcon,
849
highPriority: true
850
}
851
]);
852
}
853
}
854
}
829
855
}
830
856
break;
831
857
}
@@ -454,8 +454,10 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
454
454
LibraryActiveDailyTaskInfo?: ILibraryDailyTaskInfo;
455
455
HasResetAccount: boolean;
456
456
PendingCoupon?: IPendingCouponClient;
457
Harvestable: boolean;
458
DeathSquadable: boolean;
457
Harvestable?: boolean;
458
DeathSquadable?: boolean;
459
HarvesterPoints?: number;
460
DeathSquadPoints?: number;
459
461
EndlessXP?: IEndlessXpProgressClient[];
460
462
DescentRewards?: IDescentCategoryRewardClient[];
461
463
DialogueHistory?: IDialogueHistoryClient;