XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

SpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 1 Star 0
返回提交历史

XFEstudio/SpaceNinjaServer

feat: infested lich rewards (#1898)

Closes #1884 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1898 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>

9042e853
Sainan <63328889+Sainan@users.noreply.github.com>
提交于

代码差异

4 个文件 +127 -7
Modified src/controllers/api/inboxController.ts +2 -1
@@ -13,6 +13,7 @@ import { addItems, combineInventoryChanges, getInventory } from "@/src/services/
13 13 import { logger } from "@/src/utils/logger";
14 14 import { ExportFlavour, ExportGear } from "warframe-public-export-plus";
15 15 import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
16 import { fromStoreItem, isStoreItem } from "@/src/services/itemDataService";
16 17
17 18 export const inboxController: RequestHandler = async (req, res) => {
18 19 const { deleteId, lastMessage: latestClientMessageId, messageId } = req.query;
@@ -48,7 +49,7 @@ export const inboxController: RequestHandler = async (req, res) => {
48 49 await addItems(
49 50 inventory,
50 51 attachmentItems.map(attItem => ({
51 ItemType: attItem,
52 ItemType: isStoreItem(attItem) ? fromStoreItem(attItem) : attItem,
52 53 ItemCount: attItem in ExportGear ? (ExportGear[attItem].purchaseQuantity ?? 1) : 1
53 54 })),
54 55 inventoryChanges
Modified src/helpers/nemesisHelpers.ts +111 -3
@@ -1,12 +1,14 @@
1 1 import { ExportRegions, ExportWarframes } from "warframe-public-export-plus";
2 import { IInfNode } from "@/src/types/inventoryTypes/inventoryTypes";
3 import { SRng } from "@/src/services/rngService";
2 import { IInfNode, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
3 import { getRewardAtPercentage, SRng } from "@/src/services/rngService";
4 4 import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
5 5 import { logger } from "../utils/logger";
6 6 import { IOid } from "../types/commonTypes";
7 7 import { Types } from "mongoose";
8 import { addMods } from "../services/inventoryService";
8 import { addMods, generateRewardSeed } from "../services/inventoryService";
9 9 import { isArchwingMission } from "../services/worldStateService";
10 import { fromStoreItem, toStoreItem } from "../services/itemDataService";
11 import { createMessage } from "../services/inboxService";
10 12
11 13 export const getInfNodes = (faction: string, rank: number): IInfNode[] => {
12 14 const infNodes = [];
@@ -340,3 +342,109 @@ export const getInnateDamageValue = (fp: bigint): number => {
340 342 }
341 343 return Math.trunc(value * 0x40000000);
342 344 };
345
346 export const getKillTokenRewardCount = (fp: bigint): number => {
347 const rng = new SRng(fp);
348 return rng.randomInt(10, 15);
349 };
350
351 // /Lotus/Types/Enemies/InfestedLich/InfestedLichRewardManifest
352 const infestedLichRotA = [
353 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDJRomHuman", probability: 0.046 },
354 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDJRomInfested", probability: 0.045 },
355 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDrillbitHuman", probability: 0.046 },
356 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDrillbitInfested", probability: 0.045 },
357 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyHarddriveHuman", probability: 0.046 },
358 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyHarddriveInfested", probability: 0.045 },
359 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyPacketHuman", probability: 0.046 },
360 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyPacketInfested", probability: 0.045 },
361 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyZekeHuman", probability: 0.046 },
362 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyZekeInfested", probability: 0.045 },
363 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandBillboardPosterA", probability: 0.045 },
364 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandBillboardPosterB", probability: 0.046 },
365 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandDespairPoster", probability: 0.045 },
366 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandGridPoster", probability: 0.046 },
367 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandHuddlePoster", probability: 0.045 },
368 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandJumpPoster", probability: 0.046 },
369 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLimoPoster", probability: 0.045 },
370 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLookingDownPosterDay", probability: 0.046 },
371 {
372 type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLookingDownPosterNight",
373 probability: 0.045
374 },
375 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandSillyPoster", probability: 0.046 },
376 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandWhiteBluePoster", probability: 0.045 },
377 { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandWhitePinkPoster", probability: 0.045 }
378 ];
379 const infestedLichRotB = [
380 { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraA", probability: 0.072 },
381 { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraB", probability: 0.071 },
382 { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraC", probability: 0.072 },
383 { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraD", probability: 0.071 },
384 { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraE", probability: 0.072 },
385 { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraF", probability: 0.071 },
386 { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraG", probability: 0.071 },
387 { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraH", probability: 0.072 },
388 { type: "/Lotus/StoreItems/Types/Items/Emotes/DanceDJRomHype", probability: 0.071 },
389 { type: "/Lotus/StoreItems/Types/Items/Emotes/DancePacketWindmillShuffle", probability: 0.072 },
390 { type: "/Lotus/StoreItems/Types/Items/Emotes/DanceHarddrivePony", probability: 0.071 },
391 { type: "/Lotus/StoreItems/Types/Items/Emotes/DanceDrillbitCrisscross", probability: 0.072 },
392 { type: "/Lotus/StoreItems/Types/Items/Emotes/DanceZekeCanthavethis", probability: 0.071 },
393 { type: "/Lotus/StoreItems/Types/Items/PhotoBooth/PhotoboothTileRJLasXStadiumBossArena", probability: 0.071 }
394 ];
395 export const getInfestedLichItemRewards = (fp: bigint): string[] => {
396 const rng = new SRng(fp);
397 const rotAReward = getRewardAtPercentage(infestedLichRotA, rng.randomFloat())!.type;
398 rng.randomFloat(); // unused afaict
399 const rotBReward = getRewardAtPercentage(infestedLichRotB, rng.randomFloat())!.type;
400 return [rotAReward, rotBReward];
401 };
402
403 export const sendCodaFinishedMessage = async (
404 inventory: TInventoryDatabaseDocument,
405 fp: bigint = generateRewardSeed(),
406 name: string = "ZEKE_BEATWOMAN_TM.1999",
407 killed: boolean = true
408 ): Promise<void> => {
409 const att: string[] = [];
410
411 // First vanquish/convert gives a sigil
412 const sigil = killed
413 ? "/Lotus/Upgrades/Skins/Sigils/InfLichVanquishedSigil"
414 : "/Lotus/Upgrades/Skins/Sigils/InfLichConvertedSigil";
415 if (!inventory.WeaponSkins.find(x => x.ItemType == sigil)) {
416 att.push(toStoreItem(sigil));
417 }
418
419 const [rotAReward, rotBReward] = getInfestedLichItemRewards(fp);
420 att.push(fromStoreItem(rotAReward));
421 att.push(fromStoreItem(rotBReward));
422
423 let countedAtt: ITypeCount[] | undefined;
424 if (killed) {
425 countedAtt = [
426 {
427 ItemType: "/Lotus/Types/Items/MiscItems/CodaWeaponBucks",
428 ItemCount: getKillTokenRewardCount(fp)
429 }
430 ];
431 }
432
433 await createMessage(inventory.accountOwnerId, [
434 {
435 sndr: "/Lotus/Language/Bosses/Ordis",
436 msg: "/Lotus/Language/Inbox/VanquishBandMsgBody",
437 arg: [
438 {
439 Key: "LICH_NAME",
440 Tag: name
441 }
442 ],
443 att: att,
444 countedAtt: countedAtt,
445 sub: "/Lotus/Language/Inbox/VanquishBandMsgTitle",
446 icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
447 highPriority: true
448 }
449 ]);
450 };
Modified src/services/missionInventoryUpdateService.ts +10 -2
@@ -55,7 +55,7 @@ import kuriaMessage50 from "@/static/fixed_responses/kuriaMessages/fiftyPercent.
55 55 import kuriaMessage75 from "@/static/fixed_responses/kuriaMessages/seventyFivePercent.json";
56 56 import kuriaMessage100 from "@/static/fixed_responses/kuriaMessages/oneHundredPercent.json";
57 57 import conservationAnimals from "@/static/fixed_responses/conservationAnimals.json";
58 import { getInfNodes, getWeaponsForManifest } from "@/src/helpers/nemesisHelpers";
58 import { getInfNodes, getWeaponsForManifest, sendCodaFinishedMessage } from "@/src/helpers/nemesisHelpers";
59 59 import { Loadout } from "../models/inventoryModels/loadoutModel";
60 60 import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
61 61 import { getLiteSortie, getWorldState, idToWeek } from "./worldStateService";
@@ -639,7 +639,10 @@ export const addMissionInventoryUpdates = async (
639 639 });
640 640
641 641 if (value.killed) {
642 if (value.weaponLoc) {
642 if (
643 value.weaponLoc &&
644 inventory.Nemesis.Faction != "FC_INFESTATION" // weaponLoc is "/Lotus/Language/Weapons/DerelictCernosName" for these for some reason
645 ) {
643 646 const weaponType = getWeaponsForManifest(inventory.Nemesis.manifest)[
644 647 inventory.Nemesis.WeaponIdx
645 648 ];
@@ -657,6 +660,11 @@ export const addMissionInventoryUpdates = async (
657 660 }
658 661 }
659 662
663 // TOVERIFY: Is the inbox message also sent when converting a lich? If not, how are the rewards given?
664 if (inventory.Nemesis.Faction == "FC_INFESTATION") {
665 await sendCodaFinishedMessage(inventory, inventory.Nemesis.fp, value.nemesisName, value.killed);
666 }
667
660 668 inventory.Nemesis = undefined;
661 669 }
662 670 break;
Modified src/services/rngService.ts +4 -1
@@ -18,7 +18,10 @@ export const getRandomInt = (min: number, max: number): number => {
18 18 return Math.floor(Math.random() * (max - min + 1)) + min;
19 19 };
20 20
21 const getRewardAtPercentage = <T extends { probability: number }>(pool: T[], percentage: number): T | undefined => {
21 export const getRewardAtPercentage = <T extends { probability: number }>(
22 pool: T[],
23 percentage: number
24 ): T | undefined => {
22 25 if (pool.length == 0) return;
23 26
24 27 const totalChance = pool.reduce((accum, item) => accum + item.probability, 0);