fix: show conservation standing in progress screen, missing reward multiplications (#2776)
All checks were successful
Build Docker image / docker-arm64 (push) Successful in 1m15s
Build Docker image / docker-amd64 (push) Successful in 1m4s
Build / build (push) Successful in 2m7s

Closes #2774

Reviewed-on: #2776
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
This commit is contained in:
Sainan 2025-09-13 23:50:08 -07:00 committed by Sainan
parent 791ae389d8
commit d2aff211c6
3 changed files with 77 additions and 48 deletions

View File

@ -2,7 +2,11 @@ import type { RequestHandler } from "express";
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
import { getAccountForRequest } from "../../services/loginService.ts";
import type { IMissionInventoryUpdateRequest } from "../../types/requestTypes.ts";
import { addMissionInventoryUpdates, addMissionRewards } from "../../services/missionInventoryUpdateService.ts";
import {
addMissionInventoryUpdates,
addMissionRewards,
handleConservation
} from "../../services/missionInventoryUpdateService.ts";
import { getInventory } from "../../services/inventoryService.ts";
import { getInventoryResponse } from "./inventoryController.ts";
import { logger } from "../../utils/logger.ts";
@ -94,6 +98,7 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
SyndicateXPItemReward,
ConquestCompletedMissionsCount
} = await addMissionRewards(account, inventory, missionReport, firstCompletion);
handleConservation(inventory, missionReport, AffiliationMods); // Conservation reports have GS_SUCCESS
if (missionReport.EndOfMatchUpload) {
inventory.RewardSeed = generateRewardSeed();
@ -111,8 +116,16 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
AffiliationMods,
ConquestCompletedMissionsCount
};
if (missionReport.RJ) {
logger.debug(`railjack interstitial request, sending only deltas`, deltas);
if (
missionReport.BMI ||
missionReport.TNT ||
missionReport.SSC ||
missionReport.RJ ||
missionReport.SS ||
missionReport.CMI ||
missionReport.EJC
) {
logger.debug(`interstitial request, sending only deltas`, deltas);
res.json(deltas);
} else if (missionReport.RewardInfo) {
logger.debug(`classic mission completion, sending everything`);

View File

@ -517,46 +517,6 @@ export const addMissionInventoryUpdates = async (
}
break;
}
case "CapturedAnimals": {
for (const capturedAnimal of value) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const meta = ExportAnimals[capturedAnimal.AnimalType]?.conservation;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (meta) {
if (capturedAnimal.NumTags) {
addMiscItems(inventory, [
{
ItemType: meta.itemReward,
ItemCount: capturedAnimal.NumTags
}
]);
}
if (capturedAnimal.NumExtraRewards) {
if (meta.woundedAnimalReward) {
addMiscItems(inventory, [
{
ItemType: meta.woundedAnimalReward,
ItemCount: capturedAnimal.NumExtraRewards
}
]);
} else {
logger.warn(
`client attempted to claim unknown extra rewards for conservation of ${capturedAnimal.AnimalType}`
);
}
}
if (meta.standingReward) {
const syndicateTag =
inventoryUpdates.Missions!.Tag == "SolNode129" ? "SolarisSyndicate" : "CetusSyndicate";
logger.debug(`adding ${meta.standingReward} standing to ${syndicateTag} for conservation`);
addStanding(inventory, syndicateTag, meta.standingReward);
}
} else {
logger.warn(`ignoring conservation of unknown AnimalType: ${capturedAnimal.AnimalType}`);
}
}
break;
}
case "KubrowPetEggs": {
for (const egg of value) {
inventory.KubrowPetEggs.push({
@ -961,7 +921,7 @@ interface AddMissionRewardsReturnType {
MissionRewards: IMissionReward[];
inventoryChanges?: IInventoryChanges;
credits?: IMissionCredits;
AffiliationMods?: IAffiliationMods[];
AffiliationMods: IAffiliationMods[];
SyndicateXPItemReward?: number;
ConquestCompletedMissionsCount?: number;
}
@ -1137,10 +1097,12 @@ export const addMissionRewards = async (
}: IMissionInventoryUpdateRequest,
firstCompletion: boolean
): Promise<AddMissionRewardsReturnType> => {
AffiliationMods ??= [];
if (!rewardInfo) {
//TODO: if there is a case where you can have credits collected during a mission but no rewardInfo, add credits needs to be handled earlier
logger.debug(`Mission ${missions!.Tag} did not have Reward Info `);
return { MissionRewards: [] };
return { MissionRewards: [], AffiliationMods };
}
//TODO: check double reward merging
@ -1450,8 +1412,6 @@ export const addMissionRewards = async (
}
}
AffiliationMods ??= [];
if (rewardInfo.JobStage != undefined && rewardInfo.jobId) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [jobType, unkIndex, hubNode, syndicateMissionId] = rewardInfo.jobId.split("_");
@ -2252,6 +2212,54 @@ function getRandomMissionDrops(
return drops;
}
export const handleConservation = (
inventory: TInventoryDatabaseDocument,
missionReport: IMissionInventoryUpdateRequest,
AffiliationMods: IAffiliationMods[]
): void => {
if (missionReport.CapturedAnimals) {
for (const capturedAnimal of missionReport.CapturedAnimals) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const meta = ExportAnimals[capturedAnimal.AnimalType]?.conservation;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (meta) {
if (capturedAnimal.NumTags) {
addMiscItems(inventory, [
{
ItemType: meta.itemReward,
ItemCount: capturedAnimal.NumTags * capturedAnimal.Count
}
]);
}
if (capturedAnimal.NumExtraRewards) {
if (meta.woundedAnimalReward) {
addMiscItems(inventory, [
{
ItemType: meta.woundedAnimalReward,
ItemCount: capturedAnimal.NumExtraRewards * capturedAnimal.Count
}
]);
} else {
logger.warn(
`client attempted to claim unknown extra rewards for conservation of ${capturedAnimal.AnimalType}`
);
}
}
if (meta.standingReward) {
addStanding(
inventory,
missionReport.Missions!.Tag == "SolNode129" ? "SolarisSyndicate" : "CetusSyndicate",
[2, 1.5, 1][capturedAnimal.CaptureRating] * meta.standingReward * capturedAnimal.Count,
AffiliationMods
);
}
} else {
logger.warn(`ignoring conservation of unknown AnimalType: ${capturedAnimal.AnimalType}`);
}
}
}
};
const corruptedMods = [
"/Lotus/StoreItems/Upgrades/Mods/Melee/DualStat/CorruptedHeavyDamageChargeSpeedMod", // Corrupt Charge
"/Lotus/StoreItems/Upgrades/Mods/Pistol/DualStat/CorruptedCritDamagePistol", // Hollow Point

View File

@ -45,6 +45,15 @@ export type IMissionInventoryUpdateRequest = {
EmailItems?: ITypeCount[];
ShipDecorations?: ITypeCount[];
// flags for interstitial requests
BMI?: boolean;
TNT?: boolean; // Conservation; definitely need to include AffiliationMods in this case, so a normal 'inventory sync' would not work here.
SSC?: boolean; // K-Drive race?
RJ?: boolean; // Railjack. InventoryJson should only be returned when going back to dojo.
SS?: boolean;
CMI?: boolean;
EJC?: boolean;
SyndicateId?: string;
SortieId?: string;
CalendarProgress?: { challenge: string }[];
@ -149,7 +158,6 @@ export type IMissionInventoryUpdateRequest = {
MultiProgress: unknown[];
}[];
InvasionProgress?: IInvasionProgressClient[];
RJ?: boolean;
ConquestMissionsCompleted?: number;
duviriSuitSelection?: string;
duviriPistolSelection?: string;