From a5fc6cd99dad5a9250cccdee216a8cf816bc76ff Mon Sep 17 00:00:00 2001 From: Sainan Date: Fri, 7 Mar 2025 06:37:32 +0100 Subject: [PATCH 1/4] remove IGuild --- src/types/guildTypes.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/types/guildTypes.ts b/src/types/guildTypes.ts index 4802070f..b85d97e2 100644 --- a/src/types/guildTypes.ts +++ b/src/types/guildTypes.ts @@ -2,12 +2,9 @@ import { Types } from "mongoose"; import { IOid, IMongoDate } from "@/src/types/commonTypes"; import { IFusionTreasure, IMiscItem, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes"; -export interface IGuild { - Name: string; -} - -export interface IGuildDatabase extends IGuild { +export interface IGuildDatabase { _id: Types.ObjectId; + Name: string; DojoComponents: IDojoComponentDatabase[]; DojoCapacity: number; DojoEnergy: number; -- 2.47.2 From de655943fc48c8624201cfbcd2b9170dbbe6e956 Mon Sep 17 00:00:00 2001 From: Sainan Date: Fri, 7 Mar 2025 08:45:10 +0100 Subject: [PATCH 2/4] update PE+ --- package-lock.json | 8 ++++---- package.json | 2 +- .../api/contributeToDojoComponentController.ts | 4 ++-- src/controllers/api/dojoComponentRushController.ts | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index ad2dcbc8..13edcb84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "copyfiles": "^2.4.1", "express": "^5", "mongoose": "^8.11.0", - "warframe-public-export-plus": "^0.5.39", + "warframe-public-export-plus": "^0.5.40", "warframe-riven-info": "^0.1.2", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" @@ -4083,9 +4083,9 @@ } }, "node_modules/warframe-public-export-plus": { - "version": "0.5.39", - "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.39.tgz", - "integrity": "sha512-sEGZedtW4I/M2ceoDs6MQ5eHD7sJgv1KRNLt8BWByXLuDa7qTR3Y9px5TGxqt/rBHKGUyPO1LUxu4bDGZi6yXw==" + "version": "0.5.40", + "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.40.tgz", + "integrity": "sha512-/qr46LE/KqDdEkW4z52EG0vZP0Z8U26FscFJ2G5K5ewbQdlSVxtf5fpOnzRkAO7jWWKfgoqx7l5WUgaLSPDj0g==" }, "node_modules/warframe-riven-info": { "version": "0.1.2", diff --git a/package.json b/package.json index aae92ef4..6fcb225d 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "copyfiles": "^2.4.1", "express": "^5", "mongoose": "^8.11.0", - "warframe-public-export-plus": "^0.5.39", + "warframe-public-export-plus": "^0.5.40", "warframe-riven-info": "^0.1.2", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" diff --git a/src/controllers/api/contributeToDojoComponentController.ts b/src/controllers/api/contributeToDojoComponentController.ts index 5aa74855..9d1942c1 100644 --- a/src/controllers/api/contributeToDojoComponentController.ts +++ b/src/controllers/api/contributeToDojoComponentController.ts @@ -7,7 +7,7 @@ import { IDojoContributable } from "@/src/types/guildTypes"; import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes"; import { IInventoryChanges } from "@/src/types/purchaseTypes"; import { RequestHandler } from "express"; -import { ExportDojoRecipes, IDojoRecipe } from "warframe-public-export-plus"; +import { ExportDojoRecipes, IDojoBuild } from "warframe-public-export-plus"; interface IContributeToDojoComponentRequest { ComponentId: string; @@ -57,7 +57,7 @@ const processContribution = ( request: IContributeToDojoComponentRequest, inventory: TInventoryDatabaseDocument, inventoryChanges: IInventoryChanges, - meta: IDojoRecipe, + meta: IDojoBuild, component: IDojoContributable ): void => { component.RegularCredits ??= 0; diff --git a/src/controllers/api/dojoComponentRushController.ts b/src/controllers/api/dojoComponentRushController.ts index f15bce6c..cb8e0648 100644 --- a/src/controllers/api/dojoComponentRushController.ts +++ b/src/controllers/api/dojoComponentRushController.ts @@ -3,7 +3,7 @@ import { getInventory, updateCurrency } from "@/src/services/inventoryService"; import { getAccountIdForRequest } from "@/src/services/loginService"; import { IDojoContributable } from "@/src/types/guildTypes"; import { RequestHandler } from "express"; -import { ExportDojoRecipes, IDojoRecipe } from "warframe-public-export-plus"; +import { ExportDojoRecipes, IDojoBuild } from "warframe-public-export-plus"; interface IDojoComponentRushRequest { DecoType?: string; @@ -40,7 +40,7 @@ export const dojoComponentRushController: RequestHandler = async (req, res) => { }); }; -const processContribution = (component: IDojoContributable, meta: IDojoRecipe, platinumDonated: number): void => { +const processContribution = (component: IDojoContributable, meta: IDojoBuild, platinumDonated: number): void => { const fullPlatinumCost = scaleRequiredCount(meta.skipTimePrice); const fullDurationSeconds = meta.time; const secondsPerPlatinum = fullDurationSeconds / fullPlatinumCost; -- 2.47.2 From 1221a404eb88bf57693100c662f8740e574f9617 Mon Sep 17 00:00:00 2001 From: Sainan Date: Fri, 7 Mar 2025 09:26:09 +0100 Subject: [PATCH 3/4] feat: clan XP --- .../api/contributeGuildClassController.ts | 65 +++++++++++++++++++ .../contributeToDojoComponentController.ts | 8 ++- src/controllers/api/getGuildController.ts | 17 ++++- src/controllers/api/guildTechController.ts | 14 +++- .../api/startDojoRecipeController.ts | 5 +- src/models/guildModel.ts | 9 ++- src/routes/api.ts | 2 + src/services/guildService.ts | 12 +++- src/types/guildTypes.ts | 11 ++++ 9 files changed, 134 insertions(+), 9 deletions(-) create mode 100644 src/controllers/api/contributeGuildClassController.ts diff --git a/src/controllers/api/contributeGuildClassController.ts b/src/controllers/api/contributeGuildClassController.ts new file mode 100644 index 00000000..6a32ad11 --- /dev/null +++ b/src/controllers/api/contributeGuildClassController.ts @@ -0,0 +1,65 @@ +import { toMongoDate } from "@/src/helpers/inventoryHelpers"; +import { getJSONfromString } from "@/src/helpers/stringHelpers"; +import { Guild } from "@/src/models/guildModel"; +import { getInventory } from "@/src/services/inventoryService"; +import { getAccountIdForRequest } from "@/src/services/loginService"; +import { RequestHandler } from "express"; +import { Types } from "mongoose"; + +export const contributeGuildClassController: RequestHandler = async (req, res) => { + const accountId = await getAccountIdForRequest(req); + const payload = getJSONfromString(String(req.body)); + const guild = (await Guild.findOne({ _id: payload.GuildId }))!; + + // First contributor initiates ceremony and locks the pending class. + if (!guild.CeremonyContributors) { + guild.CeremonyContributors = []; + guild.CeremonyClass = guildXpToClass(guild.XP); + guild.CeremonyEndo = 0; + for (let i = guild.Class; i != guild.CeremonyClass; ++i) { + guild.CeremonyEndo += (i + 1) * 1000; + } + } + + guild.CeremonyContributors.push(new Types.ObjectId(accountId)); + + // Once required contributor count is hit, the class is committed and there's 72 hours to claim endo. + if (guild.CeremonyContributors.length == payload.RequiredContributors) { + guild.Class = guild.CeremonyClass!; + guild.CeremonyClass = undefined; + guild.CeremonyResetDate = new Date(Date.now() + 72 * 3600_000); + } + + await guild.save(); + + // Either way, endo is given to the contributor. + const inventory = await getInventory(accountId, "FusionPoints"); + inventory.FusionPoints += guild.CeremonyEndo!; + await inventory.save(); + + res.json({ + NumContributors: guild.CeremonyContributors.length, + FusionPointReward: guild.CeremonyEndo, + Class: guild.Class, + CeremonyResetDate: guild.CeremonyResetDate ? toMongoDate(guild.CeremonyResetDate) : undefined + }); +}; + +interface IContributeGuildClassRequest { + GuildId: string; + RequiredContributors: number; +} + +const guildXpToClass = (xp: number): number => { + const cummXp = [ + 0, 11000, 34000, 69000, 114000, 168000, 231000, 302000, 381000, 68000, 563000, 665000, 774000, 891000 + ]; + let highest = 0; + for (let i = 0; i != cummXp.length; ++i) { + if (xp < cummXp[i]) { + break; + } + highest = i; + } + return highest; +}; diff --git a/src/controllers/api/contributeToDojoComponentController.ts b/src/controllers/api/contributeToDojoComponentController.ts index 9d1942c1..21be9c82 100644 --- a/src/controllers/api/contributeToDojoComponentController.ts +++ b/src/controllers/api/contributeToDojoComponentController.ts @@ -1,6 +1,11 @@ import { TGuildDatabaseDocument } from "@/src/models/guildModel"; import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel"; -import { getDojoClient, getGuildForRequestEx, scaleRequiredCount } from "@/src/services/guildService"; +import { + getDojoClient, + getGuildForRequestEx, + processDojoBuildMaterialsGathered, + scaleRequiredCount +} from "@/src/services/guildService"; import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService"; import { getAccountIdForRequest } from "@/src/services/loginService"; import { IDojoContributable } from "@/src/types/guildTypes"; @@ -134,6 +139,7 @@ const processContribution = ( } if (fullyFunded) { component.CompletionTime = new Date(Date.now() + meta.time * 1000); + processDojoBuildMaterialsGathered(guild, meta); } } }; diff --git a/src/controllers/api/getGuildController.ts b/src/controllers/api/getGuildController.ts index 6703d87c..62a27501 100644 --- a/src/controllers/api/getGuildController.ts +++ b/src/controllers/api/getGuildController.ts @@ -2,8 +2,9 @@ import { RequestHandler } from "express"; import { Inventory } from "@/src/models/inventoryModels/inventoryModel"; import { Guild } from "@/src/models/guildModel"; import { getAccountIdForRequest } from "@/src/services/loginService"; -import { toOid } from "@/src/helpers/inventoryHelpers"; +import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers"; import { getGuildVault } from "@/src/services/guildService"; +import { logger } from "@/src/utils/logger"; const getGuildController: RequestHandler = async (req, res) => { const accountId = await getAccountIdForRequest(req); @@ -15,6 +16,13 @@ const getGuildController: RequestHandler = async (req, res) => { if (inventory.GuildId) { const guild = await Guild.findOne({ _id: inventory.GuildId }); if (guild) { + if (guild.CeremonyResetDate && Date.now() >= guild.CeremonyResetDate.getTime()) { + logger.debug(`ascension ceremony is over`); + guild.CeremonyEndo = undefined; + guild.CeremonyContributors = undefined; + guild.CeremonyResetDate = undefined; + await guild.save(); + } res.json({ _id: toOid(guild._id), Name: guild.Name, @@ -64,7 +72,12 @@ const getGuildController: RequestHandler = async (req, res) => { } ], Tier: 1, - Vault: getGuildVault(guild) + Vault: getGuildVault(guild), + Class: guild.Class, + XP: guild.XP, + IsContributor: !!guild.CeremonyContributors?.find(x => x.equals(accountId)), + NumContributors: guild.CeremonyContributors?.length ?? 0, + CeremonyResetDate: guild.CeremonyResetDate ? toMongoDate(guild.CeremonyResetDate) : undefined }); return; } diff --git a/src/controllers/api/guildTechController.ts b/src/controllers/api/guildTechController.ts index a5a080b1..35dffe2d 100644 --- a/src/controllers/api/guildTechController.ts +++ b/src/controllers/api/guildTechController.ts @@ -7,6 +7,7 @@ import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes"; import { IInventoryChanges } from "@/src/types/purchaseTypes"; import { config } from "@/src/services/configService"; import { ITechProjectDatabase } from "@/src/types/guildTypes"; +import { TGuildDatabaseDocument } from "@/src/models/guildModel"; export const guildTechController: RequestHandler = async (req, res) => { const accountId = await getAccountIdForRequest(req); @@ -35,7 +36,7 @@ export const guildTechController: RequestHandler = async (req, res) => { }) - 1 ]; if (config.noDojoResearchCosts) { - processFundedProject(techProject, recipe); + processFundedProject(guild, techProject, recipe); } } await guild.save(); @@ -93,7 +94,7 @@ export const guildTechController: RequestHandler = async (req, res) => { if (techProject.ReqCredits == 0 && !techProject.ReqItems.find(x => x.ItemCount > 0)) { // This research is now fully funded. const recipe = ExportDojoRecipes.research[data.RecipeType!]; - processFundedProject(techProject, recipe); + processFundedProject(guild, techProject, recipe); } await guild.save(); @@ -131,9 +132,16 @@ export const guildTechController: RequestHandler = async (req, res) => { } }; -const processFundedProject = (techProject: ITechProjectDatabase, recipe: IDojoResearch): void => { +const processFundedProject = ( + guild: TGuildDatabaseDocument, + techProject: ITechProjectDatabase, + recipe: IDojoResearch +): void => { techProject.State = 1; techProject.CompletionDate = new Date(new Date().getTime() + (config.noDojoResearchTime ? 0 : recipe.time) * 1000); + if (recipe.guildXpValue) { + guild.XP += recipe.guildXpValue; + } }; type TGuildTechRequest = { diff --git a/src/controllers/api/startDojoRecipeController.ts b/src/controllers/api/startDojoRecipeController.ts index 30f4ed75..ee7bb202 100644 --- a/src/controllers/api/startDojoRecipeController.ts +++ b/src/controllers/api/startDojoRecipeController.ts @@ -1,6 +1,6 @@ import { RequestHandler } from "express"; import { IDojoComponentClient } from "@/src/types/guildTypes"; -import { getDojoClient, getGuildForRequest } from "@/src/services/guildService"; +import { getDojoClient, getGuildForRequest, processDojoBuildMaterialsGathered } from "@/src/services/guildService"; import { Types } from "mongoose"; import { ExportDojoRecipes } from "warframe-public-export-plus"; import { config } from "@/src/services/configService"; @@ -35,6 +35,9 @@ export const startDojoRecipeController: RequestHandler = async (req, res) => { ]; if (config.noDojoRoomBuildStage) { component.CompletionTime = new Date(Date.now()); + if (room) { + processDojoBuildMaterialsGathered(guild, room); + } } await guild.save(); res.json(await getDojoClient(guild, 0)); diff --git a/src/models/guildModel.ts b/src/models/guildModel.ts index 4fdbc223..7afceb98 100644 --- a/src/models/guildModel.ts +++ b/src/models/guildModel.ts @@ -70,7 +70,14 @@ const guildSchema = new Schema( VaultMiscItems: { type: [typeCountSchema], default: undefined }, VaultShipDecorations: { type: [typeCountSchema], default: undefined }, VaultFusionTreasures: { type: [fusionTreasuresSchema], default: undefined }, - TechProjects: { type: [techProjectSchema], default: undefined } + TechProjects: { type: [techProjectSchema], default: undefined }, + Class: { type: Number, default: 0 }, + XP: { type: Number, default: 0 }, + ClaimedXP: { type: [String], default: undefined }, + CeremonyClass: Number, + CeremonyContributors: { type: [Types.ObjectId], default: undefined }, + CeremonyResetDate: Date, + CeremonyEndo: Number }, { id: false } ); diff --git a/src/routes/api.ts b/src/routes/api.ts index 2ad923d6..bb63982e 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -13,6 +13,7 @@ import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompl import { claimLibraryDailyTaskRewardController } from "@/src/controllers/api/claimLibraryDailyTaskRewardController"; import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController"; import { completeRandomModChallengeController } from "@/src/controllers/api/completeRandomModChallengeController"; +import { contributeGuildClassController } from "@/src/controllers/api/contributeGuildClassController"; import { contributeToDojoComponentController } from "@/src/controllers/api/contributeToDojoComponentController"; import { contributeToVaultController } from "@/src/controllers/api/contributeToVaultController"; import { createGuildController } from "@/src/controllers/api/createGuildController"; @@ -153,6 +154,7 @@ apiRouter.post("/changeDojoRoot.php", changeDojoRootController); apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController); apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController); apiRouter.post("/completeRandomModChallenge.php", completeRandomModChallengeController); +apiRouter.post("/contributeGuildClass.php", contributeGuildClassController); apiRouter.post("/contributeToDojoComponent.php", contributeToDojoComponentController); apiRouter.post("/contributeToVault.php", contributeToVaultController); apiRouter.post("/createGuild.php", createGuildController); diff --git a/src/services/guildService.ts b/src/services/guildService.ts index cd877835..9c89f863 100644 --- a/src/services/guildService.ts +++ b/src/services/guildService.ts @@ -12,7 +12,7 @@ import { } from "@/src/types/guildTypes"; import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers"; import { Types } from "mongoose"; -import { ExportDojoRecipes } from "warframe-public-export-plus"; +import { ExportDojoRecipes, IDojoBuild } from "warframe-public-export-plus"; import { logger } from "../utils/logger"; export const getGuildForRequest = async (req: Request): Promise => { @@ -182,3 +182,13 @@ const moveResourcesToVault = (guild: TGuildDatabaseDocument, component: IDojoCon guild.VaultPremiumCredits += component.RushPlatinum; } }; + +export const processDojoBuildMaterialsGathered = (guild: TGuildDatabaseDocument, build: IDojoBuild): void => { + if (build.guildXpValue) { + guild.ClaimedXP ??= []; + if (!guild.ClaimedXP.find(x => x == build.resultType)) { + guild.ClaimedXP.push(build.resultType); + guild.XP += build.guildXpValue; + } + } +}; diff --git a/src/types/guildTypes.ts b/src/types/guildTypes.ts index b85d97e2..9effcfbc 100644 --- a/src/types/guildTypes.ts +++ b/src/types/guildTypes.ts @@ -5,15 +5,26 @@ import { IFusionTreasure, IMiscItem, ITypeCount } from "@/src/types/inventoryTyp export interface IGuildDatabase { _id: Types.ObjectId; Name: string; + DojoComponents: IDojoComponentDatabase[]; DojoCapacity: number; DojoEnergy: number; + VaultRegularCredits?: number; VaultPremiumCredits?: number; VaultMiscItems?: IMiscItem[]; VaultShipDecorations?: ITypeCount[]; VaultFusionTreasures?: IFusionTreasure[]; + TechProjects?: ITechProjectDatabase[]; + + Class: number; + XP: number; + ClaimedXP?: string[]; // track rooms and decos that have already granted XP + CeremonyClass?: number; + CeremonyEndo?: number; + CeremonyContributors?: Types.ObjectId[]; + CeremonyResetDate?: Date; } export interface IGuildVault { -- 2.47.2 From 4c935537a02fffc1793741d1203d4fe6faa226a4 Mon Sep 17 00:00:00 2001 From: Sainan Date: Fri, 7 Mar 2025 09:28:42 +0100 Subject: [PATCH 4/4] feat: fastClanAscension cheat --- config.json.example | 1 + src/controllers/api/contributeGuildClassController.ts | 3 ++- src/services/configService.ts | 1 + static/webui/index.html | 4 ++++ static/webui/translations/en.js | 1 + static/webui/translations/fr.js | 1 + static/webui/translations/ru.js | 1 + 7 files changed, 11 insertions(+), 1 deletion(-) diff --git a/config.json.example b/config.json.example index db0f6d41..e94a441f 100644 --- a/config.json.example +++ b/config.json.example @@ -36,5 +36,6 @@ "fastDojoRoomDestruction": true, "noDojoResearchCosts": true, "noDojoResearchTime": true, + "fastClanAscension": true, "spoofMasteryRank": -1 } diff --git a/src/controllers/api/contributeGuildClassController.ts b/src/controllers/api/contributeGuildClassController.ts index 6a32ad11..d0c91539 100644 --- a/src/controllers/api/contributeGuildClassController.ts +++ b/src/controllers/api/contributeGuildClassController.ts @@ -1,6 +1,7 @@ import { toMongoDate } from "@/src/helpers/inventoryHelpers"; import { getJSONfromString } from "@/src/helpers/stringHelpers"; import { Guild } from "@/src/models/guildModel"; +import { config } from "@/src/services/configService"; import { getInventory } from "@/src/services/inventoryService"; import { getAccountIdForRequest } from "@/src/services/loginService"; import { RequestHandler } from "express"; @@ -27,7 +28,7 @@ export const contributeGuildClassController: RequestHandler = async (req, res) = if (guild.CeremonyContributors.length == payload.RequiredContributors) { guild.Class = guild.CeremonyClass!; guild.CeremonyClass = undefined; - guild.CeremonyResetDate = new Date(Date.now() + 72 * 3600_000); + guild.CeremonyResetDate = new Date(Date.now() + (config.fastClanAscension ? 5_000 : 72 * 3600_000)); } await guild.save(); diff --git a/src/services/configService.ts b/src/services/configService.ts index e1c79534..92c8c6a8 100644 --- a/src/services/configService.ts +++ b/src/services/configService.ts @@ -62,6 +62,7 @@ interface IConfig { fastDojoRoomDestruction?: boolean; noDojoResearchCosts?: boolean; noDojoResearchTime?: boolean; + fastClanAscension?: boolean; spoofMasteryRank?: number; } diff --git a/static/webui/index.html b/static/webui/index.html index a161bd0c..bb1c88df 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -537,6 +537,10 @@ +
+ + +
diff --git a/static/webui/translations/en.js b/static/webui/translations/en.js index bc1472c0..484b0063 100644 --- a/static/webui/translations/en.js +++ b/static/webui/translations/en.js @@ -114,6 +114,7 @@ dict = { cheats_fastDojoRoomDestruction: `Fast Dojo Room Destruction`, cheats_noDojoResearchCosts: `No Dojo Research Costs`, cheats_noDojoResearchTime: `No Dojo Research Time`, + cheats_fastClanAscension: `Fast Clan Ascension`, cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`, cheats_saveSettings: `Save Settings`, cheats_account: `Account`, diff --git a/static/webui/translations/fr.js b/static/webui/translations/fr.js index 5acce802..153aad2b 100644 --- a/static/webui/translations/fr.js +++ b/static/webui/translations/fr.js @@ -115,6 +115,7 @@ dict = { cheats_fastDojoRoomDestruction: `[UNTRANSLATED] Fast Dojo Room Destruction`, cheats_noDojoResearchCosts: `Aucun coût de recherche (Dojo)`, cheats_noDojoResearchTime: `Aucun temps de recherche (Dojo)`, + cheats_fastClanAscension: `[UNTRANSLATED] Fast Clan Ascension`, cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`, cheats_saveSettings: `Sauvegarder les paramètres`, cheats_account: `Compte`, diff --git a/static/webui/translations/ru.js b/static/webui/translations/ru.js index 3da49d4d..44c6eb41 100644 --- a/static/webui/translations/ru.js +++ b/static/webui/translations/ru.js @@ -115,6 +115,7 @@ dict = { cheats_fastDojoRoomDestruction: `Мгновенные Уничтожение Комнат Додзё`, cheats_noDojoResearchCosts: `Бесплатные Исследование Додзё`, cheats_noDojoResearchTime: `Мгновенные Исследование Додзё`, + cheats_fastClanAscension: `[UNTRANSLATED] Fast Clan Ascension`, cheats_spoofMasteryRank: `Подделанный ранг мастерства (-1 для отключения)`, cheats_saveSettings: `Сохранить настройки`, cheats_account: `Аккаунт`, -- 2.47.2