feat: calendar progress
All checks were successful
Build / build (push) Successful in 54s
Build / build (pull_request) Successful in 1m21s

This commit is contained in:
Sainan 2025-04-25 07:38:23 +02:00
parent 100aefcee4
commit a7f4e661d0
9 changed files with 102 additions and 29 deletions

View File

@ -0,0 +1,39 @@
import { getCalendarProgress, getInventory } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
import { getWorldState } from "@/src/services/worldStateService";
import { IInventoryChanges } from "@/src/types/purchaseTypes";
import { RequestHandler } from "express";
// GET request; query parameters: CompletedEventIdx=0&Iteration=4&Version=19&Season=CST_SUMMER
export const completeCalendarEventController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId);
const calendarProgress = getCalendarProgress(inventory);
const currentSeason = getWorldState().KnownCalendarSeasons[0];
let inventoryChanges: IInventoryChanges = {};
let dayIndex = 0;
for (const day of currentSeason.Days) {
if (day.events.length == 0 || day.events[0].type != "CET_CHALLENGE") {
if (dayIndex == calendarProgress.SeasonProgress.LastCompletedDayIdx) {
if (day.events.length != 0) {
const selection = day.events[parseInt(req.query.CompletedEventIdx as string)];
if (selection.type == "CET_REWARD") {
inventoryChanges = (await handleStoreItemAcquisition(selection.reward!, inventory))
.InventoryChanges;
} else if (selection.type != "CET_PLOT") {
throw new Error(`unexpected selection type: ${selection.type}`);
}
}
break;
}
++dayIndex;
}
}
calendarProgress.SeasonProgress.LastCompletedDayIdx++;
await inventory.save();
res.json({
InventoryChanges: inventoryChanges,
CalendarProgress: inventory.CalendarProgress
});
};

View File

@ -1125,15 +1125,15 @@ const CustomMarkersSchema = new Schema<ICustomMarkers>(
const calenderProgressSchema = new Schema<ICalendarProgress>( const calenderProgressSchema = new Schema<ICalendarProgress>(
{ {
Version: { type: Number, default: 19 }, Version: { type: Number, default: 19 },
Iteration: { type: Number, default: 2 }, Iteration: { type: Number, required: true },
YearProgress: { YearProgress: {
Upgrades: { type: [] } Upgrades: { type: [String], default: [] }
}, },
SeasonProgress: { SeasonProgress: {
SeasonType: String, SeasonType: { type: String, required: true },
LastCompletedDayIdx: { type: Number, default: -1 }, LastCompletedDayIdx: { type: Number, default: 0 },
LastCompletedChallengeDayIdx: { type: Number, default: -1 }, LastCompletedChallengeDayIdx: { type: Number, default: 0 },
ActivatedChallenges: [] ActivatedChallenges: { type: [String], default: [] }
} }
}, },
{ _id: false } { _id: false }

View File

@ -19,6 +19,7 @@ import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompl
import { claimLibraryDailyTaskRewardController } from "@/src/controllers/api/claimLibraryDailyTaskRewardController"; import { claimLibraryDailyTaskRewardController } from "@/src/controllers/api/claimLibraryDailyTaskRewardController";
import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController"; import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
import { clearNewEpisodeRewardController } from "@/src/controllers/api/clearNewEpisodeRewardController"; import { clearNewEpisodeRewardController } from "@/src/controllers/api/clearNewEpisodeRewardController";
import { completeCalendarEventController } from "@/src/controllers/api/completeCalendarEventController";
import { completeRandomModChallengeController } from "@/src/controllers/api/completeRandomModChallengeController"; import { completeRandomModChallengeController } from "@/src/controllers/api/completeRandomModChallengeController";
import { confirmAllianceInvitationController } from "@/src/controllers/api/confirmAllianceInvitationController"; import { confirmAllianceInvitationController } from "@/src/controllers/api/confirmAllianceInvitationController";
import { confirmGuildInvitationGetController, confirmGuildInvitationPostController } from "@/src/controllers/api/confirmGuildInvitationController"; import { confirmGuildInvitationGetController, confirmGuildInvitationPostController } from "@/src/controllers/api/confirmGuildInvitationController";
@ -158,6 +159,7 @@ apiRouter.get("/changeDojoRoot.php", changeDojoRootController);
apiRouter.get("/changeGuildRank.php", changeGuildRankController); apiRouter.get("/changeGuildRank.php", changeGuildRankController);
apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController); apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController);
apiRouter.get("/claimLibraryDailyTaskReward.php", claimLibraryDailyTaskRewardController); apiRouter.get("/claimLibraryDailyTaskReward.php", claimLibraryDailyTaskRewardController);
apiRouter.get("/completeCalendarEvent.php", completeCalendarEventController);
apiRouter.get("/confirmAllianceInvitation.php", confirmAllianceInvitationController); apiRouter.get("/confirmAllianceInvitation.php", confirmAllianceInvitationController);
apiRouter.get("/confirmGuildInvitation.php", confirmGuildInvitationGetController); apiRouter.get("/confirmGuildInvitation.php", confirmGuildInvitationGetController);
apiRouter.get("/credits.php", creditsController); apiRouter.get("/credits.php", creditsController);

View File

@ -18,7 +18,6 @@ import {
IKubrowPetEggDatabase, IKubrowPetEggDatabase,
IKubrowPetEggClient, IKubrowPetEggClient,
ILibraryDailyTaskInfo, ILibraryDailyTaskInfo,
ICalendarProgress,
IDroneClient, IDroneClient,
IUpgradeClient, IUpgradeClient,
TPartialStartingGear, TPartialStartingGear,
@ -26,7 +25,8 @@ import {
ICrewMemberClient, ICrewMemberClient,
Status, Status,
IKubrowPetDetailsDatabase, IKubrowPetDetailsDatabase,
ITraits ITraits,
ICalendarProgress
} from "@/src/types/inventoryTypes/inventoryTypes"; } from "@/src/types/inventoryTypes/inventoryTypes";
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate"; import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate";
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes"; import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
@ -78,6 +78,7 @@ import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from "./rngService"; import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from "./rngService";
import { createMessage } from "./inboxService"; import { createMessage } from "./inboxService";
import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper"; import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
import { getWorldState } from "./worldStateService";
export const createInventory = async ( export const createInventory = async (
accountOwnerId: Types.ObjectId, accountOwnerId: Types.ObjectId,
@ -91,7 +92,6 @@ export const createInventory = async (
}); });
inventory.LibraryAvailableDailyTaskInfo = createLibraryDailyTask(); inventory.LibraryAvailableDailyTaskInfo = createLibraryDailyTask();
inventory.CalendarProgress = createCalendar();
inventory.RewardSeed = generateRewardSeed(); inventory.RewardSeed = generateRewardSeed();
inventory.DuviriInfo = { inventory.DuviriInfo = {
Seed: generateRewardSeed(), Seed: generateRewardSeed(),
@ -1756,20 +1756,6 @@ export const createLibraryDailyTask = (): ILibraryDailyTaskInfo => {
}; };
}; };
const createCalendar = (): ICalendarProgress => {
return {
Version: 19,
Iteration: 2,
YearProgress: { Upgrades: [] },
SeasonProgress: {
SeasonType: "CST_SPRING",
LastCompletedDayIdx: -1,
LastCompletedChallengeDayIdx: -1,
ActivatedChallenges: []
}
};
};
export const setupKahlSyndicate = (inventory: TInventoryDatabaseDocument): void => { export const setupKahlSyndicate = (inventory: TInventoryDatabaseDocument): void => {
inventory.Affiliations.push({ inventory.Affiliations.push({
Title: 1, Title: 1,
@ -1806,3 +1792,37 @@ export const cleanupInventory = (inventory: TInventoryDatabaseDocument): void =>
LibrarySyndicate.FreeFavorsEarned = undefined; LibrarySyndicate.FreeFavorsEarned = undefined;
} }
}; };
export const getCalendarProgress = (inventory: TInventoryDatabaseDocument): ICalendarProgress => {
const currentSeason = getWorldState().KnownCalendarSeasons[0];
if (!inventory.CalendarProgress) {
inventory.CalendarProgress = {
Version: 19,
Iteration: currentSeason.YearIteration,
YearProgress: {
Upgrades: []
},
SeasonProgress: {
SeasonType: currentSeason.Season,
LastCompletedDayIdx: 0,
LastCompletedChallengeDayIdx: 0,
ActivatedChallenges: []
}
};
}
const yearRolledOver = inventory.CalendarProgress.Iteration != currentSeason.YearIteration;
if (yearRolledOver) {
inventory.CalendarProgress.Iteration = currentSeason.YearIteration;
inventory.CalendarProgress.YearProgress.Upgrades = [];
}
if (yearRolledOver || inventory.CalendarProgress.SeasonProgress.SeasonType != currentSeason.Season) {
inventory.CalendarProgress.SeasonProgress.SeasonType = currentSeason.Season;
inventory.CalendarProgress.SeasonProgress.LastCompletedDayIdx = -1;
inventory.CalendarProgress.SeasonProgress.LastCompletedChallengeDayIdx = -1;
inventory.CalendarProgress.SeasonProgress.ActivatedChallenges = [];
}
return inventory.CalendarProgress;
};

View File

@ -33,6 +33,7 @@ import {
addStanding, addStanding,
combineInventoryChanges, combineInventoryChanges,
generateRewardSeed, generateRewardSeed,
getCalendarProgress,
updateCurrency, updateCurrency,
updateSyndicate updateSyndicate
} from "@/src/services/inventoryService"; } from "@/src/services/inventoryService";
@ -562,6 +563,15 @@ export const addMissionInventoryUpdates = async (
} }
break; break;
} }
case "CalendarProgress": {
const calendarProgress = getCalendarProgress(inventory);
for (const progress of value) {
const challengeName = progress.challenge.substring(progress.challenge.lastIndexOf("/") + 1);
calendarProgress.SeasonProgress.LastCompletedChallengeDayIdx++;
calendarProgress.SeasonProgress.ActivatedChallenges.push(challengeName);
}
break;
}
default: default:
// Equipment XP updates // Equipment XP updates
if (equipmentKeys.includes(key as TEquipmentKey)) { if (equipmentKeys.includes(key as TEquipmentKey)) {

View File

@ -645,7 +645,7 @@ const getCalendarSeason = (week: number): ICalendarSeason => {
Activation: { $date: { $numberLong: weekStart.toString() } }, Activation: { $date: { $numberLong: weekStart.toString() } },
Expiry: { $date: { $numberLong: weekEnd.toString() } }, Expiry: { $date: { $numberLong: weekEnd.toString() } },
Days: eventDays, Days: eventDays,
Season: ["CST_WINTER", "CST_SPRING", "CST_SUMMER", "CST_FALL"][seasonIndex], Season: (["CST_WINTER", "CST_SPRING", "CST_SUMMER", "CST_FALL"] as const)[seasonIndex],
YearIteration: Math.trunc(week / 4), YearIteration: Math.trunc(week / 4),
Version: 19, Version: 19,
UpgradeAvaliabilityRequirements: ["/Lotus/Upgrades/Calendar/1999UpgradeApplicationRequirement"] UpgradeAvaliabilityRequirements: ["/Lotus/Upgrades/Calendar/1999UpgradeApplicationRequirement"]

View File

@ -353,7 +353,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
DeathSquadable: boolean; DeathSquadable: boolean;
EndlessXP?: IEndlessXpProgress[]; EndlessXP?: IEndlessXpProgress[];
DialogueHistory?: IDialogueHistoryClient; DialogueHistory?: IDialogueHistoryClient;
CalendarProgress: ICalendarProgress; CalendarProgress?: ICalendarProgress;
SongChallenges?: ISongChallenge[]; SongChallenges?: ISongChallenge[];
EntratiVaultCountLastPeriod?: number; EntratiVaultCountLastPeriod?: number;
EntratiVaultCountResetDate?: IMongoDate; EntratiVaultCountResetDate?: IMongoDate;
@ -1193,17 +1193,18 @@ export interface IMarker {
z: number; z: number;
showInHud: boolean; showInHud: boolean;
} }
export interface ISeasonProgress { export interface ISeasonProgress {
SeasonType: "CST_UNDEFINED" | "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL"; SeasonType: "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
LastCompletedDayIdx: number; LastCompletedDayIdx: number;
LastCompletedChallengeDayIdx: number; LastCompletedChallengeDayIdx: number;
ActivatedChallenges: unknown[]; ActivatedChallenges: string[];
} }
export interface ICalendarProgress { export interface ICalendarProgress {
Version: number; Version: number;
Iteration: number; Iteration: number;
YearProgress: { Upgrades: unknown[] }; YearProgress: { Upgrades: string[] };
SeasonProgress: ISeasonProgress; SeasonProgress: ISeasonProgress;
} }

View File

@ -44,6 +44,7 @@ export type IMissionInventoryUpdateRequest = {
SyndicateId?: string; SyndicateId?: string;
SortieId?: string; SortieId?: string;
CalendarProgress?: { challenge: string }[];
SeasonChallengeCompletions?: ISeasonChallenge[]; SeasonChallengeCompletions?: ISeasonChallenge[];
AffiliationChanges?: IAffiliationChange[]; AffiliationChanges?: IAffiliationChange[];
crossPlaySetting?: string; crossPlaySetting?: string;

View File

@ -133,7 +133,7 @@ export interface ISeasonChallenge {
export interface ICalendarSeason { export interface ICalendarSeason {
Activation: IMongoDate; Activation: IMongoDate;
Expiry: IMongoDate; Expiry: IMongoDate;
Season: string; // "CST_UNDEFINED" | "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL" Season: "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
Days: ICalendarDay[]; Days: ICalendarDay[];
YearIteration: number; YearIteration: number;
Version: number; Version: number;