Compare commits

...

2 Commits

Author SHA1 Message Date
bf7fd42198 feat: tutorial and natural new player experience (#983)
Reviewed-on: OpenWF/SpaceNinjaServer#983
Co-authored-by: Ordis <134585663+OrdisPrime@users.noreply.github.com>
Co-committed-by: Ordis <134585663+OrdisPrime@users.noreply.github.com>
2025-02-22 11:10:52 -08:00
9203e0bf4d feat: infiniteHelminthMaterials cheat (#985)
Closes #728

Reviewed-on: OpenWF/SpaceNinjaServer#985
Co-authored-by: Sainan <sainan@calamity.inc>
Co-committed-by: Sainan <sainan@calamity.inc>
2025-02-22 11:09:17 -08:00
20 changed files with 330 additions and 164 deletions

View File

@ -20,6 +20,7 @@
"infinitePlatinum": true, "infinitePlatinum": true,
"infiniteEndo": true, "infiniteEndo": true,
"infiniteRegalAya": true, "infiniteRegalAya": true,
"infiniteHelminthMaterials": false,
"unlockAllShipFeatures": true, "unlockAllShipFeatures": true,
"unlockAllShipDecorations": true, "unlockAllShipDecorations": true,
"unlockAllFlavourItems": true, "unlockAllFlavourItems": true,

6
package-lock.json generated
View File

@ -4093,9 +4093,9 @@
} }
}, },
"node_modules/warframe-public-export-plus": { "node_modules/warframe-public-export-plus": {
"version": "0.5.30", "version": "0.5.32",
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.30.tgz", "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.32.tgz",
"integrity": "sha512-vzs+naEqp3iFZTbgIky4jiNbjNIovuR4oSimrFiuyIbrnfTlfXFzDfzT0hG2rgS8yEXBAbOcv2Zfm3fmWuZ0Kg==" "integrity": "sha512-jO9i2Gzz9DWibiHlEO17D975ajs6KrTay8cS5I0GkUUe1XWVU8mML4b+IYCHzM4FWq1t6p2YPCGznQfknqvorg=="
}, },
"node_modules/warframe-riven-info": { "node_modules/warframe-riven-info": {
"version": "0.1.2", "version": "0.1.2",

View File

@ -1,13 +1,11 @@
import { RequestHandler } from "express"; import { RequestHandler } from "express";
const getNewRewardSeedController: RequestHandler = (_req, res) => { export const getNewRewardSeedController: RequestHandler = (_req, res) => {
res.json({ rewardSeed: generateRewardSeed() }); res.json({ rewardSeed: generateRewardSeed() });
}; };
function generateRewardSeed(): number { export function generateRewardSeed(): number {
const min = -Number.MAX_SAFE_INTEGER; const min = -Number.MAX_SAFE_INTEGER;
const max = Number.MAX_SAFE_INTEGER; const max = Number.MAX_SAFE_INTEGER;
return Math.floor(Math.random() * (max - min + 1)) + min; return Math.floor(Math.random() * (max - min + 1)) + min;
} }
export { getNewRewardSeedController };

View File

@ -0,0 +1,96 @@
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { InventoryDocumentProps } from "@/src/models/inventoryModels/inventoryModel";
import {
addEquipment,
addItem,
combineInventoryChanges,
getInventory,
updateSlots
} from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { IInventoryClient, IInventoryDatabase, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
import { IInventoryChanges } from "@/src/types/purchaseTypes";
import { RequestHandler } from "express";
import { HydratedDocument } from "mongoose";
type TPartialStartingGear = Pick<IInventoryClient, "LongGuns" | "Suits" | "Pistols" | "Melee">;
export const giveStartingGearController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const startingGear = getJSONfromString<TPartialStartingGear>(String(req.body));
const inventory = await getInventory(accountId);
const inventoryChanges = await addStartingGear(inventory, startingGear);
await inventory.save();
res.send(inventoryChanges);
};
//TODO: RawUpgrades might need to return a LastAdded
const awakeningRewards = [
"/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem1",
"/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem2",
"/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem3",
"/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem4",
"/Lotus/Types/Restoratives/LisetAutoHack",
"/Lotus/Upgrades/Mods/Warframe/AvatarShieldMaxMod"
];
export const addStartingGear = async (
inventory: HydratedDocument<IInventoryDatabase, InventoryDocumentProps>,
startingGear: TPartialStartingGear | undefined = undefined
) => {
const { LongGuns, Pistols, Suits, Melee } = startingGear || {
LongGuns: [{ ItemType: "/Lotus/Weapons/Tenno/Rifle/Rifle" }],
Pistols: [{ ItemType: "/Lotus/Weapons/Tenno/Pistol/Pistol" }],
Suits: [{ ItemType: "/Lotus/Powersuits/Excalibur/Excalibur" }],
Melee: [{ ItemType: "/Lotus/Weapons/Tenno/Melee/LongSword/LongSword" }]
};
//TODO: properly merge weapon bin changes it is currently static here
const inventoryChanges: IInventoryChanges = {};
addEquipment(inventory, "LongGuns", LongGuns[0].ItemType, undefined, inventoryChanges);
addEquipment(inventory, "Pistols", Pistols[0].ItemType, undefined, inventoryChanges);
addEquipment(inventory, "Melee", Melee[0].ItemType, undefined, inventoryChanges);
addEquipment(inventory, "Suits", Suits[0].ItemType, undefined, inventoryChanges, { Configs: Suits[0].Configs });
addEquipment(
inventory,
"DataKnives",
"/Lotus/Weapons/Tenno/HackingDevices/TnHackingDevice/TnHackingDeviceWeapon",
undefined,
inventoryChanges,
{ XP: 450_000 }
);
addEquipment(
inventory,
"Scoops",
"/Lotus/Weapons/Tenno/Speedball/SpeedballWeaponTest",
undefined,
inventoryChanges
);
updateSlots(inventory, InventorySlot.SUITS, 0, 1);
updateSlots(inventory, InventorySlot.WEAPONS, 0, 3);
inventoryChanges.SuitBin = { count: 1, platinum: 0, Slots: -1 };
inventoryChanges.WeaponBin = { count: 3, platinum: 0, Slots: -3 };
await addItem(inventory, "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain");
inventory.ActiveQuest = "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain";
inventory.PremiumCredits = 50;
inventory.PremiumCreditsFree = 50;
inventoryChanges.PremiumCredits = 50;
inventoryChanges.PremiumCreditsFree = 50;
inventory.RegularCredits = 3000;
inventoryChanges.RegularCredits = 3000;
for (const item of awakeningRewards) {
const inventoryDelta = await addItem(inventory, item);
combineInventoryChanges(inventoryChanges, inventoryDelta.InventoryChanges);
}
inventory.PlayedParkourTutorial = true;
inventory.ReceivedStartingGear = true;
return inventoryChanges;
};

View File

@ -6,7 +6,9 @@ import { IOid } from "@/src/types/commonTypes";
import { import {
IConsumedSuit, IConsumedSuit,
IHelminthFoodRecord, IHelminthFoodRecord,
IInfestedFoundryClient,
IInfestedFoundryDatabase, IInfestedFoundryDatabase,
IInventoryClient,
IMiscItem, IMiscItem,
ITypeCount ITypeCount
} from "@/src/types/inventoryTypes/inventoryTypes"; } from "@/src/types/inventoryTypes/inventoryTypes";
@ -16,6 +18,7 @@ import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/invento
import { toMongoDate } from "@/src/helpers/inventoryHelpers"; import { toMongoDate } from "@/src/helpers/inventoryHelpers";
import { logger } from "@/src/utils/logger"; import { logger } from "@/src/utils/logger";
import { colorToShard } from "@/src/helpers/shardHelper"; import { colorToShard } from "@/src/helpers/shardHelper";
import { config } from "@/src/services/configService";
export const infestedFoundryController: RequestHandler = async (req, res) => { export const infestedFoundryController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
@ -69,18 +72,22 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
// remove from suit // remove from suit
suit.ArchonCrystalUpgrades![request.Slot] = {}; suit.ArchonCrystalUpgrades![request.Slot] = {};
if (!config.infiniteHelminthMaterials) {
// remove bile // remove bile
const bile = inventory.InfestedFoundry!.Resources!.find( const bile = inventory.InfestedFoundry!.Resources!.find(
x => x.ItemType == "/Lotus/Types/Items/InfestedFoundry/HelminthBile" x => x.ItemType == "/Lotus/Types/Items/InfestedFoundry/HelminthBile"
)!; )!;
bile.Count -= 300; bile.Count -= 300;
}
await inventory.save(); await inventory.save();
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
applyCheatsToInfestedFoundry(infestedFoundry);
res.json({ res.json({
InventoryChanges: { InventoryChanges: {
MiscItems: miscItemChanges, MiscItems: miscItemChanges,
InfestedFoundry: inventory.toJSON().InfestedFoundry InfestedFoundry: infestedFoundry
} }
}); });
break; break;
@ -105,6 +112,12 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
case "c": { case "c": {
// consume items // consume items
if (config.infiniteHelminthMaterials) {
res.status(400).end();
return;
}
const request = getJSONfromString<IHelminthFeedRequest>(String(req.body)); const request = getJSONfromString<IHelminthFeedRequest>(String(req.body));
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
inventory.InfestedFoundry ??= {}; inventory.InfestedFoundry ??= {};
@ -210,9 +223,11 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
inventory.InfestedFoundry.InvigorationsApplied = 0; inventory.InfestedFoundry.InvigorationsApplied = 0;
} }
await inventory.save(); await inventory.save();
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
applyCheatsToInfestedFoundry(infestedFoundry);
res.json({ res.json({
InventoryChanges: { InventoryChanges: {
InfestedFoundry: inventory.toJSON().InfestedFoundry InfestedFoundry: infestedFoundry
} }
}); });
break; break;
@ -223,12 +238,14 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
const request = getJSONfromString<IHelminthSubsumeRequest>(String(req.body)); const request = getJSONfromString<IHelminthSubsumeRequest>(String(req.body));
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
const recipe = getRecipe(request.Recipe)!; const recipe = getRecipe(request.Recipe)!;
if (!config.infiniteHelminthMaterials) {
for (const ingredient of recipe.secretIngredients!) { for (const ingredient of recipe.secretIngredients!) {
const resource = inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType); const resource = inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType);
if (resource) { if (resource) {
resource.Count -= ingredient.ItemCount; resource.Count -= ingredient.ItemCount;
} }
} }
}
const suit = inventory.Suits.id(request.SuitId.$oid)!; const suit = inventory.Suits.id(request.SuitId.$oid)!;
inventory.Suits.pull(suit); inventory.Suits.pull(suit);
const consumedSuit: IConsumedSuit = { s: suit.ItemType }; const consumedSuit: IConsumedSuit = { s: suit.ItemType };
@ -247,6 +264,8 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 1600_00); const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 1600_00);
addRecipes(inventory, recipeChanges); addRecipes(inventory, recipeChanges);
await inventory.save(); await inventory.save();
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
applyCheatsToInfestedFoundry(infestedFoundry);
res.json({ res.json({
InventoryChanges: { InventoryChanges: {
Recipes: recipeChanges, Recipes: recipeChanges,
@ -260,7 +279,7 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
platinum: 0, platinum: 0,
Slots: 1 Slots: 1
}, },
InfestedFoundry: inventory.toJSON().InfestedFoundry InfestedFoundry: infestedFoundry
} }
}); });
break; break;
@ -272,11 +291,13 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
const currencyChanges = updateCurrency(inventory, 50, true); const currencyChanges = updateCurrency(inventory, 50, true);
const recipeChanges = handleSubsumeCompletion(inventory); const recipeChanges = handleSubsumeCompletion(inventory);
await inventory.save(); await inventory.save();
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
applyCheatsToInfestedFoundry(infestedFoundry);
res.json({ res.json({
InventoryChanges: { InventoryChanges: {
...currencyChanges, ...currencyChanges,
Recipes: recipeChanges, Recipes: recipeChanges,
InfestedFoundry: inventory.toJSON().InfestedFoundry InfestedFoundry: infestedFoundry
} }
}); });
break; break;
@ -292,13 +313,17 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
suit.UpgradesExpiry = upgradesExpiry; suit.UpgradesExpiry = upgradesExpiry;
const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 4800_00); const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 4800_00);
addRecipes(inventory, recipeChanges); addRecipes(inventory, recipeChanges);
if (!config.infiniteHelminthMaterials) {
for (let i = 0; i != request.ResourceTypes.length; ++i) { for (let i = 0; i != request.ResourceTypes.length; ++i) {
inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == request.ResourceTypes[i])!.Count -= inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == request.ResourceTypes[i])!.Count -=
request.ResourceCosts[i]; request.ResourceCosts[i];
} }
}
inventory.InfestedFoundry!.InvigorationsApplied ??= 0; inventory.InfestedFoundry!.InvigorationsApplied ??= 0;
inventory.InfestedFoundry!.InvigorationsApplied += 1; inventory.InfestedFoundry!.InvigorationsApplied += 1;
await inventory.save(); await inventory.save();
const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
applyCheatsToInfestedFoundry(infestedFoundry);
res.json({ res.json({
SuitId: request.SuitId, SuitId: request.SuitId,
OffensiveUpgrade: request.OffensiveUpgradeType, OffensiveUpgrade: request.OffensiveUpgradeType,
@ -306,7 +331,7 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
UpgradesExpiry: toMongoDate(upgradesExpiry), UpgradesExpiry: toMongoDate(upgradesExpiry),
InventoryChanges: { InventoryChanges: {
Recipes: recipeChanges, Recipes: recipeChanges,
InfestedFoundry: inventory.toJSON().InfestedFoundry InfestedFoundry: infestedFoundry
} }
}); });
break; break;
@ -453,6 +478,19 @@ export const handleSubsumeCompletion = (inventory: TInventoryDatabaseDocument):
return recipeChanges; return recipeChanges;
}; };
export const applyCheatsToInfestedFoundry = (infestedFoundry: IInfestedFoundryClient): void => {
if (config.infiniteHelminthMaterials) {
infestedFoundry.Resources = [
{ ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthCalx", Count: 1000 },
{ ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthBiotics", Count: 1000 },
{ ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthSynthetics", Count: 1000 },
{ ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthPheromones", Count: 1000 },
{ ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthBile", Count: 1000 },
{ ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthOxides", Count: 1000 }
];
}
};
interface IHelminthOfferingsUpdate { interface IHelminthOfferingsUpdate {
OfferingsIndex: number; OfferingsIndex: number;
SuitTypes: string[]; SuitTypes: string[];

View File

@ -13,7 +13,7 @@ import {
ExportResources, ExportResources,
ExportVirtuals ExportVirtuals
} from "warframe-public-export-plus"; } from "warframe-public-export-plus";
import { handleSubsumeCompletion } from "./infestedFoundryController"; import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "./infestedFoundryController";
import { allDailyAffiliationKeys } from "@/src/services/inventoryService"; import { allDailyAffiliationKeys } from "@/src/services/inventoryService";
export const inventoryController: RequestHandler = async (request, response) => { export const inventoryController: RequestHandler = async (request, response) => {
@ -212,6 +212,10 @@ export const getInventoryResponse = async (
} }
} }
if (inventoryResponse.InfestedFoundry) {
applyCheatsToInfestedFoundry(inventoryResponse.InfestedFoundry);
}
// Fix for #380 // Fix for #380
inventoryResponse.NextRefill = { $date: { $numberLong: "9999999999999" } }; inventoryResponse.NextRefill = { $date: { $numberLong: "9999999999999" } };

View File

@ -12,6 +12,7 @@ import { addMiscItems, addRecipes, getInventory, updateCurrency } from "@/src/se
import { getRecipeByResult } from "@/src/services/itemDataService"; import { getRecipeByResult } from "@/src/services/itemDataService";
import { IInventoryChanges } from "@/src/types/purchaseTypes"; import { IInventoryChanges } from "@/src/types/purchaseTypes";
import { addInfestedFoundryXP } from "./infestedFoundryController"; import { addInfestedFoundryXP } from "./infestedFoundryController";
import { config } from "@/src/services/configService";
export const upgradesController: RequestHandler = async (req, res) => { export const upgradesController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
@ -48,10 +49,12 @@ export const upgradesController: RequestHandler = async (req, res) => {
const recipe = getRecipeByResult(operation.UpgradeRequirement)!; const recipe = getRecipeByResult(operation.UpgradeRequirement)!;
for (const ingredient of recipe.ingredients) { for (const ingredient of recipe.ingredients) {
totalPercentagePointsConsumed += ingredient.ItemCount / 10; totalPercentagePointsConsumed += ingredient.ItemCount / 10;
if (!config.infiniteHelminthMaterials) {
inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType)!.Count -= inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType)!.Count -=
ingredient.ItemCount; ingredient.ItemCount;
} }
} }
}
for (const entry of operation.PolarityRemap) { for (const entry of operation.PolarityRemap) {
suit.Configs[entry.Slot] ??= {}; suit.Configs[entry.Slot] ??= {};

View File

@ -63,8 +63,6 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
inventory.ArchwingEnabled = true; inventory.ArchwingEnabled = true;
} }
} }
inventory.ActiveQuest = "";
break; break;
} }
case "ResetAll": { case "ResetAll": {
@ -103,7 +101,6 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
inventory.ArchwingEnabled = true; inventory.ArchwingEnabled = true;
} }
} }
inventory.ActiveQuest = "";
break; break;
} }
case "giveAll": { case "giveAll": {

View File

@ -64,7 +64,11 @@ import {
IKubrowPetEggClient, IKubrowPetEggClient,
ICustomMarkers, ICustomMarkers,
IMarkerInfo, IMarkerInfo,
IMarker IMarker,
ICalendarProgress,
IPendingCouponDatabase,
IPendingCouponClient,
ILibraryAvailableDailyTaskInfo
} from "../../types/inventoryTypes/inventoryTypes"; } from "../../types/inventoryTypes/inventoryTypes";
import { IOid } from "../../types/commonTypes"; import { IOid } from "../../types/commonTypes";
import { import {
@ -323,7 +327,7 @@ MailboxSchema.set("toJSON", {
const DuviriInfoSchema = new Schema<IDuviriInfo>( const DuviriInfoSchema = new Schema<IDuviriInfo>(
{ {
Seed: Number, Seed: Number,
NumCompletions: Number NumCompletions: { type: Number, default: 0 }
}, },
{ {
_id: false, _id: false,
@ -435,6 +439,7 @@ const seasonChallengeHistorySchema = new Schema<ISeasonChallenge>(
//TODO: check whether this is complete //TODO: check whether this is complete
const playerSkillsSchema = new Schema<IPlayerSkills>( const playerSkillsSchema = new Schema<IPlayerSkills>(
{ {
LPP_NONE: { type: Number, default: 0 },
LPP_SPACE: { type: Number, default: 0 }, LPP_SPACE: { type: Number, default: 0 },
LPS_PILOTING: { type: Number, default: 0 }, LPS_PILOTING: { type: Number, default: 0 },
LPS_GUNNERY: { type: Number, default: 0 }, LPS_GUNNERY: { type: Number, default: 0 },
@ -891,19 +896,63 @@ const CustomMarkersSchema = new Schema<ICustomMarkers>(
{ _id: false } { _id: false }
); );
const calenderProgressSchema = new Schema<ICalendarProgress>(
{
Version: { type: Number, default: 19 },
Iteration: { type: Number, default: 2 },
YearProgress: {
Upgrades: { type: [] }
},
SeasonProgress: {
SeasonType: String,
LastCompletedDayIdx: { type: Number, default: -1 },
LastCompletedChallengeDayIdx: { type: Number, default: -1 },
ActivatedChallenges: []
}
},
{ _id: false }
);
const pendingCouponSchema = new Schema<IPendingCouponDatabase>(
{
Expiry: { type: Date, default: new Date(0) },
Discount: { type: Number, default: 0 }
},
{ _id: false }
);
pendingCouponSchema.set("toJSON", {
transform(_doc, ret, _options) {
(ret as IPendingCouponClient).Expiry = toMongoDate((ret as IPendingCouponDatabase).Expiry);
}
});
const libraryAvailableDailyTaskInfoSchema = new Schema<ILibraryAvailableDailyTaskInfo>(
{
EnemyTypes: [String],
EnemyLocTag: String,
EnemyIcon: String,
ScansRequired: Number,
RewardStoreItem: String,
RewardQuantity: Number,
RewardStanding: Number
},
{ _id: false }
);
const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>( const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
{ {
accountOwnerId: Schema.Types.ObjectId, accountOwnerId: Schema.Types.ObjectId,
SubscribedToEmails: Number, SubscribedToEmails: { type: Number, default: 0 },
Created: Date, SubscribedToEmailsPersonalized: { type: Number, default: 0 },
RewardSeed: Number, RewardSeed: Number,
//Credit //Credit
RegularCredits: { type: Number, default: 0 }, RegularCredits: { type: Number, default: 0 },
//Platinum //Platinum
PremiumCredits: { type: Number, default: 50 }, PremiumCredits: { type: Number, default: 0 },
//Gift Platinum(Non trade) //Gift Platinum(Non trade)
PremiumCreditsFree: { type: Number, default: 50 }, PremiumCreditsFree: { type: Number, default: 0 },
//Endo //Endo
FusionPoints: { type: Number, default: 0 }, FusionPoints: { type: Number, default: 0 },
//Regal Aya //Regal Aya
@ -911,7 +960,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
//Slots //Slots
SuitBin: { type: slotsBinSchema, default: { Slots: 3 } }, SuitBin: { type: slotsBinSchema, default: { Slots: 3 } },
WeaponBin: { type: slotsBinSchema, default: { Slots: 10 } }, WeaponBin: { type: slotsBinSchema, default: { Slots: 11 } },
SentinelBin: { type: slotsBinSchema, default: { Slots: 10 } }, SentinelBin: { type: slotsBinSchema, default: { Slots: 10 } },
SpaceSuitBin: { type: slotsBinSchema, default: { Slots: 4 } }, SpaceSuitBin: { type: slotsBinSchema, default: { Slots: 4 } },
SpaceWeaponBin: { type: slotsBinSchema, default: { Slots: 4 } }, SpaceWeaponBin: { type: slotsBinSchema, default: { Slots: 4 } },
@ -1022,7 +1071,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
//Complete Mission\Quests //Complete Mission\Quests
Missions: [missionSchema], Missions: [missionSchema],
QuestKeys: [questKeysSchema], QuestKeys: [questKeysSchema],
ActiveQuest: { type: String, default: "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain" }, //TODO: check after mission starting gear ActiveQuest: { type: String, default: "" },
//item like DojoKey or Boss missions key //item like DojoKey or Boss missions key
LevelKeys: [Schema.Types.Mixed], LevelKeys: [Schema.Types.Mixed],
//Active quests //Active quests
@ -1137,7 +1186,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
//Cephalon Simaris Entries Example:"TargetType"+"Scans"(1-10)+"Completed": true|false //Cephalon Simaris Entries Example:"TargetType"+"Scans"(1-10)+"Completed": true|false
LibraryPersonalProgress: [Schema.Types.Mixed], LibraryPersonalProgress: [Schema.Types.Mixed],
//Cephalon Simaris Daily Task //Cephalon Simaris Daily Task
LibraryAvailableDailyTaskInfo: Schema.Types.Mixed, LibraryAvailableDailyTaskInfo: libraryAvailableDailyTaskInfoSchema,
//https://warframe.fandom.com/wiki/Invasion //https://warframe.fandom.com/wiki/Invasion
InvasionChainProgress: [Schema.Types.Mixed], InvasionChainProgress: [Schema.Types.Mixed],
@ -1184,7 +1233,6 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
HandlerPoints: Number, HandlerPoints: Number,
ChallengesFixVersion: Number, ChallengesFixVersion: Number,
PlayedParkourTutorial: Boolean, PlayedParkourTutorial: Boolean,
SubscribedToEmailsPersonalized: Number,
ActiveLandscapeTraps: [Schema.Types.Mixed], ActiveLandscapeTraps: [Schema.Types.Mixed],
RepVotes: [Schema.Types.Mixed], RepVotes: [Schema.Types.Mixed],
LeagueTickets: [Schema.Types.Mixed], LeagueTickets: [Schema.Types.Mixed],
@ -1202,7 +1250,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
HasResetAccount: { type: Boolean, default: false }, HasResetAccount: { type: Boolean, default: false },
//Discount Coupon //Discount Coupon
PendingCoupon: Schema.Types.Mixed, PendingCoupon: pendingCouponSchema,
//Like BossAladV,BossCaptainVor come for you on missions % chance //Like BossAladV,BossCaptainVor come for you on missions % chance
DeathMarks: [String], DeathMarks: [String],
//Zanuka //Zanuka
@ -1212,7 +1260,8 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
EndlessXP: { type: [endlessXpProgressSchema], default: undefined }, EndlessXP: { type: [endlessXpProgressSchema], default: undefined },
DialogueHistory: dialogueHistorySchema DialogueHistory: dialogueHistorySchema,
CalendarProgress: calenderProgressSchema
}, },
{ timestamps: { createdAt: "Created", updatedAt: false } } { timestamps: { createdAt: "Created", updatedAt: false } }
); );

View File

@ -87,6 +87,7 @@ import { updateSessionGetController, updateSessionPostController } from "@/src/c
import { updateThemeController } from "../controllers/api/updateThemeController"; import { updateThemeController } from "../controllers/api/updateThemeController";
import { upgradesController } from "@/src/controllers/api/upgradesController"; import { upgradesController } from "@/src/controllers/api/upgradesController";
import { saveSettingsController } from "../controllers/api/saveSettingsController"; import { saveSettingsController } from "../controllers/api/saveSettingsController";
import { giveStartingGearController } from "@/src/controllers/api/giveStartingGearController";
const apiRouter = express.Router(); const apiRouter = express.Router();
@ -146,6 +147,7 @@ apiRouter.post("/gildWeapon.php", gildWeaponController);
apiRouter.post("/giveKeyChainTriggeredItems.php", giveKeyChainTriggeredItemsController); apiRouter.post("/giveKeyChainTriggeredItems.php", giveKeyChainTriggeredItemsController);
apiRouter.post("/giveKeyChainTriggeredMessage.php", giveKeyChainTriggeredMessageController); apiRouter.post("/giveKeyChainTriggeredMessage.php", giveKeyChainTriggeredMessageController);
apiRouter.post("/giveQuestKeyReward.php", giveQuestKeyRewardController); apiRouter.post("/giveQuestKeyReward.php", giveQuestKeyRewardController);
apiRouter.post("/giveStartingGear.php", giveStartingGearController);
apiRouter.post("/guildTech.php", guildTechController); apiRouter.post("/guildTech.php", guildTechController);
apiRouter.post("/hostSession.php", hostSessionController); apiRouter.post("/hostSession.php", hostSessionController);
apiRouter.post("/infestedFoundry.php", infestedFoundryController); apiRouter.post("/infestedFoundry.php", infestedFoundryController);

View File

@ -46,6 +46,7 @@ interface IConfig {
infinitePlatinum?: boolean; infinitePlatinum?: boolean;
infiniteEndo?: boolean; infiniteEndo?: boolean;
infiniteRegalAya?: boolean; infiniteRegalAya?: boolean;
infiniteHelminthMaterials?: boolean;
unlockAllShipFeatures?: boolean; unlockAllShipFeatures?: boolean;
unlockAllShipDecorations?: boolean; unlockAllShipDecorations?: boolean;
unlockAllFlavourItems?: boolean; unlockAllFlavourItems?: boolean;

View File

@ -2,7 +2,7 @@ import { IMessageDatabase, Inbox } from "@/src/models/inboxModel";
import { getAccountForRequest } from "@/src/services/loginService"; import { getAccountForRequest } from "@/src/services/loginService";
import { HydratedDocument } from "mongoose"; import { HydratedDocument } from "mongoose";
import { Request } from "express"; import { Request } from "express";
import messages from "@/static/fixed_responses/messages.json"; import eventMessages from "@/static/fixed_responses/eventMessages.json";
import { logger } from "@/src/utils/logger"; import { logger } from "@/src/utils/logger";
export const getAllMessagesSorted = async (accountId: string): Promise<HydratedDocument<IMessageDatabase>[]> => { export const getAllMessagesSorted = async (accountId: string): Promise<HydratedDocument<IMessageDatabase>[]> => {
@ -32,7 +32,7 @@ export const createNewEventMessages = async (req: Request) => {
const latestEventMessageDate = account.LatestEventMessageDate; const latestEventMessageDate = account.LatestEventMessageDate;
//TODO: is baroo there? create these kind of messages too (periodical messages) //TODO: is baroo there? create these kind of messages too (periodical messages)
const newEventMessages = messages.Messages.filter(m => new Date(m.eventMessageDate) > latestEventMessageDate); const newEventMessages = eventMessages.Messages.filter(m => new Date(m.eventMessageDate) > latestEventMessageDate);
if (newEventMessages.length === 0) { if (newEventMessages.length === 0) {
logger.debug(`No new event messages. Latest event message date: ${latestEventMessageDate.toISOString()}`); logger.debug(`No new event messages. Latest event message date: ${latestEventMessageDate.toISOString()}`);

View File

@ -22,7 +22,9 @@ import {
IDailyAffiliations, IDailyAffiliations,
IInventoryDatabase, IInventoryDatabase,
IKubrowPetEggDatabase, IKubrowPetEggDatabase,
IKubrowPetEggClient IKubrowPetEggClient,
ILibraryAvailableDailyTaskInfo,
ICalendarProgress
} from "@/src/types/inventoryTypes/inventoryTypes"; } from "@/src/types/inventoryTypes/inventoryTypes";
import { IGenericUpdate } from "../types/genericUpdate"; import { IGenericUpdate } from "../types/genericUpdate";
import { import {
@ -32,7 +34,7 @@ import {
} from "../types/requestTypes"; } from "../types/requestTypes";
import { logger } from "@/src/utils/logger"; import { logger } from "@/src/utils/logger";
import { getExalted, getKeyChainItems } from "@/src/services/itemDataService"; import { getExalted, getKeyChainItems } from "@/src/services/itemDataService";
import { IEquipmentClient, IItemConfig } from "../types/inventoryTypes/commonInventoryTypes"; import { IEquipmentClient, IEquipmentDatabase, IItemConfig } from "../types/inventoryTypes/commonInventoryTypes";
import { import {
ExportArcanes, ExportArcanes,
ExportCustoms, ExportCustoms,
@ -51,6 +53,9 @@ import { createShip } from "./shipService";
import { creditBundles, fusionBundles } from "@/src/services/missionInventoryUpdateService"; import { creditBundles, fusionBundles } from "@/src/services/missionInventoryUpdateService";
import { IKeyChainRequest } from "@/src/controllers/api/giveKeyChainTriggeredItemsController"; import { IKeyChainRequest } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
import { toOid } from "../helpers/inventoryHelpers"; import { toOid } from "../helpers/inventoryHelpers";
import { generateRewardSeed } from "@/src/controllers/api/getNewRewardSeedController";
import { addStartingGear } from "@/src/controllers/api/giveStartingGearController";
import { completeQuest } from "@/src/services/questService";
export const createInventory = async ( export const createInventory = async (
accountOwnerId: Types.ObjectId, accountOwnerId: Types.ObjectId,
@ -65,65 +70,18 @@ export const createInventory = async (
ReceivedStartingGear: config.skipTutorial ReceivedStartingGear: config.skipTutorial
}); });
inventory.LibraryAvailableDailyTaskInfo = createLibraryAvailableDailyTaskInfo();
inventory.CalendarProgress = createCalendar();
inventory.RewardSeed = generateRewardSeed();
inventory.DuviriInfo = {
Seed: generateRewardSeed(),
NumCompletions: 0
};
await addItem(inventory, "/Lotus/Types/Friendly/PlayerControllable/Weapons/DuviriDualSwords");
if (config.skipTutorial) { if (config.skipTutorial) {
const defaultEquipment = [ await addStartingGear(inventory);
// Awakening rewards await completeQuest(inventory, "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain");
{ ItemCount: 1, ItemType: "/Lotus/Powersuits/Excalibur/Excalibur" },
{ ItemCount: 1, ItemType: "/Lotus/Weapons/Tenno/Melee/LongSword/LongSword" },
{ ItemCount: 1, ItemType: "/Lotus/Weapons/Tenno/Pistol/Pistol" },
{ ItemCount: 1, ItemType: "/Lotus/Weapons/Tenno/Rifle/Rifle" },
{ ItemCount: 1, ItemType: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem1" },
{ ItemCount: 1, ItemType: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem2" },
{ ItemCount: 1, ItemType: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem3" },
{ ItemCount: 1, ItemType: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem4" },
{ ItemCount: 1, ItemType: "/Lotus/Types/Restoratives/LisetAutoHack" }
];
// const vorsPrizeRewards = [
// // Vor's Prize rewards
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarHealthMaxMod" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarShieldMaxMod" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarAbilityRangeMod" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarAbilityStrengthMod" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarAbilityDurationMod" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarPickupBonusMod" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarPowerMaxMod" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarEnemyRadarMod" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Melee/WeaponFireRateMod" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Melee/WeaponMeleeDamageMod" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Rifle/WeaponFactionDamageCorpus" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Rifle/WeaponFactionDamageGrineer" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Rifle/WeaponDamageAmountMod" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Pistol/WeaponFireDamageMod" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Pistol/WeaponElectricityDamageMod" },
// { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Pistol/WeaponDamageAmountMod" },
// { ItemCount: 1, ItemType: "/Lotus/Types/Recipes/Weapons/BurstonRifleBlueprint" },
// { ItemCount: 1, ItemType: "/Lotus/Types/Items/MiscItems/Morphic" },
// { ItemCount: 400, ItemType: "/Lotus/Types/Items/MiscItems/PolymerBundle" },
// { ItemCount: 150, ItemType: "/Lotus/Types/Items/MiscItems/AlloyPlate" }
// ];
for (const equipment of defaultEquipment) {
await addItem(inventory, equipment.ItemType, equipment.ItemCount);
}
// Missing in Public Export
inventory.Horses.push({
ItemType: "/Lotus/Types/NeutralCreatures/ErsatzHorse/ErsatzHorsePowerSuit"
});
inventory.DataKnives.push({
ItemType: "/Lotus/Weapons/Tenno/HackingDevices/TnHackingDevice/TnHackingDeviceWeapon",
XP: 450000
});
inventory.Scoops.push({
ItemType: "/Lotus/Weapons/Tenno/Speedball/SpeedballWeaponTest"
});
inventory.DrifterMelee.push({
ItemType: "/Lotus/Types/Friendly/PlayerControllable/Weapons/DuviriDualSwords"
});
inventory.QuestKeys.push({
ItemType: "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain"
});
const completedMissions = ["SolNode27", "SolNode89", "SolNode63", "SolNode85", "SolNode15", "SolNode79"]; const completedMissions = ["SolNode27", "SolNode89", "SolNode63", "SolNode85", "SolNode15", "SolNode79"];
@ -133,14 +91,11 @@ export const createInventory = async (
Tag: tag Tag: tag
})) }))
); );
inventory.RegularCredits = 25000;
inventory.FusionPoints = 180;
} }
await inventory.save(); await inventory.save();
} catch (error) { } catch (error) {
throw new Error(`Error creating inventory: ${error instanceof Error ? error.message : "Unknown error"}`); throw new Error(`Error creating inventory: ${error instanceof Error ? error.message : "Unknown error type"}`);
} }
}; };
@ -150,6 +105,7 @@ export const createInventory = async (
* @param InventoryChanges - will hold the combined changes * @param InventoryChanges - will hold the combined changes
* @param delta - inventory changes to be added * @param delta - inventory changes to be added
*/ */
//TODO: this fails silently when providing an incorrect object to delta
export const combineInventoryChanges = (InventoryChanges: IInventoryChanges, delta: IInventoryChanges): void => { export const combineInventoryChanges = (InventoryChanges: IInventoryChanges, delta: IInventoryChanges): void => {
for (const key in delta) { for (const key in delta) {
if (!(key in InventoryChanges)) { if (!(key in InventoryChanges)) {
@ -779,15 +735,19 @@ export const addEquipment = (
category: TEquipmentKey, category: TEquipmentKey,
type: string, type: string,
modularParts: string[] | undefined = undefined, modularParts: string[] | undefined = undefined,
inventoryChanges: IInventoryChanges = {} inventoryChanges: IInventoryChanges = {},
defaultOverwrites: Partial<IEquipmentDatabase> | undefined = undefined
): IInventoryChanges => { ): IInventoryChanges => {
const index = const equipment = Object.assign(
inventory[category].push({ {
ItemType: type, ItemType: type,
Configs: [], Configs: [],
XP: 0, XP: 0,
ModularParts: modularParts ModularParts: modularParts
}) - 1; },
defaultOverwrites
);
const index = inventory[category].push(equipment) - 1;
inventoryChanges[category] ??= []; inventoryChanges[category] ??= [];
inventoryChanges[category].push(inventory[category][index].toJSON<IEquipmentClient>()); inventoryChanges[category].push(inventory[category][index].toJSON<IEquipmentClient>());
@ -1173,3 +1133,28 @@ export const addKeyChainItems = async (
return inventoryChanges; return inventoryChanges;
}; };
const createLibraryAvailableDailyTaskInfo = (): ILibraryAvailableDailyTaskInfo => {
return {
EnemyTypes: ["/Lotus/Types/Enemies/Orokin/RifleLancerAvatar"],
EnemyLocTag: "/Lotus/Language/Game/CorruptedLancer",
EnemyIcon: "/Lotus/Interface/Icons/Npcs/OrokinRifleLancerAvatar.png",
ScansRequired: 3,
RewardStoreItem: "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/UncommonFusionBundle",
RewardQuantity: 7,
RewardStanding: 7500
};
};
const createCalendar = (): ICalendarProgress => {
return {
Version: 19,
Iteration: 2,
YearProgress: { Upgrades: [] },
SeasonProgress: {
SeasonType: "CST_SPRING",
LastCompletedDayIdx: -1,
LastCompletedChallengeDayIdx: -1,
ActivatedChallenges: []
}
};
};

View File

@ -126,7 +126,8 @@ export const completeQuest = async (inventory: TInventoryDatabaseDocument, quest
}); });
} }
} }
//TODO: handle quest completions inventory.ActiveQuest = "";
//TODO: handle quest completion items
}; };
export const giveKeyChainItem = async (inventory: TInventoryDatabaseDocument, keyChainInfo: IKeyChainRequest) => { export const giveKeyChainItem = async (inventory: TInventoryDatabaseDocument, keyChainInfo: IKeyChainRequest) => {

View File

@ -38,6 +38,7 @@ export interface IInventoryDatabase
| "InfestedFoundry" | "InfestedFoundry"
| "DialogueHistory" | "DialogueHistory"
| "KubrowPetEggs" | "KubrowPetEggs"
| "PendingCoupon"
| TEquipmentKey | TEquipmentKey
>, >,
InventoryDatabaseEquipment { InventoryDatabaseEquipment {
@ -61,6 +62,7 @@ export interface IInventoryDatabase
InfestedFoundry?: IInfestedFoundryDatabase; InfestedFoundry?: IInfestedFoundryDatabase;
DialogueHistory?: IDialogueHistoryDatabase; DialogueHistory?: IDialogueHistoryDatabase;
KubrowPetEggs?: IKubrowPetEggDatabase[]; KubrowPetEggs?: IKubrowPetEggDatabase[];
PendingCoupon: IPendingCouponDatabase;
} }
export interface IQuestKeyDatabase { export interface IQuestKeyDatabase {
@ -318,11 +320,12 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
CollectibleSeries: ICollectibleSery[]; CollectibleSeries: ICollectibleSery[];
LibraryAvailableDailyTaskInfo: ILibraryAvailableDailyTaskInfo; LibraryAvailableDailyTaskInfo: ILibraryAvailableDailyTaskInfo;
HasResetAccount: boolean; HasResetAccount: boolean;
PendingCoupon: IPendingCoupon; PendingCoupon: IPendingCouponClient;
Harvestable: boolean; Harvestable: boolean;
DeathSquadable: boolean; DeathSquadable: boolean;
EndlessXP?: IEndlessXpProgress[]; EndlessXP?: IEndlessXpProgress[];
DialogueHistory?: IDialogueHistoryClient; DialogueHistory?: IDialogueHistoryClient;
CalendarProgress: ICalendarProgress;
} }
export interface IAffiliation { export interface IAffiliation {
@ -759,7 +762,12 @@ export enum Manifest {
LotusTypesGameNemesisKuvaLichKuvaLichManifestVersionTwo = "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionTwo" LotusTypesGameNemesisKuvaLichKuvaLichManifestVersionTwo = "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionTwo"
} }
export interface IPendingCoupon { export interface IPendingCouponDatabase {
Expiry: Date;
Discount: number;
}
export interface IPendingCouponClient {
Expiry: IMongoDate; Expiry: IMongoDate;
Discount: number; Discount: number;
} }
@ -858,6 +866,7 @@ export interface IPersonalTechProject {
} }
export interface IPlayerSkills { export interface IPlayerSkills {
LPP_NONE: number;
LPP_SPACE: number; LPP_SPACE: number;
LPS_PILOTING: number; LPS_PILOTING: number;
LPS_GUNNERY: number; LPS_GUNNERY: number;
@ -1042,3 +1051,16 @@ export interface IMarker {
z: number; z: number;
showInHud: boolean; showInHud: boolean;
} }
export interface ISeasonProgress {
SeasonType: "CST_UNDEFINED" | "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
LastCompletedDayIdx: number;
LastCompletedChallengeDayIdx: number;
ActivatedChallenges: unknown[];
}
export interface ICalendarProgress {
Version: number;
Iteration: number;
YearProgress: { Upgrades: unknown[] };
SeasonProgress: ISeasonProgress;
}

View File

@ -0,0 +1,12 @@
{
"Messages": [
{
"sub": "Welcome to Space Ninja Server",
"sndr": "/Lotus/Language/Bosses/Ordis",
"msg": "Enjoy your Space Ninja Experience",
"icon": "/Lotus/Interface/Icons/Npcs/Darvo.png",
"eventMessageDate": "2025-01-30T13:00:00.000Z",
"r": false
}
]
}

View File

@ -1,49 +0,0 @@
{
"Messages": [
{
"sub": "Welcome to Space Ninja Server",
"sndr": "/Lotus/Language/Bosses/Ordis",
"msg": "Enjoy your Space Ninja Experience",
"icon": "/Lotus/Interface/Icons/Npcs/Darvo.png",
"eventMessageDate": "2025-01-30T13:00:00.000Z",
"r": false
},
{
"sub": "/Lotus/Language/Inbox/DarvoWeaponCraftingMessageBTitle",
"sndr": "/Lotus/Language/Bosses/Darvo",
"msg": "/Lotus/Language/Inbox/DarvoWeaponCraftingMessageBDesc",
"icon": "/Lotus/Interface/Icons/Npcs/Darvo.png",
"countedAtt": [
{
"ItemCount": 1,
"ItemType": "/Lotus/Types/Recipes/Weapons/BurstonRifleBlueprint"
},
{
"ItemCount": 1,
"ItemType": "/Lotus/Types/Items/MiscItems/Morphic"
},
{
"ItemCount": 400,
"ItemType": "/Lotus/Types/Items/MiscItems/PolymerBundle"
},
{
"ItemCount": 150,
"ItemType": "/Lotus/Types/Items/MiscItems/AlloyPlate"
}
],
"highPriority": true,
"eventMessageDate": "2023-10-01T17:00:00.000Z",
"r": false
},
{
"sub": "/Lotus/Language/G1Quests/Beginner_Growth_Inbox_Title",
"sndr": "/Lotus/Language/Menu/Mailbox_WarframeSender",
"msg": "/Lotus/Language/G1Quests/Beginner_Growth_Inbox_Desc",
"icon": "/Lotus/Interface/Icons/Npcs/Lotus_d.png",
"transmission": "/Lotus/Sounds/Dialog/VorsPrize/DLisetPostAssassinate110Lotus",
"highPriority": true,
"eventMessageDate": "2023-09-01T17:00:00.000Z",
"r": false
}
]
}

View File

@ -473,6 +473,10 @@
<input class="form-check-input" type="checkbox" id="infiniteRegalAya" /> <input class="form-check-input" type="checkbox" id="infiniteRegalAya" />
<label class="form-check-label" for="infiniteRegalAya" data-loc="cheats_infiniteRegalAya"></label> <label class="form-check-label" for="infiniteRegalAya" data-loc="cheats_infiniteRegalAya"></label>
</div> </div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="infiniteHelminthMaterials" />
<label class="form-check-label" for="infiniteHelminthMaterials" data-loc="cheats_infiniteHelminthMaterials"></label>
</div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllShipFeatures" /> <input class="form-check-input" type="checkbox" id="unlockAllShipFeatures" />
<label class="form-check-label" for="unlockAllShipFeatures" data-loc="cheats_unlockAllShipFeatures"></label> <label class="form-check-label" for="unlockAllShipFeatures" data-loc="cheats_unlockAllShipFeatures"></label>

View File

@ -99,6 +99,7 @@ dict = {
cheats_infinitePlatinum: `Infinite Platinum`, cheats_infinitePlatinum: `Infinite Platinum`,
cheats_infiniteEndo: `Infinite Endo`, cheats_infiniteEndo: `Infinite Endo`,
cheats_infiniteRegalAya: `Infinite Regal Aya`, cheats_infiniteRegalAya: `Infinite Regal Aya`,
cheats_infiniteHelminthMaterials: `Infinite Helminth Materials`,
cheats_unlockAllShipFeatures: `Unlock All Ship Features`, cheats_unlockAllShipFeatures: `Unlock All Ship Features`,
cheats_unlockAllShipDecorations: `Unlock All Ship Decorations`, cheats_unlockAllShipDecorations: `Unlock All Ship Decorations`,
cheats_unlockAllFlavourItems: `Unlock All <abbr title=\"Animation Sets, Glyphs, Plattes, etc.\">Flavor Items</abbr>`, cheats_unlockAllFlavourItems: `Unlock All <abbr title=\"Animation Sets, Glyphs, Plattes, etc.\">Flavor Items</abbr>`,

View File

@ -100,6 +100,7 @@ dict = {
cheats_infinitePlatinum: `Бесконечная платина`, cheats_infinitePlatinum: `Бесконечная платина`,
cheats_infiniteEndo: `Бесконечное эндо`, cheats_infiniteEndo: `Бесконечное эндо`,
cheats_infiniteRegalAya: `Бесконечная Королевская Айя`, cheats_infiniteRegalAya: `Бесконечная Королевская Айя`,
cheats_infiniteHelminthMaterials: `[UNTRANSLATED] Infinite Helminth Materials`,
cheats_unlockAllShipFeatures: `Разблокировать все функции корабля`, cheats_unlockAllShipFeatures: `Разблокировать все функции корабля`,
cheats_unlockAllShipDecorations: `Разблокировать все украшения корабля`, cheats_unlockAllShipDecorations: `Разблокировать все украшения корабля`,
cheats_unlockAllFlavourItems: `Разблокировать все <abbr title=\"Наборы анимаций, глифы, палитры и т. д.\">уникальные предметы</abbr>`, cheats_unlockAllFlavourItems: `Разблокировать все <abbr title=\"Наборы анимаций, глифы, палитры и т. д.\">уникальные предметы</abbr>`,