返回提交历史
Modified
src/controllers/api/claimCompletedRecipeController.ts
+8
-1
Modified
src/controllers/api/nemesisController.ts
+2
-48
Modified
src/helpers/nemesisHelpers.ts
+145
-1
Modified
src/models/inventoryModels/inventoryModel.ts
+6
-4
Modified
src/services/inventoryService.ts
+108
-2
Modified
src/services/missionInventoryUpdateService.ts
+49
-1
Modified
src/types/inventoryTypes/inventoryTypes.ts
+16
-3
Modified
src/types/requestTypes.ts
+10
-1
XFEstudio/SpaceNinjaServer
feat: handle NemesisKillConvert at missionInventoryUpdate (#1880)
Closes #1848 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1880 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
ee1a49f5
代码差异
8 个文件
+344
-61
@@ -133,7 +133,14 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
133
133
if (recipe.secretIngredientAction != "SIA_UNBRAND") {
134
134
InventoryChanges = {
135
135
...InventoryChanges,
136
...(await addItem(inventory, recipe.resultType, recipe.num, false))
136
...(await addItem(
137
inventory,
138
recipe.resultType,
139
recipe.num,
140
false,
141
undefined,
142
pendingRecipe.TargetFingerprint
143
))
137
144
};
138
145
}
139
146
await inventory.save();
@@ -3,6 +3,7 @@ import {
3
3
encodeNemesisGuess,
4
4
getInfNodes,
5
5
getNemesisPasscode,
6
getWeaponsForManifest,
6
7
IKnifeResponse
7
8
} from "@/src/helpers/nemesisHelpers";
8
9
import { getJSONfromString } from "@/src/helpers/stringHelpers";
@@ -170,18 +171,7 @@ export const nemesisController: RequestHandler = async (req, res) => {
170
171
171
172
let weaponIdx = -1;
172
173
if (body.target.Faction != "FC_INFESTATION") {
173
let weapons: readonly string[];
174
if (body.target.manifest == "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionSix") {
175
weapons = kuvaLichVersionSixWeapons;
176
} else if (
177
body.target.manifest == "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour" ||
178
body.target.manifest == "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree"
179
) {
180
weapons = corpusVersionThreeWeapons;
181
} else {
182
throw new Error(`unknown nemesis manifest: ${body.target.manifest}`);
183
}
184
174
const weapons = getWeaponsForManifest(body.target.manifest);
185
175
const initialWeaponIdx = new SRng(body.target.fp).randomInt(0, weapons.length - 1);
186
176
weaponIdx = initialWeaponIdx;
187
177
do {
@@ -283,39 +273,3 @@ interface INemesisRequiemRequest {
283
273
HiddenWhenHolstered: boolean;
284
274
};
285
275
}
286
287
const kuvaLichVersionSixWeapons = [
288
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Drakgoon/KuvaDrakgoon",
289
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Karak/KuvaKarak",
290
"/Lotus/Weapons/Grineer/Melee/GrnKuvaLichScythe/GrnKuvaLichScytheWeapon",
291
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Kohm/KuvaKohm",
292
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Ogris/KuvaOgris",
293
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Quartakk/KuvaQuartakk",
294
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Tonkor/KuvaTonkor",
295
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Brakk/KuvaBrakk",
296
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Kraken/KuvaKraken",
297
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Seer/KuvaSeer",
298
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Stubba/KuvaStubba",
299
"/Lotus/Weapons/Grineer/HeavyWeapons/GrnHeavyGrenadeLauncher",
300
"/Lotus/Weapons/Grineer/LongGuns/GrnKuvaLichRifle/GrnKuvaLichRifleWeapon",
301
"/Lotus/Weapons/Grineer/Bows/GrnBow/GrnBowWeapon",
302
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hind/KuvaHind",
303
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Nukor/KuvaNukor",
304
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hek/KuvaHekWeapon",
305
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Zarr/KuvaZarr",
306
"/Lotus/Weapons/Grineer/KuvaLich/HeavyWeapons/Grattler/KuvaGrattler",
307
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Sobek/KuvaSobek"
308
];
309
310
const corpusVersionThreeWeapons = [
311
"/Lotus/Weapons/Corpus/LongGuns/CrpBriefcaseLauncher/CrpBriefcaseLauncher",
312
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEArcaPlasmor/CrpBEArcaPlasmor",
313
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEFluxRifle/CrpBEFluxRifle",
314
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBETetra/CrpBETetra",
315
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBECycron/CrpBECycron",
316
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEDetron/CrpBEDetron",
317
"/Lotus/Weapons/Corpus/Pistols/CrpIgniterPistol/CrpIgniterPistol",
318
"/Lotus/Weapons/Corpus/Pistols/CrpBriefcaseAkimbo/CrpBriefcaseAkimboPistol",
319
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEPlinx/CrpBEPlinxWeapon",
320
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEGlaxion/CrpBEGlaxion"
321
];
@@ -1,4 +1,4 @@
1
import { ExportRegions } from "warframe-public-export-plus";
1
import { ExportRegions, ExportWarframes } from "warframe-public-export-plus";
2
2
import { IInfNode } from "@/src/types/inventoryTypes/inventoryTypes";
3
3
import { SRng } from "@/src/services/rngService";
4
4
import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
@@ -129,3 +129,147 @@ export const consumeModCharge = (
129
129
response.UpgradeNew.push(true);
130
130
}
131
131
};
132
133
const kuvaLichVersionSixWeapons = [
134
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Drakgoon/KuvaDrakgoon",
135
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Karak/KuvaKarak",
136
"/Lotus/Weapons/Grineer/Melee/GrnKuvaLichScythe/GrnKuvaLichScytheWeapon",
137
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Kohm/KuvaKohm",
138
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Ogris/KuvaOgris",
139
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Quartakk/KuvaQuartakk",
140
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Tonkor/KuvaTonkor",
141
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Brakk/KuvaBrakk",
142
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Kraken/KuvaKraken",
143
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Seer/KuvaSeer",
144
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Stubba/KuvaStubba",
145
"/Lotus/Weapons/Grineer/HeavyWeapons/GrnHeavyGrenadeLauncher",
146
"/Lotus/Weapons/Grineer/LongGuns/GrnKuvaLichRifle/GrnKuvaLichRifleWeapon",
147
"/Lotus/Weapons/Grineer/Bows/GrnBow/GrnBowWeapon",
148
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hind/KuvaHind",
149
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Nukor/KuvaNukor",
150
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hek/KuvaHekWeapon",
151
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Zarr/KuvaZarr",
152
"/Lotus/Weapons/Grineer/KuvaLich/HeavyWeapons/Grattler/KuvaGrattler",
153
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Sobek/KuvaSobek"
154
];
155
156
const corpusVersionThreeWeapons = [
157
"/Lotus/Weapons/Corpus/LongGuns/CrpBriefcaseLauncher/CrpBriefcaseLauncher",
158
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEArcaPlasmor/CrpBEArcaPlasmor",
159
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEFluxRifle/CrpBEFluxRifle",
160
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBETetra/CrpBETetra",
161
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBECycron/CrpBECycron",
162
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEDetron/CrpBEDetron",
163
"/Lotus/Weapons/Corpus/Pistols/CrpIgniterPistol/CrpIgniterPistol",
164
"/Lotus/Weapons/Corpus/Pistols/CrpBriefcaseAkimbo/CrpBriefcaseAkimboPistol",
165
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEPlinx/CrpBEPlinxWeapon",
166
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEGlaxion/CrpBEGlaxion"
167
];
168
169
export const getWeaponsForManifest = (manifest: string): readonly string[] => {
170
switch (manifest) {
171
case "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionSix":
172
return kuvaLichVersionSixWeapons;
173
case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree":
174
case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour":
175
return corpusVersionThreeWeapons;
176
}
177
throw new Error(`unknown nemesis manifest: ${manifest}`);
178
};
179
180
// TODO: This sucks.
181
export const getInnateDamageTag = (
182
KillingSuit: string
183
):
184
| "InnateElectricityDamage"
185
| "InnateFreezeDamage"
186
| "InnateHeatDamage"
187
| "InnateImpactDamage"
188
| "InnateMagDamage"
189
| "InnateRadDamage"
190
| "InnateToxinDamage" => {
191
const baseSuitType = ExportWarframes[KillingSuit].parentName;
192
switch (baseSuitType) {
193
case "/Lotus/Powersuits/Volt/VoltBaseSuit":
194
case "/Lotus/Powersuits/Excalibur/ExcaliburBaseSuit":
195
case "/Lotus/Powersuits/AntiMatter/NovaBaseSuit":
196
case "/Lotus/Powersuits/Banshee/BansheeBaseSuit":
197
case "/Lotus/Powersuits/Berserker/BerserkerBaseSuit":
198
case "/Lotus/Powersuits/Magician/MagicianBaseSuit":
199
case "/Lotus/Powersuits/Sentient/SentientBaseSuit":
200
case "/Lotus/Powersuits/Gyre/GyreBaseSuit":
201
return "InnateElectricityDamage";
202
case "/Lotus/Powersuits/Ember/EmberBaseSuit":
203
case "/Lotus/Powersuits/Dragon/DragonBaseSuit":
204
case "/Lotus/Powersuits/Nezha/NezhaBaseSuit":
205
case "/Lotus/Powersuits/Sandman/SandmanBaseSuit":
206
case "/Lotus/Powersuits/Trapper/TrapperBaseSuit":
207
case "/Lotus/Powersuits/Wisp/WispBaseSuit":
208
case "/Lotus/Powersuits/Odalisk/OdaliskBaseSuit":
209
case "/Lotus/Powersuits/PaxDuviricus/PaxDuviricusBaseSuit":
210
case "/Lotus/Powersuits/Choir/ChoirBaseSuit":
211
case "/Lotus/Powersuits/Temple/TempleBaseSuit":
212
return "InnateHeatDamage";
213
case "/Lotus/Powersuits/Frost/FrostBaseSuit":
214
case "/Lotus/Powersuits/Glass/GlassBaseSuit":
215
case "/Lotus/Powersuits/Fairy/FairyBaseSuit":
216
case "/Lotus/Powersuits/IronFrame/IronFrameBaseSuit":
217
case "/Lotus/Powersuits/Revenant/RevenantBaseSuit":
218
case "/Lotus/Powersuits/Trinity/TrinityBaseSuit":
219
case "/Lotus/Powersuits/Hoplite/HopliteBaseSuit":
220
case "/Lotus/Powersuits/Koumei/KoumeiBaseSuit":
221
return "InnateFreezeDamage";
222
case "/Lotus/Powersuits/Saryn/SarynBaseSuit":
223
case "/Lotus/Powersuits/Paladin/PaladinBaseSuit":
224
case "/Lotus/Powersuits/Brawler/BrawlerBaseSuit":
225
case "/Lotus/Powersuits/Infestation/InfestationBaseSuit":
226
case "/Lotus/Powersuits/Necro/NecroBaseSuit":
227
case "/Lotus/Powersuits/Khora/KhoraBaseSuit":
228
case "/Lotus/Powersuits/Ranger/RangerBaseSuit":
229
case "/Lotus/Powersuits/Dagath/DagathBaseSuit":
230
return "InnateToxinDamage";
231
case "/Lotus/Powersuits/Mag/MagBaseSuit":
232
case "/Lotus/Powersuits/Pirate/PirateBaseSuit":
233
case "/Lotus/Powersuits/Cowgirl/CowgirlBaseSuit":
234
case "/Lotus/Powersuits/Priest/PriestBaseSuit":
235
case "/Lotus/Powersuits/BrokenFrame/BrokenFrameBaseSuit":
236
case "/Lotus/Powersuits/Alchemist/AlchemistBaseSuit":
237
case "/Lotus/Powersuits/Yareli/YareliBaseSuit":
238
case "/Lotus/Powersuits/Geode/GeodeBaseSuit":
239
case "/Lotus/Powersuits/Frumentarius/FrumentariusBaseSuit":
240
return "InnateMagDamage";
241
case "/Lotus/Powersuits/Loki/LokiBaseSuit":
242
case "/Lotus/Powersuits/Ninja/NinjaBaseSuit":
243
case "/Lotus/Powersuits/Jade/JadeBaseSuit":
244
case "/Lotus/Powersuits/Bard/BardBaseSuit":
245
case "/Lotus/Powersuits/Harlequin/HarlequinBaseSuit":
246
case "/Lotus/Powersuits/Garuda/GarudaBaseSuit":
247
case "/Lotus/Powersuits/YinYang/YinYangBaseSuit":
248
case "/Lotus/Powersuits/Werewolf/WerewolfBaseSuit":
249
case "/Lotus/Powersuits/ConcreteFrame/ConcreteFrameBaseSuit":
250
return "InnateRadDamage";
251
case "/Lotus/Powersuits/Rhino/RhinoBaseSuit":
252
case "/Lotus/Powersuits/Tengu/TenguBaseSuit":
253
case "/Lotus/Powersuits/MonkeyKing/MonkeyKingBaseSuit":
254
case "/Lotus/Powersuits/Runner/RunnerBaseSuit":
255
case "/Lotus/Powersuits/Pacifist/PacifistBaseSuit":
256
case "/Lotus/Powersuits/Devourer/DevourerBaseSuit":
257
case "/Lotus/Powersuits/Wraith/WraithBaseSuit":
258
case "/Lotus/Powersuits/Pagemaster/PagemasterBaseSuit":
259
return "InnateImpactDamage";
260
}
261
logger.warn(`unknown innate damage type for ${KillingSuit}, using heat as a fallback`);
262
return "InnateHeatDamage";
263
};
264
265
// TODO: For -1399275245665749231n, the value should be 75306944, but we're off by 59 with 75307003.
266
export const getInnateDamageValue = (fp: bigint): number => {
267
const rng = new SRng(fp);
268
rng.randomFloat(); // used for the weapon index
269
const WeaponUpgradeValueAttenuationExponent = 2.25;
270
let value = Math.pow(rng.randomFloat(), WeaponUpgradeValueAttenuationExponent);
271
if (value >= 0.941428) {
272
value = 1;
273
}
274
return Math.trunc(value * 0x40000000);
275
};
@@ -1039,6 +1039,8 @@ const pendingRecipeSchema = new Schema<IPendingRecipeDatabase>(
1039
1039
{
1040
1040
ItemType: String,
1041
1041
CompletionDate: Date,
1042
TargetItemId: String,
1043
TargetFingerprint: String,
1042
1044
LongGuns: { type: [EquipmentSchema], default: undefined },
1043
1045
Pistols: { type: [EquipmentSchema], default: undefined },
1044
1046
Melee: { type: [EquipmentSchema], default: undefined },
@@ -1260,11 +1262,11 @@ const nemesisSchema = new Schema<INemesisDatabase>(
1260
1262
PrevOwners: Number,
1261
1263
SecondInCommand: Boolean,
1262
1264
Weakened: Boolean,
1263
InfNodes: [infNodeSchema],
1265
InfNodes: { type: [infNodeSchema], default: undefined },
1264
1266
HenchmenKilled: Number,
1265
1267
HintProgress: Number,
1266
Hints: [Number],
1267
GuessHistory: [Number],
1268
Hints: { type: [Number], default: undefined },
1269
GuessHistory: { type: [Number], default: undefined },
1268
1270
MissionCount: Number,
1269
1271
LastEnc: Number
1270
1272
},
@@ -1609,7 +1611,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
1609
1611
//CorpusLich or GrineerLich
1610
1612
NemesisAbandonedRewards: { type: [String], default: [] },
1611
1613
Nemesis: nemesisSchema,
1612
NemesisHistory: [Schema.Types.Mixed],
1614
NemesisHistory: { type: [nemesisSchema], default: undefined },
1613
1615
LastNemesisAllySpawnTime: Schema.Types.Mixed,
1614
1616
1615
1617
//TradingRulesConfirmed,ShowFriendInvNotifications(Option->Social)
@@ -26,7 +26,9 @@ import {
26
26
Status,
27
27
IKubrowPetDetailsDatabase,
28
28
ITraits,
29
ICalendarProgress
29
ICalendarProgress,
30
INemesisWeaponTargetFingerprint,
31
INemesisPetTargetFingerprint
30
32
} from "@/src/types/inventoryTypes/inventoryTypes";
31
33
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate";
32
34
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
@@ -79,6 +81,7 @@ import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from ".
79
81
import { createMessage } from "./inboxService";
80
82
import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
81
83
import { getWorldState } from "./worldStateService";
84
import { getInnateDamageTag, getInnateDamageValue } from "../helpers/nemesisHelpers";
82
85
83
86
export const createInventory = async (
84
87
accountOwnerId: Types.ObjectId,
@@ -327,7 +330,8 @@ export const addItem = async (
327
330
typeName: string,
328
331
quantity: number = 1,
329
332
premiumPurchase: boolean = false,
330
seed?: bigint
333
seed?: bigint,
334
targetFingerprint?: string
331
335
): Promise<IInventoryChanges> => {
332
336
// 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.
333
337
if (typeName in ExportBundles) {
@@ -530,6 +534,12 @@ export const addItem = async (
530
534
]
531
535
});
532
536
}
537
if (targetFingerprint) {
538
const targetFingerprintObj = JSON.parse(targetFingerprint) as INemesisWeaponTargetFingerprint;
539
defaultOverwrites.UpgradeType = targetFingerprintObj.ItemType;
540
defaultOverwrites.UpgradeFingerprint = JSON.stringify(targetFingerprintObj.UpgradeFingerprint);
541
defaultOverwrites.ItemName = targetFingerprintObj.Name;
542
}
533
543
const inventoryChanges = addEquipment(inventory, weapon.productCategory, typeName, defaultOverwrites);
534
544
if (weapon.additionalItems) {
535
545
for (const item of weapon.additionalItems) {
@@ -544,6 +554,27 @@ export const addItem = async (
544
554
premiumPurchase
545
555
)
546
556
};
557
} else if (targetFingerprint) {
558
// Sister's Hound
559
const targetFingerprintObj = JSON.parse(targetFingerprint) as INemesisPetTargetFingerprint;
560
const head = targetFingerprintObj.Parts[0];
561
const defaultOverwrites: Partial<IEquipmentDatabase> = {
562
ModularParts: targetFingerprintObj.Parts,
563
ItemName: targetFingerprintObj.Name,
564
Configs: applyDefaultUpgrades(inventory, ExportWeapons[head].defaultUpgrades)
565
};
566
const itemType = {
567
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadA":
568
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetAPowerSuit",
569
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadB":
570
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetBPowerSuit",
571
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadC":
572
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetCPowerSuit"
573
}[head] as string;
574
return {
575
...addEquipment(inventory, "MoaPets", itemType, defaultOverwrites),
576
...occupySlot(inventory, InventorySlot.SENTINELS, premiumPurchase)
577
};
547
578
} else {
548
579
// Modular weapon parts
549
580
const miscItemChanges = [
@@ -1851,3 +1882,78 @@ export const getCalendarProgress = (inventory: TInventoryDatabaseDocument): ICal
1851
1882
1852
1883
return inventory.CalendarProgress;
1853
1884
};
1885
1886
export const giveNemesisWeaponRecipe = (
1887
inventory: TInventoryDatabaseDocument,
1888
weaponType: string,
1889
nemesisName: string = "AGOR ROK",
1890
weaponLoc?: string,
1891
KillingSuit: string = "/Lotus/Powersuits/Ember/Ember",
1892
fp: bigint = generateRewardSeed()
1893
): void => {
1894
if (!weaponLoc) {
1895
weaponLoc = ExportWeapons[weaponType].name;
1896
}
1897
const recipeType = Object.entries(ExportRecipes).find(arr => arr[1].resultType == weaponType)![0];
1898
addRecipes(inventory, [
1899
{
1900
ItemType: recipeType,
1901
ItemCount: 1
1902
}
1903
]);
1904
inventory.PendingRecipes.push({
1905
CompletionDate: new Date(),
1906
ItemType: recipeType,
1907
TargetFingerprint: JSON.stringify({
1908
ItemType: "/Lotus/Weapons/Grineer/KuvaLich/Upgrades/InnateDamageRandomMod",
1909
UpgradeFingerprint: {
1910
compat: weaponType,
1911
buffs: [
1912
{
1913
Tag: getInnateDamageTag(KillingSuit),
1914
Value: getInnateDamageValue(fp)
1915
}
1916
]
1917
},
1918
Name: weaponLoc + "|" + nemesisName
1919
} satisfies INemesisWeaponTargetFingerprint)
1920
});
1921
};
1922
1923
export const giveNemesisPetRecipe = (inventory: TInventoryDatabaseDocument, nemesisName: string = "AGOR ROK"): void => {
1924
const head = getRandomElement([
1925
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadA",
1926
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadB",
1927
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadC"
1928
]);
1929
const body = getRandomElement([
1930
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyA",
1931
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyB",
1932
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyC"
1933
]);
1934
const legs = getRandomElement([
1935
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsA",
1936
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsB",
1937
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsC"
1938
]);
1939
const tail = getRandomElement([
1940
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailA",
1941
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailB",
1942
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailC"
1943
]);
1944
const recipeType = Object.entries(ExportRecipes).find(arr => arr[1].resultType == head)![0];
1945
addRecipes(inventory, [
1946
{
1947
ItemType: recipeType,
1948
ItemCount: 1
1949
}
1950
]);
1951
inventory.PendingRecipes.push({
1952
CompletionDate: new Date(),
1953
ItemType: recipeType,
1954
TargetFingerprint: JSON.stringify({
1955
Parts: [head, body, legs, tail],
1956
Name: "/Lotus/Language/Pets/ZanukaPetName|" + nemesisName
1957
} satisfies INemesisPetTargetFingerprint)
1958
});
1959
};
@@ -35,6 +35,8 @@ import {
35
35
combineInventoryChanges,
36
36
generateRewardSeed,
37
37
getCalendarProgress,
38
giveNemesisPetRecipe,
39
giveNemesisWeaponRecipe,
38
40
updateCurrency,
39
41
updateSyndicate
40
42
} from "@/src/services/inventoryService";
@@ -53,7 +55,7 @@ import kuriaMessage50 from "@/static/fixed_responses/kuriaMessages/fiftyPercent.
53
55
import kuriaMessage75 from "@/static/fixed_responses/kuriaMessages/seventyFivePercent.json";
54
56
import kuriaMessage100 from "@/static/fixed_responses/kuriaMessages/oneHundredPercent.json";
55
57
import conservationAnimals from "@/static/fixed_responses/conservationAnimals.json";
56
import { getInfNodes } from "@/src/helpers/nemesisHelpers";
58
import { getInfNodes, getWeaponsForManifest } from "@/src/helpers/nemesisHelpers";
57
59
import { Loadout } from "../models/inventoryModels/loadoutModel";
58
60
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
59
61
import { getLiteSortie, getWorldState, idToWeek } from "./worldStateService";
@@ -612,6 +614,52 @@ export const addMissionInventoryUpdates = async (
612
614
}
613
615
break;
614
616
}
617
case "NemesisKillConvert":
618
if (inventory.Nemesis) {
619
inventory.NemesisHistory ??= [];
620
inventory.NemesisHistory.push({
621
// Copy over all 'base' values
622
fp: inventory.Nemesis.fp,
623
d: inventory.Nemesis.d,
624
manifest: inventory.Nemesis.manifest,
625
KillingSuit: inventory.Nemesis.KillingSuit,
626
killingDamageType: inventory.Nemesis.killingDamageType,
627
ShoulderHelmet: inventory.Nemesis.ShoulderHelmet,
628
WeaponIdx: inventory.Nemesis.WeaponIdx,
629
AgentIdx: inventory.Nemesis.AgentIdx,
630
BirthNode: inventory.Nemesis.BirthNode,
631
Faction: inventory.Nemesis.Faction,
632
Rank: inventory.Nemesis.Rank,
633
Traded: inventory.Nemesis.Traded,
634
PrevOwners: inventory.Nemesis.PrevOwners,
635
SecondInCommand: inventory.Nemesis.SecondInCommand,
636
Weakened: inventory.Nemesis.Weakened,
637
// And set killed flag
638
k: value.killed
639
});
640
641
if (value.killed) {
642
if (value.weaponLoc) {
643
const weaponType = getWeaponsForManifest(inventory.Nemesis.manifest)[
644
inventory.Nemesis.WeaponIdx
645
];
646
giveNemesisWeaponRecipe(
647
inventory,
648
weaponType,
649
value.nemesisName,
650
value.weaponLoc,
651
inventory.Nemesis.KillingSuit,
652
inventory.Nemesis.fp
653
);
654
}
655
if (value.petLoc) {
656
giveNemesisPetRecipe(inventory);
657
}
658
}
659
660
inventory.Nemesis = undefined;
661
}
662
break;
615
663
default:
616
664
// Equipment XP updates
617
665
if (equipmentKeys.includes(key as TEquipmentKey)) {
@@ -43,6 +43,7 @@ export interface IInventoryDatabase
43
43
| "RecentVendorPurchases"
44
44
| "NextRefill"
45
45
| "Nemesis"
46
| "NemesisHistory"
46
47
| "EntratiVaultCountResetDate"
47
48
| "BrandedSuits"
48
49
| "LockedWeaponGroup"
@@ -79,6 +80,7 @@ export interface IInventoryDatabase
79
80
RecentVendorPurchases?: IRecentVendorPurchaseDatabase[];
80
81
NextRefill?: Date;
81
82
Nemesis?: INemesisDatabase;
83
NemesisHistory?: INemesisBaseDatabase[];
82
84
EntratiVaultCountResetDate?: Date;
83
85
BrandedSuits?: Types.ObjectId[];
84
86
LockedWeaponGroup?: ILockedWeaponGroupDatabase;
@@ -313,7 +315,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
313
315
EquippedInstrument?: string;
314
316
InvasionChainProgress: IInvasionChainProgress[];
315
317
Nemesis?: INemesisClient;
316
NemesisHistory: INemesisBaseClient[];
318
NemesisHistory?: INemesisBaseClient[];
317
319
LastNemesisAllySpawnTime?: IMongoDate;
318
320
Settings?: ISettings;
319
321
PersonalTechProjects: IPersonalTechProjectClient[];
@@ -902,8 +904,8 @@ export interface IPendingRecipeDatabase {
902
904
ItemType: string;
903
905
CompletionDate: Date;
904
906
ItemId: IOid;
905
TargetItemId?: string; // likely related to liches
906
TargetFingerprint?: string; // likely related to liches
907
TargetItemId?: string; // unsure what this is for
908
TargetFingerprint?: string;
907
909
LongGuns?: IEquipmentDatabase[];
908
910
Pistols?: IEquipmentDatabase[];
909
911
Melee?: IEquipmentDatabase[];
@@ -951,6 +953,17 @@ export interface ICrewShipComponentFingerprint extends IInnateDamageFingerprint
951
953
SubroutineIndex?: number;
952
954
}
953
955
956
export interface INemesisWeaponTargetFingerprint {
957
ItemType: string;
958
UpgradeFingerprint: IInnateDamageFingerprint;
959
Name: string;
960
}
961
962
export interface INemesisPetTargetFingerprint {
963
Parts: string[];
964
Name: string;
965
}
966
954
967
export enum GettingSlotOrderInfo {
955
968
Empty = "",
956
969
LotusUpgradesModsRandomizedPlayerMeleeWeaponRandomModRare0 = "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare:0",
@@ -22,7 +22,8 @@ import {
22
22
ILoadOutPresets,
23
23
IInvasionProgressClient,
24
24
IWeaponSkinClient,
25
IKubrowPetEggClient
25
IKubrowPetEggClient,
26
INemesisClient
26
27
} from "./inventoryTypes/inventoryTypes";
27
28
import { IGroup } from "./loginTypes";
28
29
@@ -74,6 +75,14 @@ export type IMissionInventoryUpdateRequest = {
74
75
PS: string;
75
76
ActiveDojoColorResearch: string;
76
77
RewardInfo?: IRewardInfo;
78
NemesisKillConvert?: {
79
nemesisName: string;
80
weaponLoc: string;
81
petLoc: "" | "/Lotus/Language/Pets/ZanukaPetName";
82
fingerprint: bigint | number;
83
killed: boolean;
84
};
85
target?: INemesisClient;
77
86
ReceivedCeremonyMsg: boolean;
78
87
LastCeremonyResetDate: number;
79
88
MissionPTS: number;