From d4e4a29ca0abe16f38cc82908a42ee07d3714619 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Fri, 27 Jun 2025 04:25:34 +0200 Subject: [PATCH 1/4] feat: daily first win Bit of a weird one because the client doesn't even seem to acknowledge it, but I've mainly wanted to cleanup the underlying logic here, esp. because missionCompletionCredits were being added to inventory inconsistently (sometimes once, sometimes twice). --- .../api/checkDailyMissionBonusController.ts | 22 ++++---- .../api/missionInventoryUpdateController.ts | 2 +- .../custom/completeAllMissionsController.ts | 2 +- src/models/loginModel.ts | 3 +- src/services/missionInventoryUpdateService.ts | 51 +++++++++++-------- src/services/questService.ts | 2 +- src/types/loginTypes.ts | 1 + src/types/missionTypes.ts | 6 +-- 8 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/controllers/api/checkDailyMissionBonusController.ts b/src/controllers/api/checkDailyMissionBonusController.ts index 97b838fe..8e457142 100644 --- a/src/controllers/api/checkDailyMissionBonusController.ts +++ b/src/controllers/api/checkDailyMissionBonusController.ts @@ -1,16 +1,12 @@ +import { getAccountForRequest } from "@/src/services/loginService"; import { RequestHandler } from "express"; -const checkDailyMissionBonusController: RequestHandler = (_req, res) => { - const data = Buffer.from([ - 0x44, 0x61, 0x69, 0x6c, 0x79, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x6f, 0x6e, 0x75, 0x73, 0x3a, - 0x31, 0x2d, 0x44, 0x61, 0x69, 0x6c, 0x79, 0x50, 0x56, 0x50, 0x57, 0x69, 0x6e, 0x42, 0x6f, 0x6e, 0x75, 0x73, - 0x3a, 0x31, 0x0a - ]); - res.writeHead(200, { - "Content-Type": "text/html", - "Content-Length": data.length - }); - res.end(data); +export const checkDailyMissionBonusController: RequestHandler = async (req, res) => { + const account = await getAccountForRequest(req); + const today = Math.trunc(Date.now() / 86400000) * 86400; + if (account.DailyFirstWinDate != today) { + res.send("DailyMissionBonus:1-DailyPVPWinBonus:1\n"); + } else { + res.send("DailyMissionBonus:0-DailyPVPWinBonus:1\n"); + } }; - -export { checkDailyMissionBonusController }; diff --git a/src/controllers/api/missionInventoryUpdateController.ts b/src/controllers/api/missionInventoryUpdateController.ts index 93f8033c..e3b86b71 100644 --- a/src/controllers/api/missionInventoryUpdateController.ts +++ b/src/controllers/api/missionInventoryUpdateController.ts @@ -88,7 +88,7 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res) AffiliationMods, SyndicateXPItemReward, ConquestCompletedMissionsCount - } = await addMissionRewards(inventory, missionReport, firstCompletion); + } = await addMissionRewards(account, inventory, missionReport, firstCompletion); if (missionReport.EndOfMatchUpload) { inventory.RewardSeed = generateRewardSeed(); diff --git a/src/controllers/custom/completeAllMissionsController.ts b/src/controllers/custom/completeAllMissionsController.ts index f6ab486d..66ac3c13 100644 --- a/src/controllers/custom/completeAllMissionsController.ts +++ b/src/controllers/custom/completeAllMissionsController.ts @@ -26,7 +26,7 @@ export const completeAllMissionsController: RequestHandler = async (req, res) => if (mission.Completes == 0) { mission.Completes++; if (node.missionReward) { - addFixedLevelRewards(node.missionReward, inventory, MissionRewards); + addFixedLevelRewards(node.missionReward, MissionRewards); } } mission.Tier = 1; diff --git a/src/models/loginModel.ts b/src/models/loginModel.ts index 44dab113..aea5b993 100644 --- a/src/models/loginModel.ts +++ b/src/models/loginModel.ts @@ -25,7 +25,8 @@ const databaseAccountSchema = new Schema( LastLogin: { type: Date, default: 0 }, LatestEventMessageDate: { type: Date, default: 0 }, LastLoginRewardDate: { type: Number, default: 0 }, - LoginDays: { type: Number, default: 1 } + LoginDays: { type: Number, default: 1 }, + DailyFirstWinDate: { type: Number, default: 0 } }, opts ); diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index ec3ee941..445c02fe 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -968,6 +968,7 @@ const droptableAliases: Record = { //TODO: return type of partial missioninventoryupdate response export const addMissionRewards = async ( + account: TAccountDocument, inventory: TInventoryDatabaseDocument, { wagerTier: wagerTier, @@ -1015,13 +1016,17 @@ export const addMissionRewards = async ( const fixedLevelRewards = getLevelKeyRewards(levelKeyName); //logger.debug(`fixedLevelRewards ${fixedLevelRewards}`); if (fixedLevelRewards.levelKeyRewards) { - addFixedLevelRewards(fixedLevelRewards.levelKeyRewards, inventory, MissionRewards, rewardInfo); + missionCompletionCredits += addFixedLevelRewards( + fixedLevelRewards.levelKeyRewards, + MissionRewards, + rewardInfo + ); } if (fixedLevelRewards.levelKeyRewards2) { for (const reward of fixedLevelRewards.levelKeyRewards2) { //quest stage completion credit rewards if (reward.rewardType == "RT_CREDITS") { - missionCompletionCredits += reward.amount; // will be added to inventory in addCredits + missionCompletionCredits += reward.amount; continue; } MissionRewards.push({ @@ -1050,12 +1055,11 @@ export const addMissionRewards = async ( ) { const levelCreditReward = getLevelCreditRewards(node); missionCompletionCredits += levelCreditReward; - inventory.RegularCredits += levelCreditReward; logger.debug(`levelCreditReward ${levelCreditReward}`); } if (node.missionReward) { - missionCompletionCredits += addFixedLevelRewards(node.missionReward, inventory, MissionRewards, rewardInfo); + missionCompletionCredits += addFixedLevelRewards(node.missionReward, MissionRewards, rewardInfo); } if (rewardInfo.sortieTag == "Mission1") { @@ -1165,7 +1169,9 @@ export const addMissionRewards = async ( combineInventoryChanges(inventoryChanges, inventoryChange.InventoryChanges); } - const credits = addCredits(inventory, { + inventory.RegularCredits += missionCompletionCredits; + + const credits = await addCredits(account, inventory, { missionCompletionCredits, missionDropCredits: creditDrops ?? 0, rngRewardCredits: inventoryChanges.RegularCredits ?? 0 @@ -1390,46 +1396,47 @@ export const addMissionRewards = async ( //creditBonus is not entirely accurate. //TODO: consider ActiveBoosters -export const addCredits = ( +export const addCredits = async ( + account: TAccountDocument, inventory: TInventoryDatabaseDocument, { missionDropCredits, missionCompletionCredits, rngRewardCredits }: { missionDropCredits: number; missionCompletionCredits: number; rngRewardCredits: number } -): IMissionCredits => { - const hasDailyCreditBonus = true; - const totalCredits = missionDropCredits + missionCompletionCredits + rngRewardCredits; - +): Promise => { const finalCredits: IMissionCredits = { MissionCredits: [missionDropCredits, missionDropCredits], - CreditBonus: [missionCompletionCredits, missionCompletionCredits], - TotalCredits: [totalCredits, totalCredits] + CreditsBonus: [missionCompletionCredits, missionCompletionCredits], + TotalCredits: [0, 0] }; - if (hasDailyCreditBonus) { + const today = Math.trunc(Date.now() / 86400000) * 86400; + if (account.DailyFirstWinDate != today) { + account.DailyFirstWinDate = today; + await account.save(); + + logger.debug(`daily first win, doubling missionCompletionCredits (${missionCompletionCredits})`); + + finalCredits.DailyMissionBonus = true; inventory.RegularCredits += missionCompletionCredits; - finalCredits.CreditBonus[1] *= 2; - finalCredits.MissionCredits[1] *= 2; - finalCredits.TotalCredits[1] *= 2; + finalCredits.CreditsBonus[1] *= 2; } - if (!hasDailyCreditBonus) { - return finalCredits; - } - return { ...finalCredits, DailyMissionBonus: true }; + const totalCredits = finalCredits.MissionCredits[1] + finalCredits.CreditsBonus[1] + rngRewardCredits; + finalCredits.TotalCredits = [totalCredits, totalCredits]; + + return finalCredits; }; export const addFixedLevelRewards = ( rewards: IMissionRewardExternal, - inventory: TInventoryDatabaseDocument, MissionRewards: IMissionReward[], rewardInfo?: IRewardInfo ): number => { let missionBonusCredits = 0; if (rewards.credits) { missionBonusCredits += rewards.credits; - inventory.RegularCredits += rewards.credits; } if (rewards.items) { for (const item of rewards.items) { diff --git a/src/services/questService.ts b/src/services/questService.ts index 053f6eb4..633f1022 100644 --- a/src/services/questService.ts +++ b/src/services/questService.ts @@ -331,7 +331,7 @@ export const giveKeyChainMissionReward = async ( const fixedLevelRewards = getLevelKeyRewards(missionName); if (fixedLevelRewards.levelKeyRewards) { const missionRewards: { StoreItem: string; ItemCount: number }[] = []; - addFixedLevelRewards(fixedLevelRewards.levelKeyRewards, inventory, missionRewards); + inventory.RegularCredits += addFixedLevelRewards(fixedLevelRewards.levelKeyRewards, missionRewards); for (const reward of missionRewards) { await addItem(inventory, fromStoreItem(reward.StoreItem), reward.ItemCount); diff --git a/src/types/loginTypes.ts b/src/types/loginTypes.ts index ef280188..0f5cea60 100644 --- a/src/types/loginTypes.ts +++ b/src/types/loginTypes.ts @@ -25,6 +25,7 @@ export interface IDatabaseAccount extends IDatabaseAccountRequiredFields { LatestEventMessageDate: Date; LastLoginRewardDate: number; LoginDays: number; + DailyFirstWinDate: number; } // Includes virtual ID diff --git a/src/types/missionTypes.ts b/src/types/missionTypes.ts index 3de75318..bb70fc30 100644 --- a/src/types/missionTypes.ts +++ b/src/types/missionTypes.ts @@ -17,9 +17,9 @@ export interface IMissionReward { } export interface IMissionCredits { - MissionCredits: number[]; - CreditBonus: number[]; - TotalCredits: number[]; + MissionCredits: [number, number]; + CreditsBonus: [number, number]; // "Credit Reward"; `CreditsBonus[1]` is `CreditsBonus[0] * 2` if DailyMissionBonus + TotalCredits: [number, number]; DailyMissionBonus?: boolean; } -- 2.47.2 From 0e9078320c1988a8109a73076e3fc56e854e4f0e Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Fri, 27 Jun 2025 05:34:26 +0200 Subject: [PATCH 2/4] boosters --- src/controllers/custom/setBoosterController.ts | 4 ++-- src/services/missionInventoryUpdateService.ts | 14 ++++++++++++++ static/webui/script.js | 3 +-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/controllers/custom/setBoosterController.ts b/src/controllers/custom/setBoosterController.ts index 28939614..b0a1ddbf 100644 --- a/src/controllers/custom/setBoosterController.ts +++ b/src/controllers/custom/setBoosterController.ts @@ -23,9 +23,9 @@ export const setBoosterController: RequestHandler = async (req, res) => { res.status(400).send("Invalid ItemType provided."); return; } - const now = Math.floor(Date.now() / 1000); + const now = Math.trunc(Date.now() / 1000); for (const { ItemType, ExpiryDate } of requests) { - if (ExpiryDate < now) { + if (ExpiryDate <= now) { // remove expired boosters const index = boosters.findIndex(item => item.ItemType === ItemType); if (index !== -1) { diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index 445c02fe..d44b06fb 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -1426,6 +1426,20 @@ export const addCredits = async ( const totalCredits = finalCredits.MissionCredits[1] + finalCredits.CreditsBonus[1] + rngRewardCredits; finalCredits.TotalCredits = [totalCredits, totalCredits]; + if (config.worldState?.creditBoost) { + inventory.RegularCredits += finalCredits.TotalCredits[1]; + finalCredits.TotalCredits[1] += finalCredits.TotalCredits[1]; + } + const now = Math.trunc(Date.now() / 1000); + if ((inventory.Boosters.find(x => x.ItemType == "/Lotus/Types/Boosters/CreditBooster")?.ExpiryDate ?? 0) > now) { + inventory.RegularCredits += finalCredits.TotalCredits[1]; + finalCredits.TotalCredits[1] += finalCredits.TotalCredits[1]; + } + if ((inventory.Boosters.find(x => x.ItemType == "/Lotus/Types/Boosters/CreditBlessing")?.ExpiryDate ?? 0) > now) { + inventory.RegularCredits += finalCredits.TotalCredits[1]; + finalCredits.TotalCredits[1] += finalCredits.TotalCredits[1]; + } + return finalCredits; }; diff --git a/static/webui/script.js b/static/webui/script.js index 91cc54a1..60ef4cad 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -2275,14 +2275,13 @@ function doAcquireBoosters() { const ExpiryDate = Date.now() / 1000 + 3 * 24 * 60 * 60; // default 3 days setBooster(uniqueName, ExpiryDate, () => { $("#acquire-type-Boosters").val(""); - updateInventory(); }); } function doChangeBoosterExpiry(ItemType, ExpiryDateInput) { console.log("Changing booster expiry for", ItemType, "to", ExpiryDateInput.value); // cast local datetime string to unix timestamp - const ExpiryDate = new Date(ExpiryDateInput.value).getTime() / 1000; + const ExpiryDate = Math.trunc(new Date(ExpiryDateInput.value).getTime() / 1000); if (isNaN(ExpiryDate)) { ExpiryDateInput.addClass("is-invalid").focus(); return false; -- 2.47.2 From e9b3cc3ddad216ab24641a3053c474c003f5e2dd Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Fri, 27 Jun 2025 05:43:54 +0200 Subject: [PATCH 3/4] remove comments --- src/services/missionInventoryUpdateService.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index d44b06fb..f8439050 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -1394,8 +1394,6 @@ export const addMissionRewards = async ( }; }; -//creditBonus is not entirely accurate. -//TODO: consider ActiveBoosters export const addCredits = async ( account: TAccountDocument, inventory: TInventoryDatabaseDocument, -- 2.47.2 From a41a24e45aecd37003e124e5951eb1b82e1a7afe Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Fri, 27 Jun 2025 07:48:36 +0200 Subject: [PATCH 4/4] note --- src/services/missionInventoryUpdateService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index f8439050..97132eb4 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -1428,7 +1428,7 @@ export const addCredits = async ( inventory.RegularCredits += finalCredits.TotalCredits[1]; finalCredits.TotalCredits[1] += finalCredits.TotalCredits[1]; } - const now = Math.trunc(Date.now() / 1000); + const now = Math.trunc(Date.now() / 1000); // TOVERIFY: Should we maybe subtract mission time as to apply credit boosters that expired during mission? if ((inventory.Boosters.find(x => x.ItemType == "/Lotus/Types/Boosters/CreditBooster")?.ExpiryDate ?? 0) > now) { inventory.RegularCredits += finalCredits.TotalCredits[1]; finalCredits.TotalCredits[1] += finalCredits.TotalCredits[1]; -- 2.47.2