feat: tutorial and natural new player experience #983
6
package-lock.json
generated
6
package-lock.json
generated
@ -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",
|
||||||
|
@ -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 };
|
|
||||||
|
96
src/controllers/api/giveStartingGearController.ts
Normal file
96
src/controllers/api/giveStartingGearController.ts
Normal 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;
|
||||||
|
};
|
@ -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": {
|
||||||
|
@ -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 } }
|
||||||
);
|
);
|
||||||
|
@ -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);
|
||||||
|
@ -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()}`);
|
||||||
|
@ -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: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -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) => {
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
12
static/fixed_responses/eventMessages.json
Normal file
12
static/fixed_responses/eventMessages.json
Normal 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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -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
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user