Compare commits

..

3 Commits

Author SHA1 Message Date
ca13c3fc81 fix: handle quest replay
All checks were successful
Build / build (pull_request) Successful in 1m23s
Closes #2496
2025-09-14 12:16:31 +02:00
d2aff211c6 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>
2025-09-13 23:50:08 -07:00
791ae389d8 fix: correct Activation/Expiry date for Ghoul Emergence (#2777)
Some checks failed
Build Docker image / docker-amd64 (push) Waiting to run
Build Docker image / docker-arm64 (push) Has been cancelled
Build / build (push) Has been cancelled
Closes #2775

Reviewed-on: #2777
Reviewed-by: Sainan <63328889+sainan@users.noreply.github.com>
Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
Co-committed-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
2025-09-13 23:50:00 -07:00
4 changed files with 80 additions and 59 deletions

View File

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

View File

@ -517,46 +517,6 @@ export const addMissionInventoryUpdates = async (
} }
break; 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": { case "KubrowPetEggs": {
for (const egg of value) { for (const egg of value) {
inventory.KubrowPetEggs.push({ inventory.KubrowPetEggs.push({
@ -961,7 +921,7 @@ interface AddMissionRewardsReturnType {
MissionRewards: IMissionReward[]; MissionRewards: IMissionReward[];
inventoryChanges?: IInventoryChanges; inventoryChanges?: IInventoryChanges;
credits?: IMissionCredits; credits?: IMissionCredits;
AffiliationMods?: IAffiliationMods[]; AffiliationMods: IAffiliationMods[];
SyndicateXPItemReward?: number; SyndicateXPItemReward?: number;
ConquestCompletedMissionsCount?: number; ConquestCompletedMissionsCount?: number;
} }
@ -1137,10 +1097,12 @@ export const addMissionRewards = async (
}: IMissionInventoryUpdateRequest, }: IMissionInventoryUpdateRequest,
firstCompletion: boolean firstCompletion: boolean
): Promise<AddMissionRewardsReturnType> => { ): Promise<AddMissionRewardsReturnType> => {
AffiliationMods ??= [];
if (!rewardInfo) { 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 //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 `); logger.debug(`Mission ${missions!.Tag} did not have Reward Info `);
return { MissionRewards: [] }; return { MissionRewards: [], AffiliationMods };
} }
//TODO: check double reward merging //TODO: check double reward merging
@ -1450,8 +1412,6 @@ export const addMissionRewards = async (
} }
} }
AffiliationMods ??= [];
if (rewardInfo.JobStage != undefined && rewardInfo.jobId) { if (rewardInfo.JobStage != undefined && rewardInfo.jobId) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const [jobType, unkIndex, hubNode, syndicateMissionId] = rewardInfo.jobId.split("_"); const [jobType, unkIndex, hubNode, syndicateMissionId] = rewardInfo.jobId.split("_");
@ -2252,6 +2212,54 @@ function getRandomMissionDrops(
return drops; 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 = [ const corruptedMods = [
"/Lotus/StoreItems/Upgrades/Mods/Melee/DualStat/CorruptedHeavyDamageChargeSpeedMod", // Corrupt Charge "/Lotus/StoreItems/Upgrades/Mods/Melee/DualStat/CorruptedHeavyDamageChargeSpeedMod", // Corrupt Charge
"/Lotus/StoreItems/Upgrades/Mods/Pistol/DualStat/CorruptedCritDamagePistol", // Hollow Point "/Lotus/StoreItems/Upgrades/Mods/Pistol/DualStat/CorruptedCritDamagePistol", // Hollow Point

View File

@ -2803,7 +2803,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
const activeStartDay = day - ghoulsCycleDay + 17; const activeStartDay = day - ghoulsCycleDay + 17;
const activeEndDay = activeStartDay + 5; const activeEndDay = activeStartDay + 5;
const dayWithFraction = (timeMs - EPOCH) / 86400000; const dayWithFraction = (timeMs - EPOCH) / unixTimesInMs.day;
const progress = (dayWithFraction - activeStartDay) / (activeEndDay - activeStartDay); const progress = (dayWithFraction - activeStartDay) / (activeEndDay - activeStartDay);
const healthPct = 1 - Math.min(Math.max(progress, 0), 1); const healthPct = 1 - Math.min(Math.max(progress, 0), 1);
@ -2814,22 +2814,14 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
$date: { $date: {
$numberLong: config.worldState?.ghoulEmergenceOverride $numberLong: config.worldState?.ghoulEmergenceOverride
? "1753204900185" ? "1753204900185"
: Date.UTC( : (EPOCH + activeStartDay * unixTimesInMs.day).toString()
date.getUTCFullYear(),
date.getUTCMonth(),
date.getUTCDate() + activeStartDay
).toString()
} }
}, },
Expiry: { Expiry: {
$date: { $date: {
$numberLong: config.worldState?.ghoulEmergenceOverride $numberLong: config.worldState?.ghoulEmergenceOverride
? "2000000000000" ? "2000000000000"
: Date.UTC( : (EPOCH + activeEndDay * unixTimesInMs.day).toString()
date.getUTCFullYear(),
date.getUTCMonth(),
date.getUTCDate() + activeEndDay
).toString()
} }
}, },
HealthPct: config.worldState?.ghoulEmergenceOverride ? 1 : healthPct, HealthPct: config.worldState?.ghoulEmergenceOverride ? 1 : healthPct,

View File

@ -45,6 +45,15 @@ export type IMissionInventoryUpdateRequest = {
EmailItems?: ITypeCount[]; EmailItems?: ITypeCount[];
ShipDecorations?: 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; SyndicateId?: string;
SortieId?: string; SortieId?: string;
CalendarProgress?: { challenge: string }[]; CalendarProgress?: { challenge: string }[];
@ -149,7 +158,6 @@ export type IMissionInventoryUpdateRequest = {
MultiProgress: unknown[]; MultiProgress: unknown[];
}[]; }[];
InvasionProgress?: IInvasionProgressClient[]; InvasionProgress?: IInvasionProgressClient[];
RJ?: boolean;
ConquestMissionsCompleted?: number; ConquestMissionsCompleted?: number;
duviriSuitSelection?: string; duviriSuitSelection?: string;
duviriPistolSelection?: string; duviriPistolSelection?: string;