Compare commits

..

1 Commits

Author SHA1 Message Date
97a2169e74 chore: enable "incremental" in tsconfig
This should make subsequent runs of `npm run build` a bit faster.
2025-03-05 05:08:01 +01:00
25 changed files with 88 additions and 459 deletions

View File

@ -33,7 +33,6 @@
"noDailyStandingLimits": true, "noDailyStandingLimits": true,
"instantResourceExtractorDrones": false, "instantResourceExtractorDrones": false,
"noDojoRoomBuildStage": true, "noDojoRoomBuildStage": true,
"fastDojoRoomDestruction": true,
"noDojoResearchCosts": true, "noDojoResearchCosts": true,
"noDojoResearchTime": true, "noDojoResearchTime": true,
"spoofMasteryRank": -1 "spoofMasteryRank": -1

View File

@ -1,4 +1,4 @@
// Based on https://onlyg.it/OpenWF/Translations/src/branch/main/update.php // Based on http://209.141.38.3/OpenWF/Translations/src/branch/main/update.php
// Converted via ChatGPT-4o // Converted via ChatGPT-4o
const fs = require("fs"); const fs = require("fs");

View File

@ -1,4 +1,4 @@
import { getDojoClient, getGuildForRequestEx, removeDojoDeco, removeDojoRoom } from "@/src/services/guildService"; import { getDojoClient, getGuildForRequestEx } from "@/src/services/guildService";
import { getInventory } from "@/src/services/inventoryService"; import { getInventory } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService"; import { getAccountIdForRequest } from "@/src/services/loginService";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
@ -8,19 +8,12 @@ export const abortDojoComponentController: RequestHandler = async (req, res) =>
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
const guild = await getGuildForRequestEx(req, inventory); const guild = await getGuildForRequestEx(req, inventory);
const request = JSON.parse(String(req.body)) as IAbortDojoComponentRequest; const request = JSON.parse(String(req.body)) as IAbortDojoComponentRequest;
// TODO: Move already-contributed credits & items to the clan vault
if (request.DecoId) { guild.DojoComponents.pull({ _id: request.ComponentId });
removeDojoDeco(guild, request.ComponentId, request.DecoId);
} else {
removeDojoRoom(guild, request.ComponentId);
}
await guild.save(); await guild.save();
res.json(await getDojoClient(guild, 0, request.ComponentId)); res.json(getDojoClient(guild, 0));
}; };
interface IAbortDojoComponentRequest { export interface IAbortDojoComponentRequest {
DecoType?: string;
ComponentId: string; ComponentId: string;
DecoId?: string;
} }

View File

@ -1,12 +0,0 @@
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService";
import { RequestHandler } from "express";
export const abortDojoComponentDestructionController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequest(req);
const componentId = req.query.componentId as string;
guild.DojoComponents.id(componentId)!.DestructionTime = undefined;
await guild.save();
res.json(await getDojoClient(guild, 0, componentId));
};

View File

@ -58,7 +58,7 @@ export const changeDojoRootController: RequestHandler = async (req, res) => {
await guild.save(); await guild.save();
res.json(await getDojoClient(guild, 0)); res.json(getDojoClient(guild, 0));
}; };
interface INode { interface INode {

View File

@ -1,26 +1,10 @@
import { TGuildDatabaseDocument } from "@/src/models/guildModel";
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
import { getDojoClient, getGuildForRequestEx, scaleRequiredCount } from "@/src/services/guildService"; import { getDojoClient, getGuildForRequestEx, scaleRequiredCount } from "@/src/services/guildService";
import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService"; import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService"; import { getAccountIdForRequest } from "@/src/services/loginService";
import { IDojoContributable } from "@/src/types/guildTypes";
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes"; import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
import { IInventoryChanges } from "@/src/types/purchaseTypes"; import { IInventoryChanges } from "@/src/types/purchaseTypes";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import { ExportDojoRecipes, IDojoRecipe } from "warframe-public-export-plus"; import { ExportDojoRecipes } from "warframe-public-export-plus";
interface IContributeToDojoComponentRequest {
ComponentId: string;
DecoId?: string;
DecoType?: string;
IngredientContributions: {
ItemType: string;
ItemCount: number;
}[];
RegularCredits: number;
VaultIngredientContributions: [];
VaultCredits: number;
}
export const contributeToDojoComponentController: RequestHandler = async (req, res) => { export const contributeToDojoComponentController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
@ -29,54 +13,21 @@ export const contributeToDojoComponentController: RequestHandler = async (req, r
// Any clan member should have permission to contribute although notably permission is denied if they have not crafted the dojo key and were simply invited in. // Any clan member should have permission to contribute although notably permission is denied if they have not crafted the dojo key and were simply invited in.
const request = JSON.parse(String(req.body)) as IContributeToDojoComponentRequest; const request = JSON.parse(String(req.body)) as IContributeToDojoComponentRequest;
const component = guild.DojoComponents.id(request.ComponentId)!; const component = guild.DojoComponents.id(request.ComponentId)!;
const componentMeta = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == component.pf)!;
const inventoryChanges: IInventoryChanges = {};
if (!component.CompletionTime) {
// Room is in "Collecting Materials" state
if (request.DecoId) {
throw new Error("attempt to contribute to a deco in an unfinished room?!");
}
const meta = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == component.pf)!;
await processContribution(guild, request, inventory, inventoryChanges, meta, component);
} else {
// Room is past "Collecting Materials"
if (request.DecoId) {
const deco = component.Decos!.find(x => x._id.equals(request.DecoId))!;
const meta = Object.values(ExportDojoRecipes.decos).find(x => x.resultType == deco.Type)!;
await processContribution(guild, request, inventory, inventoryChanges, meta, deco);
}
}
await guild.save();
await inventory.save();
res.json({
...(await getDojoClient(guild, 0, component._id)),
InventoryChanges: inventoryChanges
});
};
const processContribution = async (
guild: TGuildDatabaseDocument,
request: IContributeToDojoComponentRequest,
inventory: TInventoryDatabaseDocument,
inventoryChanges: IInventoryChanges,
meta: IDojoRecipe,
component: IDojoContributable
): Promise<void> => {
component.RegularCredits ??= 0; component.RegularCredits ??= 0;
if (component.RegularCredits + request.RegularCredits > scaleRequiredCount(meta.price)) { if (component.RegularCredits + request.RegularCredits > scaleRequiredCount(componentMeta.price)) {
request.RegularCredits = scaleRequiredCount(meta.price) - component.RegularCredits; request.RegularCredits = scaleRequiredCount(componentMeta.price) - component.RegularCredits;
} }
component.RegularCredits += request.RegularCredits; component.RegularCredits += request.RegularCredits;
inventoryChanges.RegularCredits = -request.RegularCredits; const inventoryChanges: IInventoryChanges = updateCurrency(inventory, request.RegularCredits, false);
updateCurrency(inventory, request.RegularCredits, false);
component.MiscItems ??= []; component.MiscItems ??= [];
const miscItemChanges: IMiscItem[] = []; const miscItemChanges: IMiscItem[] = [];
for (const ingredientContribution of request.IngredientContributions) { for (const ingredientContribution of request.IngredientContributions) {
const componentMiscItem = component.MiscItems.find(x => x.ItemType == ingredientContribution.ItemType); const componentMiscItem = component.MiscItems.find(x => x.ItemType == ingredientContribution.ItemType);
if (componentMiscItem) { if (componentMiscItem) {
const ingredientMeta = meta.ingredients.find(x => x.ItemType == ingredientContribution.ItemType)!; const ingredientMeta = componentMeta.ingredients.find(x => x.ItemType == ingredientContribution.ItemType)!;
if ( if (
componentMiscItem.ItemCount + ingredientContribution.ItemCount > componentMiscItem.ItemCount + ingredientContribution.ItemCount >
scaleRequiredCount(ingredientMeta.ItemCount) scaleRequiredCount(ingredientMeta.ItemCount)
@ -96,9 +47,9 @@ const processContribution = async (
addMiscItems(inventory, miscItemChanges); addMiscItems(inventory, miscItemChanges);
inventoryChanges.MiscItems = miscItemChanges; inventoryChanges.MiscItems = miscItemChanges;
if (component.RegularCredits >= scaleRequiredCount(meta.price)) { if (component.RegularCredits >= scaleRequiredCount(componentMeta.price)) {
let fullyFunded = true; let fullyFunded = true;
for (const ingredient of meta.ingredients) { for (const ingredient of componentMeta.ingredients) {
const componentMiscItem = component.MiscItems.find(x => x.ItemType == ingredient.ItemType); const componentMiscItem = component.MiscItems.find(x => x.ItemType == ingredient.ItemType);
if (!componentMiscItem || componentMiscItem.ItemCount < scaleRequiredCount(ingredient.ItemCount)) { if (!componentMiscItem || componentMiscItem.ItemCount < scaleRequiredCount(ingredient.ItemCount)) {
fullyFunded = false; fullyFunded = false;
@ -106,13 +57,27 @@ const processContribution = async (
} }
} }
if (fullyFunded) { if (fullyFunded) {
if (request.IngredientContributions.length) {
// We've already updated subpaths of MiscItems, we need to allow MongoDB to save this before we remove MiscItems.
await guild.save();
}
component.RegularCredits = undefined; component.RegularCredits = undefined;
component.MiscItems = undefined; component.MiscItems = undefined;
component.CompletionTime = new Date(Date.now() + meta.time * 1000); component.CompletionTime = new Date(Date.now() + componentMeta.time * 1000);
} }
} }
await guild.save();
await inventory.save();
res.json({
...getDojoClient(guild, 0, component._id),
InventoryChanges: inventoryChanges
});
}; };
export interface IContributeToDojoComponentRequest {
ComponentId: string;
IngredientContributions: {
ItemType: string;
ItemCount: number;
}[];
RegularCredits: number;
VaultIngredientContributions: [];
VaultCredits: number;
}

View File

@ -1,18 +0,0 @@
import { getDojoClient, getGuildForRequest, removeDojoDeco } from "@/src/services/guildService";
import { RequestHandler } from "express";
export const destroyDojoDecoController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequest(req);
const request = JSON.parse(String(req.body)) as IDestroyDojoDecoRequest;
removeDojoDeco(guild, request.ComponentId, request.DecoId);
await guild.save();
res.json(await getDojoClient(guild, 0, request.ComponentId));
};
interface IDestroyDojoDecoRequest {
DecoType: string;
ComponentId: string;
DecoId: string;
}

View File

@ -1,18 +1,8 @@
import { getDojoClient, getGuildForRequestEx, scaleRequiredCount } from "@/src/services/guildService"; import { getDojoClient, getGuildForRequestEx, scaleRequiredCount } from "@/src/services/guildService";
import { getInventory, updateCurrency } from "@/src/services/inventoryService"; import { getInventory, updateCurrency } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService"; import { getAccountIdForRequest } from "@/src/services/loginService";
import { IDojoContributable } from "@/src/types/guildTypes";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import { ExportDojoRecipes, IDojoRecipe } from "warframe-public-export-plus"; import { ExportDojoRecipes } from "warframe-public-export-plus";
interface IDojoComponentRushRequest {
DecoType?: string;
DecoId?: string;
ComponentId: string;
Amount: number;
VaultAmount: number;
AllianceVaultAmount: number;
}
export const dojoComponentRushController: RequestHandler = async (req, res) => { export const dojoComponentRushController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
@ -20,31 +10,27 @@ export const dojoComponentRushController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequestEx(req, inventory); const guild = await getGuildForRequestEx(req, inventory);
const request = JSON.parse(String(req.body)) as IDojoComponentRushRequest; const request = JSON.parse(String(req.body)) as IDojoComponentRushRequest;
const component = guild.DojoComponents.id(request.ComponentId)!; const component = guild.DojoComponents.id(request.ComponentId)!;
const componentMeta = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == component.pf)!;
if (request.DecoId) { const fullPlatinumCost = scaleRequiredCount(componentMeta.skipTimePrice);
const deco = component.Decos!.find(x => x._id.equals(request.DecoId))!; const fullDurationSeconds = componentMeta.time;
const meta = Object.values(ExportDojoRecipes.decos).find(x => x.resultType == deco.Type)!; const secondsPerPlatinum = fullDurationSeconds / fullPlatinumCost;
processContribution(deco, meta, request.Amount); component.CompletionTime = new Date(
} else { component.CompletionTime!.getTime() - secondsPerPlatinum * request.Amount * 1000
const meta = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == component.pf)!; );
processContribution(component, meta, request.Amount);
}
const inventoryChanges = updateCurrency(inventory, request.Amount, true); const inventoryChanges = updateCurrency(inventory, request.Amount, true);
await guild.save(); await guild.save();
await inventory.save(); await inventory.save();
res.json({ res.json({
...(await getDojoClient(guild, 0, component._id)), ...getDojoClient(guild, 0, component._id),
InventoryChanges: inventoryChanges InventoryChanges: inventoryChanges
}); });
}; };
const processContribution = (component: IDojoContributable, meta: IDojoRecipe, platinumDonated: number): void => { interface IDojoComponentRushRequest {
const fullPlatinumCost = scaleRequiredCount(meta.skipTimePrice); ComponentId: string;
const fullDurationSeconds = meta.time; Amount: number;
const secondsPerPlatinum = fullDurationSeconds / fullPlatinumCost; VaultAmount: number;
component.CompletionTime = new Date( AllianceVaultAmount: number;
component.CompletionTime!.getTime() - secondsPerPlatinum * platinumDonated * 1000 }
);
};

View File

@ -23,11 +23,12 @@ export const fusionTreasuresController: RequestHandler = async (req, res) => {
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
const request = JSON.parse(String(req.body)) as IFusionTreasureRequest; const request = JSON.parse(String(req.body)) as IFusionTreasureRequest;
// Swap treasures
const oldTreasure = parseFusionTreasure(request.oldTreasureName, -1); const oldTreasure = parseFusionTreasure(request.oldTreasureName, -1);
const newTreasure = parseFusionTreasure(request.newTreasureName, 1); const newTreasure = parseFusionTreasure(request.newTreasureName, 1);
const fusionTreasureChanges = [oldTreasure, newTreasure];
addFusionTreasures(inventory, fusionTreasureChanges); // Swap treasures
addFusionTreasures(inventory, [oldTreasure]);
addFusionTreasures(inventory, [newTreasure]);
// Remove consumed stars // Remove consumed stars
const miscItemChanges: IMiscItem[] = []; const miscItemChanges: IMiscItem[] = [];
@ -44,9 +45,5 @@ export const fusionTreasuresController: RequestHandler = async (req, res) => {
addMiscItems(inventory, miscItemChanges); addMiscItems(inventory, miscItemChanges);
await inventory.save(); await inventory.save();
// The response itself is the inventory changes for this endpoint. res.end();
res.json({
MiscItems: miscItemChanges,
FusionTreasures: fusionTreasureChanges
});
}; };

View File

@ -18,11 +18,10 @@ export const getGuildDojoController: RequestHandler = async (req, res) => {
_id: new Types.ObjectId(), _id: new Types.ObjectId(),
pf: "/Lotus/Levels/ClanDojo/DojoHall.level", pf: "/Lotus/Levels/ClanDojo/DojoHall.level",
ppf: "", ppf: "",
CompletionTime: new Date(Date.now()), CompletionTime: new Date(Date.now())
DecoCapacity: 600
}); });
await guild.save(); await guild.save();
} }
res.json(await getDojoClient(guild, 0)); res.json(getDojoClient(guild, 0));
}; };

View File

@ -1,43 +0,0 @@
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService";
import { RequestHandler } from "express";
import { Types } from "mongoose";
import { ExportDojoRecipes } from "warframe-public-export-plus";
export const placeDecoInComponentController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequest(req);
const request = JSON.parse(String(req.body)) as IPlaceDecoInComponentRequest;
// At this point, we know that a member of the guild is making this request. Assuming they are allowed to place decorations.
const component = guild.DojoComponents.id(request.ComponentId)!;
if (component.DecoCapacity === undefined) {
component.DecoCapacity = Object.values(ExportDojoRecipes.rooms).find(
x => x.resultType == component.pf
)!.decoCapacity;
}
component.Decos ??= [];
component.Decos.push({
_id: new Types.ObjectId(),
Type: request.Type,
Pos: request.Pos,
Rot: request.Rot,
Name: request.Name
});
const meta = Object.values(ExportDojoRecipes.decos).find(x => x.resultType == request.Type);
if (meta && meta.capacityCost) {
component.DecoCapacity -= meta.capacityCost;
}
await guild.save();
res.json(await getDojoClient(guild, 0, component._id));
};
interface IPlaceDecoInComponentRequest {
ComponentId: string;
Revision: number;
Type: string;
Pos: number[];
Rot: number[];
Name?: string;
}

View File

@ -1,15 +1,19 @@
import { config } from "@/src/services/configService";
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService"; import { getDojoClient, getGuildForRequest } from "@/src/services/guildService";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import { ExportDojoRecipes } from "warframe-public-export-plus";
export const queueDojoComponentDestructionController: RequestHandler = async (req, res) => { export const queueDojoComponentDestructionController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequest(req); const guild = await getGuildForRequest(req);
const componentId = req.query.componentId as string; const componentId = req.query.componentId as string;
const component = guild.DojoComponents.splice(
guild.DojoComponents.id(componentId)!.DestructionTime = new Date( guild.DojoComponents.findIndex(x => x._id.toString() === componentId),
Date.now() + (config.fastDojoRoomDestruction ? 5_000 : 2 * 3600_000) 1
); )[0];
const room = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == component.pf);
if (room) {
guild.DojoCapacity -= room.capacity;
guild.DojoEnergy -= room.energy;
}
await guild.save(); await guild.save();
res.json(await getDojoClient(guild, 0, componentId)); res.json(getDojoClient(guild, 1));
}; };

View File

@ -12,7 +12,7 @@ export const setDojoComponentMessageController: RequestHandler = async (req, res
component.Message = payload.Message; component.Message = payload.Message;
} }
await guild.save(); await guild.save();
res.json(await getDojoClient(guild, 0, component._id)); res.json(getDojoClient(guild, 0, component._id));
}; };
type SetDojoComponentMessageRequest = { Name: string } | { Message: string }; type SetDojoComponentMessageRequest = { Name: string } | { Message: string };

View File

@ -29,13 +29,12 @@ export const startDojoRecipeController: RequestHandler = async (req, res) => {
ppf: request.PlacedComponent.ppf, ppf: request.PlacedComponent.ppf,
pi: new Types.ObjectId(request.PlacedComponent.pi!.$oid), pi: new Types.ObjectId(request.PlacedComponent.pi!.$oid),
op: request.PlacedComponent.op, op: request.PlacedComponent.op,
pp: request.PlacedComponent.pp, pp: request.PlacedComponent.pp
DecoCapacity: room?.decoCapacity
}) - 1 }) - 1
]; ];
if (config.noDojoRoomBuildStage) { if (config.noDojoRoomBuildStage) {
component.CompletionTime = new Date(Date.now()); component.CompletionTime = new Date(Date.now());
} }
await guild.save(); await guild.save();
res.json(await getDojoClient(guild, 0)); res.json(getDojoClient(guild, 0));
}; };

View File

@ -2,23 +2,12 @@ import {
IGuildDatabase, IGuildDatabase,
IDojoComponentDatabase, IDojoComponentDatabase,
ITechProjectDatabase, ITechProjectDatabase,
ITechProjectClient, ITechProjectClient
IDojoDecoDatabase
} from "@/src/types/guildTypes"; } from "@/src/types/guildTypes";
import { Document, Model, model, Schema, Types } from "mongoose"; import { Document, Model, model, Schema, Types } from "mongoose";
import { typeCountSchema } from "./inventoryModels/inventoryModel"; import { typeCountSchema } from "./inventoryModels/inventoryModel";
import { toMongoDate } from "../helpers/inventoryHelpers"; import { toMongoDate } from "../helpers/inventoryHelpers";
const dojoDecoSchema = new Schema<IDojoDecoDatabase>({
Type: String,
Pos: [Number],
Rot: [Number],
Name: String,
RegularCredits: Number,
MiscItems: { type: [typeCountSchema], default: undefined },
CompletionTime: Date
});
const dojoComponentSchema = new Schema<IDojoComponentDatabase>({ const dojoComponentSchema = new Schema<IDojoComponentDatabase>({
pf: { type: String, required: true }, pf: { type: String, required: true },
ppf: String, ppf: String,
@ -29,10 +18,7 @@ const dojoComponentSchema = new Schema<IDojoComponentDatabase>({
Message: String, Message: String,
RegularCredits: Number, RegularCredits: Number,
MiscItems: { type: [typeCountSchema], default: undefined }, MiscItems: { type: [typeCountSchema], default: undefined },
CompletionTime: Date, CompletionTime: Date
DestructionTime: Date,
Decos: [dojoDecoSchema],
DecoCapacity: Number
}); });
const techProjectSchema = new Schema<ITechProjectDatabase>( const techProjectSchema = new Schema<ITechProjectDatabase>(

View File

@ -1,7 +1,6 @@
import express from "express"; import express from "express";
import { abandonLibraryDailyTaskController } from "@/src/controllers/api/abandonLibraryDailyTaskController"; import { abandonLibraryDailyTaskController } from "@/src/controllers/api/abandonLibraryDailyTaskController";
import { abortDojoComponentController } from "@/src/controllers/api/abortDojoComponentController"; import { abortDojoComponentController } from "@/src/controllers/api/abortDojoComponentController";
import { abortDojoComponentDestructionController } from "@/src/controllers/api/abortDojoComponentDestructionController";
import { activateRandomModController } from "@/src/controllers/api/activateRandomModController"; import { activateRandomModController } from "@/src/controllers/api/activateRandomModController";
import { addFriendImageController } from "@/src/controllers/api/addFriendImageController"; import { addFriendImageController } from "@/src/controllers/api/addFriendImageController";
import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController"; import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
@ -17,7 +16,6 @@ import { contributeToDojoComponentController } from "@/src/controllers/api/contr
import { createGuildController } from "@/src/controllers/api/createGuildController"; import { createGuildController } from "@/src/controllers/api/createGuildController";
import { creditsController } from "@/src/controllers/api/creditsController"; import { creditsController } from "@/src/controllers/api/creditsController";
import { deleteSessionController } from "@/src/controllers/api/deleteSessionController"; import { deleteSessionController } from "@/src/controllers/api/deleteSessionController";
import { destroyDojoDecoController } from "@/src/controllers/api/destroyDojoDecoController";
import { dojoComponentRushController } from "@/src/controllers/api/dojoComponentRushController"; import { dojoComponentRushController } from "@/src/controllers/api/dojoComponentRushController";
import { dojoController } from "@/src/controllers/api/dojoController"; import { dojoController } from "@/src/controllers/api/dojoController";
import { dronesController } from "@/src/controllers/api/dronesController"; import { dronesController } from "@/src/controllers/api/dronesController";
@ -61,7 +59,6 @@ import { missionInventoryUpdateController } from "@/src/controllers/api/missionI
import { modularWeaponCraftingController } from "@/src/controllers/api/modularWeaponCraftingController"; import { modularWeaponCraftingController } from "@/src/controllers/api/modularWeaponCraftingController";
import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController"; import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController";
import { nameWeaponController } from "@/src/controllers/api/nameWeaponController"; import { nameWeaponController } from "@/src/controllers/api/nameWeaponController";
import { placeDecoInComponentController } from "@/src/controllers/api/placeDecoInComponentController";
import { playerSkillsController } from "@/src/controllers/api/playerSkillsController"; import { playerSkillsController } from "@/src/controllers/api/playerSkillsController";
import { projectionManagerController } from "@/src/controllers/api/projectionManagerController"; import { projectionManagerController } from "@/src/controllers/api/projectionManagerController";
import { purchaseController } from "@/src/controllers/api/purchaseController"; import { purchaseController } from "@/src/controllers/api/purchaseController";
@ -106,7 +103,6 @@ const apiRouter = express.Router();
// get // get
apiRouter.get("/abandonLibraryDailyTask.php", abandonLibraryDailyTaskController); apiRouter.get("/abandonLibraryDailyTask.php", abandonLibraryDailyTaskController);
apiRouter.get("/abortDojoComponentDestruction.php", abortDojoComponentDestructionController);
apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController); apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController);
apiRouter.get("/claimLibraryDailyTaskReward.php", claimLibraryDailyTaskRewardController); apiRouter.get("/claimLibraryDailyTaskReward.php", claimLibraryDailyTaskRewardController);
apiRouter.get("/credits.php", creditsController); apiRouter.get("/credits.php", creditsController);
@ -154,7 +150,6 @@ apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
apiRouter.post("/completeRandomModChallenge.php", completeRandomModChallengeController); apiRouter.post("/completeRandomModChallenge.php", completeRandomModChallengeController);
apiRouter.post("/contributeToDojoComponent.php", contributeToDojoComponentController); apiRouter.post("/contributeToDojoComponent.php", contributeToDojoComponentController);
apiRouter.post("/createGuild.php", createGuildController); apiRouter.post("/createGuild.php", createGuildController);
apiRouter.post("/destroyDojoDeco.php", destroyDojoDecoController);
apiRouter.post("/dojoComponentRush.php", dojoComponentRushController); apiRouter.post("/dojoComponentRush.php", dojoComponentRushController);
apiRouter.post("/drones.php", dronesController); apiRouter.post("/drones.php", dronesController);
apiRouter.post("/endlessXp.php", endlessXpController); apiRouter.post("/endlessXp.php", endlessXpController);
@ -180,7 +175,6 @@ apiRouter.post("/login.php", loginController);
apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController); apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController);
apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController); apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController);
apiRouter.post("/nameWeapon.php", nameWeaponController); apiRouter.post("/nameWeapon.php", nameWeaponController);
apiRouter.post("/placeDecoInComponent.php", placeDecoInComponentController);
apiRouter.post("/playerSkills.php", playerSkillsController); apiRouter.post("/playerSkills.php", playerSkillsController);
apiRouter.post("/projectionManager.php", projectionManagerController); apiRouter.post("/projectionManager.php", projectionManagerController);
apiRouter.post("/purchase.php", purchaseController); apiRouter.post("/purchase.php", purchaseController);

View File

@ -59,7 +59,6 @@ interface IConfig {
noDailyStandingLimits?: boolean; noDailyStandingLimits?: boolean;
instantResourceExtractorDrones?: boolean; instantResourceExtractorDrones?: boolean;
noDojoRoomBuildStage?: boolean; noDojoRoomBuildStage?: boolean;
fastDojoRoomDestruction?: boolean;
noDojoResearchCosts?: boolean; noDojoResearchCosts?: boolean;
noDojoResearchTime?: boolean; noDojoResearchTime?: boolean;
spoofMasteryRank?: number; spoofMasteryRank?: number;

View File

@ -6,8 +6,6 @@ import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/invento
import { IDojoClient, IDojoComponentClient } from "@/src/types/guildTypes"; import { IDojoClient, IDojoComponentClient } from "@/src/types/guildTypes";
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers"; import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
import { Types } from "mongoose"; import { Types } from "mongoose";
import { ExportDojoRecipes } from "warframe-public-export-plus";
import { logger } from "../utils/logger";
export const getGuildForRequest = async (req: Request): Promise<TGuildDatabaseDocument> => { export const getGuildForRequest = async (req: Request): Promise<TGuildDatabaseDocument> => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
@ -30,11 +28,11 @@ export const getGuildForRequestEx = async (
return guild; return guild;
}; };
export const getDojoClient = async ( export const getDojoClient = (
guild: TGuildDatabaseDocument, guild: TGuildDatabaseDocument,
status: number, status: number,
componentId: Types.ObjectId | string | undefined = undefined componentId: Types.ObjectId | undefined = undefined
): Promise<IDojoClient> => { ): IDojoClient => {
const dojo: IDojoClient = { const dojo: IDojoClient = {
_id: { $oid: guild._id.toString() }, _id: { $oid: guild._id.toString() },
Name: guild.Name, Name: guild.Name,
@ -47,16 +45,15 @@ export const getDojoClient = async (
DojoRequestStatus: status, DojoRequestStatus: status,
DojoComponents: [] DojoComponents: []
}; };
const roomsToRemove: Types.ObjectId[] = [];
guild.DojoComponents.forEach(dojoComponent => { guild.DojoComponents.forEach(dojoComponent => {
if (!componentId || dojoComponent._id.equals(componentId)) { if (!componentId || componentId == dojoComponent._id) {
const clientComponent: IDojoComponentClient = { const clientComponent: IDojoComponentClient = {
id: toOid(dojoComponent._id), id: toOid(dojoComponent._id),
pf: dojoComponent.pf, pf: dojoComponent.pf,
ppf: dojoComponent.ppf, ppf: dojoComponent.ppf,
Name: dojoComponent.Name, Name: dojoComponent.Name,
Message: dojoComponent.Message, Message: dojoComponent.Message,
DecoCapacity: dojoComponent.DecoCapacity ?? 600 DecoCapacity: 600
}; };
if (dojoComponent.pi) { if (dojoComponent.pi) {
clientComponent.pi = toOid(dojoComponent.pi); clientComponent.pi = toOid(dojoComponent.pi);
@ -65,41 +62,13 @@ export const getDojoClient = async (
} }
if (dojoComponent.CompletionTime) { if (dojoComponent.CompletionTime) {
clientComponent.CompletionTime = toMongoDate(dojoComponent.CompletionTime); clientComponent.CompletionTime = toMongoDate(dojoComponent.CompletionTime);
if (dojoComponent.DestructionTime) {
if (Date.now() >= dojoComponent.DestructionTime.getTime()) {
roomsToRemove.push(dojoComponent._id);
return;
}
clientComponent.DestructionTime = toMongoDate(dojoComponent.DestructionTime);
}
} else { } else {
clientComponent.RegularCredits = dojoComponent.RegularCredits; clientComponent.RegularCredits = dojoComponent.RegularCredits;
clientComponent.MiscItems = dojoComponent.MiscItems; clientComponent.MiscItems = dojoComponent.MiscItems;
} }
if (dojoComponent.Decos) {
clientComponent.Decos = [];
for (const deco of dojoComponent.Decos) {
clientComponent.Decos.push({
id: toOid(deco._id),
Type: deco.Type,
Pos: deco.Pos,
Rot: deco.Rot,
CompletionTime: deco.CompletionTime ? toMongoDate(deco.CompletionTime) : undefined,
RegularCredits: deco.RegularCredits,
MiscItems: deco.MiscItems
});
}
}
dojo.DojoComponents.push(clientComponent); dojo.DojoComponents.push(clientComponent);
} }
}); });
if (roomsToRemove.length) {
logger.debug(`removing now-destroyed rooms`, roomsToRemove);
for (const id of roomsToRemove) {
removeDojoRoom(guild, id);
}
await guild.save();
}
return dojo; return dojo;
}; };
@ -107,33 +76,3 @@ export const scaleRequiredCount = (count: number): number => {
// The recipes in the export are for Moon clans. For now we'll just assume we only have Ghost clans. // The recipes in the export are for Moon clans. For now we'll just assume we only have Ghost clans.
return Math.max(1, Math.trunc(count / 100)); return Math.max(1, Math.trunc(count / 100));
}; };
export const removeDojoRoom = (guild: TGuildDatabaseDocument, componentId: Types.ObjectId | string): void => {
const component = guild.DojoComponents.splice(
guild.DojoComponents.findIndex(x => x._id.equals(componentId)),
1
)[0];
const meta = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == component.pf);
if (meta) {
guild.DojoCapacity -= meta.capacity;
guild.DojoEnergy -= meta.energy;
}
// TODO: Add resources spent to the clan vault
};
export const removeDojoDeco = (
guild: TGuildDatabaseDocument,
componentId: Types.ObjectId | string,
decoId: Types.ObjectId | string
): void => {
const component = guild.DojoComponents.id(componentId)!;
const deco = component.Decos!.splice(
component.Decos!.findIndex(x => x._id.equals(decoId)),
1
)[0];
const meta = Object.values(ExportDojoRecipes.decos).find(x => x.resultType == deco.Type);
if (meta && meta.capacityCost) {
component.DecoCapacity! += meta.capacityCost;
}
// TODO: Add resources spent to the clan vault
};

View File

@ -41,33 +41,18 @@ export interface IDojoComponentClient {
CompletionTime?: IMongoDate; CompletionTime?: IMongoDate;
RushPlatinum?: number; RushPlatinum?: number;
DestructionTime?: IMongoDate; DestructionTime?: IMongoDate;
Decos?: IDojoDecoClient[];
DecoCapacity?: number; DecoCapacity?: number;
} }
export interface IDojoComponentDatabase export interface IDojoComponentDatabase
extends Omit<IDojoComponentClient, "id" | "pi" | "CompletionTime" | "RushPlatinum" | "DestructionTime" | "Decos"> { extends Omit<
IDojoComponentClient,
"id" | "pi" | "CompletionTime" | "RushPlatinum" | "DestructionTime" | "DecoCapacity"
> {
_id: Types.ObjectId; _id: Types.ObjectId;
pi?: Types.ObjectId; pi?: Types.ObjectId;
CompletionTime?: Date; CompletionTime?: Date;
DestructionTime?: Date; //DestructionTime?: Date;
Decos?: IDojoDecoDatabase[];
}
export interface IDojoDecoClient {
id: IOid;
Type: string;
Pos: number[];
Rot: number[];
Name?: string; // for teleporters
RegularCredits?: number;
MiscItems?: IMiscItem[];
CompletionTime?: IMongoDate;
}
export interface IDojoDecoDatabase extends Omit<IDojoDecoClient, "id" | "CompletionTime"> {
_id: Types.ObjectId;
CompletionTime?: Date;
} }
export interface ITechProjectClient { export interface ITechProjectClient {
@ -81,9 +66,3 @@ export interface ITechProjectClient {
export interface ITechProjectDatabase extends Omit<ITechProjectClient, "CompletionDate"> { export interface ITechProjectDatabase extends Omit<ITechProjectClient, "CompletionDate"> {
CompletionDate?: Date; CompletionDate?: Date;
} }
export interface IDojoContributable {
RegularCredits?: number;
MiscItems?: IMiscItem[];
CompletionTime?: Date;
}

View File

@ -525,10 +525,6 @@
<input class="form-check-input" type="checkbox" id="noDojoRoomBuildStage" /> <input class="form-check-input" type="checkbox" id="noDojoRoomBuildStage" />
<label class="form-check-label" for="noDojoRoomBuildStage" data-loc="cheats_noDojoRoomBuildStage"></label> <label class="form-check-label" for="noDojoRoomBuildStage" data-loc="cheats_noDojoRoomBuildStage"></label>
</div> </div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="fastDojoRoomDestruction" />
<label class="form-check-label" for="fastDojoRoomDestruction" data-loc="cheats_fastDojoRoomDestruction"></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>

View File

@ -128,7 +128,7 @@ function setActiveLanguage(lang) {
document.querySelector("[data-lang=" + lang + "]").classList.add("active"); document.querySelector("[data-lang=" + lang + "]").classList.add("active");
window.dictPromise = new Promise(resolve => { window.dictPromise = new Promise(resolve => {
const webui_lang = ["en", "ru", "fr"].indexOf(lang) == -1 ? "en" : lang; const webui_lang = ["en", "ru"].indexOf(lang) == -1 ? "en" : lang;
const script = document.createElement("script"); const script = document.createElement("script");
script.src = "/translations/" + webui_lang + ".js"; script.src = "/translations/" + webui_lang + ".js";
script.onload = function () { script.onload = function () {

View File

@ -94,6 +94,8 @@ dict = {
cheats_skipAllDialogue: `Skip All Dialogue`, cheats_skipAllDialogue: `Skip All Dialogue`,
cheats_unlockAllScans: `Unlock All Scans`, cheats_unlockAllScans: `Unlock All Scans`,
cheats_unlockAllMissions: `Unlock All Missions`, cheats_unlockAllMissions: `Unlock All Missions`,
cheats_unlockAllQuests: `Unlock All Quests`,
cheats_completeAllQuests: `Complete All Quests`,
cheats_infiniteCredits: `Infinite Credits`, cheats_infiniteCredits: `Infinite Credits`,
cheats_infinitePlatinum: `Infinite Platinum`, cheats_infinitePlatinum: `Infinite Platinum`,
cheats_infiniteEndo: `Infinite Endo`, cheats_infiniteEndo: `Infinite Endo`,
@ -111,7 +113,6 @@ dict = {
cheats_noDailyStandingLimits: `No Daily Standing Limits`, cheats_noDailyStandingLimits: `No Daily Standing Limits`,
cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`, cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`,
cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`, cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`,
cheats_fastDojoRoomDestruction: `Fast Dojo Room Destruction`,
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)`,

View File

@ -1,135 +0,0 @@
// French translation by Vitruvio
dict = {
general_inventoryUpdateNote: `Note : Les changements effectués ici seront appliqués lors de la syncrhonisation. Visiter la navigation appliquera les changements apportés à l'inventaire.`,
general_addButton: `Ajouter`,
general_bulkActions: `Action groupée`,
code_nonValidAuthz: `Informations de connexion invalides`,
code_changeNameConfirm: `Nouveau nom du compte :`,
code_deleteAccountConfirm: `Supprimer |DISPLAYNAME| (|EMAIL|) ? Cette action est irreversible.`,
code_archgun: `Archgun`,
code_melee: `Melee`,
code_pistol: `Pistolet`,
code_rifle: `Fusil`,
code_shotgun: `Fusil à Pompe`,
code_kitgun: `Kitgun`,
code_zaw: `Zaw`,
code_moteAmp: `Amplificateur Faible`,
code_amp: `Amplificateur`,
code_sirocco: `Sirocco`,
code_kDrive: `K-Drive`,
code_legendaryCore: `Coeur Légendaire`,
code_traumaticPeculiar: `Traumatisme Atypique`,
code_starter: `|MOD| (Défectueux)`,
code_badItem: `(Imposteur)`,
code_maxRank: `Rang Max`,
code_rename: `Renommer`,
code_renamePrompt: `Nouveau nom :`,
code_remove: `Retirer`,
code_addItemsConfirm: `Ajouter |COUNT| items à l'inventaire ?`,
code_noEquipmentToRankUp: `No equipment to rank up.`,
code_succAdded: `Ajouté.`,
code_buffsNumber: `Nombre de buffs`,
code_cursesNumber: `Nombre de débuffs`,
code_rerollsNumber: `Nombre de rerolls`,
code_viewStats: `Voir les stats`,
code_rank: `Rang`,
code_count: `Quantité`,
code_focusAllUnlocked: `Les écoles de Focus sont déjà déverrouillées.`,
code_focusUnlocked: `|COUNT| écoles de Focus déverrouillées ! Synchronisation de l'inventaire nécessaire.`,
code_addModsConfirm: `Ajouter |COUNT| mods à l'inventaire ?`,
code_succImport: `Importé.`,
login_description: `Connexion avec les informations de connexion OpenWF.`,
login_emailLabel: `Email`,
login_passwordLabel: `Mot de passe`,
login_loginButton: `Connexion`,
navbar_logout: `Déconnexion`,
navbar_renameAccount: `Renommer le compte`,
navbar_deleteAccount: `Supprimer le compte`,
navbar_inventory: `Inventaire`,
navbar_mods: `Mods`,
navbar_quests: `Quêtes`,
navbar_cheats: `Cheats`,
navbar_import: `Importer`,
inventory_addItems: `Ajouter des items`,
inventory_suits: `Warframes`,
inventory_longGuns: `Armes principales`,
inventory_pistols: `Armes secondaires`,
inventory_melee: `Armes de melee`,
inventory_spaceSuits: `Archwings`,
inventory_spaceGuns: `Archguns`,
inventory_spaceMelee: `Archmelee`,
inventory_mechSuits: `Necramechs`,
inventory_sentinels: `Sentinelles`,
inventory_sentinelWeapons: `Armes de sentinelles`,
inventory_operatorAmps: `Amplificateurs`,
inventory_hoverboards: `K-Drives`,
inventory_bulkAddSuits: `Ajouter les Warframes manquantes`,
inventory_bulkAddWeapons: `Ajouter les armes manquantes`,
inventory_bulkAddSpaceSuits: `Ajouter les Archwings manquants`,
inventory_bulkAddSpaceWeapons: `Ajouter les armes d'Archwing manquantes`,
inventory_bulkAddSentinels: `Ajouter les Sentinelles manquantes`,
inventory_bulkAddSentinelWeapons: `Ajouter les armes de Sentinelles manquantes`,
inventory_bulkRankUpSuits: `Toutes les Warframes rang max`,
inventory_bulkRankUpWeapons: `Toutes les armes rang max`,
inventory_bulkRankUpSpaceSuits: `Tous les Archwings rang max`,
inventory_bulkRankUpSpaceWeapons: `Toutes les armes d'Archwing rang max`,
inventory_bulkRankUpSentinels: `Toutes les Sentinelles rang max`,
inventory_bulkRankUpSentinelWeapons: `Toutes les armes de Sentinelles rang max`,
currency_RegularCredits: `Crédits`,
currency_PremiumCredits: `Platinum`,
currency_FusionPoints: `Endo`,
currency_PrimeTokens: `Aya Raffiné`,
currency_owned: `|COUNT| possédés.`,
powersuit_archonShardsLabel: `Emplacements de fragments d'Archonte`,
powersuit_archonShardsDescription: `Slots illimités pour appliquer plusieurs améliorations.`,
mods_addRiven: `Ajouter un riven`,
mods_fingerprint: `Empreinte`,
mods_fingerprintHelp: `Besoin d'aide pour l'empreinte ?`,
mods_rivens: `Rivens`,
mods_mods: `Mods`,
mods_bulkAddMods: `Ajouter les mods manquants`,
cheats_administratorRequirement: `Rôle d'administrateur requis pour cette fonctionnalité. Ajoutez <code>|DISPLAYNAME|</code> à la ligne <code>administratorNames</code> dans le fichier config.json.`,
cheats_server: `Serveur`,
cheats_skipTutorial: `Passer le tutoriel`,
cheats_skipAllDialogue: `Passer les dialogues`,
cheats_unlockAllScans: `Débloquer tous les scans`,
cheats_unlockAllMissions: `Débloquer toutes les missions`,
cheats_infiniteCredits: `Crédits infinis`,
cheats_infinitePlatinum: `Platinum infini`,
cheats_infiniteEndo: `Endo infini`,
cheats_infiniteRegalAya: `Aya Raffiné infini`,
cheats_infiniteHelminthMaterials: `Ressources d'Helminth infinies`,
cheats_unlockAllShipFeatures: `Débloquer tous les segments du vaisseau`,
cheats_unlockAllShipDecorations: `Débloquer toutes les décorations du vaisseau`,
cheats_unlockAllFlavourItems: `Débloquer tous les <abbr title=\"Animations, Glyphes, Palettes, etc.\">Flavor Items</abbr>`,
cheats_unlockAllSkins: `Débloquer tous les skins`,
cheats_unlockAllCapturaScenes: `Débloquer toutes les scènes captura`,
cheats_universalPolarityEverywhere: `Polarités universelles partout`,
cheats_unlockDoubleCapacityPotatoesEverywhere: `Réacteurs et Catalyseurs partout`,
cheats_unlockExilusEverywhere: `Adaptateurs Exilus partout`,
cheats_unlockArcanesEverywhere: `Adaptateur d'Arcanes partout`,
cheats_noDailyStandingLimits: `Pas de limite de réputation journalière`,
cheats_instantResourceExtractorDrones: `Ressources de drone d'extraction instantannées`,
cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`,
cheats_fastDojoRoomDestruction: `[UNTRANSLATED] Fast Dojo Room Destruction`,
cheats_noDojoResearchCosts: `Aucun coût de recherche (Dojo)`,
cheats_noDojoResearchTime: `Aucun temps de recherche (Dojo)`,
cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`,
cheats_saveSettings: `Sauvegarder les paramètres`,
cheats_account: `Compte`,
cheats_unlockAllFocusSchools: `Débloquer toutes les écoles de focus`,
cheats_helminthUnlockAll: `Helminth niveau max`,
cheats_changeSupportedSyndicate: `Allégeance`,
cheats_changeButton: `Changer`,
cheats_none: `Aucun`,
cheats_quests: `Quêtes`,
cheats_quests_unlockAll: `Débloquer toutes les quêtes`,
cheats_quests_completeAll: `Compléter toutes les quêtes`,
cheats_quests_completeAllUnlocked: `Compléter toutes les quêtes déverrouillées`,
cheats_quests_resetAll: `Réinitialiser toutes les quêtes`,
cheats_quests_giveAll: `Obtenir toutes les quêtes`,
import_importNote: `Import manuel. Toutes les modifcations supportées par l'inventaire <b>écraseront celles présentes dans la base de données</b>.`,
import_submit: `Soumettre`,
prettier_sucks_ass: ``
};

View File

@ -95,6 +95,8 @@ dict = {
cheats_skipAllDialogue: `Пропустить все диалоги`, cheats_skipAllDialogue: `Пропустить все диалоги`,
cheats_unlockAllScans: `Разблокировать все сканирования`, cheats_unlockAllScans: `Разблокировать все сканирования`,
cheats_unlockAllMissions: `Разблокировать все миссии`, cheats_unlockAllMissions: `Разблокировать все миссии`,
cheats_unlockAllQuests: `Разблокировать все квесты`,
cheats_completeAllQuests: `Завершить все квесты`,
cheats_infiniteCredits: `Бесконечные кредиты`, cheats_infiniteCredits: `Бесконечные кредиты`,
cheats_infinitePlatinum: `Бесконечная платина`, cheats_infinitePlatinum: `Бесконечная платина`,
cheats_infiniteEndo: `Бесконечное эндо`, cheats_infiniteEndo: `Бесконечное эндо`,
@ -112,7 +114,6 @@ dict = {
cheats_noDailyStandingLimits: `Без ежедневных ограничений репутации`, cheats_noDailyStandingLimits: `Без ежедневных ограничений репутации`,
cheats_instantResourceExtractorDrones: `[UNTRANSLATED] Instant Resource Extractor Drones`, cheats_instantResourceExtractorDrones: `[UNTRANSLATED] Instant Resource Extractor Drones`,
cheats_noDojoRoomBuildStage: `[UNTRANSLATED] No Dojo Room Build Stage`, cheats_noDojoRoomBuildStage: `[UNTRANSLATED] No Dojo Room Build Stage`,
cheats_fastDojoRoomDestruction: `[UNTRANSLATED] Fast Dojo Room Destruction`,
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 для отключения)`,

View File

@ -3,7 +3,7 @@
/* Visit https://aka.ms/tsconfig to read more about this file */ /* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */ /* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */