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: credit boosters (+ daily first win) (#2324)

Daily first win is kinda weird because the client doesn't even seem to acknowledge it. Also fixed missionCompletionCredits being added to inventory inconsistently (sometimes once, sometimes twice). Closes #1086 Closes #2322 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2324 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>

4895b463
Sainan <63328889+Sainan@users.noreply.github.com>
提交于

代码差异

10 个文件 +63 -47
Modified src/controllers/api/checkDailyMissionBonusController.ts +9 -13
@@ -1,16 +1,12 @@
1 import { getAccountForRequest } from "@/src/services/loginService";
1 2 import { RequestHandler } from "express";
2 3
3 const checkDailyMissionBonusController: RequestHandler = (_req, res) => {
4 const data = Buffer.from([
5 0x44, 0x61, 0x69, 0x6c, 0x79, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x6f, 0x6e, 0x75, 0x73, 0x3a,
6 0x31, 0x2d, 0x44, 0x61, 0x69, 0x6c, 0x79, 0x50, 0x56, 0x50, 0x57, 0x69, 0x6e, 0x42, 0x6f, 0x6e, 0x75, 0x73,
7 0x3a, 0x31, 0x0a
8 ]);
9 res.writeHead(200, {
10 "Content-Type": "text/html",
11 "Content-Length": data.length
12 });
13 res.end(data);
4 export const checkDailyMissionBonusController: RequestHandler = async (req, res) => {
5 const account = await getAccountForRequest(req);
6 const today = Math.trunc(Date.now() / 86400000) * 86400;
7 if (account.DailyFirstWinDate != today) {
8 res.send("DailyMissionBonus:1-DailyPVPWinBonus:1\n");
9 } else {
10 res.send("DailyMissionBonus:0-DailyPVPWinBonus:1\n");
11 }
14 12 };
15
16 export { checkDailyMissionBonusController };
Modified src/controllers/api/missionInventoryUpdateController.ts +1 -1
@@ -88,7 +88,7 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
88 88 AffiliationMods,
89 89 SyndicateXPItemReward,
90 90 ConquestCompletedMissionsCount
91 } = await addMissionRewards(inventory, missionReport, firstCompletion);
91 } = await addMissionRewards(account, inventory, missionReport, firstCompletion);
92 92
93 93 if (missionReport.EndOfMatchUpload) {
94 94 inventory.RewardSeed = generateRewardSeed();
Modified src/controllers/custom/completeAllMissionsController.ts +1 -1
@@ -26,7 +26,7 @@ export const completeAllMissionsController: RequestHandler = async (req, res) =>
26 26 if (mission.Completes == 0) {
27 27 mission.Completes++;
28 28 if (node.missionReward) {
29 addFixedLevelRewards(node.missionReward, inventory, MissionRewards);
29 addFixedLevelRewards(node.missionReward, MissionRewards);
30 30 }
31 31 }
32 32 mission.Tier = 1;
Modified src/controllers/custom/setBoosterController.ts +2 -2
@@ -23,9 +23,9 @@ export const setBoosterController: RequestHandler = async (req, res) => {
23 23 res.status(400).send("Invalid ItemType provided.");
24 24 return;
25 25 }
26 const now = Math.floor(Date.now() / 1000);
26 const now = Math.trunc(Date.now() / 1000);
27 27 for (const { ItemType, ExpiryDate } of requests) {
28 if (ExpiryDate < now) {
28 if (ExpiryDate <= now) {
29 29 // remove expired boosters
30 30 const index = boosters.findIndex(item => item.ItemType === ItemType);
31 31 if (index !== -1) {
Modified src/models/loginModel.ts +2 -1
@@ -25,7 +25,8 @@ const databaseAccountSchema = new Schema<IDatabaseAccountJson>(
25 25 LastLogin: { type: Date, default: 0 },
26 26 LatestEventMessageDate: { type: Date, default: 0 },
27 27 LastLoginRewardDate: { type: Number, default: 0 },
28 LoginDays: { type: Number, default: 1 }
28 LoginDays: { type: Number, default: 1 },
29 DailyFirstWinDate: { type: Number, default: 0 }
29 30 },
30 31 opts
31 32 );
Modified src/services/missionInventoryUpdateService.ts +42 -23
@@ -962,6 +962,7 @@ const droptableAliases: Record<string, string> = {
962 962
963 963 //TODO: return type of partial missioninventoryupdate response
964 964 export const addMissionRewards = async (
965 account: TAccountDocument,
965 966 inventory: TInventoryDatabaseDocument,
966 967 {
967 968 wagerTier: wagerTier,
@@ -1009,13 +1010,17 @@ export const addMissionRewards = async (
1009 1010 const fixedLevelRewards = getLevelKeyRewards(levelKeyName);
1010 1011 //logger.debug(`fixedLevelRewards ${fixedLevelRewards}`);
1011 1012 if (fixedLevelRewards.levelKeyRewards) {
1012 addFixedLevelRewards(fixedLevelRewards.levelKeyRewards, inventory, MissionRewards, rewardInfo);
1013 missionCompletionCredits += addFixedLevelRewards(
1014 fixedLevelRewards.levelKeyRewards,
1015 MissionRewards,
1016 rewardInfo
1017 );
1013 1018 }
1014 1019 if (fixedLevelRewards.levelKeyRewards2) {
1015 1020 for (const reward of fixedLevelRewards.levelKeyRewards2) {
1016 1021 //quest stage completion credit rewards
1017 1022 if (reward.rewardType == "RT_CREDITS") {
1018 missionCompletionCredits += reward.amount; // will be added to inventory in addCredits
1023 missionCompletionCredits += reward.amount;
1019 1024 continue;
1020 1025 }
1021 1026 MissionRewards.push({
@@ -1044,12 +1049,11 @@ export const addMissionRewards = async (
1044 1049 ) {
1045 1050 const levelCreditReward = getLevelCreditRewards(node);
1046 1051 missionCompletionCredits += levelCreditReward;
1047 inventory.RegularCredits += levelCreditReward;
1048 1052 logger.debug(`levelCreditReward ${levelCreditReward}`);
1049 1053 }
1050 1054
1051 1055 if (node.missionReward) {
1052 missionCompletionCredits += addFixedLevelRewards(node.missionReward, inventory, MissionRewards, rewardInfo);
1056 missionCompletionCredits += addFixedLevelRewards(node.missionReward, MissionRewards, rewardInfo);
1053 1057 }
1054 1058
1055 1059 if (rewardInfo.sortieTag == "Mission1") {
@@ -1159,7 +1163,9 @@ export const addMissionRewards = async (
1159 1163 combineInventoryChanges(inventoryChanges, inventoryChange.InventoryChanges);
1160 1164 }
1161 1165
1162 const credits = addCredits(inventory, {
1166 inventory.RegularCredits += missionCompletionCredits;
1167
1168 const credits = await addCredits(account, inventory, {
1163 1169 missionCompletionCredits,
1164 1170 missionDropCredits: creditDrops ?? 0,
1165 1171 rngRewardCredits: inventoryChanges.RegularCredits ?? 0
@@ -1382,48 +1388,61 @@ export const addMissionRewards = async (
1382 1388 };
1383 1389 };
1384 1390
1385 //creditBonus is not entirely accurate.
1386 //TODO: consider ActiveBoosters
1387 export const addCredits = (
1391 export const addCredits = async (
1392 account: TAccountDocument,
1388 1393 inventory: TInventoryDatabaseDocument,
1389 1394 {
1390 1395 missionDropCredits,
1391 1396 missionCompletionCredits,
1392 1397 rngRewardCredits
1393 1398 }: { missionDropCredits: number; missionCompletionCredits: number; rngRewardCredits: number }
1394 ): IMissionCredits => {
1395 const hasDailyCreditBonus = true;
1396 const totalCredits = missionDropCredits + missionCompletionCredits + rngRewardCredits;
1397
1399 ): Promise<IMissionCredits> => {
1398 1400 const finalCredits: IMissionCredits = {
1399 1401 MissionCredits: [missionDropCredits, missionDropCredits],
1400 CreditBonus: [missionCompletionCredits, missionCompletionCredits],
1401 TotalCredits: [totalCredits, totalCredits]
1402 CreditsBonus: [missionCompletionCredits, missionCompletionCredits],
1403 TotalCredits: [0, 0]
1402 1404 };
1403 1405
1404 if (hasDailyCreditBonus) {
1406 const today = Math.trunc(Date.now() / 86400000) * 86400;
1407 if (account.DailyFirstWinDate != today) {
1408 account.DailyFirstWinDate = today;
1409 await account.save();
1410
1411 logger.debug(`daily first win, doubling missionCompletionCredits (${missionCompletionCredits})`);
1412
1413 finalCredits.DailyMissionBonus = true;
1405 1414 inventory.RegularCredits += missionCompletionCredits;
1406 finalCredits.CreditBonus[1] *= 2;
1407 finalCredits.MissionCredits[1] *= 2;
1408 finalCredits.TotalCredits[1] *= 2;
1415 finalCredits.CreditsBonus[1] *= 2;
1409 1416 }
1410 1417
1411 if (!hasDailyCreditBonus) {
1412 return finalCredits;
1418 const totalCredits = finalCredits.MissionCredits[1] + finalCredits.CreditsBonus[1] + rngRewardCredits;
1419 finalCredits.TotalCredits = [totalCredits, totalCredits];
1420
1421 if (config.worldState?.creditBoost) {
1422 inventory.RegularCredits += finalCredits.TotalCredits[1];
1423 finalCredits.TotalCredits[1] += finalCredits.TotalCredits[1];
1424 }
1425 const now = Math.trunc(Date.now() / 1000); // TOVERIFY: Should we maybe subtract mission time as to apply credit boosters that expired during mission?
1426 if ((inventory.Boosters.find(x => x.ItemType == "/Lotus/Types/Boosters/CreditBooster")?.ExpiryDate ?? 0) > now) {
1427 inventory.RegularCredits += finalCredits.TotalCredits[1];
1428 finalCredits.TotalCredits[1] += finalCredits.TotalCredits[1];
1429 }
1430 if ((inventory.Boosters.find(x => x.ItemType == "/Lotus/Types/Boosters/CreditBlessing")?.ExpiryDate ?? 0) > now) {
1431 inventory.RegularCredits += finalCredits.TotalCredits[1];
1432 finalCredits.TotalCredits[1] += finalCredits.TotalCredits[1];
1413 1433 }
1414 return { ...finalCredits, DailyMissionBonus: true };
1434
1435 return finalCredits;
1415 1436 };
1416 1437
1417 1438 export const addFixedLevelRewards = (
1418 1439 rewards: IMissionRewardExternal,
1419 inventory: TInventoryDatabaseDocument,
1420 1440 MissionRewards: IMissionReward[],
1421 1441 rewardInfo?: IRewardInfo
1422 1442 ): number => {
1423 1443 let missionBonusCredits = 0;
1424 1444 if (rewards.credits) {
1425 1445 missionBonusCredits += rewards.credits;
1426 inventory.RegularCredits += rewards.credits;
1427 1446 }
1428 1447 if (rewards.items) {
1429 1448 for (const item of rewards.items) {
Modified src/services/questService.ts +1 -1
@@ -331,7 +331,7 @@ export const giveKeyChainMissionReward = async (
331 331 const fixedLevelRewards = getLevelKeyRewards(missionName);
332 332 if (fixedLevelRewards.levelKeyRewards) {
333 333 const missionRewards: { StoreItem: string; ItemCount: number }[] = [];
334 addFixedLevelRewards(fixedLevelRewards.levelKeyRewards, inventory, missionRewards);
334 inventory.RegularCredits += addFixedLevelRewards(fixedLevelRewards.levelKeyRewards, missionRewards);
335 335
336 336 for (const reward of missionRewards) {
337 337 await addItem(inventory, fromStoreItem(reward.StoreItem), reward.ItemCount);
Modified src/types/loginTypes.ts +1 -0
@@ -25,6 +25,7 @@ export interface IDatabaseAccount extends IDatabaseAccountRequiredFields {
25 25 LatestEventMessageDate: Date;
26 26 LastLoginRewardDate: number;
27 27 LoginDays: number;
28 DailyFirstWinDate: number;
28 29 }
29 30
30 31 // Includes virtual ID
Modified src/types/missionTypes.ts +3 -3
@@ -17,9 +17,9 @@ export interface IMissionReward {
17 17 }
18 18
19 19 export interface IMissionCredits {
20 MissionCredits: number[];
21 CreditBonus: number[];
22 TotalCredits: number[];
20 MissionCredits: [number, number];
21 CreditsBonus: [number, number]; // "Credit Reward"; `CreditsBonus[1]` is `CreditsBonus[0] * 2` if DailyMissionBonus
22 TotalCredits: [number, number];
23 23 DailyMissionBonus?: boolean;
24 24 }
25 25
Modified static/webui/script.js +1 -2
@@ -2289,14 +2289,13 @@ function doAcquireBoosters() {
2289 2289 const ExpiryDate = Date.now() / 1000 + 3 * 24 * 60 * 60; // default 3 days
2290 2290 setBooster(uniqueName, ExpiryDate, () => {
2291 2291 $("#acquire-type-Boosters").val("");
2292 updateInventory();
2293 2292 });
2294 2293 }
2295 2294
2296 2295 function doChangeBoosterExpiry(ItemType, ExpiryDateInput) {
2297 2296 console.log("Changing booster expiry for", ItemType, "to", ExpiryDateInput.value);
2298 2297 // cast local datetime string to unix timestamp
2299 const ExpiryDate = new Date(ExpiryDateInput.value).getTime() / 1000;
2298 const ExpiryDate = Math.trunc(new Date(ExpiryDateInput.value).getTime() / 1000);
2300 2299 if (isNaN(ExpiryDate)) {
2301 2300 ExpiryDateInput.addClass("is-invalid").focus();
2302 2301 return false;