forked from OpenWF/SpaceNinjaServer
Compare commits
10 Commits
3a904753f2
...
9ea061fdb3
Author | SHA1 | Date | |
---|---|---|---|
9ea061fdb3 | |||
9de0aee6f0 | |||
69f544c8d1 | |||
8cdcb209ae | |||
ab0d472c75 | |||
e266f9e36c | |||
6a1e508109 | |||
a167216730 | |||
30ae95bec8 | |||
dcc2b903ac |
@ -25,7 +25,7 @@ export const addToGuildController: RequestHandler = async (req, res) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const guild = (await Guild.findById(payload.GuildId.$oid, "Name"))!;
|
const guild = (await Guild.findById(payload.GuildId.$oid, "Name Ranks"))!;
|
||||||
const senderAccount = await getAccountForRequest(req);
|
const senderAccount = await getAccountForRequest(req);
|
||||||
if (!(await hasGuildPermission(guild, senderAccount._id.toString(), GuildPermission.Recruiter))) {
|
if (!(await hasGuildPermission(guild, senderAccount._id.toString(), GuildPermission.Recruiter))) {
|
||||||
res.status(400).json("Invalid permission");
|
res.status(400).json("Invalid permission");
|
||||||
|
@ -28,7 +28,17 @@ export const createGuildController: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
await updateInventoryForConfirmedGuildJoin(accountId, guild._id);
|
await updateInventoryForConfirmedGuildJoin(accountId, guild._id);
|
||||||
|
|
||||||
res.json(await getGuildClient(guild, accountId));
|
res.json({
|
||||||
|
...(await getGuildClient(guild, accountId)),
|
||||||
|
InventoryChanges: {
|
||||||
|
Recipes: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ICreateGuildRequest {
|
interface ICreateGuildRequest {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getVendorManifestByTypeName } from "@/src/services/serversideVendorsService";
|
import { getVendorManifestByTypeName, preprocessVendorManifest } from "@/src/services/serversideVendorsService";
|
||||||
|
|
||||||
export const getVendorInfoController: RequestHandler = (req, res) => {
|
export const getVendorInfoController: RequestHandler = (req, res) => {
|
||||||
if (typeof req.query.vendor == "string") {
|
if (typeof req.query.vendor == "string") {
|
||||||
@ -7,7 +7,7 @@ export const getVendorInfoController: RequestHandler = (req, res) => {
|
|||||||
if (!manifest) {
|
if (!manifest) {
|
||||||
throw new Error(`Unknown vendor: ${req.query.vendor}`);
|
throw new Error(`Unknown vendor: ${req.query.vendor}`);
|
||||||
}
|
}
|
||||||
res.json(manifest);
|
res.json(preprocessVendorManifest(manifest));
|
||||||
} else {
|
} else {
|
||||||
res.status(400).end();
|
res.status(400).end();
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,8 @@ import {
|
|||||||
claimLoginReward,
|
claimLoginReward,
|
||||||
getRandomLoginRewards,
|
getRandomLoginRewards,
|
||||||
ILoginRewardsReponse,
|
ILoginRewardsReponse,
|
||||||
isLoginRewardAChoice
|
isLoginRewardAChoice,
|
||||||
|
setAccountGotLoginRewardToday
|
||||||
} from "@/src/services/loginRewardService";
|
} from "@/src/services/loginRewardService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
|
||||||
@ -44,8 +45,11 @@ export const loginRewardsController: RequestHandler = async (req, res) => {
|
|||||||
if (!isMilestoneDay && randomRewards.length == 1) {
|
if (!isMilestoneDay && randomRewards.length == 1) {
|
||||||
response.DailyTributeInfo.HasChosenReward = true;
|
response.DailyTributeInfo.HasChosenReward = true;
|
||||||
response.DailyTributeInfo.ChosenReward = randomRewards[0];
|
response.DailyTributeInfo.ChosenReward = randomRewards[0];
|
||||||
response.DailyTributeInfo.NewInventory = await claimLoginReward(account, inventory, randomRewards[0]);
|
response.DailyTributeInfo.NewInventory = await claimLoginReward(inventory, randomRewards[0]);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
|
setAccountGotLoginRewardToday(account);
|
||||||
|
await account.save();
|
||||||
}
|
}
|
||||||
res.json(response);
|
res.json(response);
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { claimLoginReward, getRandomLoginRewards } from "@/src/services/loginRewardService";
|
import {
|
||||||
|
claimLoginReward,
|
||||||
|
getRandomLoginRewards,
|
||||||
|
setAccountGotLoginRewardToday
|
||||||
|
} from "@/src/services/loginRewardService";
|
||||||
import { getAccountForRequest } from "@/src/services/loginService";
|
import { getAccountForRequest } from "@/src/services/loginService";
|
||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
@ -28,9 +32,13 @@ export const loginRewardsSelectionController: RequestHandler = async (req, res)
|
|||||||
} else {
|
} else {
|
||||||
const randomRewards = getRandomLoginRewards(account, inventory);
|
const randomRewards = getRandomLoginRewards(account, inventory);
|
||||||
chosenReward = randomRewards.find(x => x.StoreItemType == body.ChosenReward)!;
|
chosenReward = randomRewards.find(x => x.StoreItemType == body.ChosenReward)!;
|
||||||
inventoryChanges = await claimLoginReward(account, inventory, chosenReward);
|
inventoryChanges = await claimLoginReward(inventory, chosenReward);
|
||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
|
setAccountGotLoginRewardToday(account);
|
||||||
|
await account.save();
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
DailyTributeInfo: {
|
DailyTributeInfo: {
|
||||||
NewInventory: inventoryChanges,
|
NewInventory: inventoryChanges,
|
||||||
|
27
src/controllers/api/maturePetController.ts
Normal file
27
src/controllers/api/maturePetController.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
export const maturePetController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId, "KubrowPets");
|
||||||
|
const data = getJSONfromString<IMaturePetRequest>(String(req.body));
|
||||||
|
const details = inventory.KubrowPets.id(data.petId)!.Details!;
|
||||||
|
details.IsPuppy = data.revert;
|
||||||
|
await inventory.save();
|
||||||
|
res.json({
|
||||||
|
petId: data.petId,
|
||||||
|
updateCollar: true,
|
||||||
|
armorSkins: ["", "", ""],
|
||||||
|
furPatterns: data.revert
|
||||||
|
? ["", "", ""]
|
||||||
|
: [details.DominantTraits.FurPattern, details.DominantTraits.FurPattern, details.DominantTraits.FurPattern],
|
||||||
|
unmature: data.revert
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IMaturePetRequest {
|
||||||
|
petId: string;
|
||||||
|
revert: boolean;
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import { GuildMember } from "@/src/models/guildModel";
|
import { GuildMember } from "@/src/models/guildModel";
|
||||||
|
import { Inbox } from "@/src/models/inboxModel";
|
||||||
import { Account } from "@/src/models/loginModel";
|
import { Account } from "@/src/models/loginModel";
|
||||||
import { getGuildForRequest, hasGuildPermission } from "@/src/services/guildService";
|
import { getGuildForRequest, hasGuildPermission } from "@/src/services/guildService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
@ -28,7 +29,7 @@ export const removeFromGuildController: RequestHandler = async (req, res) => {
|
|||||||
} else {
|
} else {
|
||||||
const recipeIndex = inventory.Recipes.findIndex(x => x.ItemType == "/Lotus/Types/Keys/DojoKeyBlueprint");
|
const recipeIndex = inventory.Recipes.findIndex(x => x.ItemType == "/Lotus/Types/Keys/DojoKeyBlueprint");
|
||||||
if (recipeIndex != -1) {
|
if (recipeIndex != -1) {
|
||||||
inventory.Recipes.splice(itemIndex, 1);
|
inventory.Recipes.splice(recipeIndex, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +37,12 @@ export const removeFromGuildController: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
// TODO: Handle clan leader kicking themselves (guild should be deleted in this case, I think)
|
// TODO: Handle clan leader kicking themselves (guild should be deleted in this case, I think)
|
||||||
} else if (guildMember.status == 2) {
|
} else if (guildMember.status == 2) {
|
||||||
// TODO: Maybe the inbox message for the sent invite should be deleted?
|
// Delete the inbox message for the invite
|
||||||
|
await Inbox.deleteOne({
|
||||||
|
ownerId: guildMember.accountId,
|
||||||
|
contextInfo: guild._id.toString(),
|
||||||
|
acceptAction: "GUILD_INVITE"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
await GuildMember.deleteOne({ _id: guildMember._id });
|
await GuildMember.deleteOne({ _id: guildMember._id });
|
||||||
|
|
||||||
|
20
src/controllers/custom/addModularEquipmentController.ts
Normal file
20
src/controllers/custom/addModularEquipmentController.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { getInventory, addEquipment, occupySlot, productCategoryToInventoryBin } from "@/src/services/inventoryService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { modularWeaponTypes } from "@/src/helpers/modularWeaponHelper";
|
||||||
|
|
||||||
|
export const addModularEquipmentController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const request = req.body as IAddModularEquipmentRequest;
|
||||||
|
const inventory = await getInventory(accountId);
|
||||||
|
const category = modularWeaponTypes[request.ItemType];
|
||||||
|
addEquipment(inventory, category, request.ItemType, request.ModularParts);
|
||||||
|
occupySlot(inventory, productCategoryToInventoryBin(category)!, true);
|
||||||
|
await inventory.save();
|
||||||
|
res.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IAddModularEquipmentRequest {
|
||||||
|
ItemType: string;
|
||||||
|
ModularParts: string[];
|
||||||
|
}
|
@ -25,6 +25,7 @@ interface ListedItem {
|
|||||||
fusionLimit?: number;
|
fusionLimit?: number;
|
||||||
exalted?: string[];
|
exalted?: string[];
|
||||||
badReason?: "starter" | "frivolous" | "notraw";
|
badReason?: "starter" | "frivolous" | "notraw";
|
||||||
|
partType?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
||||||
@ -79,7 +80,8 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
) {
|
) {
|
||||||
res.ModularParts.push({
|
res.ModularParts.push({
|
||||||
uniqueName,
|
uniqueName,
|
||||||
name: getString(item.name, lang)
|
name: getString(item.name, lang),
|
||||||
|
partType: item.partType
|
||||||
});
|
});
|
||||||
if (uniqueName.split("/")[5] != "SentTrainingAmplifier") {
|
if (uniqueName.split("/")[5] != "SentTrainingAmplifier") {
|
||||||
res.miscitems.push({
|
res.miscitems.push({
|
||||||
|
@ -586,7 +586,8 @@ const spectreLoadoutsSchema = new Schema<ISpectreLoadout>(
|
|||||||
|
|
||||||
const weaponSkinsSchema = new Schema<IWeaponSkinDatabase>(
|
const weaponSkinsSchema = new Schema<IWeaponSkinDatabase>(
|
||||||
{
|
{
|
||||||
ItemType: String
|
ItemType: String,
|
||||||
|
IsNew: Boolean
|
||||||
},
|
},
|
||||||
{ id: false }
|
{ id: false }
|
||||||
);
|
);
|
||||||
|
@ -72,6 +72,7 @@ import { loginRewardsController } from "@/src/controllers/api/loginRewardsContro
|
|||||||
import { loginRewardsSelectionController } from "@/src/controllers/api/loginRewardsSelectionController";
|
import { loginRewardsSelectionController } from "@/src/controllers/api/loginRewardsSelectionController";
|
||||||
import { logoutController } from "@/src/controllers/api/logoutController";
|
import { logoutController } from "@/src/controllers/api/logoutController";
|
||||||
import { marketRecommendationsController } from "@/src/controllers/api/marketRecommendationsController";
|
import { marketRecommendationsController } from "@/src/controllers/api/marketRecommendationsController";
|
||||||
|
import { maturePetController } from "@/src/controllers/api/maturePetController";
|
||||||
import { missionInventoryUpdateController } from "@/src/controllers/api/missionInventoryUpdateController";
|
import { missionInventoryUpdateController } from "@/src/controllers/api/missionInventoryUpdateController";
|
||||||
import { modularWeaponCraftingController } from "@/src/controllers/api/modularWeaponCraftingController";
|
import { modularWeaponCraftingController } from "@/src/controllers/api/modularWeaponCraftingController";
|
||||||
import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController";
|
import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController";
|
||||||
@ -219,6 +220,7 @@ apiRouter.post("/inventorySlots.php", inventorySlotsController);
|
|||||||
apiRouter.post("/joinSession.php", joinSessionController);
|
apiRouter.post("/joinSession.php", joinSessionController);
|
||||||
apiRouter.post("/login.php", loginController);
|
apiRouter.post("/login.php", loginController);
|
||||||
apiRouter.post("/loginRewardsSelection.php", loginRewardsSelectionController);
|
apiRouter.post("/loginRewardsSelection.php", loginRewardsSelectionController);
|
||||||
|
apiRouter.post("/maturePet.php", maturePetController);
|
||||||
apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController);
|
apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController);
|
||||||
apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController);
|
apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController);
|
||||||
apiRouter.post("/modularWeaponSale.php", modularWeaponSaleController);
|
apiRouter.post("/modularWeaponSale.php", modularWeaponSaleController);
|
||||||
|
@ -13,8 +13,9 @@ import { unlockAllIntrinsicsController } from "@/src/controllers/custom/unlockAl
|
|||||||
|
|
||||||
import { createAccountController } from "@/src/controllers/custom/createAccountController";
|
import { createAccountController } from "@/src/controllers/custom/createAccountController";
|
||||||
import { createMessageController } from "@/src/controllers/custom/createMessageController";
|
import { createMessageController } from "@/src/controllers/custom/createMessageController";
|
||||||
import { addCurrencyController } from "../controllers/custom/addCurrencyController";
|
import { addCurrencyController } from "@/src/controllers/custom/addCurrencyController";
|
||||||
import { addItemsController } from "@/src/controllers/custom/addItemsController";
|
import { addItemsController } from "@/src/controllers/custom/addItemsController";
|
||||||
|
import { addModularEquipmentController } from "@/src/controllers/custom/addModularEquipmentController";
|
||||||
import { addXpController } from "@/src/controllers/custom/addXpController";
|
import { addXpController } from "@/src/controllers/custom/addXpController";
|
||||||
import { importController } from "@/src/controllers/custom/importController";
|
import { importController } from "@/src/controllers/custom/importController";
|
||||||
|
|
||||||
@ -39,6 +40,7 @@ customRouter.post("/createAccount", createAccountController);
|
|||||||
customRouter.post("/createMessage", createMessageController);
|
customRouter.post("/createMessage", createMessageController);
|
||||||
customRouter.post("/addCurrency", addCurrencyController);
|
customRouter.post("/addCurrency", addCurrencyController);
|
||||||
customRouter.post("/addItems", addItemsController);
|
customRouter.post("/addItems", addItemsController);
|
||||||
|
customRouter.post("/addModularEquipment", addModularEquipmentController);
|
||||||
customRouter.post("/addXp", addXpController);
|
customRouter.post("/addXp", addXpController);
|
||||||
customRouter.post("/import", importController);
|
customRouter.post("/import", importController);
|
||||||
customRouter.post("/manageQuests", manageQuestsController);
|
customRouter.post("/manageQuests", manageQuestsController);
|
||||||
|
@ -293,7 +293,7 @@ export const updateInventoryForConfirmedGuildJoin = async (
|
|||||||
accountId: string,
|
accountId: string,
|
||||||
guildId: Types.ObjectId
|
guildId: Types.ObjectId
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId, "GuildId Recipes");
|
||||||
|
|
||||||
// Set GuildId
|
// Set GuildId
|
||||||
inventory.GuildId = guildId;
|
inventory.GuildId = guildId;
|
||||||
|
@ -938,7 +938,7 @@ export const addSkin = (
|
|||||||
typeName: string,
|
typeName: string,
|
||||||
inventoryChanges: IInventoryChanges = {}
|
inventoryChanges: IInventoryChanges = {}
|
||||||
): IInventoryChanges => {
|
): IInventoryChanges => {
|
||||||
const index = inventory.WeaponSkins.push({ ItemType: typeName }) - 1;
|
const index = inventory.WeaponSkins.push({ ItemType: typeName, IsNew: true }) - 1;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
inventoryChanges.WeaponSkins ??= [];
|
inventoryChanges.WeaponSkins ??= [];
|
||||||
(inventoryChanges.WeaponSkins as IWeaponSkinClient[]).push(
|
(inventoryChanges.WeaponSkins as IWeaponSkinClient[]).push(
|
||||||
|
@ -15,8 +15,7 @@ export const submitLeaderboardScore = async (
|
|||||||
expiry = new Date(Math.trunc(Date.now() / 86400000) * 86400000 + 86400000);
|
expiry = new Date(Math.trunc(Date.now() / 86400000) * 86400000 + 86400000);
|
||||||
} else {
|
} else {
|
||||||
const EPOCH = 1734307200 * 1000; // Monday
|
const EPOCH = 1734307200 * 1000; // Monday
|
||||||
const day = Math.trunc((Date.now() - EPOCH) / 86400000);
|
const week = Math.trunc((Date.now() - EPOCH) / 604800000);
|
||||||
const week = Math.trunc(day / 7);
|
|
||||||
const weekStart = EPOCH + week * 604800000;
|
const weekStart = EPOCH + week * 604800000;
|
||||||
const weekEnd = weekStart + 604800000;
|
const weekEnd = weekStart + 604800000;
|
||||||
expiry = new Date(weekEnd);
|
expiry = new Date(weekEnd);
|
||||||
|
@ -121,14 +121,9 @@ const getRandomLoginReward = (rng: CRng, day: number, inventory: TInventoryDatab
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const claimLoginReward = async (
|
export const claimLoginReward = async (
|
||||||
account: TAccountDocument,
|
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
reward: ILoginReward
|
reward: ILoginReward
|
||||||
): Promise<IInventoryChanges> => {
|
): Promise<IInventoryChanges> => {
|
||||||
account.LoginDays += 1;
|
|
||||||
account.LastLoginRewardDate = Math.trunc(Date.now() / 86400000) * 86400;
|
|
||||||
await account.save();
|
|
||||||
|
|
||||||
switch (reward.RewardType) {
|
switch (reward.RewardType) {
|
||||||
case "RT_RESOURCE":
|
case "RT_RESOURCE":
|
||||||
case "RT_STORE_ITEM":
|
case "RT_STORE_ITEM":
|
||||||
@ -150,3 +145,8 @@ export const claimLoginReward = async (
|
|||||||
}
|
}
|
||||||
throw new Error(`unknown login reward type: ${reward.RewardType}`);
|
throw new Error(`unknown login reward type: ${reward.RewardType}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setAccountGotLoginRewardToday = (account: TAccountDocument): void => {
|
||||||
|
account.LoginDays += 1;
|
||||||
|
account.LastLoginRewardDate = Math.trunc(Date.now() / 86400000) * 86400;
|
||||||
|
};
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
updateSlots
|
updateSlots
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
import { getRandomWeightedRewardUc } from "@/src/services/rngService";
|
import { getRandomWeightedRewardUc } from "@/src/services/rngService";
|
||||||
import { getVendorManifestByOid } from "@/src/services/serversideVendorsService";
|
import { getVendorManifestByOid, preprocessVendorManifest } from "@/src/services/serversideVendorsService";
|
||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { IPurchaseRequest, IPurchaseResponse, SlotPurchase, IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IPurchaseRequest, IPurchaseResponse, SlotPurchase, IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
@ -52,8 +52,9 @@ export const handlePurchase = async (
|
|||||||
|
|
||||||
const prePurchaseInventoryChanges: IInventoryChanges = {};
|
const prePurchaseInventoryChanges: IInventoryChanges = {};
|
||||||
if (purchaseRequest.PurchaseParams.Source == 7) {
|
if (purchaseRequest.PurchaseParams.Source == 7) {
|
||||||
const manifest = getVendorManifestByOid(purchaseRequest.PurchaseParams.SourceId!);
|
const rawManifest = getVendorManifestByOid(purchaseRequest.PurchaseParams.SourceId!);
|
||||||
if (manifest) {
|
if (rawManifest) {
|
||||||
|
const manifest = preprocessVendorManifest(rawManifest);
|
||||||
let ItemId: string | undefined;
|
let ItemId: string | undefined;
|
||||||
if (purchaseRequest.PurchaseParams.ExtraPurchaseInfoJson) {
|
if (purchaseRequest.PurchaseParams.ExtraPurchaseInfoJson) {
|
||||||
ItemId = (JSON.parse(purchaseRequest.PurchaseParams.ExtraPurchaseInfoJson) as { ItemId: string })
|
ItemId = (JSON.parse(purchaseRequest.PurchaseParams.ExtraPurchaseInfoJson) as { ItemId: string })
|
||||||
@ -87,16 +88,28 @@ export const handlePurchase = async (
|
|||||||
}) - 1
|
}) - 1
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
let expiry = parseInt(offer.Expiry.$date.$numberLong);
|
||||||
|
if (purchaseRequest.PurchaseParams.IsWeekly) {
|
||||||
|
const EPOCH = 1734307200 * 1000; // Monday
|
||||||
|
const week = Math.trunc((Date.now() - EPOCH) / 604800000);
|
||||||
|
const weekStart = EPOCH + week * 604800000;
|
||||||
|
expiry = weekStart + 604800000;
|
||||||
|
}
|
||||||
const historyEntry = vendorPurchases.PurchaseHistory.find(x => x.ItemId == ItemId);
|
const historyEntry = vendorPurchases.PurchaseHistory.find(x => x.ItemId == ItemId);
|
||||||
let numPurchased = purchaseRequest.PurchaseParams.Quantity;
|
let numPurchased = purchaseRequest.PurchaseParams.Quantity;
|
||||||
if (historyEntry) {
|
if (historyEntry) {
|
||||||
numPurchased += historyEntry.NumPurchased;
|
if (Date.now() >= historyEntry.Expiry.getTime()) {
|
||||||
historyEntry.NumPurchased += purchaseRequest.PurchaseParams.Quantity;
|
historyEntry.NumPurchased = numPurchased;
|
||||||
|
historyEntry.Expiry = new Date(expiry);
|
||||||
|
} else {
|
||||||
|
numPurchased += historyEntry.NumPurchased;
|
||||||
|
historyEntry.NumPurchased += purchaseRequest.PurchaseParams.Quantity;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
vendorPurchases.PurchaseHistory.push({
|
vendorPurchases.PurchaseHistory.push({
|
||||||
ItemId: ItemId,
|
ItemId: ItemId,
|
||||||
NumPurchased: purchaseRequest.PurchaseParams.Quantity,
|
NumPurchased: purchaseRequest.PurchaseParams.Quantity,
|
||||||
Expiry: new Date(parseInt(offer.Expiry.$date.$numberLong))
|
Expiry: new Date(expiry)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
prePurchaseInventoryChanges.NewVendorPurchase = {
|
prePurchaseInventoryChanges.NewVendorPurchase = {
|
||||||
@ -105,7 +118,7 @@ export const handlePurchase = async (
|
|||||||
{
|
{
|
||||||
ItemId: ItemId,
|
ItemId: ItemId,
|
||||||
NumPurchased: numPurchased,
|
NumPurchased: numPurchased,
|
||||||
Expiry: offer.Expiry
|
Expiry: { $date: { $numberLong: expiry.toString() } }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
@ -140,6 +140,13 @@ export const handleInventoryItemConfigChange = async (
|
|||||||
inventory.UseAdultOperatorLoadout = equipment as boolean;
|
inventory.UseAdultOperatorLoadout = equipment as boolean;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "WeaponSkins": {
|
||||||
|
const itemEntries = equipment as IItemEntry;
|
||||||
|
for (const [itemId, itemConfigEntries] of Object.entries(itemEntries)) {
|
||||||
|
inventory.WeaponSkins.id(itemId)!.IsNew = itemConfigEntries.IsNew;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
if (equipmentKeys.includes(equipmentName as TEquipmentKey) && equipmentName != "ValidNewLoadoutId") {
|
if (equipmentKeys.includes(equipmentName as TEquipmentKey) && equipmentName != "ValidNewLoadoutId") {
|
||||||
logger.debug(`general Item config saved of type ${equipmentName}`, {
|
logger.debug(`general Item config saved of type ${equipmentName}`, {
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
import { CRng, mixSeeds } from "@/src/services/rngService";
|
||||||
|
import { IMongoDate } from "@/src/types/commonTypes";
|
||||||
|
import { IVendorManifest, IVendorManifestPreprocessed } from "@/src/types/vendorTypes";
|
||||||
|
|
||||||
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
|
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
|
||||||
import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
|
import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
|
||||||
@ -31,25 +33,6 @@ import SolarisProspectorVendorManifest from "@/static/fixed_responses/getVendorI
|
|||||||
import TeshinHardModeVendorManifest from "@/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json";
|
import TeshinHardModeVendorManifest from "@/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json";
|
||||||
import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVendorInfo/ZarimanCommisionsManifestArchimedean.json";
|
import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVendorInfo/ZarimanCommisionsManifestArchimedean.json";
|
||||||
|
|
||||||
interface IVendorManifest {
|
|
||||||
VendorInfo: {
|
|
||||||
_id: IOid;
|
|
||||||
TypeName: string;
|
|
||||||
ItemManifest: {
|
|
||||||
StoreItem: string;
|
|
||||||
ItemPrices?: { ItemType: string; ItemCount: number; ProductCategory: string }[];
|
|
||||||
Bin: string;
|
|
||||||
QuantityMultiplier: number;
|
|
||||||
Expiry: IMongoDate;
|
|
||||||
PurchaseQuantityLimit?: number;
|
|
||||||
RotatedWeekly?: boolean;
|
|
||||||
AllowMultipurchase: boolean;
|
|
||||||
Id: IOid;
|
|
||||||
}[];
|
|
||||||
Expiry: IMongoDate;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const vendorManifests: IVendorManifest[] = [
|
const vendorManifests: IVendorManifest[] = [
|
||||||
ArchimedeanVendorManifest,
|
ArchimedeanVendorManifest,
|
||||||
DeimosEntratiFragmentVendorProductsManifest,
|
DeimosEntratiFragmentVendorProductsManifest,
|
||||||
@ -65,8 +48,8 @@ const vendorManifests: IVendorManifest[] = [
|
|||||||
DuviriAcrithisVendorManifest,
|
DuviriAcrithisVendorManifest,
|
||||||
EntratiLabsEntratiLabsCommisionsManifest,
|
EntratiLabsEntratiLabsCommisionsManifest,
|
||||||
EntratiLabsEntratiLabVendorManifest,
|
EntratiLabsEntratiLabVendorManifest,
|
||||||
GuildAdvertisementVendorManifest,
|
GuildAdvertisementVendorManifest, // uses preprocessing
|
||||||
HubsIronwakeDondaVendorManifest,
|
HubsIronwakeDondaVendorManifest, // uses preprocessing
|
||||||
HubsPerrinSequenceWeaponVendorManifest,
|
HubsPerrinSequenceWeaponVendorManifest,
|
||||||
HubsRailjackCrewMemberVendorManifest,
|
HubsRailjackCrewMemberVendorManifest,
|
||||||
MaskSalesmanManifest,
|
MaskSalesmanManifest,
|
||||||
@ -79,7 +62,7 @@ const vendorManifests: IVendorManifest[] = [
|
|||||||
SolarisDebtTokenVendorRepossessionsManifest,
|
SolarisDebtTokenVendorRepossessionsManifest,
|
||||||
SolarisFishmongerVendorManifest,
|
SolarisFishmongerVendorManifest,
|
||||||
SolarisProspectorVendorManifest,
|
SolarisProspectorVendorManifest,
|
||||||
TeshinHardModeVendorManifest,
|
TeshinHardModeVendorManifest, // uses preprocessing
|
||||||
ZarimanCommisionsManifestArchimedean
|
ZarimanCommisionsManifestArchimedean
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -100,3 +83,38 @@ export const getVendorManifestByOid = (oid: string): IVendorManifest | undefined
|
|||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const preprocessVendorManifest = (originalManifest: IVendorManifest): IVendorManifestPreprocessed => {
|
||||||
|
if (Date.now() >= parseInt(originalManifest.VendorInfo.Expiry.$date.$numberLong)) {
|
||||||
|
const manifest = structuredClone(originalManifest);
|
||||||
|
const info = manifest.VendorInfo;
|
||||||
|
refreshExpiry(info.Expiry);
|
||||||
|
for (const offer of info.ItemManifest) {
|
||||||
|
const iteration = refreshExpiry(offer.Expiry);
|
||||||
|
if (offer.ItemPrices) {
|
||||||
|
for (const price of offer.ItemPrices) {
|
||||||
|
if (typeof price.ItemType != "string") {
|
||||||
|
const itemSeed = parseInt(offer.Id.$oid.substring(16), 16);
|
||||||
|
const rng = new CRng(mixSeeds(itemSeed, iteration));
|
||||||
|
price.ItemType = rng.randomElement(price.ItemType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return manifest as IVendorManifestPreprocessed;
|
||||||
|
}
|
||||||
|
return originalManifest as IVendorManifestPreprocessed;
|
||||||
|
};
|
||||||
|
|
||||||
|
const refreshExpiry = (expiry: IMongoDate): number => {
|
||||||
|
const period = parseInt(expiry.$date.$numberLong);
|
||||||
|
if (Date.now() >= period) {
|
||||||
|
const epoch = 1734307200 * 1000; // Monday (for weekly schedules)
|
||||||
|
const iteration = Math.trunc((Date.now() - epoch) / period);
|
||||||
|
const start = epoch + iteration * period;
|
||||||
|
const end = start + period;
|
||||||
|
expiry.$date.$numberLong = end.toString();
|
||||||
|
return iteration;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
@ -1017,6 +1017,7 @@ export interface ITaunt {
|
|||||||
|
|
||||||
export interface IWeaponSkinDatabase {
|
export interface IWeaponSkinDatabase {
|
||||||
ItemType: string;
|
ItemType: string;
|
||||||
|
IsNew?: boolean;
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ export interface ISaveLoadoutRequest {
|
|||||||
EquippedGear: string[];
|
EquippedGear: string[];
|
||||||
EquippedEmotes: string[];
|
EquippedEmotes: string[];
|
||||||
UseAdultOperatorLoadout: boolean;
|
UseAdultOperatorLoadout: boolean;
|
||||||
|
WeaponSkins: IItemEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaveLoadoutRequestNoUpgradeVer extends Omit<ISaveLoadoutRequest, "UpgradeVer"> {}
|
export interface ISaveLoadoutRequestNoUpgradeVer extends Omit<ISaveLoadoutRequest, "UpgradeVer"> {}
|
||||||
|
46
src/types/vendorTypes.ts
Normal file
46
src/types/vendorTypes.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { IMongoDate, IOid } from "./commonTypes";
|
||||||
|
|
||||||
|
interface IItemPrice {
|
||||||
|
ItemType: string | string[]; // If string[], preprocessing will use RNG to pick one for the current period.
|
||||||
|
ItemCount: number;
|
||||||
|
ProductCategory: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IItemPricePreprocessed extends Omit<IItemPrice, "ItemType"> {
|
||||||
|
ItemType: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IItemManifest {
|
||||||
|
StoreItem: string;
|
||||||
|
ItemPrices?: IItemPrice[];
|
||||||
|
Bin: string;
|
||||||
|
QuantityMultiplier: number;
|
||||||
|
Expiry: IMongoDate; // Either a date in the distant future or a period in milliseconds for preprocessing.
|
||||||
|
PurchaseQuantityLimit?: number;
|
||||||
|
RotatedWeekly?: boolean;
|
||||||
|
AllowMultipurchase: boolean;
|
||||||
|
Id: IOid;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IItemManifestPreprocessed extends Omit<IItemManifest, "ItemPrices"> {
|
||||||
|
ItemPrices?: IItemPricePreprocessed[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IVendorInfo {
|
||||||
|
_id: IOid;
|
||||||
|
TypeName: string;
|
||||||
|
ItemManifest: IItemManifest[];
|
||||||
|
Expiry: IMongoDate; // Either a date in the distant future or a period in milliseconds for preprocessing.
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IVendorInfoPreprocessed extends Omit<IVendorInfo, "ItemManifest"> {
|
||||||
|
ItemManifest: IItemManifestPreprocessed[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IVendorManifest {
|
||||||
|
VendorInfo: IVendorInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IVendorManifestPreprocessed {
|
||||||
|
VendorInfo: IVendorInfoPreprocessed;
|
||||||
|
}
|
@ -5,11 +5,17 @@
|
|||||||
"ItemManifest": [
|
"ItemManifest": [
|
||||||
{
|
{
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementMoon",
|
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementMoon",
|
||||||
"ItemPrices": [{ "ItemType": "/Lotus/Types/Items/Research/ChemComponent", "ItemCount": 12, "ProductCategory": "MiscItems" }],
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
|
||||||
|
"ItemCount": 12,
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
"RegularPrice": [1, 1],
|
"RegularPrice": [1, 1],
|
||||||
"Bin": "BIN_4",
|
"Bin": "BIN_4",
|
||||||
"QuantityMultiplier": 1,
|
"QuantityMultiplier": 1,
|
||||||
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
|
"Expiry": { "$date": { "$numberLong": "604800000" } },
|
||||||
"PurchaseQuantityLimit": 1,
|
"PurchaseQuantityLimit": 1,
|
||||||
"AllowMultipurchase": false,
|
"AllowMultipurchase": false,
|
||||||
"LocTagRandSeed": 79554843,
|
"LocTagRandSeed": 79554843,
|
||||||
@ -17,11 +23,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementMountain",
|
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementMountain",
|
||||||
"ItemPrices": [{ "ItemType": "/Lotus/Types/Items/Research/ChemComponent", "ItemCount": 7, "ProductCategory": "MiscItems" }],
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
|
||||||
|
"ItemCount": 7,
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
"RegularPrice": [1, 1],
|
"RegularPrice": [1, 1],
|
||||||
"Bin": "BIN_3",
|
"Bin": "BIN_3",
|
||||||
"QuantityMultiplier": 1,
|
"QuantityMultiplier": 1,
|
||||||
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
|
"Expiry": { "$date": { "$numberLong": "604800000" } },
|
||||||
"PurchaseQuantityLimit": 1,
|
"PurchaseQuantityLimit": 1,
|
||||||
"AllowMultipurchase": false,
|
"AllowMultipurchase": false,
|
||||||
"LocTagRandSeed": 2413820225,
|
"LocTagRandSeed": 2413820225,
|
||||||
@ -29,11 +41,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementStorm",
|
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementStorm",
|
||||||
"ItemPrices": [{ "ItemType": "/Lotus/Types/Items/Research/ChemComponent", "ItemCount": 3, "ProductCategory": "MiscItems" }],
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
|
||||||
|
"ItemCount": 3,
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
"RegularPrice": [1, 1],
|
"RegularPrice": [1, 1],
|
||||||
"Bin": "BIN_2",
|
"Bin": "BIN_2",
|
||||||
"QuantityMultiplier": 1,
|
"QuantityMultiplier": 1,
|
||||||
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
|
"Expiry": { "$date": { "$numberLong": "604800000" } },
|
||||||
"PurchaseQuantityLimit": 1,
|
"PurchaseQuantityLimit": 1,
|
||||||
"AllowMultipurchase": false,
|
"AllowMultipurchase": false,
|
||||||
"LocTagRandSeed": 3262300883,
|
"LocTagRandSeed": 3262300883,
|
||||||
@ -41,11 +59,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementShadow",
|
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementShadow",
|
||||||
"ItemPrices": [{ "ItemType": "/Lotus/Types/Items/Research/EnergyFragment", "ItemCount": 20, "ProductCategory": "MiscItems" }],
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
|
||||||
|
"ItemCount": 20,
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
"RegularPrice": [1, 1],
|
"RegularPrice": [1, 1],
|
||||||
"Bin": "BIN_1",
|
"Bin": "BIN_1",
|
||||||
"QuantityMultiplier": 1,
|
"QuantityMultiplier": 1,
|
||||||
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
|
"Expiry": { "$date": { "$numberLong": "604800000" } },
|
||||||
"PurchaseQuantityLimit": 1,
|
"PurchaseQuantityLimit": 1,
|
||||||
"AllowMultipurchase": false,
|
"AllowMultipurchase": false,
|
||||||
"LocTagRandSeed": 2797325750,
|
"LocTagRandSeed": 2797325750,
|
||||||
@ -53,11 +77,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementGhost",
|
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementGhost",
|
||||||
"ItemPrices": [{ "ItemType": "/Lotus/Types/Items/Research/EnergyFragment", "ItemCount": 10, "ProductCategory": "MiscItems" }],
|
"ItemPrices": [
|
||||||
|
{
|
||||||
|
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
|
||||||
|
"ItemCount": 10,
|
||||||
|
"ProductCategory": "MiscItems"
|
||||||
|
}
|
||||||
|
],
|
||||||
"RegularPrice": [1, 1],
|
"RegularPrice": [1, 1],
|
||||||
"Bin": "BIN_0",
|
"Bin": "BIN_0",
|
||||||
"QuantityMultiplier": 1,
|
"QuantityMultiplier": 1,
|
||||||
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
|
"Expiry": { "$date": { "$numberLong": "604800000" } },
|
||||||
"PurchaseQuantityLimit": 1,
|
"PurchaseQuantityLimit": 1,
|
||||||
"AllowMultipurchase": false,
|
"AllowMultipurchase": false,
|
||||||
"LocTagRandSeed": 554932310,
|
"LocTagRandSeed": 554932310,
|
||||||
@ -66,6 +96,6 @@
|
|||||||
],
|
],
|
||||||
"PropertyTextHash": "255AFE2169BAE4130B4B20D7C55D14FA",
|
"PropertyTextHash": "255AFE2169BAE4130B4B20D7C55D14FA",
|
||||||
"RandomSeedType": "VRST_FLAVOUR_TEXT",
|
"RandomSeedType": "VRST_FLAVOUR_TEXT",
|
||||||
"Expiry": { "$date": { "$numberLong": "9999999000000" } }
|
"Expiry": { "$date": { "$numberLong": "604800000" } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
"QuantityMultiplier": 1,
|
"QuantityMultiplier": 1,
|
||||||
"Expiry": {
|
"Expiry": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "9999999000000"
|
"$numberLong": "604800000"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AllowMultipurchase": true,
|
"AllowMultipurchase": true,
|
||||||
@ -39,7 +39,7 @@
|
|||||||
"QuantityMultiplier": 1,
|
"QuantityMultiplier": 1,
|
||||||
"Expiry": {
|
"Expiry": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "9999999000000"
|
"$numberLong": "604800000"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"PurchaseQuantityLimit": 1,
|
"PurchaseQuantityLimit": 1,
|
||||||
@ -61,7 +61,7 @@
|
|||||||
"QuantityMultiplier": 1,
|
"QuantityMultiplier": 1,
|
||||||
"Expiry": {
|
"Expiry": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "9999999000000"
|
"$numberLong": "604800000"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"PurchaseQuantityLimit": 1,
|
"PurchaseQuantityLimit": 1,
|
||||||
@ -83,7 +83,7 @@
|
|||||||
"QuantityMultiplier": 35000,
|
"QuantityMultiplier": 35000,
|
||||||
"Expiry": {
|
"Expiry": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "9999999000000"
|
"$numberLong": "604800000"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"PurchaseQuantityLimit": 1,
|
"PurchaseQuantityLimit": 1,
|
||||||
@ -105,7 +105,7 @@
|
|||||||
"QuantityMultiplier": 1,
|
"QuantityMultiplier": 1,
|
||||||
"Expiry": {
|
"Expiry": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "9999999000000"
|
"$numberLong": "604800000"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"PurchaseQuantityLimit": 1,
|
"PurchaseQuantityLimit": 1,
|
||||||
@ -118,7 +118,7 @@
|
|||||||
"PropertyTextHash": "62B64A8065B7C0FA345895D4BC234621",
|
"PropertyTextHash": "62B64A8065B7C0FA345895D4BC234621",
|
||||||
"Expiry": {
|
"Expiry": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "9999999000000"
|
"$numberLong": "604800000"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -561,7 +561,7 @@
|
|||||||
"QuantityMultiplier": 1,
|
"QuantityMultiplier": 1,
|
||||||
"Expiry": {
|
"Expiry": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "2051240400000"
|
"$numberLong": "604800000"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"PurchaseQuantityLimit": 25,
|
"PurchaseQuantityLimit": 25,
|
||||||
@ -583,7 +583,7 @@
|
|||||||
"QuantityMultiplier": 10000,
|
"QuantityMultiplier": 10000,
|
||||||
"Expiry": {
|
"Expiry": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "2051240400000"
|
"$numberLong": "604800000"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"PurchaseQuantityLimit": 25,
|
"PurchaseQuantityLimit": 25,
|
||||||
@ -596,7 +596,7 @@
|
|||||||
"PropertyTextHash": "0A0F20AFA748FBEE490510DBF5A33A0D",
|
"PropertyTextHash": "0A0F20AFA748FBEE490510DBF5A33A0D",
|
||||||
"Expiry": {
|
"Expiry": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "2051240400000"
|
"$numberLong": "604800000"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,6 +299,12 @@
|
|||||||
<div class="card mb-3" style="height: 400px;">
|
<div class="card mb-3" style="height: 400px;">
|
||||||
<h5 class="card-header" data-loc="inventory_operatorAmps"></h5>
|
<h5 class="card-header" data-loc="inventory_operatorAmps"></h5>
|
||||||
<div class="card-body overflow-auto">
|
<div class="card-body overflow-auto">
|
||||||
|
<form class="input-group mb-3" onsubmit="doAcquireModularEquipment('OperatorAmps');return false;">
|
||||||
|
<input class="form-control" id="acquire-type-OperatorAmps-AMP_OCULUS" list="datalist-ModularParts-AMP_OCULUS" />
|
||||||
|
<input class="form-control" id="acquire-type-OperatorAmps-AMP_CORE" list="datalist-ModularParts-AMP_CORE" />
|
||||||
|
<input class="form-control" id="acquire-type-OperatorAmps-AMP_BRACE" list="datalist-ModularParts-AMP_BRACE" />
|
||||||
|
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
||||||
|
</form>
|
||||||
<table class="table table-hover w-100">
|
<table class="table table-hover w-100">
|
||||||
<tbody id="OperatorAmps-list"></tbody>
|
<tbody id="OperatorAmps-list"></tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -309,6 +315,13 @@
|
|||||||
<div class="card mb-3" style="height: 400px;">
|
<div class="card mb-3" style="height: 400px;">
|
||||||
<h5 class="card-header" data-loc="inventory_hoverboards"></h5>
|
<h5 class="card-header" data-loc="inventory_hoverboards"></h5>
|
||||||
<div class="card-body overflow-auto">
|
<div class="card-body overflow-auto">
|
||||||
|
<form class="input-group mb-3" onsubmit="doAcquireModularEquipment('HoverBoards');return false;">
|
||||||
|
<input class="form-control" id="acquire-type-HoverBoards-HB_DECK" list="datalist-ModularParts-HB_DECK" />
|
||||||
|
<input class="form-control" id="acquire-type-HoverBoards-HB_ENGINE" list="datalist-ModularParts-HB_ENGINE" />
|
||||||
|
<input class="form-control" id="acquire-type-HoverBoards-HB_FRONT" list="datalist-ModularParts-HB_FRONT" />
|
||||||
|
<input class="form-control" id="acquire-type-HoverBoards-HB_JET" list="datalist-ModularParts-HB_JET" />
|
||||||
|
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
||||||
|
</form>
|
||||||
<table class="table table-hover w-100">
|
<table class="table table-hover w-100">
|
||||||
<tbody id="Hoverboards-list"></tbody>
|
<tbody id="Hoverboards-list"></tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -604,7 +617,6 @@
|
|||||||
<datalist id="datalist-SpaceMelee"></datalist>
|
<datalist id="datalist-SpaceMelee"></datalist>
|
||||||
<datalist id="datalist-SentinelWeapons"></datalist>
|
<datalist id="datalist-SentinelWeapons"></datalist>
|
||||||
<datalist id="datalist-Sentinels"></datalist>
|
<datalist id="datalist-Sentinels"></datalist>
|
||||||
<datalist id="datalist-ModularParts"></datalist>
|
|
||||||
<datalist id="datalist-MechSuits"></datalist>
|
<datalist id="datalist-MechSuits"></datalist>
|
||||||
<datalist id="datalist-Syndicates"></datalist>
|
<datalist id="datalist-Syndicates"></datalist>
|
||||||
<datalist id="datalist-miscitems"></datalist>
|
<datalist id="datalist-miscitems"></datalist>
|
||||||
@ -613,6 +625,14 @@
|
|||||||
<option data-key="/Lotus/Upgrades/CosmeticEnhancers/Peculiars/CyoteMod" value="Traumatic Peculiar"></option>
|
<option data-key="/Lotus/Upgrades/CosmeticEnhancers/Peculiars/CyoteMod" value="Traumatic Peculiar"></option>
|
||||||
</datalist>
|
</datalist>
|
||||||
<datalist id="datalist-archonCrystalUpgrades"></datalist>
|
<datalist id="datalist-archonCrystalUpgrades"></datalist>
|
||||||
|
<datalist id="datalist-ModularParts"></datalist>
|
||||||
|
<datalist id="datalist-ModularParts-HB_DECK"></datalist>
|
||||||
|
<datalist id="datalist-ModularParts-HB_ENGINE"></datalist>
|
||||||
|
<datalist id="datalist-ModularParts-HB_FRONT"></datalist>
|
||||||
|
<datalist id="datalist-ModularParts-HB_JET"></datalist>
|
||||||
|
<datalist id="datalist-ModularParts-AMP_OCULUS"></datalist>
|
||||||
|
<datalist id="datalist-ModularParts-AMP_CORE"></datalist>
|
||||||
|
<datalist id="datalist-ModularParts-AMP_BRACE"></datalist>
|
||||||
<script src="/webui/libs/jquery-3.6.0.min.js"></script>
|
<script src="/webui/libs/jquery-3.6.0.min.js"></script>
|
||||||
<script src="/webui/libs/whirlpool-js.min.js"></script>
|
<script src="/webui/libs/whirlpool-js.min.js"></script>
|
||||||
<script src="/webui/libs/single.js"></script>
|
<script src="/webui/libs/single.js"></script>
|
||||||
|
@ -233,6 +233,30 @@ function fetchItemList() {
|
|||||||
if (type == "Syndicates" && item.uniqueName.startsWith("RadioLegion")) {
|
if (type == "Syndicates" && item.uniqueName.startsWith("RadioLegion")) {
|
||||||
item.name += " (" + item.uniqueName + ")";
|
item.name += " (" + item.uniqueName + ")";
|
||||||
}
|
}
|
||||||
|
if (type == "ModularParts") {
|
||||||
|
const supportedModularParts = [
|
||||||
|
"LWPT_HB_DECK",
|
||||||
|
"LWPT_HB_ENGINE",
|
||||||
|
"LWPT_HB_FRONT",
|
||||||
|
"LWPT_HB_JET",
|
||||||
|
"LWPT_AMP_OCULUS",
|
||||||
|
"LWPT_AMP_CORE",
|
||||||
|
"LWPT_AMP_BRACE"
|
||||||
|
];
|
||||||
|
if (supportedModularParts.includes(item.partType)) {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.setAttribute("data-key", item.uniqueName);
|
||||||
|
option.value = item.name;
|
||||||
|
document
|
||||||
|
.getElementById("datalist-" + type + "-" + item.partType.slice(5))
|
||||||
|
.appendChild(option);
|
||||||
|
} else {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.setAttribute("data-key", item.uniqueName);
|
||||||
|
option.value = item.name;
|
||||||
|
document.getElementById("datalist-" + type).appendChild(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (item.badReason != "notraw") {
|
if (item.badReason != "notraw") {
|
||||||
const option = document.createElement("option");
|
const option = document.createElement("option");
|
||||||
option.setAttribute("data-key", item.uniqueName);
|
option.setAttribute("data-key", item.uniqueName);
|
||||||
@ -622,6 +646,61 @@ function doAcquireEquipment(category) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function doAcquireModularEquipment(category) {
|
||||||
|
let ItemType;
|
||||||
|
let requiredParts;
|
||||||
|
let ModularParts = [];
|
||||||
|
switch (category) {
|
||||||
|
case "HoverBoards":
|
||||||
|
ItemType = "/Lotus/Types/Vehicles/Hoverboard/HoverboardSuit";
|
||||||
|
requiredParts = ["HB_DECK", "HB_ENGINE", "HB_FRONT", "HB_JET"];
|
||||||
|
break;
|
||||||
|
case "OperatorAmps":
|
||||||
|
ItemType = "/Lotus/Weapons/Sentients/OperatorAmplifiers/OperatorAmpWeapon";
|
||||||
|
requiredParts = ["AMP_OCULUS", "AMP_CORE", "AMP_BRACE"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
requiredParts.forEach(part => {
|
||||||
|
const partName = getKey(document.getElementById("acquire-type-" + category + "-" + part));
|
||||||
|
if (partName) {
|
||||||
|
ModularParts.push(partName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (ModularParts.length != requiredParts.length) {
|
||||||
|
let isFirstPart = true;
|
||||||
|
requiredParts.forEach(part => {
|
||||||
|
const partSelector = document.getElementById("acquire-type-" + category + "-" + part);
|
||||||
|
if (!getKey(partSelector)) {
|
||||||
|
if (isFirstPart) {
|
||||||
|
isFirstPart = false;
|
||||||
|
$("#acquire-type-" + category + "-" + part)
|
||||||
|
.addClass("is-invalid")
|
||||||
|
.focus();
|
||||||
|
} else {
|
||||||
|
$("#acquire-type-" + category + "-" + part).addClass("is-invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
revalidateAuthz(() => {
|
||||||
|
const req = $.post({
|
||||||
|
url: "/custom/addModularEquipment?" + window.authz,
|
||||||
|
contentType: "application/json",
|
||||||
|
data: JSON.stringify({
|
||||||
|
ItemType,
|
||||||
|
ModularParts
|
||||||
|
})
|
||||||
|
});
|
||||||
|
req.done(() => {
|
||||||
|
requiredParts.forEach(part => {
|
||||||
|
document.getElementById("acquire-type-" + category + "-" + part).value = "";
|
||||||
|
});
|
||||||
|
updateInventory();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$("input[list]").on("input", function () {
|
$("input[list]").on("input", function () {
|
||||||
$(this).removeClass("is-invalid");
|
$(this).removeClass("is-invalid");
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user