返回提交历史
Modified
src/controllers/api/checkDailyMissionBonusController.ts
+9
-13
Modified
src/controllers/api/missionInventoryUpdateController.ts
+1
-1
Modified
src/controllers/custom/completeAllMissionsController.ts
+1
-1
Modified
src/controllers/custom/setBoosterController.ts
+2
-2
Modified
src/models/loginModel.ts
+2
-1
Modified
src/services/missionInventoryUpdateService.ts
+42
-23
Modified
src/services/questService.ts
+1
-1
Modified
src/types/loginTypes.ts
+1
-0
Modified
src/types/missionTypes.ts
+3
-3
Modified
static/webui/script.js
+1
-2
XFEstudio/SpaceNinjaServer
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
代码差异
10 个文件
+63
-47
@@ -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 };
@@ -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();
@@ -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;
@@ -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) {
@@ -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
);
@@ -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) {
@@ -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);
@@ -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
@@ -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
@@ -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;