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

XFESpaceNinjaServer

A simple server for a small space ninja game

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

XFEstudio/XFESpaceNinjaServer

feat: bounty standing reward (#1556)

Re #388 I think this only missing `Field Bounties` and `Arcana Isolation Vault` Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1556 Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Co-committed-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>

946f3129
AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
提交于

代码差异

6 个文件 +149 -70
Modified src/controllers/api/fishmongerController.ts +5 -23
@@ -1,10 +1,9 @@
1 1 import { getJSONfromString } from "@/src/helpers/stringHelpers";
2 import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
3 import { addMiscItems, getInventory, getStandingLimit, updateStandingLimit } from "@/src/services/inventoryService";
2 import { addMiscItems, addStanding, getInventory } from "@/src/services/inventoryService";
4 3 import { getAccountIdForRequest } from "@/src/services/loginService";
5 4 import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
6 5 import { RequestHandler } from "express";
7 import { ExportResources, ExportSyndicates } from "warframe-public-export-plus";
6 import { ExportResources } from "warframe-public-export-plus";
8 7
9 8 export const fishmongerController: RequestHandler = async (req, res) => {
10 9 const accountId = await getAccountIdForRequest(req);
@@ -31,32 +30,15 @@ export const fishmongerController: RequestHandler = async (req, res) => {
31 30 miscItemChanges.push({ ItemType: fish.ItemType, ItemCount: fish.ItemCount * -1 });
32 31 }
33 32 addMiscItems(inventory, miscItemChanges);
34 if (gainedStanding && syndicateTag) {
35 let syndicate = inventory.Affiliations.find(x => x.Tag == syndicateTag);
36 if (!syndicate) {
37 syndicate = inventory.Affiliations[inventory.Affiliations.push({ Tag: syndicateTag, Standing: 0 }) - 1];
38 }
39 const syndicateMeta = ExportSyndicates[syndicateTag];
40
41 const max = getMaxStanding(syndicateMeta, syndicate.Title ?? 0);
42 if (syndicate.Standing + gainedStanding > max) {
43 gainedStanding = max - syndicate.Standing;
44 }
45 if (gainedStanding > getStandingLimit(inventory, syndicateMeta.dailyLimitBin)) {
46 gainedStanding = getStandingLimit(inventory, syndicateMeta.dailyLimitBin);
47 }
48
49 syndicate.Standing += gainedStanding;
50
51 updateStandingLimit(inventory, syndicateMeta.dailyLimitBin, gainedStanding);
52 }
33 let affiliationMod;
34 if (gainedStanding && syndicateTag) affiliationMod = addStanding(inventory, syndicateTag, gainedStanding);
53 35 await inventory.save();
54 36 res.json({
55 37 InventoryChanges: {
56 38 MiscItems: miscItemChanges
57 39 },
58 40 SyndicateTag: syndicateTag,
59 StandingChange: gainedStanding
41 StandingChange: affiliationMod?.Standing || 0
60 42 });
61 43 };
62 44
Modified src/controllers/api/missionInventoryUpdateController.ts +9 -4
@@ -55,8 +55,10 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
55 55 const inventory = await getInventory(accountId);
56 56 const inventoryUpdates = await addMissionInventoryUpdates(inventory, missionReport);
57 57
58 // skip mission rewards if not GS_SUCCESS and not a bounty (by presence of jobId, as there's a reward every stage but only the last stage has GS_SUCCESS)
59 if (missionReport.MissionStatus !== "GS_SUCCESS" && !missionReport.RewardInfo?.jobId) {
58 if (
59 missionReport.MissionStatus !== "GS_SUCCESS" &&
60 !(missionReport.RewardInfo?.jobId || missionReport.RewardInfo?.challengeMissionId)
61 ) {
60 62 await inventory.save();
61 63 const inventoryResponse = await getInventoryResponse(inventory, true);
62 64 res.json({
@@ -66,7 +68,8 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
66 68 return;
67 69 }
68 70
69 const { MissionRewards, inventoryChanges, credits } = await addMissionRewards(inventory, missionReport);
71 const { MissionRewards, inventoryChanges, credits, AffiliationMods, SyndicateXPItemReward } =
72 await addMissionRewards(inventory, missionReport);
70 73
71 74 await inventory.save();
72 75 const inventoryResponse = await getInventoryResponse(inventory, true);
@@ -78,7 +81,9 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
78 81 MissionRewards,
79 82 ...credits,
80 83 ...inventoryUpdates,
81 FusionPoints: inventoryChanges?.FusionPoints
84 FusionPoints: inventoryChanges?.FusionPoints,
85 SyndicateXPItemReward,
86 AffiliationMods
82 87 });
83 88 };
84 89
Modified src/controllers/api/syndicateStandingBonusController.ts +3 -35
@@ -1,16 +1,9 @@
1 1 import { RequestHandler } from "express";
2 2 import { getAccountIdForRequest } from "@/src/services/loginService";
3 import {
4 addMiscItems,
5 freeUpSlot,
6 getInventory,
7 getStandingLimit,
8 updateStandingLimit
9 } from "@/src/services/inventoryService";
3 import { addMiscItems, addStanding, freeUpSlot, getInventory } from "@/src/services/inventoryService";
10 4 import { IMiscItem, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
11 5 import { IOid } from "@/src/types/commonTypes";
12 6 import { ExportSyndicates, ExportWeapons } from "warframe-public-export-plus";
13 import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
14 7 import { logger } from "@/src/utils/logger";
15 8 import { IInventoryChanges } from "@/src/types/purchaseTypes";
16 9 import { EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
@@ -61,38 +54,13 @@ export const syndicateStandingBonusController: RequestHandler = async (req, res)
61 54 inventoryChanges[slotBin] = { count: -1, platinum: 0, Slots: 1 };
62 55 }
63 56
64 let syndicate = inventory.Affiliations.find(x => x.Tag == request.Operation.AffiliationTag);
65 if (!syndicate) {
66 syndicate =
67 inventory.Affiliations[
68 inventory.Affiliations.push({ Tag: request.Operation.AffiliationTag, Standing: 0 }) - 1
69 ];
70 }
71
72 const max = getMaxStanding(syndicateMeta, syndicate.Title ?? 0);
73 if (syndicate.Standing + gainedStanding > max) {
74 gainedStanding = max - syndicate.Standing;
75 }
76
77 if (syndicateMeta.medallionsCappedByDailyLimit) {
78 if (gainedStanding > getStandingLimit(inventory, syndicateMeta.dailyLimitBin)) {
79 gainedStanding = getStandingLimit(inventory, syndicateMeta.dailyLimitBin);
80 }
81 updateStandingLimit(inventory, syndicateMeta.dailyLimitBin, gainedStanding);
82 }
83
84 syndicate.Standing += gainedStanding;
57 const affiliationMod = addStanding(inventory, request.Operation.AffiliationTag, gainedStanding, true);
85 58
86 59 await inventory.save();
87 60
88 61 res.json({
89 62 InventoryChanges: inventoryChanges,
90 AffiliationMods: [
91 {
92 Tag: request.Operation.AffiliationTag,
93 Standing: gainedStanding
94 }
95 ]
63 AffiliationMods: [affiliationMod]
96 64 });
97 65 };
98 66
Modified src/services/inventoryService.ts +34 -6
@@ -65,6 +65,7 @@ import { handleBundleAcqusition } from "./purchaseService";
65 65 import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
66 66 import { getRandomElement, getRandomInt, SRng } from "./rngService";
67 67 import { createMessage } from "./inboxService";
68 import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
68 69
69 70 export const createInventory = async (
70 71 accountOwnerId: Types.ObjectId,
@@ -930,23 +931,50 @@ const standingLimitBinToInventoryKey: Record<
930 931
931 932 export const allDailyAffiliationKeys: (keyof IDailyAffiliations)[] = Object.values(standingLimitBinToInventoryKey);
932 933
933 export const getStandingLimit = (inventory: IDailyAffiliations, bin: TStandingLimitBin): number => {
934 const getStandingLimit = (inventory: IDailyAffiliations, bin: TStandingLimitBin): number => {
934 935 if (bin == "STANDING_LIMIT_BIN_NONE" || config.noDailyStandingLimits) {
935 936 return Number.MAX_SAFE_INTEGER;
936 937 }
937 938 return inventory[standingLimitBinToInventoryKey[bin]];
938 939 };
939 940
940 export const updateStandingLimit = (
941 inventory: IDailyAffiliations,
942 bin: TStandingLimitBin,
943 subtrahend: number
944 ): void => {
941 const updateStandingLimit = (inventory: IDailyAffiliations, bin: TStandingLimitBin, subtrahend: number): void => {
945 942 if (bin != "STANDING_LIMIT_BIN_NONE" && !config.noDailyStandingLimits) {
946 943 inventory[standingLimitBinToInventoryKey[bin]] -= subtrahend;
947 944 }
948 945 };
949 946
947 export const addStanding = (
948 inventory: TInventoryDatabaseDocument,
949 syndicateTag: string,
950 gainedStanding: number,
951 isMedallion: boolean = false
952 ): IAffiliationMods => {
953 let syndicate = inventory.Affiliations.find(x => x.Tag == syndicateTag);
954 const syndicateMeta = ExportSyndicates[syndicateTag];
955
956 if (!syndicate) {
957 syndicate =
958 inventory.Affiliations[inventory.Affiliations.push({ Tag: syndicateTag, Standing: 0, Title: 0 }) - 1];
959 }
960
961 const max = getMaxStanding(syndicateMeta, syndicate.Title ?? 0);
962 if (syndicate.Standing + gainedStanding > max) gainedStanding = max - syndicate.Standing;
963
964 if (!isMedallion || (isMedallion && syndicateMeta.medallionsCappedByDailyLimit)) {
965 if (gainedStanding > getStandingLimit(inventory, syndicateMeta.dailyLimitBin)) {
966 gainedStanding = getStandingLimit(inventory, syndicateMeta.dailyLimitBin);
967 }
968 updateStandingLimit(inventory, syndicateMeta.dailyLimitBin, gainedStanding);
969 }
970
971 syndicate.Standing += gainedStanding;
972 return {
973 Tag: syndicateTag,
974 Standing: gainedStanding
975 };
976 };
977
950 978 // TODO: AffiliationMods support (Nightwave).
951 979 export const updateGeneric = async (data: IGenericUpdate, accountId: string): Promise<IUpdateNodeIntrosResponse> => {
952 980 const inventory = await getInventory(accountId, "NodeIntrosCompleted MiscItems");
Modified src/services/missionInventoryUpdateService.ts +97 -2
@@ -28,13 +28,14 @@ import {
28 28 addMods,
29 29 addRecipes,
30 30 addShipDecorations,
31 addStanding,
31 32 combineInventoryChanges,
32 33 updateCurrency,
33 34 updateSyndicate
34 35 } from "@/src/services/inventoryService";
35 36 import { updateQuestKey } from "@/src/services/questService";
36 37 import { Types } from "mongoose";
37 import { IInventoryChanges } from "@/src/types/purchaseTypes";
38 import { IAffiliationMods, IInventoryChanges } from "@/src/types/purchaseTypes";
38 39 import { getLevelKeyRewards, toStoreItem } from "@/src/services/itemDataService";
39 40 import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
40 41 import { getEntriesUnsafe } from "@/src/utils/ts-utils";
@@ -529,6 +530,8 @@ interface AddMissionRewardsReturnType {
529 530 MissionRewards: IMissionReward[];
530 531 inventoryChanges?: IInventoryChanges;
531 532 credits?: IMissionCredits;
533 AffiliationMods?: IAffiliationMods[];
534 SyndicateXPItemReward?: number;
532 535 }
533 536
534 537 //TODO: return type of partial missioninventoryupdate response
@@ -555,6 +558,8 @@ export const addMissionRewards = async (
555 558 const MissionRewards: IMissionReward[] = getRandomMissionDrops(rewardInfo, wagerTier);
556 559 logger.debug("random mission drops:", MissionRewards);
557 560 const inventoryChanges: IInventoryChanges = {};
561 const AffiliationMods: IAffiliationMods[] = [];
562 let SyndicateXPItemReward;
558 563
559 564 let missionCompletionCredits = 0;
560 565 //inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display
@@ -718,7 +723,97 @@ export const addMissionRewards = async (
718 723 inventoryChanges.Nemesis.InfNodes = inventory.Nemesis.InfNodes;
719 724 }
720 725 }
721 return { inventoryChanges, MissionRewards, credits };
726
727 if (rewardInfo.JobStage != undefined && rewardInfo.jobId) {
728 // eslint-disable-next-line @typescript-eslint/no-unused-vars
729 const [jobType, tierStr, hubNode, syndicateId, locationTag] = rewardInfo.jobId.split("_");
730 const tier = Number(tierStr);
731
732 const worldState = getWorldState();
733 let syndicateEntry = worldState.SyndicateMissions.find(m => m._id.$oid === syndicateId);
734 if (!syndicateEntry) syndicateEntry = worldState.SyndicateMissions.find(m => m.Tag === syndicateId); // Sometimes syndicateId can be tag
735 if (syndicateEntry && syndicateEntry.Jobs) {
736 let currentJob = syndicateEntry.Jobs[tier];
737 if (syndicateEntry.Tag === "EntratiSyndicate") {
738 const vault = syndicateEntry.Jobs.find(j => j.locationTag === locationTag);
739 if (vault) currentJob = vault;
740 let medallionAmount = currentJob.xpAmounts[rewardInfo.JobStage];
741
742 if (
743 ["DeimosEndlessAreaDefenseBounty", "DeimosEndlessExcavateBounty", "DeimosEndlessPurifyBounty"].some(
744 ending => jobType.endsWith(ending)
745 )
746 ) {
747 const endlessJob = syndicateEntry.Jobs.find(j => j.endless);
748 if (endlessJob) {
749 const index = rewardInfo.JobStage % endlessJob.xpAmounts.length;
750 const excess = Math.floor(rewardInfo.JobStage / endlessJob.xpAmounts.length);
751 medallionAmount = Math.floor(endlessJob.xpAmounts[index] * (1 + 0.15000001 * excess));
752 }
753 }
754 await addItem(inventory, "/Lotus/Types/Items/Deimos/EntratiFragmentUncommonB", medallionAmount);
755 MissionRewards.push({
756 StoreItem: "/Lotus/StoreItems/Types/Items/Deimos/EntratiFragmentUncommonB",
757 ItemCount: medallionAmount
758 });
759 SyndicateXPItemReward = medallionAmount;
760 } else {
761 if (tier >= 0) {
762 AffiliationMods.push(
763 addStanding(inventory, syndicateEntry.Tag, currentJob.xpAmounts[rewardInfo.JobStage])
764 );
765 } else {
766 if (jobType.endsWith("Heists/HeistProfitTakerBountyOne") && rewardInfo.JobStage === 2) {
767 AffiliationMods.push(addStanding(inventory, syndicateEntry.Tag, 1000));
768 }
769 if (jobType.endsWith("Hunts/AllTeralystsHunt") && rewardInfo.JobStage === 2) {
770 AffiliationMods.push(addStanding(inventory, syndicateEntry.Tag, 5000));
771 }
772 if (
773 [
774 "Hunts/TeralystHunt",
775 "Heists/HeistProfitTakerBountyTwo",
776 "Heists/HeistProfitTakerBountyThree",
777 "Heists/HeistProfitTakerBountyFour",
778 "Heists/HeistExploiterBountyOne"
779 ].some(ending => jobType.endsWith(ending))
780 ) {
781 AffiliationMods.push(addStanding(inventory, syndicateEntry.Tag, 1000));
782 }
783 }
784 }
785 }
786 }
787
788 if (rewardInfo.challengeMissionId) {
789 const [syndicateTag, tierStr] = rewardInfo.challengeMissionId.split("_"); // TODO: third part in HexSyndicate jobs - Chemistry points
790 const tier = Number(tierStr);
791 const isSteelPath = missions?.Tier;
792 if (syndicateTag === "ZarimanSyndicate") {
793 let medallionAmount = tier + 1;
794 if (isSteelPath) medallionAmount = Math.round(medallionAmount * 1.5);
795 await addItem(inventory, "/Lotus/Types/Gameplay/Zariman/Resources/ZarimanDogTagBounty", medallionAmount);
796 MissionRewards.push({
797 StoreItem: "/Lotus/StoreItems/Types/Gameplay/Zariman/Resources/ZarimanDogTagBounty",
798 ItemCount: medallionAmount
799 });
800 SyndicateXPItemReward = medallionAmount;
801 } else {
802 let standingAmount = (tier + 1) * 1000;
803 if (tier > 5) standingAmount = 7500; // InfestedLichBounty
804 if (isSteelPath) standingAmount *= 1.5;
805 AffiliationMods.push(addStanding(inventory, syndicateTag, standingAmount));
806 }
807 if (isSteelPath) {
808 await addItem(inventory, "/Lotus/Types/Items/MiscItems/SteelEssence", 1);
809 MissionRewards.push({
810 StoreItem: "/Lotus/StoreItems/Types/Items/MiscItems/SteelEssence",
811 ItemCount: 1
812 });
813 }
814 }
815
816 return { inventoryChanges, MissionRewards, credits, AffiliationMods, SyndicateXPItemReward };
722 817 };
723 818
724 819 interface IMissionCredits {
Modified src/types/requestTypes.ts +1 -0
@@ -150,6 +150,7 @@ export interface IRewardInfo {
150 150 JobStage?: number;
151 151 Q?: boolean; // likely indicates that the bonus objective for this stage was completed
152 152 CheckpointCounter?: number; // starts at 1, is incremented with each job stage upload, and does not reset when starting a new job
153 challengeMissionId?: string;
153 154 }
154 155
155 156 export type IMissionStatus = "GS_SUCCESS" | "GS_FAILURE" | "GS_DUMPED" | "GS_QUIT" | "GS_INTERRUPTED";