parent
36d12e08c7
commit
b3003b9fb3
@ -31,6 +31,7 @@
|
|||||||
"unlockExilusEverywhere": true,
|
"unlockExilusEverywhere": true,
|
||||||
"unlockArcanesEverywhere": true,
|
"unlockArcanesEverywhere": true,
|
||||||
"noDailyStandingLimits": true,
|
"noDailyStandingLimits": true,
|
||||||
|
"instantResourceExtractorDrones": false,
|
||||||
"noDojoResearchCosts": true,
|
"noDojoResearchCosts": true,
|
||||||
"noDojoResearchTime": true,
|
"noDojoResearchTime": true,
|
||||||
"spoofMasteryRank": -1
|
"spoofMasteryRank": -1
|
||||||
|
8
package-lock.json
generated
8
package-lock.json
generated
@ -12,7 +12,7 @@
|
|||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"express": "^5",
|
"express": "^5",
|
||||||
"mongoose": "^8.11.0",
|
"mongoose": "^8.11.0",
|
||||||
"warframe-public-export-plus": "^0.5.38",
|
"warframe-public-export-plus": "^0.5.39",
|
||||||
"warframe-riven-info": "^0.1.2",
|
"warframe-riven-info": "^0.1.2",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0"
|
"winston-daily-rotate-file": "^5.0.0"
|
||||||
@ -4083,9 +4083,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/warframe-public-export-plus": {
|
"node_modules/warframe-public-export-plus": {
|
||||||
"version": "0.5.38",
|
"version": "0.5.39",
|
||||||
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.38.tgz",
|
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.39.tgz",
|
||||||
"integrity": "sha512-yvc86eOmYPSnnU8LzLBhg/lR1AS1RHID24TqFHVcZuOzMYc934NL8Cv7rtllyefWAMyl7iA5x9tyXSuJWbi6CA=="
|
"integrity": "sha512-sEGZedtW4I/M2ceoDs6MQ5eHD7sJgv1KRNLt8BWByXLuDa7qTR3Y9px5TGxqt/rBHKGUyPO1LUxu4bDGZi6yXw=="
|
||||||
},
|
},
|
||||||
"node_modules/warframe-riven-info": {
|
"node_modules/warframe-riven-info": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"express": "^5",
|
"express": "^5",
|
||||||
"mongoose": "^8.11.0",
|
"mongoose": "^8.11.0",
|
||||||
"warframe-public-export-plus": "^0.5.38",
|
"warframe-public-export-plus": "^0.5.39",
|
||||||
"warframe-riven-info": "^0.1.2",
|
"warframe-riven-info": "^0.1.2",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0"
|
"winston-daily-rotate-file": "^5.0.0"
|
||||||
|
@ -1,7 +1,140 @@
|
|||||||
|
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
|
import { config } from "@/src/services/configService";
|
||||||
|
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { getRandomInt, getRandomWeightedReward3 } from "@/src/services/rngService";
|
||||||
|
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
||||||
|
import { IDroneClient } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
import { ExportDrones, ExportResources, ExportSystems } from "warframe-public-export-plus";
|
||||||
|
|
||||||
const dronesController: RequestHandler = (_req, res) => {
|
export const dronesController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId);
|
||||||
|
if ("GetActive" in req.query) {
|
||||||
|
const activeDrones: IActiveDrone[] = [];
|
||||||
|
for (const drone of inventory.Drones) {
|
||||||
|
if (drone.DeployTime) {
|
||||||
|
activeDrones.push({
|
||||||
|
DeployTime: toMongoDate(drone.DeployTime),
|
||||||
|
System: drone.System!,
|
||||||
|
ItemId: toOid(drone._id),
|
||||||
|
ItemType: drone.ItemType,
|
||||||
|
CurrentHP: drone.CurrentHP,
|
||||||
|
DamageTime: toMongoDate(drone.DamageTime!),
|
||||||
|
PendingDamage: drone.PendingDamage!,
|
||||||
|
Resources: [
|
||||||
|
{
|
||||||
|
ItemType: drone.ResourceType!,
|
||||||
|
BinTotal: drone.ResourceCount!,
|
||||||
|
StartTime: toMongoDate(drone.DeployTime)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.json({
|
||||||
|
ActiveDrones: activeDrones
|
||||||
|
});
|
||||||
|
} else if ("droneId" in req.query && "systemIndex" in req.query) {
|
||||||
|
const drone = inventory.Drones.id(req.query.droneId as string)!;
|
||||||
|
const droneMeta = ExportDrones[drone.ItemType];
|
||||||
|
drone.DeployTime = config.instantResourceExtractorDrones ? new Date(0) : new Date();
|
||||||
|
if (drone.RepairStart) {
|
||||||
|
const repairMinutes = (Date.now() - drone.RepairStart.getTime()) / 60_000;
|
||||||
|
const hpPerMinute = droneMeta.repairRate / 60;
|
||||||
|
drone.CurrentHP = Math.min(drone.CurrentHP + Math.round(repairMinutes * hpPerMinute), droneMeta.durability);
|
||||||
|
drone.RepairStart = undefined;
|
||||||
|
}
|
||||||
|
drone.System = parseInt(req.query.systemIndex as string);
|
||||||
|
const system = ExportSystems[drone.System - 1];
|
||||||
|
drone.DamageTime = config.instantResourceExtractorDrones
|
||||||
|
? new Date()
|
||||||
|
: new Date(Date.now() + getRandomInt(3 * 3600 * 1000, 4 * 3600 * 1000));
|
||||||
|
drone.PendingDamage =
|
||||||
|
Math.random() < system.damageChance
|
||||||
|
? getRandomInt(system.droneDamage.minValue, system.droneDamage.maxValue)
|
||||||
|
: 0;
|
||||||
|
const resource = getRandomWeightedReward3(system.resources, droneMeta.probabilities)!;
|
||||||
|
//logger.debug(`drone rolled`, resource);
|
||||||
|
drone.ResourceType = "/Lotus/" + resource.StoreItem.substring(18);
|
||||||
|
const resourceMeta = ExportResources[drone.ResourceType];
|
||||||
|
if (resourceMeta.pickupQuantity) {
|
||||||
|
const pickupsToCollect = droneMeta.binCapacity * droneMeta.capacityMultipliers[resource.Rarity];
|
||||||
|
drone.ResourceCount = 0;
|
||||||
|
for (let i = 0; i != pickupsToCollect; ++i) {
|
||||||
|
drone.ResourceCount += getRandomInt(
|
||||||
|
resourceMeta.pickupQuantity.minValue,
|
||||||
|
resourceMeta.pickupQuantity.maxValue
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
drone.ResourceCount = 1;
|
||||||
|
}
|
||||||
|
await inventory.save();
|
||||||
res.json({});
|
res.json({});
|
||||||
|
} else if ("collectDroneId" in req.query) {
|
||||||
|
const drone = inventory.Drones.id(req.query.collectDroneId as string)!;
|
||||||
|
|
||||||
|
if (new Date() >= drone.DamageTime!) {
|
||||||
|
drone.CurrentHP -= drone.PendingDamage!;
|
||||||
|
drone.RepairStart = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
|
if (drone.CurrentHP <= 0) {
|
||||||
|
inventory.RegularCredits += 100;
|
||||||
|
inventoryChanges.RegularCredits = 100;
|
||||||
|
inventory.Drones.pull({ _id: req.query.collectDroneId as string });
|
||||||
|
inventoryChanges.RemovedIdItems = [
|
||||||
|
{
|
||||||
|
ItemId: { $oid: req.query.collectDroneId }
|
||||||
|
}
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
const completionTime = drone.DeployTime!.getTime() + ExportDrones[drone.ItemType].fillRate * 3600_000;
|
||||||
|
if (Date.now() >= completionTime) {
|
||||||
|
const miscItemChanges = [
|
||||||
|
{
|
||||||
|
ItemType: drone.ResourceType!,
|
||||||
|
ItemCount: drone.ResourceCount!
|
||||||
|
}
|
||||||
|
];
|
||||||
|
addMiscItems(inventory, miscItemChanges);
|
||||||
|
inventoryChanges.MiscItems = miscItemChanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
drone.DeployTime = undefined;
|
||||||
|
drone.System = undefined;
|
||||||
|
drone.DamageTime = undefined;
|
||||||
|
drone.PendingDamage = undefined;
|
||||||
|
drone.ResourceType = undefined;
|
||||||
|
drone.ResourceCount = undefined;
|
||||||
|
|
||||||
|
inventoryChanges.Drones = [drone.toJSON<IDroneClient>()];
|
||||||
|
}
|
||||||
|
|
||||||
|
await inventory.save();
|
||||||
|
res.json({
|
||||||
|
InventoryChanges: inventoryChanges
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new Error(`drones.php query not handled`);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export { dronesController };
|
interface IActiveDrone {
|
||||||
|
DeployTime: IMongoDate;
|
||||||
|
System: number;
|
||||||
|
ItemId: IOid;
|
||||||
|
ItemType: string;
|
||||||
|
CurrentHP: number;
|
||||||
|
DamageTime: IMongoDate;
|
||||||
|
PendingDamage: number;
|
||||||
|
Resources: {
|
||||||
|
ItemType: string;
|
||||||
|
BinTotal: number;
|
||||||
|
StartTime: IMongoDate;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
@ -86,6 +86,11 @@ export const sellController: RequestHandler = async (req, res) => {
|
|||||||
inventory.Hoverboards.pull({ _id: sellItem.String });
|
inventory.Hoverboards.pull({ _id: sellItem.String });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (payload.Items.Drones) {
|
||||||
|
payload.Items.Drones.forEach(sellItem => {
|
||||||
|
inventory.Drones.pull({ _id: sellItem.String });
|
||||||
|
});
|
||||||
|
}
|
||||||
if (payload.Items.Consumables) {
|
if (payload.Items.Consumables) {
|
||||||
const consumablesChanges = [];
|
const consumablesChanges = [];
|
||||||
for (const sellItem of payload.Items.Consumables) {
|
for (const sellItem of payload.Items.Consumables) {
|
||||||
@ -152,6 +157,7 @@ interface ISellRequest {
|
|||||||
SentinelWeapons?: ISellItem[];
|
SentinelWeapons?: ISellItem[];
|
||||||
OperatorAmps?: ISellItem[];
|
OperatorAmps?: ISellItem[];
|
||||||
Hoverboards?: ISellItem[];
|
Hoverboards?: ISellItem[];
|
||||||
|
Drones?: ISellItem[];
|
||||||
};
|
};
|
||||||
SellPrice: number;
|
SellPrice: number;
|
||||||
SellCurrency:
|
SellCurrency:
|
||||||
|
@ -336,7 +336,14 @@ const droneSchema = new Schema<IDroneDatabase>(
|
|||||||
{
|
{
|
||||||
ItemType: String,
|
ItemType: String,
|
||||||
CurrentHP: Number,
|
CurrentHP: Number,
|
||||||
RepairStart: { type: Date, default: undefined }
|
RepairStart: { type: Date, default: undefined },
|
||||||
|
|
||||||
|
DeployTime: { type: Date, default: undefined },
|
||||||
|
System: Number,
|
||||||
|
DamageTime: { type: Date, default: undefined },
|
||||||
|
PendingDamage: Number,
|
||||||
|
ResourceType: String,
|
||||||
|
ResourceCount: Number
|
||||||
},
|
},
|
||||||
{ id: false }
|
{ id: false }
|
||||||
);
|
);
|
||||||
@ -347,6 +354,16 @@ droneSchema.set("toJSON", {
|
|||||||
const db = obj as IDroneDatabase;
|
const db = obj as IDroneDatabase;
|
||||||
|
|
||||||
client.ItemId = toOid(db._id);
|
client.ItemId = toOid(db._id);
|
||||||
|
if (db.RepairStart) {
|
||||||
|
client.RepairStart = toMongoDate(db.RepairStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete db.DeployTime;
|
||||||
|
delete db.System;
|
||||||
|
delete db.DamageTime;
|
||||||
|
delete db.PendingDamage;
|
||||||
|
delete db.ResourceType;
|
||||||
|
delete db.ResourceCount;
|
||||||
|
|
||||||
delete obj._id;
|
delete obj._id;
|
||||||
delete obj.__v;
|
delete obj.__v;
|
||||||
|
@ -145,6 +145,7 @@ apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
|
|||||||
apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
|
apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
|
||||||
apiRouter.post("/completeRandomModChallenge.php", completeRandomModChallengeController);
|
apiRouter.post("/completeRandomModChallenge.php", completeRandomModChallengeController);
|
||||||
apiRouter.post("/createGuild.php", createGuildController);
|
apiRouter.post("/createGuild.php", createGuildController);
|
||||||
|
apiRouter.post("/drones.php", dronesController);
|
||||||
apiRouter.post("/endlessXp.php", endlessXpController);
|
apiRouter.post("/endlessXp.php", endlessXpController);
|
||||||
apiRouter.post("/evolveWeapon.php", evolveWeaponController);
|
apiRouter.post("/evolveWeapon.php", evolveWeaponController);
|
||||||
apiRouter.post("/findSessions.php", findSessionsController);
|
apiRouter.post("/findSessions.php", findSessionsController);
|
||||||
|
@ -57,6 +57,7 @@ interface IConfig {
|
|||||||
unlockExilusEverywhere?: boolean;
|
unlockExilusEverywhere?: boolean;
|
||||||
unlockArcanesEverywhere?: boolean;
|
unlockArcanesEverywhere?: boolean;
|
||||||
noDailyStandingLimits?: boolean;
|
noDailyStandingLimits?: boolean;
|
||||||
|
instantResourceExtractorDrones?: boolean;
|
||||||
noDojoResearchCosts?: boolean;
|
noDojoResearchCosts?: boolean;
|
||||||
noDojoResearchTime?: boolean;
|
noDojoResearchTime?: boolean;
|
||||||
spoofMasteryRank?: number;
|
spoofMasteryRank?: number;
|
||||||
|
@ -18,7 +18,7 @@ export const getRandomInt = (min: number, max: number): number => {
|
|||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getRandomReward = (pool: IRngResult[]): IRngResult | undefined => {
|
export const getRandomReward = <T extends { probability: number }>(pool: T[]): T | undefined => {
|
||||||
if (pool.length == 0) return;
|
if (pool.length == 0) return;
|
||||||
|
|
||||||
const totalChance = pool.reduce((accum, item) => accum + item.probability, 0);
|
const totalChance = pool.reduce((accum, item) => accum + item.probability, 0);
|
||||||
@ -71,3 +71,21 @@ export const getRandomWeightedReward2 = (
|
|||||||
}
|
}
|
||||||
return getRandomReward(resultPool);
|
return getRandomReward(resultPool);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getRandomWeightedReward3 = <T extends { Rarity: TRarity }>(
|
||||||
|
pool: T[],
|
||||||
|
weights: Record<TRarity, number>
|
||||||
|
): (T & { probability: number }) | undefined => {
|
||||||
|
const resultPool: (T & { probability: number })[] = [];
|
||||||
|
const rarityCounts: Record<TRarity, number> = { COMMON: 0, UNCOMMON: 0, RARE: 0, LEGENDARY: 0 };
|
||||||
|
for (const entry of pool) {
|
||||||
|
++rarityCounts[entry.Rarity];
|
||||||
|
}
|
||||||
|
for (const entry of pool) {
|
||||||
|
resultPool.push({
|
||||||
|
...entry,
|
||||||
|
probability: weights[entry.Rarity] / rarityCounts[entry.Rarity]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return getRandomReward(resultPool);
|
||||||
|
};
|
||||||
|
@ -520,6 +520,13 @@ export interface IDroneDatabase {
|
|||||||
CurrentHP: number;
|
CurrentHP: number;
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
RepairStart?: Date;
|
RepairStart?: Date;
|
||||||
|
|
||||||
|
DeployTime?: Date;
|
||||||
|
System?: number;
|
||||||
|
DamageTime?: Date;
|
||||||
|
PendingDamage?: number;
|
||||||
|
ResourceType?: string;
|
||||||
|
ResourceCount?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITypeXPItem {
|
export interface ITypeXPItem {
|
||||||
|
@ -517,6 +517,10 @@
|
|||||||
<input class="form-check-input" type="checkbox" id="noDailyStandingLimits" />
|
<input class="form-check-input" type="checkbox" id="noDailyStandingLimits" />
|
||||||
<label class="form-check-label" for="noDailyStandingLimits" data-loc="cheats_noDailyStandingLimits"></label>
|
<label class="form-check-label" for="noDailyStandingLimits" data-loc="cheats_noDailyStandingLimits"></label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="instantResourceExtractorDrones" />
|
||||||
|
<label class="form-check-label" for="instantResourceExtractorDrones" data-loc="cheats_instantResourceExtractorDrones"></label>
|
||||||
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="noDojoResearchCosts" />
|
<input class="form-check-input" type="checkbox" id="noDojoResearchCosts" />
|
||||||
<label class="form-check-label" for="noDojoResearchCosts" data-loc="cheats_noDojoResearchCosts"></label>
|
<label class="form-check-label" for="noDojoResearchCosts" data-loc="cheats_noDojoResearchCosts"></label>
|
||||||
|
@ -111,6 +111,7 @@ dict = {
|
|||||||
cheats_unlockExilusEverywhere: `Exilus Adapters Everywhere`,
|
cheats_unlockExilusEverywhere: `Exilus Adapters Everywhere`,
|
||||||
cheats_unlockArcanesEverywhere: `Arcane Adapters Everywhere`,
|
cheats_unlockArcanesEverywhere: `Arcane Adapters Everywhere`,
|
||||||
cheats_noDailyStandingLimits: `No Daily Standing Limits`,
|
cheats_noDailyStandingLimits: `No Daily Standing Limits`,
|
||||||
|
cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`,
|
||||||
cheats_noDojoResearchCosts: `No Dojo Research Costs`,
|
cheats_noDojoResearchCosts: `No Dojo Research Costs`,
|
||||||
cheats_noDojoResearchTime: `No Dojo Research Time`,
|
cheats_noDojoResearchTime: `No Dojo Research Time`,
|
||||||
cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`,
|
cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`,
|
||||||
|
@ -112,6 +112,7 @@ dict = {
|
|||||||
cheats_unlockExilusEverywhere: `Адаптеры Эксилус везде`,
|
cheats_unlockExilusEverywhere: `Адаптеры Эксилус везде`,
|
||||||
cheats_unlockArcanesEverywhere: `Адаптеры для мистификаторов везде`,
|
cheats_unlockArcanesEverywhere: `Адаптеры для мистификаторов везде`,
|
||||||
cheats_noDailyStandingLimits: `Без ежедневных ограничений репутации`,
|
cheats_noDailyStandingLimits: `Без ежедневных ограничений репутации`,
|
||||||
|
cheats_instantResourceExtractorDrones: `[UNTRANSLATED] Instant Resource Extractor Drones`,
|
||||||
cheats_noDojoResearchCosts: `[UNTRANSLATED] No Dojo Research Costs`,
|
cheats_noDojoResearchCosts: `[UNTRANSLATED] No Dojo Research Costs`,
|
||||||
cheats_noDojoResearchTime: `[UNTRANSLATED] No Dojo Research Time`,
|
cheats_noDojoResearchTime: `[UNTRANSLATED] No Dojo Research Time`,
|
||||||
cheats_spoofMasteryRank: `Подделанный ранг мастерства (-1 для отключения)`,
|
cheats_spoofMasteryRank: `Подделанный ранг мастерства (-1 для отключения)`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user