feat: implement awakening quest completion (/api/giveStartingGear) #977

Closed
neon wants to merge 3 commits from neon/SpaceNinjaServer:starting-gear into main
3 changed files with 214 additions and 4 deletions

View File

@ -0,0 +1,208 @@
import { config } from "@/src/services/configService";
import { toOid } from "@/src/helpers/inventoryHelpers";
import { IOid } from "@/src/types/commonTypes";
import { Types } from "mongoose";
import { RequestHandler } from "express";
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
import {
IDailyAffiliations,
IInventoryClient,
IPlayerSkills,
ITypeCount
} from "@/src/types/inventoryTypes/inventoryTypes";
import { addConsumables, addKeyChainItems, addMods, getInventory } from "@/src/services/inventoryService";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { getAccountIdForRequest } from "@/src/services/loginService";
export const giveStartingGearController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId);
const dataJSON = getJSONfromString<IStartingGearClient>(String(req.body));
for (const key of Object.keys(dataJSON) as Array<keyof IStartingGearClient>) {
Review

this should not be here, the game handles trigger items itself.

this should not be here, the game handles trigger items itself.
Review

if youre talking about missionInventoryUpdate, then no. the awakening quest doesnt call that. this is why it needs to be done here.

if youre talking about missionInventoryUpdate, then no. the awakening quest doesnt call that. this is why it needs to be done here.
Review

if youre talking about missionInventoryUpdate, then no. the awakening quest doesnt call that. this is why it needs to be done here.

What mission inventory update?
I marked the line addKeychain Items, this is not meant to be done here.

> if youre talking about missionInventoryUpdate, then no. the awakening quest doesnt call that. this is why it needs to be done here. What mission inventory update? I marked the line addKeychain Items, this is not meant to be done here.
Review

Where else would u do it?

Where else would u do it?
Review

Not at all, because, as I said "the game handles trigger items itself."

Not at all, because, as I said "the game handles trigger items itself."
Review

try it without but it didnt work for me

try it without but it didnt work for me
switch (key) {
// This is the only gear we receive as the rest will come from future quests
case "LongGuns":
case "Pistols":
case "Melee":
case "Suits":
// Filter out already owned items (shouldnt happen but this was mostly for testing)
const existingItems = new Set(inventory[key].map(item => item.ItemType));
// Adding items to inventory
inventory[key].push(
...dataJSON[key]
.filter(item => !existingItems.has(item.ItemType))
.map(x => ({
_id: new Types.ObjectId(),
ItemType: x.ItemType,
XP: x.XP,
Configs: [{}, {}, {}]
}))
);
}
}
// Give the Arsenal Segment which is given after the Awakening. (MissionInventoryUpdate doesnt get called so we can't do it there)
await addKeyChainItems(inventory, {
KeyChain: "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain",
ChainStage: 0 // /Lotus/Types/Keys/VorsPrize/MissionOne
});
addConsumables(inventory, [{ ItemCount: 1, ItemType: "/Lotus/Types/Restoratives/LisetAutoHack" }]);
if (!config.unlockAllFlavourItems) {
inventory.FlavourItems.push([
{ ItemType: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem1" },
{ ItemType: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem2" },
{ ItemType: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem3" },
{ ItemType: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem4" }
]);
}
addMods(inventory, [
{
ItemCount: 1,
ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarShieldMaxMod",
LastAdded: toOid(new Types.ObjectId())
}
]);
inventory.DrifterMelee.push({
ItemType: "/Lotus/Types/Friendly/PlayerControllable/Weapons/DuviriDualSwords",
_id: new Types.ObjectId()
});
inventory.PlayedParkourTutorial = true;
inventory.ReceivedStartingGear = true;
inventory.TrainingDate = new Date();
inventory.QuestKeys.push({
Progress: [{ i: true }],
unlock: false,
ItemType: "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain"
});
await inventory.save();
res.json({});
};
// Alot of stuff is not received in the request, instead of being redundant I will just omit an already created type (pain)
interface IStartingGearClient
extends Omit<
IInventoryClient,
| keyof IDailyAffiliations
| "Missions"
| "RandomUpgradesIdentified"
| "LastRegionPlayed"
| "TradesRemaining"
| "DailyFocus"
| "GiftsRemaining"
| "HasOwnedVoidProjectionsPreviously"
| "ChallengesFixVersion"
| "ChallengeProgress"
| "ReceivedStartingGear"
| "PendingRecipes"
| "PendingTrades"
| "DeathMarks"
| "WebFlags"
| "CompletedAlerts"
| "TauntHistory"
| "StoryModeChoice"
| "PeriodicMissionCompletions"
| "ActiveDojoColorResearch"
| "SentientSpawnChanceBoosters"
| "SupportedSyndicate"
| "Affiliations"
| "QualifyingInvasions"
| "FactionScores"
| "ArchwingEnabled"
| "PendingSpectreLoadouts"
| "SpectreLoadouts"
| "CompletedSyndicates"
| "FocusXP"
| "Alignment"
| "CompletedSorties"
| "LastSortieReward"
| "ActiveAvatarImageType"
| "DiscoveredMarkers"
| "CompletedJobs"
| "FocusAbility"
| "HasContributedToDojo"
| "HWIDProtectEnabled"
| "AlignmentReplay"
| "PersonalGoalProgress"
| "ThemeStyle"
| "ThemeBackground"
| "ThemeSounds"
| "BountyScore"
| "ChallengeInstanceStates"
| "LoginMilestoneRewards"
| "NodeIntrosCompleted"
| "GuildId"
| "CompletedJobChains"
| "SeasonChallengeHistory"
| "EquippedInstrument"
| "InvasionChainProgress"
| "NemesisHistory"
| "LastNemesisAllySpawnTime"
| "Settings"
| "PersonalTechProjects"
| "PlayerSkills"
| "TradeBannedUntil"
| "PlayedParkourTutorial"
| "SubscribedToEmailsPersonalized"
| "BlessingCooldown"
| "NemesisAbandonedRewards"
| "LastInventorySync"
| "NextRefill"
| "CustomMarkers"
| "ActiveLandscapeTraps"
| "EvolutionProgress"
| "RepVotes"
| "UsedDailyDeals"
| "LibraryPersonalTarget"
| "LibraryPersonalProgress"
| "CollectibleSeries"
| "LibraryAvailableDailyTaskInfo"
| "HasResetAccount"
| "PendingCoupon"
| "Harvestable"
| "DeathSquadable"
| "EndlessXP"
| "DialogueHistory"
> {
LongGuns: IStartingGearItem[];
Melee: IStartingGearItem[];
Pistols: IStartingGearItem[];
Suits: IStartingGearItem[];
XPLost?: unknown[];
CrewShipFusionPoints?: number;
PlayerSkillGains?: IPlayerSkills[];
// Lot's of unknown but these never receive data (at least not in this request)
StrippedItems?: unknown[];
BonusMiscItems?: unknown[];
EmailItems: ITypeCount[];
OneTimePurchases?: unknown[];
Rating?: number;
WishlistChanges?: unknown[];
RecentVendorPurchases: (string | number)[];
RemovedIdItems?: { ItemId: number }[];
SongChallenges?: unknown[];
}
interface IStartingGearItem
extends Omit<
IEquipmentClient,
| "_id"
| "InfestationDate"
| "InfestationDays"
| "InfestationType"
| "UnlockLevel"
| "Weapon"
| "Customization"
| "RailjackImage"
| "CrewMembers"
| "Details"
> {
// Warframe sends an ItemId instead _id, it will be converted to _id before being pushed to the inventory
ItemId: IOid;
Favorite?: boolean;
}

View File

@ -35,6 +35,7 @@ import { gildWeaponController } from "@/src/controllers/api/gildWeaponController
import { giveKeyChainTriggeredItemsController } from "@/src/controllers/api/giveKeyChainTriggeredItemsController"; import { giveKeyChainTriggeredItemsController } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
import { giveKeyChainTriggeredMessageController } from "@/src/controllers/api/giveKeyChainTriggeredMessageController"; import { giveKeyChainTriggeredMessageController } from "@/src/controllers/api/giveKeyChainTriggeredMessageController";
import { giveQuestKeyRewardController } from "@/src/controllers/api/giveQuestKey"; import { giveQuestKeyRewardController } from "@/src/controllers/api/giveQuestKey";
import { giveStartingGearController } from "../controllers/api/giveStartingGear";
import { guildTechController } from "../controllers/api/guildTechController"; import { guildTechController } from "../controllers/api/guildTechController";
import { hostSessionController } from "@/src/controllers/api/hostSessionController"; import { hostSessionController } from "@/src/controllers/api/hostSessionController";
import { hubController } from "@/src/controllers/api/hubController"; import { hubController } from "@/src/controllers/api/hubController";
@ -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

@ -914,10 +914,10 @@ export interface IQuestKeyClient extends Omit<IQuestKeyDatabase, "CompletionDate
} }
export interface IQuestStage { export interface IQuestStage {
c?: number; c?: number; // Completed?
i?: boolean; i?: boolean; // keyChainItemsGiven?
m?: boolean; m?: boolean; // keyChainMessage[Given](Sent)?
b?: any[]; b?: any[]; // unknown/unused
} }
export interface IRawUpgrade { export interface IRawUpgrade {