diff --git a/src/controllers/api/createGuildController.ts b/src/controllers/api/createGuildController.ts index 0db8799b..fb9474c6 100644 --- a/src/controllers/api/createGuildController.ts +++ b/src/controllers/api/createGuildController.ts @@ -5,11 +5,23 @@ import { Guild, GuildMember } from "../../models/guildModel.ts"; import { createUniqueClanName, getGuildClient, giveClanKey } from "../../services/guildService.ts"; import { getInventory } from "../../services/inventoryService.ts"; import type { IInventoryChanges } from "../../types/purchaseTypes.ts"; +import { sendWsBroadcastTo } from "../../services/wsService.ts"; export const createGuildController: RequestHandler = async (req, res) => { const account = await getAccountForRequest(req); const payload = getJSONfromString(String(req.body)); + const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes"); + if (inventory.GuildId) { + const guild = await Guild.findById(inventory.GuildId); + if (guild) { + res.json({ + ...(await getGuildClient(guild, account)) + }); + return; + } + } + // Remove pending applications for this account await GuildMember.deleteMany({ accountId: account._id, status: 1 }); @@ -27,7 +39,6 @@ export const createGuildController: RequestHandler = async (req, res) => { rank: 0 }); - const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes"); inventory.GuildId = guild._id; const inventoryChanges: IInventoryChanges = {}; giveClanKey(inventory, inventoryChanges); @@ -37,6 +48,7 @@ export const createGuildController: RequestHandler = async (req, res) => { ...(await getGuildClient(guild, account)), InventoryChanges: inventoryChanges }); + sendWsBroadcastTo(account._id.toString(), { update_inventory: true }); }; interface ICreateGuildRequest { diff --git a/src/controllers/api/inventoryController.ts b/src/controllers/api/inventoryController.ts index 76484e6f..f5b2b2b3 100644 --- a/src/controllers/api/inventoryController.ts +++ b/src/controllers/api/inventoryController.ts @@ -461,6 +461,9 @@ export const getInventoryResponse = async ( toLegacyOid(id); } } + if (inventoryResponse.GuildId) { + toLegacyOid(inventoryResponse.GuildId); + } } } } diff --git a/src/controllers/api/missionInventoryUpdateController.ts b/src/controllers/api/missionInventoryUpdateController.ts index 3633e02a..eb912e40 100644 --- a/src/controllers/api/missionInventoryUpdateController.ts +++ b/src/controllers/api/missionInventoryUpdateController.ts @@ -129,14 +129,22 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res) res.json(deltas); } else if (missionReport.RewardInfo) { logger.debug(`classic mission completion, sending everything`); - const inventoryResponse = await getInventoryResponse(inventory, true, account.BuildLabel); + const inventoryResponse = await getInventoryResponse( + inventory, + "xpBasedLevelCapDisabled" in req.query, + account.BuildLabel + ); res.json({ InventoryJson: JSON.stringify(inventoryResponse), ...deltas } satisfies IMissionInventoryUpdateResponse); } else { logger.debug(`no reward info, assuming this wasn't a mission completion and we should just sync inventory`); - const inventoryResponse = await getInventoryResponse(inventory, true, account.BuildLabel); + const inventoryResponse = await getInventoryResponse( + inventory, + "xpBasedLevelCapDisabled" in req.query, + account.BuildLabel + ); res.json({ InventoryJson: JSON.stringify(inventoryResponse) } satisfies IMissionInventoryUpdateResponseBackToDryDock); diff --git a/src/controllers/api/nemesisController.ts b/src/controllers/api/nemesisController.ts index cc5602ba..2388d0a7 100644 --- a/src/controllers/api/nemesisController.ts +++ b/src/controllers/api/nemesisController.ts @@ -310,6 +310,17 @@ export const nemesisController: RequestHandler = async (req, res) => { res.json({ target: inventory.toJSON().Nemesis }); + } else if ((req.query.mode as string) == "d") { + const inventory = await getInventory(account._id.toString(), "NemesisHistory"); + const body = getJSONfromString(String(req.body)); + for (const fp of body.nemesisFingerprints) { + const index = inventory.NemesisHistory!.findIndex(x => x.fp == fp); + if (index != -1) { + inventory.NemesisHistory!.splice(index, 1); + } + } + await inventory.save(); + res.json(body); } else if ((req.query.mode as string) == "w") { const inventory = await getInventory(account._id.toString(), "Nemesis"); //const body = getJSONfromString(String(req.body)); @@ -447,3 +458,7 @@ const consumeModCharge = ( response.UpgradeNew.push(true); } }; + +interface IRelinquishAdversariesRequest { + nemesisFingerprints: (bigint | number)[]; +} diff --git a/src/controllers/api/removeFromGuildController.ts b/src/controllers/api/removeFromGuildController.ts index 9535d4d7..7d4917d0 100644 --- a/src/controllers/api/removeFromGuildController.ts +++ b/src/controllers/api/removeFromGuildController.ts @@ -10,6 +10,7 @@ import { import { createMessage } from "../../services/inboxService.ts"; import { getInventory } from "../../services/inventoryService.ts"; import { getAccountForRequest, getSuffixedName } from "../../services/loginService.ts"; +import { sendWsBroadcastTo } from "../../services/wsService.ts"; import { GuildPermission } from "../../types/guildTypes.ts"; import type { RequestHandler } from "express"; @@ -85,6 +86,7 @@ export const removeFromGuildController: RequestHandler = async (req, res) => { ItemToRemove: "/Lotus/Types/Keys/DojoKey", RecipeToRemove: "/Lotus/Types/Keys/DojoKeyBlueprint" }); + sendWsBroadcastTo(payload.userId, { update_inventory: true }); }; interface IRemoveFromGuildRequest { diff --git a/src/controllers/api/startDojoRecipeController.ts b/src/controllers/api/startDojoRecipeController.ts index bfca8b08..dd5de407 100644 --- a/src/controllers/api/startDojoRecipeController.ts +++ b/src/controllers/api/startDojoRecipeController.ts @@ -13,6 +13,7 @@ import { Types } from "mongoose"; import { ExportDojoRecipes } from "warframe-public-export-plus"; import { getAccountForRequest } from "../../services/loginService.ts"; import { getInventory } from "../../services/inventoryService.ts"; +import { fromOid } from "../../helpers/inventoryHelpers.ts"; interface IStartDojoRecipeRequest { PlacedComponent: IDojoComponentClient; @@ -50,7 +51,7 @@ export const startDojoRecipeController: RequestHandler = async (req, res) => { _id: componentId, pf: request.PlacedComponent.pf, ppf: request.PlacedComponent.ppf, - pi: new Types.ObjectId(request.PlacedComponent.pi!.$oid), + pi: new Types.ObjectId(fromOid(request.PlacedComponent.pi!)), op: request.PlacedComponent.op, pp: request.PlacedComponent.pp, DecoCapacity: room?.decoCapacity diff --git a/src/controllers/custom/setAccountCheatController.ts b/src/controllers/custom/setAccountCheatController.ts index 586cebb6..efd7f6c8 100644 --- a/src/controllers/custom/setAccountCheatController.ts +++ b/src/controllers/custom/setAccountCheatController.ts @@ -1,6 +1,6 @@ import { getInventory } from "../../services/inventoryService.ts"; import { getAccountIdForRequest } from "../../services/loginService.ts"; -import { sendWsBroadcastTo } from "../../services/wsService.ts"; +import { sendWsBroadcastEx, sendWsBroadcastTo } from "../../services/wsService.ts"; import type { IAccountCheats } from "../../types/inventoryTypes/inventoryTypes.ts"; import type { RequestHandler } from "express"; import { logger } from "../../utils/logger.ts"; @@ -20,6 +20,8 @@ export const setAccountCheatController: RequestHandler = async (req, res) => { res.end(); if (["infiniteCredits", "infinitePlatinum", "infiniteEndo", "infiniteRegalAya"].indexOf(payload.key) != -1) { sendWsBroadcastTo(accountId, { update_inventory: true, sync_inventory: true }); + } else { + sendWsBroadcastEx({ update_inventory: true }, accountId, parseInt(String(req.query.wsid))); } }; diff --git a/src/services/guildService.ts b/src/services/guildService.ts index 8f609877..8c5f13a0 100644 --- a/src/services/guildService.ts +++ b/src/services/guildService.ts @@ -22,7 +22,7 @@ import type { ITechProjectDatabase } from "../types/guildTypes.ts"; import { GuildPermission } from "../types/guildTypes.ts"; -import { toMongoDate, toOid, toOid2 } from "../helpers/inventoryHelpers.ts"; +import { toMongoDate, toOid, toOid2, version_compare } from "../helpers/inventoryHelpers.ts"; import type { Types } from "mongoose"; import type { IDojoBuild, IDojoResearch } from "warframe-public-export-plus"; import { ExportDojoRecipes, ExportResources } from "warframe-public-export-plus"; @@ -68,9 +68,15 @@ export const getGuildClient = async ( let missingEntry = true; const dataFillInPromises: Promise[] = []; for (const guildMember of guildMembers) { + // Use 1-based indexing for clan ranks for versions before U24. In my testing, 2018.06.14.23.21 and below used 1-based indexing and 2019.04.04.21.31 and above used 0-based indexing. I didn't narrow it down further, but I think U24 is a good spot for them to have changed it. + let rankBase = 0; + if (account.BuildLabel && version_compare(account.BuildLabel, "2018.11.08.14.45") < 0) { + rankBase += 1; + } + const member: IGuildMemberClient = { _id: toOid2(guildMember.accountId, account.BuildLabel), - Rank: guildMember.rank, + Rank: guildMember.rank + rankBase, Status: guildMember.status, Note: guildMember.RequestMsg, RequestExpiry: guildMember.RequestExpiry ? toMongoDate(guildMember.RequestExpiry) : undefined diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index e3621a8e..0c2a4f4c 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -309,9 +309,6 @@ export const addMissionInventoryUpdates = async ( } break; } - case "Missions": - addMissionComplete(inventory, value); - break; case "LastRegionPlayed": if (!(config.unfaithfulBugFixes?.ignore1999LastRegionPlayed && value === "1999MapName")) { inventory.LastRegionPlayed = value; @@ -1229,6 +1226,9 @@ export const addMissionRewards = async ( if (missions && missions.Tag in ExportRegions) { const node = ExportRegions[missions.Tag]; + // cannot add this with normal updates because { Tier: 1 } would mark the SP node as completed even on a failure + addMissionComplete(inventory, missions); + //node based credit rewards for mission completion if (isEligibleForCreditReward(rewardInfo, missions, node)) { const levelCreditReward = getLevelCreditRewards(node); diff --git a/static/webui/script.js b/static/webui/script.js index c6400db7..a2615eef 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -1202,7 +1202,7 @@ function updateInventory() { a.href = "#"; a.onclick = function (event) { event.preventDefault(); - doQuestUpdate("setInactive", item.ItemType); + debounce(doQuestUpdate, "setInactive", item.ItemType); }; a.title = loc("code_setInactive"); a.innerHTML = ``; @@ -1213,7 +1213,7 @@ function updateInventory() { a.href = "#"; a.onclick = function (event) { event.preventDefault(); - doQuestUpdate("resetKey", item.ItemType); + debounce(doQuestUpdate, "resetKey", item.ItemType); }; a.title = loc("code_reset"); a.innerHTML = ``; @@ -1224,7 +1224,7 @@ function updateInventory() { a.href = "#"; a.onclick = function (event) { event.preventDefault(); - doQuestUpdate("completeKey", item.ItemType); + debounce(doQuestUpdate, "completeKey", item.ItemType); }; a.title = loc("code_complete"); a.innerHTML = ``; @@ -1235,7 +1235,7 @@ function updateInventory() { a.href = "#"; a.onclick = function (event) { event.preventDefault(); - doQuestUpdate("prevStage", item.ItemType); + debounce(doQuestUpdate, "prevStage", item.ItemType); }; a.title = loc("code_prevStage"); a.innerHTML = ``; @@ -1250,7 +1250,7 @@ function updateInventory() { a.href = "#"; a.onclick = function (event) { event.preventDefault(); - doQuestUpdate("nextStage", item.ItemType); + debounce(doQuestUpdate, "nextStage", item.ItemType); }; a.title = loc("code_nextStage"); a.innerHTML = ``; @@ -1262,7 +1262,7 @@ function updateInventory() { a.onclick = function (event) { event.preventDefault(); reAddToItemList(itemMap, "QuestKeys", item.ItemType); - doQuestUpdate("deleteKey", item.ItemType); + debounce(doQuestUpdate, "deleteKey", item.ItemType); }; a.title = loc("code_remove"); a.innerHTML = ``; @@ -3195,13 +3195,16 @@ function doIntrinsicsUnlockAll() { document.querySelectorAll("#account-cheats input[type=checkbox]").forEach(elm => { elm.onchange = function () { revalidateAuthz().then(() => { + const value = elm.checked; $.post({ url: "/custom/setAccountCheat?" + window.authz, contentType: "application/json", data: JSON.stringify({ key: elm.id, - value: elm.checked + value: value }) + }).done(() => { + elm.checked = value; }); }); }; @@ -3237,6 +3240,8 @@ document.querySelectorAll("#account-cheats .input-group").forEach(grp => { key: input.id, value: parseInt(value) }) + }).done(() => { + btn.value = value; }); }); };