diff --git a/src/controllers/api/abandonLibraryDailyTaskController.ts b/src/controllers/api/abandonLibraryDailyTaskController.ts new file mode 100644 index 000000000..ac5156094 --- /dev/null +++ b/src/controllers/api/abandonLibraryDailyTaskController.ts @@ -0,0 +1,11 @@ +import { getInventory } from "@/src/services/inventoryService"; +import { getAccountIdForRequest } from "@/src/services/loginService"; +import { RequestHandler } from "express"; + +export const abandonLibraryDailyTaskController: RequestHandler = async (req, res) => { + const accountId = await getAccountIdForRequest(req); + const inventory = await getInventory(accountId); + inventory.LibraryActiveDailyTaskInfo = undefined; + await inventory.save(); + res.status(200).end(); +}; diff --git a/src/controllers/api/claimLibraryDailyTaskRewardController.ts b/src/controllers/api/claimLibraryDailyTaskRewardController.ts new file mode 100644 index 000000000..6d8e1d419 --- /dev/null +++ b/src/controllers/api/claimLibraryDailyTaskRewardController.ts @@ -0,0 +1,31 @@ +import { getInventory } from "@/src/services/inventoryService"; +import { getAccountIdForRequest } from "@/src/services/loginService"; +import { RequestHandler } from "express"; + +export const claimLibraryDailyTaskRewardController: RequestHandler = async (req, res) => { + const accountId = await getAccountIdForRequest(req); + const inventory = await getInventory(accountId); + + const rewardQuantity = inventory.LibraryActiveDailyTaskInfo!.RewardQuantity; + const rewardStanding = inventory.LibraryActiveDailyTaskInfo!.RewardStanding; + inventory.LibraryActiveDailyTaskInfo = undefined; + inventory.LibraryAvailableDailyTaskInfo = undefined; + + let syndicate = inventory.Affiliations.find(x => x.Tag == "LibrarySyndicate"); + if (!syndicate) { + syndicate = inventory.Affiliations[inventory.Affiliations.push({ Tag: "LibrarySyndicate", Standing: 0 }) - 1]; + } + syndicate.Standing += rewardStanding; + + inventory.FusionPoints += 80 * rewardQuantity; + await inventory.save(); + + res.json({ + RewardItem: "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/RareFusionBundle", + RewardQuantity: rewardQuantity, + StandingAwarded: rewardStanding, + InventoryChanges: { + FusionPoints: 80 * rewardQuantity + } + }); +}; diff --git a/src/controllers/api/inventoryController.ts b/src/controllers/api/inventoryController.ts index 82b55ff56..0b33eba4b 100644 --- a/src/controllers/api/inventoryController.ts +++ b/src/controllers/api/inventoryController.ts @@ -14,7 +14,7 @@ import { ExportVirtuals } from "warframe-public-export-plus"; import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "./infestedFoundryController"; -import { allDailyAffiliationKeys } from "@/src/services/inventoryService"; +import { allDailyAffiliationKeys, createLibraryDailyTask } from "@/src/services/inventoryService"; export const inventoryController: RequestHandler = async (request, response) => { const account = await getAccountForRequest(request); @@ -36,6 +36,9 @@ export const inventoryController: RequestHandler = async (request, response) => inventory[key] = 16000 + inventory.PlayerLevel * 500; } inventory.DailyFocus = 250000 + inventory.PlayerLevel * 5000; + + inventory.LibraryAvailableDailyTaskInfo = createLibraryDailyTask(); + await inventory.save(); } diff --git a/src/controllers/api/startLibraryDailyTaskController.ts b/src/controllers/api/startLibraryDailyTaskController.ts new file mode 100644 index 000000000..e8b8425b8 --- /dev/null +++ b/src/controllers/api/startLibraryDailyTaskController.ts @@ -0,0 +1,11 @@ +import { getInventory } from "@/src/services/inventoryService"; +import { getAccountIdForRequest } from "@/src/services/loginService"; +import { RequestHandler } from "express"; + +export const startLibraryDailyTaskController: RequestHandler = async (req, res) => { + const accountId = await getAccountIdForRequest(req); + const inventory = await getInventory(accountId); + inventory.LibraryActiveDailyTaskInfo = inventory.LibraryAvailableDailyTaskInfo; + await inventory.save(); + res.json(inventory.LibraryAvailableDailyTaskInfo); +}; diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index a4c6557be..5ddfbdeca 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -68,7 +68,7 @@ import { ICalendarProgress, IPendingCouponDatabase, IPendingCouponClient, - ILibraryAvailableDailyTaskInfo, + ILibraryDailyTaskInfo, IDroneDatabase, IDroneClient } from "../../types/inventoryTypes/inventoryTypes"; @@ -950,11 +950,12 @@ pendingCouponSchema.set("toJSON", { } }); -const libraryAvailableDailyTaskInfoSchema = new Schema( +const libraryDailyTaskInfoSchema = new Schema( { EnemyTypes: [String], EnemyLocTag: String, EnemyIcon: String, + Scans: Number, ScansRequired: Number, RewardStoreItem: String, RewardQuantity: Number, @@ -1209,7 +1210,8 @@ const inventorySchema = new Schema( //Cephalon Simaris Entries Example:"TargetType"+"Scans"(1-10)+"Completed": true|false LibraryPersonalProgress: [Schema.Types.Mixed], //Cephalon Simaris Daily Task - LibraryAvailableDailyTaskInfo: libraryAvailableDailyTaskInfoSchema, + LibraryAvailableDailyTaskInfo: libraryDailyTaskInfoSchema, + LibraryActiveDailyTaskInfo: libraryDailyTaskInfoSchema, //https://warframe.fandom.com/wiki/Invasion InvasionChainProgress: [Schema.Types.Mixed], diff --git a/src/routes/api.ts b/src/routes/api.ts index 0a2c67167..335c59dfc 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -1,4 +1,5 @@ import express from "express"; +import { abandonLibraryDailyTaskController } from "@/src/controllers/api/abandonLibraryDailyTaskController"; import { activateRandomModController } from "@/src/controllers/api/activateRandomModController"; import { addFriendImageController } from "@/src/controllers/api/addFriendImageController"; import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController"; @@ -7,6 +8,7 @@ import { artifactsController } from "@/src/controllers/api/artifactsController"; import { changeDojoRootController } from "@/src/controllers/api/changeDojoRootController"; import { checkDailyMissionBonusController } from "@/src/controllers/api/checkDailyMissionBonusController"; import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController"; +import { claimLibraryDailyTaskRewardController } from "@/src/controllers/api/claimLibraryDailyTaskRewardController"; import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController"; import { completeRandomModChallengeController } from "@/src/controllers/api/completeRandomModChallengeController"; import { createGuildController } from "@/src/controllers/api/createGuildController"; @@ -75,6 +77,7 @@ import { setSupportedSyndicateController } from "@/src/controllers/api/setSuppor import { setWeaponSkillTreeController } from "@/src/controllers/api/setWeaponSkillTreeController"; import { shipDecorationsController } from "@/src/controllers/api/shipDecorationsController"; import { startDojoRecipeController } from "@/src/controllers/api/startDojoRecipeController"; +import { startLibraryDailyTaskController } from "@/src/controllers/api/startLibraryDailyTaskController"; import { startLibraryPersonalTargetController } from "@/src/controllers/api/startLibraryPersonalTargetController"; import { startRecipeController } from "@/src/controllers/api/startRecipeController"; import { stepSequencersController } from "@/src/controllers/api/stepSequencersController"; @@ -93,7 +96,9 @@ import { upgradesController } from "@/src/controllers/api/upgradesController"; const apiRouter = express.Router(); // get +apiRouter.get("/abandonLibraryDailyTask.php", abandonLibraryDailyTaskController); apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController); +apiRouter.get("/claimLibraryDailyTaskReward.php", claimLibraryDailyTaskRewardController); apiRouter.get("/credits.php", creditsController); apiRouter.get("/deleteSession.php", deleteSessionController); apiRouter.get("/dojo", dojoController); @@ -121,6 +126,7 @@ apiRouter.get("/setActiveQuest.php", setActiveQuestController); apiRouter.get("/setActiveShip.php", setActiveShipController); apiRouter.get("/setBootLocation.php", setBootLocationController); apiRouter.get("/setSupportedSyndicate.php", setSupportedSyndicateController); +apiRouter.get("/startLibraryDailyTask.php", startLibraryDailyTaskController); apiRouter.get("/startLibraryPersonalTarget.php", startLibraryPersonalTargetController); apiRouter.get("/surveys.php", surveysController); apiRouter.get("/updateSession.php", updateSessionGetController); diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 917a3934f..5370c74c6 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -23,7 +23,7 @@ import { IInventoryDatabase, IKubrowPetEggDatabase, IKubrowPetEggClient, - ILibraryAvailableDailyTaskInfo, + ILibraryDailyTaskInfo, ICalendarProgress, IDroneClient, IUpgradeClient @@ -42,6 +42,7 @@ import { ExportBundles, ExportCustoms, ExportDrones, + ExportEnemies, ExportFlavour, ExportFusionBundles, ExportGear, @@ -63,6 +64,8 @@ import { generateRewardSeed } from "@/src/controllers/api/getNewRewardSeedContro import { addStartingGear } from "@/src/controllers/api/giveStartingGearController"; import { addQuestKey, completeQuest } from "@/src/services/questService"; import { handleBundleAcqusition } from "./purchaseService"; +import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json"; +import { getRandomElement, getRandomInt } from "./rngService"; export const createInventory = async ( accountOwnerId: Types.ObjectId, @@ -77,7 +80,7 @@ export const createInventory = async ( ReceivedStartingGear: config.skipTutorial }); - inventory.LibraryAvailableDailyTaskInfo = createLibraryAvailableDailyTaskInfo(); + inventory.LibraryAvailableDailyTaskInfo = createLibraryDailyTask(); inventory.CalendarProgress = createCalendar(); inventory.RewardSeed = generateRewardSeed(); inventory.DuviriInfo = { @@ -1193,15 +1196,19 @@ export const addKeyChainItems = async ( return inventoryChanges; }; -const createLibraryAvailableDailyTaskInfo = (): ILibraryAvailableDailyTaskInfo => { + +export const createLibraryDailyTask = (): ILibraryDailyTaskInfo => { + const enemyTypes = getRandomElement(libraryDailyTasks); + const enemyAvatar = ExportEnemies.avatars[enemyTypes[0]]; + const scansRequired = getRandomInt(2, 4); 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 + EnemyTypes: enemyTypes, + EnemyLocTag: enemyAvatar.name, + EnemyIcon: enemyAvatar.icon!, + ScansRequired: scansRequired, + RewardStoreItem: "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/RareFusionBundle", + RewardQuantity: Math.trunc(scansRequired * 2.5), + RewardStanding: 2500 * scansRequired }; }; diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index da505c05c..774a5db08 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -185,6 +185,22 @@ export const addMissionInventoryUpdates = ( } }); break; + case "LibraryScans": + value.forEach(scan => { + if (inventory.LibraryActiveDailyTaskInfo) { + if (inventory.LibraryActiveDailyTaskInfo.EnemyTypes.find(x => x == scan.EnemyType)) { + inventory.LibraryActiveDailyTaskInfo.Scans ??= 0; + inventory.LibraryActiveDailyTaskInfo.Scans += scan.Count; + } else { + logger.warn( + `ignoring synthesis of ${scan.EnemyType} as it's not part of the active daily task` + ); + } + } else { + logger.warn(`no library daily task active, ignoring synthesis of ${scan.EnemyType}`); + } + }); + break; case "SyndicateId": { inventory.CompletedSyndicates.push(value); break; diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index e93f6b3c5..e9acbfc82 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -320,7 +320,8 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu LibraryPersonalTarget: string; LibraryPersonalProgress: ILibraryPersonalProgress[]; CollectibleSeries: ICollectibleSery[]; - LibraryAvailableDailyTaskInfo: ILibraryAvailableDailyTaskInfo; + LibraryAvailableDailyTaskInfo?: ILibraryDailyTaskInfo; + LibraryActiveDailyTaskInfo?: ILibraryDailyTaskInfo; HasResetAccount: boolean; PendingCoupon?: IPendingCouponClient; Harvestable: boolean; @@ -658,10 +659,11 @@ export interface ILastSortieReward { Manifest: string; } -export interface ILibraryAvailableDailyTaskInfo { +export interface ILibraryDailyTaskInfo { EnemyTypes: string[]; EnemyLocTag: string; EnemyIcon: string; + Scans?: number; ScansRequired: number; RewardStoreItem: string; RewardQuantity: number; diff --git a/src/types/requestTypes.ts b/src/types/requestTypes.ts index 0220240ac..7905dc230 100644 --- a/src/types/requestTypes.ts +++ b/src/types/requestTypes.ts @@ -92,6 +92,12 @@ export type IMissionInventoryUpdateRequest = { IsFinalWave: boolean; Participants: IVoidTearParticipantInfo[]; }; + LibraryScans?: { + EnemyType: string; + Count: number; + CodexScanCount: number; + Standing: number; + }[]; } & { [K in TEquipmentKey]?: IEquipmentClient[]; }; diff --git a/static/fixed_responses/libraryDailyTasks.json b/static/fixed_responses/libraryDailyTasks.json new file mode 100644 index 000000000..8e6df125f --- /dev/null +++ b/static/fixed_responses/libraryDailyTasks.json @@ -0,0 +1,148 @@ +[ + [ + "/Lotus/Types/Enemies/Corpus/BipedRobot/AIWeek/LaserCannonBipedAvatar", + "/Lotus/Types/Enemies/Corpus/BipedRobot/AIWeek/RailgunBipedAvatar", + "/Lotus/Types/Enemies/Corpus/BipedRobot/AIWeek/ShockwaveBipedAvatar" + ], + [ + "/Lotus/Types/Enemies/Corpus/BipedRobot/AIWeek/LaserDiscBipedAvatar" + ], + [ + "/Lotus/Types/Enemies/Corpus/BipedRobot/AIWeek/SuperMoaBipedAvatar" + ], + [ + "/Lotus/Types/Enemies/Corpus/Spaceman/EliteSpacemanAvatar", + "/Lotus/Types/Enemies/Corpus/Spaceman/AIWeek/RifleSpacemanAvatar", + "/Lotus/Types/Enemies/Corpus/Spaceman/AIWeek/DeployableSpacemanAvatar", + "/Lotus/Types/Enemies/Corpus/Spaceman/AIWeek/MeleeSpacemanAvatar", + "/Lotus/Types/Enemies/Corpus/Spaceman/AIWeek/ShotgunSpacemanAvatar", + "/Lotus/Types/Enemies/Corpus/Spaceman/AIWeek/SniperSpacemanAvatar" + ], + [ + "/Lotus/Types/Enemies/Corpus/Spaceman/AIWeek/NullifySpacemanAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/BeastMasterAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/BladeSawmanAvatar", + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/BlowtorchSawmanAvatar", + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/PistonSawmanAvatar", + "/Lotus/Types/Enemies/Grineer/Desert/Avatars/BladeSawmanAvatar", + "/Lotus/Types/Enemies/Grineer/Forest/Avatars/BladeSawmanAvatar", + "/Lotus/Types/Enemies/Grineer/SeaLab/Avatars/BladeSawmanAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/RifleLancerAvatar", + "/Lotus/Types/Enemies/Grineer/Desert/Avatars/EliteRifleLancerAvatar", + "/Lotus/Types/Enemies/Grineer/Desert/Avatars/RifleLancerAvatar", + "/Lotus/Types/Enemies/Grineer/Forest/Avatars/EliteRifleLancerAvatar", + "/Lotus/Types/Enemies/Grineer/Forest/Avatars/RifleLancerAvatar", + "/Lotus/Types/Enemies/Grineer/SeaLab/Avatars/EliteRifleLancerAvatar", + "/Lotus/Types/Enemies/Grineer/SeaLab/Avatars/RifleLancerAvatar", + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/EliteRifleLancerAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/EviseratorLancerAvatar", + "/Lotus/Types/Enemies/Grineer/Forest/Avatars/EvisceratorLancerAvatar", + "/Lotus/Types/Enemies/Grineer/SeaLab/Avatars/EvisceratorLancerAvatar", + "/Lotus/Types/Enemies/Grineer/Desert/Avatars/EvisceratorLancerAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/FemaleGrineerAvatar", + "/Lotus/Types/Enemies/Grineer/SeaLab/Avatars/FemaleGrineerSniperAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/FlameLancerAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/GrineerMeleeStaffAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/HeavyFemaleGrineerAvatar", + "/Lotus/Types/Enemies/Grineer/Desert/HeavyFemaleGrineerAvatarDesert", + "/Lotus/Types/Enemies/Grineer/Forest/HeavyFemaleGrineerAvatarDesert", + "/Lotus/Types/Enemies/Grineer/SeaLab/Avatars/FemaleGrineerHeavyAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/IncendiaryBombardAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/JetpackMarineAvatar", + "/Lotus/Types/Enemies/Grineer/Desert/Avatars/JetpackMarineAvatar", + "/Lotus/Types/Enemies/Grineer/Forest/Avatars/JetpackMarineAvatar", + "/Lotus/Types/Enemies/Grineer/SeaLab/Avatars/JetpackMarineAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/MacheteWomanAvatar", + "/Lotus/Types/Enemies/Grineer/SeaLab/Avatars/FemaleGrineerMacheteAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/ShieldLancerAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/ShotgunLancerAvatar", + "/Lotus/Types/Enemies/Grineer/Desert/Avatars/ShotgunLancerAvatar", + "/Lotus/Types/Enemies/Grineer/Forest/Avatars/ShotgunLancerAvatar", + "/Lotus/Types/Enemies/Grineer/SeaLab/Avatars/ShotgunLancerAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/GrineerAvatars/GrineerMarinePistolAvatar", + "/Lotus/Types/Enemies/Grineer/Desert/Avatars/GrineerMarinePistolAvatar", + "/Lotus/Types/Enemies/Grineer/Forest/Avatars/GrineerMarinePistolAvatar", + "/Lotus/Types/Enemies/Grineer/SeaLab/Avatars/GrineerMarinePistolAvatar" + ], + [ + "/Lotus/Types/Enemies/Infested/AiWeek/Ancients/AncientAvatar", + "/Lotus/Types/Enemies/Infested/AiWeek/Ancients/HealingAncientAvatar", + "/Lotus/Types/Enemies/Infested/AiWeek/Ancients/ToxicAncientAvatar" + ], + [ + "/Lotus/Types/Enemies/Infested/AiWeek/Ancients/DiseasedAncientAvatar" + ], + [ + "/Lotus/Types/Enemies/Infested/AiWeek/Ancients/SpawningAncientAvatar" + ], + [ + "/Lotus/Types/Enemies/Infested/AiWeek/Crawlers/CrawlerAvatar", + "/Lotus/Types/Enemies/Infested/AiWeek/Crawlers/NoxiousCrawlerAvatar", + "/Lotus/Types/Enemies/Infested/AiWeek/Crawlers/GraspingCrawlerAvatar", + "/Lotus/Types/Enemies/Infested/AiWeek/Crawlers/GrenadeAvatar", + "/Lotus/Types/Enemies/Infested/AiWeek/Crawlers/LightningAvatar" + ], + [ + "/Lotus/Types/Enemies/Infested/AiWeek/InfestedMoas/NaniteCloudBipedAvatar", + "/Lotus/Types/Enemies/Infested/AiWeek/InfestedMoas/SlowBombBipedAvatar" + ], + [ + "/Lotus/Types/Enemies/Infested/AiWeek/Quadrupeds/QuadrupedAvatar" + ], + [ + "/Lotus/Types/Enemies/Infested/AiWeek/Runners/LeapingRunnerAvatar", + "/Lotus/Types/Enemies/Infested/AiWeek/Runners/RunnerAvatar" + ], + [ + "/Lotus/Types/Enemies/Orokin/OrokinBladeSawmanAvatar" + ], + [ + "/Lotus/Types/Enemies/Orokin/OrokinHealingAncientAvatar" + ], + [ + "/Lotus/Types/Enemies/Orokin/OrokinHeavyFemaleAvatar" + ], + [ + "/Lotus/Types/Enemies/Orokin/OrokinNullifySpacemanAvatar" + ], + [ + "/Lotus/Types/Enemies/Orokin/OrokinRocketBombardAvatar" + ], + [ + "/Lotus/Types/Enemies/Orokin/RifleLancerAvatar" + ], + [ + "/Lotus/Types/Enemies/Orokin/RifleSpacemanAvatar" + ], + [ + "/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/RocketBombardAvatar" + ] +] \ No newline at end of file