XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

SpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 1 Star 0
返回提交历史

XFEstudio/SpaceNinjaServer

feat: resource extractor drones (#1068)

Closes #793 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1068

b3003b9f
Sainan <sainan@calamity.inc>
提交于

代码差异

13 个文件 +200 -10
Modified config.json.example +1 -0
@@ -31,6 +31,7 @@
31 31 "unlockExilusEverywhere": true,
32 32 "unlockArcanesEverywhere": true,
33 33 "noDailyStandingLimits": true,
34 "instantResourceExtractorDrones": false,
34 35 "noDojoResearchCosts": true,
35 36 "noDojoResearchTime": true,
36 37 "spoofMasteryRank": -1
Modified package-lock.json +4 -4
@@ -12,7 +12,7 @@
12 12 "copyfiles": "^2.4.1",
13 13 "express": "^5",
14 14 "mongoose": "^8.11.0",
15 "warframe-public-export-plus": "^0.5.38",
15 "warframe-public-export-plus": "^0.5.39",
16 16 "warframe-riven-info": "^0.1.2",
17 17 "winston": "^3.17.0",
18 18 "winston-daily-rotate-file": "^5.0.0"
@@ -4083,9 +4083,9 @@
4083 4083 }
4084 4084 },
4085 4085 "node_modules/warframe-public-export-plus": {
4086 "version": "0.5.38",
4087 "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.38.tgz",
4088 "integrity": "sha512-yvc86eOmYPSnnU8LzLBhg/lR1AS1RHID24TqFHVcZuOzMYc934NL8Cv7rtllyefWAMyl7iA5x9tyXSuJWbi6CA=="
4086 "version": "0.5.39",
4087 "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.39.tgz",
4088 "integrity": "sha512-sEGZedtW4I/M2ceoDs6MQ5eHD7sJgv1KRNLt8BWByXLuDa7qTR3Y9px5TGxqt/rBHKGUyPO1LUxu4bDGZi6yXw=="
4089 4089 },
4090 4090 "node_modules/warframe-riven-info": {
4091 4091 "version": "0.1.2",
Modified package.json +1 -1
@@ -17,7 +17,7 @@
17 17 "copyfiles": "^2.4.1",
18 18 "express": "^5",
19 19 "mongoose": "^8.11.0",
20 "warframe-public-export-plus": "^0.5.38",
20 "warframe-public-export-plus": "^0.5.39",
21 21 "warframe-riven-info": "^0.1.2",
22 22 "winston": "^3.17.0",
23 23 "winston-daily-rotate-file": "^5.0.0"
Modified src/controllers/api/dronesController.ts +136 -3
@@ -1,7 +1,140 @@
1 import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
2 import { config } from "@/src/services/configService";
3 import { addMiscItems, getInventory } from "@/src/services/inventoryService";
4 import { getAccountIdForRequest } from "@/src/services/loginService";
5 import { getRandomInt, getRandomWeightedReward3 } from "@/src/services/rngService";
6 import { IMongoDate, IOid } from "@/src/types/commonTypes";
7 import { IDroneClient } from "@/src/types/inventoryTypes/inventoryTypes";
8 import { IInventoryChanges } from "@/src/types/purchaseTypes";
1 9 import { RequestHandler } from "express";
10 import { ExportDrones, ExportResources, ExportSystems } from "warframe-public-export-plus";
2 11
3 const dronesController: RequestHandler = (_req, res) => {
4 res.json({});
12 export const dronesController: RequestHandler = async (req, res) => {
13 const accountId = await getAccountIdForRequest(req);
14 const inventory = await getInventory(accountId);
15 if ("GetActive" in req.query) {
16 const activeDrones: IActiveDrone[] = [];
17 for (const drone of inventory.Drones) {
18 if (drone.DeployTime) {
19 activeDrones.push({
20 DeployTime: toMongoDate(drone.DeployTime),
21 System: drone.System!,
22 ItemId: toOid(drone._id),
23 ItemType: drone.ItemType,
24 CurrentHP: drone.CurrentHP,
25 DamageTime: toMongoDate(drone.DamageTime!),
26 PendingDamage: drone.PendingDamage!,
27 Resources: [
28 {
29 ItemType: drone.ResourceType!,
30 BinTotal: drone.ResourceCount!,
31 StartTime: toMongoDate(drone.DeployTime)
32 }
33 ]
34 });
35 }
36 }
37 res.json({
38 ActiveDrones: activeDrones
39 });
40 } else if ("droneId" in req.query && "systemIndex" in req.query) {
41 const drone = inventory.Drones.id(req.query.droneId as string)!;
42 const droneMeta = ExportDrones[drone.ItemType];
43 drone.DeployTime = config.instantResourceExtractorDrones ? new Date(0) : new Date();
44 if (drone.RepairStart) {
45 const repairMinutes = (Date.now() - drone.RepairStart.getTime()) / 60_000;
46 const hpPerMinute = droneMeta.repairRate / 60;
47 drone.CurrentHP = Math.min(drone.CurrentHP + Math.round(repairMinutes * hpPerMinute), droneMeta.durability);
48 drone.RepairStart = undefined;
49 }
50 drone.System = parseInt(req.query.systemIndex as string);
51 const system = ExportSystems[drone.System - 1];
52 drone.DamageTime = config.instantResourceExtractorDrones
53 ? new Date()
54 : new Date(Date.now() + getRandomInt(3 * 3600 * 1000, 4 * 3600 * 1000));
55 drone.PendingDamage =
56 Math.random() < system.damageChance
57 ? getRandomInt(system.droneDamage.minValue, system.droneDamage.maxValue)
58 : 0;
59 const resource = getRandomWeightedReward3(system.resources, droneMeta.probabilities)!;
60 //logger.debug(`drone rolled`, resource);
61 drone.ResourceType = "/Lotus/" + resource.StoreItem.substring(18);
62 const resourceMeta = ExportResources[drone.ResourceType];
63 if (resourceMeta.pickupQuantity) {
64 const pickupsToCollect = droneMeta.binCapacity * droneMeta.capacityMultipliers[resource.Rarity];
65 drone.ResourceCount = 0;
66 for (let i = 0; i != pickupsToCollect; ++i) {
67 drone.ResourceCount += getRandomInt(
68 resourceMeta.pickupQuantity.minValue,
69 resourceMeta.pickupQuantity.maxValue
70 );
71 }
72 } else {
73 drone.ResourceCount = 1;
74 }
75 await inventory.save();
76 res.json({});
77 } else if ("collectDroneId" in req.query) {
78 const drone = inventory.Drones.id(req.query.collectDroneId as string)!;
79
80 if (new Date() >= drone.DamageTime!) {
81 drone.CurrentHP -= drone.PendingDamage!;
82 drone.RepairStart = new Date();
83 }
84
85 const inventoryChanges: IInventoryChanges = {};
86 if (drone.CurrentHP <= 0) {
87 inventory.RegularCredits += 100;
88 inventoryChanges.RegularCredits = 100;
89 inventory.Drones.pull({ _id: req.query.collectDroneId as string });
90 inventoryChanges.RemovedIdItems = [
91 {
92 ItemId: { $oid: req.query.collectDroneId }
93 }
94 ];
95 } else {
96 const completionTime = drone.DeployTime!.getTime() + ExportDrones[drone.ItemType].fillRate * 3600_000;
97 if (Date.now() >= completionTime) {
98 const miscItemChanges = [
99 {
100 ItemType: drone.ResourceType!,
101 ItemCount: drone.ResourceCount!
102 }
103 ];
104 addMiscItems(inventory, miscItemChanges);
105 inventoryChanges.MiscItems = miscItemChanges;
106 }
107
108 drone.DeployTime = undefined;
109 drone.System = undefined;
110 drone.DamageTime = undefined;
111 drone.PendingDamage = undefined;
112 drone.ResourceType = undefined;
113 drone.ResourceCount = undefined;
114
115 inventoryChanges.Drones = [drone.toJSON<IDroneClient>()];
116 }
117
118 await inventory.save();
119 res.json({
120 InventoryChanges: inventoryChanges
121 });
122 } else {
123 throw new Error(`drones.php query not handled`);
124 }
5 125 };
6 126
7 export { dronesController };
127 interface IActiveDrone {
128 DeployTime: IMongoDate;
129 System: number;
130 ItemId: IOid;
131 ItemType: string;
132 CurrentHP: number;
133 DamageTime: IMongoDate;
134 PendingDamage: number;
135 Resources: {
136 ItemType: string;
137 BinTotal: number;
138 StartTime: IMongoDate;
139 }[];
140 }
Modified src/controllers/api/sellController.ts +6 -0
@@ -86,6 +86,11 @@ export const sellController: RequestHandler = async (req, res) => {
86 86 inventory.Hoverboards.pull({ _id: sellItem.String });
87 87 });
88 88 }
89 if (payload.Items.Drones) {
90 payload.Items.Drones.forEach(sellItem => {
91 inventory.Drones.pull({ _id: sellItem.String });
92 });
93 }
89 94 if (payload.Items.Consumables) {
90 95 const consumablesChanges = [];
91 96 for (const sellItem of payload.Items.Consumables) {
@@ -152,6 +157,7 @@ interface ISellRequest {
152 157 SentinelWeapons?: ISellItem[];
153 158 OperatorAmps?: ISellItem[];
154 159 Hoverboards?: ISellItem[];
160 Drones?: ISellItem[];
155 161 };
156 162 SellPrice: number;
157 163 SellCurrency:
Modified src/models/inventoryModels/inventoryModel.ts +18 -1
@@ -336,7 +336,14 @@ const droneSchema = new Schema<IDroneDatabase>(
336 336 {
337 337 ItemType: String,
338 338 CurrentHP: Number,
339 RepairStart: { type: Date, default: undefined }
339 RepairStart: { type: Date, default: undefined },
340
341 DeployTime: { type: Date, default: undefined },
342 System: Number,
343 DamageTime: { type: Date, default: undefined },
344 PendingDamage: Number,
345 ResourceType: String,
346 ResourceCount: Number
340 347 },
341 348 { id: false }
342 349 );
@@ -347,6 +354,16 @@ droneSchema.set("toJSON", {
347 354 const db = obj as IDroneDatabase;
348 355
349 356 client.ItemId = toOid(db._id);
357 if (db.RepairStart) {
358 client.RepairStart = toMongoDate(db.RepairStart);
359 }
360
361 delete db.DeployTime;
362 delete db.System;
363 delete db.DamageTime;
364 delete db.PendingDamage;
365 delete db.ResourceType;
366 delete db.ResourceCount;
350 367
351 368 delete obj._id;
352 369 delete obj.__v;
Modified src/routes/api.ts +1 -0
@@ -145,6 +145,7 @@ apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
145 145 apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
146 146 apiRouter.post("/completeRandomModChallenge.php", completeRandomModChallengeController);
147 147 apiRouter.post("/createGuild.php", createGuildController);
148 apiRouter.post("/drones.php", dronesController);
148 149 apiRouter.post("/endlessXp.php", endlessXpController);
149 150 apiRouter.post("/evolveWeapon.php", evolveWeaponController);
150 151 apiRouter.post("/findSessions.php", findSessionsController);
Modified src/services/configService.ts +1 -0
@@ -57,6 +57,7 @@ interface IConfig {
57 57 unlockExilusEverywhere?: boolean;
58 58 unlockArcanesEverywhere?: boolean;
59 59 noDailyStandingLimits?: boolean;
60 instantResourceExtractorDrones?: boolean;
60 61 noDojoResearchCosts?: boolean;
61 62 noDojoResearchTime?: boolean;
62 63 spoofMasteryRank?: number;
Modified src/services/rngService.ts +19 -1
@@ -18,7 +18,7 @@ export const getRandomInt = (min: number, max: number): number => {
18 18 return Math.floor(Math.random() * (max - min + 1)) + min;
19 19 };
20 20
21 export const getRandomReward = (pool: IRngResult[]): IRngResult | undefined => {
21 export const getRandomReward = <T extends { probability: number }>(pool: T[]): T | undefined => {
22 22 if (pool.length == 0) return;
23 23
24 24 const totalChance = pool.reduce((accum, item) => accum + item.probability, 0);
@@ -71,3 +71,21 @@ export const getRandomWeightedReward2 = (
71 71 }
72 72 return getRandomReward(resultPool);
73 73 };
74
75 export const getRandomWeightedReward3 = <T extends { Rarity: TRarity }>(
76 pool: T[],
77 weights: Record<TRarity, number>
78 ): (T & { probability: number }) | undefined => {
79 const resultPool: (T & { probability: number })[] = [];
80 const rarityCounts: Record<TRarity, number> = { COMMON: 0, UNCOMMON: 0, RARE: 0, LEGENDARY: 0 };
81 for (const entry of pool) {
82 ++rarityCounts[entry.Rarity];
83 }
84 for (const entry of pool) {
85 resultPool.push({
86 ...entry,
87 probability: weights[entry.Rarity] / rarityCounts[entry.Rarity]
88 });
89 }
90 return getRandomReward(resultPool);
91 };
Modified src/types/inventoryTypes/inventoryTypes.ts +7 -0
@@ -520,6 +520,13 @@ export interface IDroneDatabase {
520 520 CurrentHP: number;
521 521 _id: Types.ObjectId;
522 522 RepairStart?: Date;
523
524 DeployTime?: Date;
525 System?: number;
526 DamageTime?: Date;
527 PendingDamage?: number;
528 ResourceType?: string;
529 ResourceCount?: number;
523 530 }
524 531
525 532 export interface ITypeXPItem {
Modified static/webui/index.html +4 -0
@@ -517,6 +517,10 @@
517 517 <input class="form-check-input" type="checkbox" id="noDailyStandingLimits" />
518 518 <label class="form-check-label" for="noDailyStandingLimits" data-loc="cheats_noDailyStandingLimits"></label>
519 519 </div>
520 <div class="form-check">
521 <input class="form-check-input" type="checkbox" id="instantResourceExtractorDrones" />
522 <label class="form-check-label" for="instantResourceExtractorDrones" data-loc="cheats_instantResourceExtractorDrones"></label>
523 </div>
520 524 <div class="form-check">
521 525 <input class="form-check-input" type="checkbox" id="noDojoResearchCosts" />
522 526 <label class="form-check-label" for="noDojoResearchCosts" data-loc="cheats_noDojoResearchCosts"></label>
Modified static/webui/translations/en.js +1 -0
@@ -111,6 +111,7 @@ dict = {
111 111 cheats_unlockExilusEverywhere: `Exilus Adapters Everywhere`,
112 112 cheats_unlockArcanesEverywhere: `Arcane Adapters Everywhere`,
113 113 cheats_noDailyStandingLimits: `No Daily Standing Limits`,
114 cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`,
114 115 cheats_noDojoResearchCosts: `No Dojo Research Costs`,
115 116 cheats_noDojoResearchTime: `No Dojo Research Time`,
116 117 cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`,
Modified static/webui/translations/ru.js +1 -0