Compare commits

..

No commits in common. "9ea061fdb3048ba8554ce6ff30a9dcde9207d79d" and "3a904753f2067c7192b1a050b76e41744e03caa7" have entirely different histories.

27 changed files with 73 additions and 369 deletions

View File

@ -25,7 +25,7 @@ export const addToGuildController: RequestHandler = async (req, res) => {
return;
}
const guild = (await Guild.findById(payload.GuildId.$oid, "Name Ranks"))!;
const guild = (await Guild.findById(payload.GuildId.$oid, "Name"))!;
const senderAccount = await getAccountForRequest(req);
if (!(await hasGuildPermission(guild, senderAccount._id.toString(), GuildPermission.Recruiter))) {
res.status(400).json("Invalid permission");

View File

@ -28,17 +28,7 @@ export const createGuildController: RequestHandler = async (req, res) => {
await updateInventoryForConfirmedGuildJoin(accountId, guild._id);
res.json({
...(await getGuildClient(guild, accountId)),
InventoryChanges: {
Recipes: [
{
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
ItemCount: 1
}
]
}
});
res.json(await getGuildClient(guild, accountId));
};
interface ICreateGuildRequest {

View File

@ -1,5 +1,5 @@
import { RequestHandler } from "express";
import { getVendorManifestByTypeName, preprocessVendorManifest } from "@/src/services/serversideVendorsService";
import { getVendorManifestByTypeName } from "@/src/services/serversideVendorsService";
export const getVendorInfoController: RequestHandler = (req, res) => {
if (typeof req.query.vendor == "string") {
@ -7,7 +7,7 @@ export const getVendorInfoController: RequestHandler = (req, res) => {
if (!manifest) {
throw new Error(`Unknown vendor: ${req.query.vendor}`);
}
res.json(preprocessVendorManifest(manifest));
res.json(manifest);
} else {
res.status(400).end();
}

View File

@ -4,8 +4,7 @@ import {
claimLoginReward,
getRandomLoginRewards,
ILoginRewardsReponse,
isLoginRewardAChoice,
setAccountGotLoginRewardToday
isLoginRewardAChoice
} from "@/src/services/loginRewardService";
import { getInventory } from "@/src/services/inventoryService";
@ -45,11 +44,8 @@ export const loginRewardsController: RequestHandler = async (req, res) => {
if (!isMilestoneDay && randomRewards.length == 1) {
response.DailyTributeInfo.HasChosenReward = true;
response.DailyTributeInfo.ChosenReward = randomRewards[0];
response.DailyTributeInfo.NewInventory = await claimLoginReward(inventory, randomRewards[0]);
response.DailyTributeInfo.NewInventory = await claimLoginReward(account, inventory, randomRewards[0]);
await inventory.save();
setAccountGotLoginRewardToday(account);
await account.save();
}
res.json(response);
};

View File

@ -1,9 +1,5 @@
import { getInventory } from "@/src/services/inventoryService";
import {
claimLoginReward,
getRandomLoginRewards,
setAccountGotLoginRewardToday
} from "@/src/services/loginRewardService";
import { claimLoginReward, getRandomLoginRewards } from "@/src/services/loginRewardService";
import { getAccountForRequest } from "@/src/services/loginService";
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
import { IInventoryChanges } from "@/src/types/purchaseTypes";
@ -32,13 +28,9 @@ export const loginRewardsSelectionController: RequestHandler = async (req, res)
} else {
const randomRewards = getRandomLoginRewards(account, inventory);
chosenReward = randomRewards.find(x => x.StoreItemType == body.ChosenReward)!;
inventoryChanges = await claimLoginReward(inventory, chosenReward);
inventoryChanges = await claimLoginReward(account, inventory, chosenReward);
}
await inventory.save();
setAccountGotLoginRewardToday(account);
await account.save();
res.json({
DailyTributeInfo: {
NewInventory: inventoryChanges,

View File

@ -1,27 +0,0 @@
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;
}

View File

@ -1,5 +1,4 @@
import { GuildMember } from "@/src/models/guildModel";
import { Inbox } from "@/src/models/inboxModel";
import { Account } from "@/src/models/loginModel";
import { getGuildForRequest, hasGuildPermission } from "@/src/services/guildService";
import { getInventory } from "@/src/services/inventoryService";
@ -29,7 +28,7 @@ export const removeFromGuildController: RequestHandler = async (req, res) => {
} else {
const recipeIndex = inventory.Recipes.findIndex(x => x.ItemType == "/Lotus/Types/Keys/DojoKeyBlueprint");
if (recipeIndex != -1) {
inventory.Recipes.splice(recipeIndex, 1);
inventory.Recipes.splice(itemIndex, 1);
}
}
@ -37,12 +36,7 @@ export const removeFromGuildController: RequestHandler = async (req, res) => {
// TODO: Handle clan leader kicking themselves (guild should be deleted in this case, I think)
} else if (guildMember.status == 2) {
// Delete the inbox message for the invite
await Inbox.deleteOne({
ownerId: guildMember.accountId,
contextInfo: guild._id.toString(),
acceptAction: "GUILD_INVITE"
});
// TODO: Maybe the inbox message for the sent invite should be deleted?
}
await GuildMember.deleteOne({ _id: guildMember._id });

View File

@ -1,20 +0,0 @@
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[];
}

View File

@ -25,7 +25,6 @@ interface ListedItem {
fusionLimit?: number;
exalted?: string[];
badReason?: "starter" | "frivolous" | "notraw";
partType?: string;
}
const relicQualitySuffixes: Record<TRelicQuality, string> = {
@ -80,8 +79,7 @@ const getItemListsController: RequestHandler = (req, response) => {
) {
res.ModularParts.push({
uniqueName,
name: getString(item.name, lang),
partType: item.partType
name: getString(item.name, lang)
});
if (uniqueName.split("/")[5] != "SentTrainingAmplifier") {
res.miscitems.push({

View File

@ -586,8 +586,7 @@ const spectreLoadoutsSchema = new Schema<ISpectreLoadout>(
const weaponSkinsSchema = new Schema<IWeaponSkinDatabase>(
{
ItemType: String,
IsNew: Boolean
ItemType: String
},
{ id: false }
);

View File

@ -72,7 +72,6 @@ import { loginRewardsController } from "@/src/controllers/api/loginRewardsContro
import { loginRewardsSelectionController } from "@/src/controllers/api/loginRewardsSelectionController";
import { logoutController } from "@/src/controllers/api/logoutController";
import { marketRecommendationsController } from "@/src/controllers/api/marketRecommendationsController";
import { maturePetController } from "@/src/controllers/api/maturePetController";
import { missionInventoryUpdateController } from "@/src/controllers/api/missionInventoryUpdateController";
import { modularWeaponCraftingController } from "@/src/controllers/api/modularWeaponCraftingController";
import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController";
@ -220,7 +219,6 @@ apiRouter.post("/inventorySlots.php", inventorySlotsController);
apiRouter.post("/joinSession.php", joinSessionController);
apiRouter.post("/login.php", loginController);
apiRouter.post("/loginRewardsSelection.php", loginRewardsSelectionController);
apiRouter.post("/maturePet.php", maturePetController);
apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController);
apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController);
apiRouter.post("/modularWeaponSale.php", modularWeaponSaleController);

View File

@ -13,9 +13,8 @@ import { unlockAllIntrinsicsController } from "@/src/controllers/custom/unlockAl
import { createAccountController } from "@/src/controllers/custom/createAccountController";
import { createMessageController } from "@/src/controllers/custom/createMessageController";
import { addCurrencyController } from "@/src/controllers/custom/addCurrencyController";
import { addCurrencyController } from "../controllers/custom/addCurrencyController";
import { addItemsController } from "@/src/controllers/custom/addItemsController";
import { addModularEquipmentController } from "@/src/controllers/custom/addModularEquipmentController";
import { addXpController } from "@/src/controllers/custom/addXpController";
import { importController } from "@/src/controllers/custom/importController";
@ -40,7 +39,6 @@ customRouter.post("/createAccount", createAccountController);
customRouter.post("/createMessage", createMessageController);
customRouter.post("/addCurrency", addCurrencyController);
customRouter.post("/addItems", addItemsController);
customRouter.post("/addModularEquipment", addModularEquipmentController);
customRouter.post("/addXp", addXpController);
customRouter.post("/import", importController);
customRouter.post("/manageQuests", manageQuestsController);

View File

@ -293,7 +293,7 @@ export const updateInventoryForConfirmedGuildJoin = async (
accountId: string,
guildId: Types.ObjectId
): Promise<void> => {
const inventory = await getInventory(accountId, "GuildId Recipes");
const inventory = await getInventory(accountId);
// Set GuildId
inventory.GuildId = guildId;

View File

@ -938,7 +938,7 @@ export const addSkin = (
typeName: string,
inventoryChanges: IInventoryChanges = {}
): IInventoryChanges => {
const index = inventory.WeaponSkins.push({ ItemType: typeName, IsNew: true }) - 1;
const index = inventory.WeaponSkins.push({ ItemType: typeName }) - 1;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
inventoryChanges.WeaponSkins ??= [];
(inventoryChanges.WeaponSkins as IWeaponSkinClient[]).push(

View File

@ -15,7 +15,8 @@ export const submitLeaderboardScore = async (
expiry = new Date(Math.trunc(Date.now() / 86400000) * 86400000 + 86400000);
} else {
const EPOCH = 1734307200 * 1000; // Monday
const week = Math.trunc((Date.now() - EPOCH) / 604800000);
const day = Math.trunc((Date.now() - EPOCH) / 86400000);
const week = Math.trunc(day / 7);
const weekStart = EPOCH + week * 604800000;
const weekEnd = weekStart + 604800000;
expiry = new Date(weekEnd);

View File

@ -121,9 +121,14 @@ const getRandomLoginReward = (rng: CRng, day: number, inventory: TInventoryDatab
};
export const claimLoginReward = async (
account: TAccountDocument,
inventory: TInventoryDatabaseDocument,
reward: ILoginReward
): Promise<IInventoryChanges> => {
account.LoginDays += 1;
account.LastLoginRewardDate = Math.trunc(Date.now() / 86400000) * 86400;
await account.save();
switch (reward.RewardType) {
case "RT_RESOURCE":
case "RT_STORE_ITEM":
@ -145,8 +150,3 @@ export const claimLoginReward = async (
}
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;
};

View File

@ -9,7 +9,7 @@ import {
updateSlots
} from "@/src/services/inventoryService";
import { getRandomWeightedRewardUc } from "@/src/services/rngService";
import { getVendorManifestByOid, preprocessVendorManifest } from "@/src/services/serversideVendorsService";
import { getVendorManifestByOid } from "@/src/services/serversideVendorsService";
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
import { IPurchaseRequest, IPurchaseResponse, SlotPurchase, IInventoryChanges } from "@/src/types/purchaseTypes";
import { logger } from "@/src/utils/logger";
@ -52,9 +52,8 @@ export const handlePurchase = async (
const prePurchaseInventoryChanges: IInventoryChanges = {};
if (purchaseRequest.PurchaseParams.Source == 7) {
const rawManifest = getVendorManifestByOid(purchaseRequest.PurchaseParams.SourceId!);
if (rawManifest) {
const manifest = preprocessVendorManifest(rawManifest);
const manifest = getVendorManifestByOid(purchaseRequest.PurchaseParams.SourceId!);
if (manifest) {
let ItemId: string | undefined;
if (purchaseRequest.PurchaseParams.ExtraPurchaseInfoJson) {
ItemId = (JSON.parse(purchaseRequest.PurchaseParams.ExtraPurchaseInfoJson) as { ItemId: string })
@ -88,28 +87,16 @@ export const handlePurchase = async (
}) - 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);
let numPurchased = purchaseRequest.PurchaseParams.Quantity;
if (historyEntry) {
if (Date.now() >= historyEntry.Expiry.getTime()) {
historyEntry.NumPurchased = numPurchased;
historyEntry.Expiry = new Date(expiry);
} else {
numPurchased += historyEntry.NumPurchased;
historyEntry.NumPurchased += purchaseRequest.PurchaseParams.Quantity;
}
numPurchased += historyEntry.NumPurchased;
historyEntry.NumPurchased += purchaseRequest.PurchaseParams.Quantity;
} else {
vendorPurchases.PurchaseHistory.push({
ItemId: ItemId,
NumPurchased: purchaseRequest.PurchaseParams.Quantity,
Expiry: new Date(expiry)
Expiry: new Date(parseInt(offer.Expiry.$date.$numberLong))
});
}
prePurchaseInventoryChanges.NewVendorPurchase = {
@ -118,7 +105,7 @@ export const handlePurchase = async (
{
ItemId: ItemId,
NumPurchased: numPurchased,
Expiry: { $date: { $numberLong: expiry.toString() } }
Expiry: offer.Expiry
}
]
};

View File

@ -140,13 +140,6 @@ export const handleInventoryItemConfigChange = async (
inventory.UseAdultOperatorLoadout = equipment as boolean;
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: {
if (equipmentKeys.includes(equipmentName as TEquipmentKey) && equipmentName != "ValidNewLoadoutId") {
logger.debug(`general Item config saved of type ${equipmentName}`, {

View File

@ -1,6 +1,4 @@
import { CRng, mixSeeds } from "@/src/services/rngService";
import { IMongoDate } from "@/src/types/commonTypes";
import { IVendorManifest, IVendorManifestPreprocessed } from "@/src/types/vendorTypes";
import { IMongoDate, IOid } from "@/src/types/commonTypes";
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
@ -33,6 +31,25 @@ import SolarisProspectorVendorManifest from "@/static/fixed_responses/getVendorI
import TeshinHardModeVendorManifest from "@/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.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[] = [
ArchimedeanVendorManifest,
DeimosEntratiFragmentVendorProductsManifest,
@ -48,8 +65,8 @@ const vendorManifests: IVendorManifest[] = [
DuviriAcrithisVendorManifest,
EntratiLabsEntratiLabsCommisionsManifest,
EntratiLabsEntratiLabVendorManifest,
GuildAdvertisementVendorManifest, // uses preprocessing
HubsIronwakeDondaVendorManifest, // uses preprocessing
GuildAdvertisementVendorManifest,
HubsIronwakeDondaVendorManifest,
HubsPerrinSequenceWeaponVendorManifest,
HubsRailjackCrewMemberVendorManifest,
MaskSalesmanManifest,
@ -62,7 +79,7 @@ const vendorManifests: IVendorManifest[] = [
SolarisDebtTokenVendorRepossessionsManifest,
SolarisFishmongerVendorManifest,
SolarisProspectorVendorManifest,
TeshinHardModeVendorManifest, // uses preprocessing
TeshinHardModeVendorManifest,
ZarimanCommisionsManifestArchimedean
];
@ -83,38 +100,3 @@ export const getVendorManifestByOid = (oid: string): IVendorManifest | 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;
};

View File

@ -1017,7 +1017,6 @@ export interface ITaunt {
export interface IWeaponSkinDatabase {
ItemType: string;
IsNew?: boolean;
_id: Types.ObjectId;
}

View File

@ -36,7 +36,6 @@ export interface ISaveLoadoutRequest {
EquippedGear: string[];
EquippedEmotes: string[];
UseAdultOperatorLoadout: boolean;
WeaponSkins: IItemEntry;
}
export interface ISaveLoadoutRequestNoUpgradeVer extends Omit<ISaveLoadoutRequest, "UpgradeVer"> {}

View File

@ -1,46 +0,0 @@
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;
}

View File

@ -5,17 +5,11 @@
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementMoon",
"ItemPrices": [
{
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
"ItemCount": 12,
"ProductCategory": "MiscItems"
}
],
"ItemPrices": [{ "ItemType": "/Lotus/Types/Items/Research/ChemComponent", "ItemCount": 12, "ProductCategory": "MiscItems" }],
"RegularPrice": [1, 1],
"Bin": "BIN_4",
"QuantityMultiplier": 1,
"Expiry": { "$date": { "$numberLong": "604800000" } },
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 79554843,
@ -23,17 +17,11 @@
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementMountain",
"ItemPrices": [
{
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
"ItemCount": 7,
"ProductCategory": "MiscItems"
}
],
"ItemPrices": [{ "ItemType": "/Lotus/Types/Items/Research/ChemComponent", "ItemCount": 7, "ProductCategory": "MiscItems" }],
"RegularPrice": [1, 1],
"Bin": "BIN_3",
"QuantityMultiplier": 1,
"Expiry": { "$date": { "$numberLong": "604800000" } },
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2413820225,
@ -41,17 +29,11 @@
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementStorm",
"ItemPrices": [
{
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
"ItemCount": 3,
"ProductCategory": "MiscItems"
}
],
"ItemPrices": [{ "ItemType": "/Lotus/Types/Items/Research/ChemComponent", "ItemCount": 3, "ProductCategory": "MiscItems" }],
"RegularPrice": [1, 1],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": { "$date": { "$numberLong": "604800000" } },
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 3262300883,
@ -59,17 +41,11 @@
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementShadow",
"ItemPrices": [
{
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
"ItemCount": 20,
"ProductCategory": "MiscItems"
}
],
"ItemPrices": [{ "ItemType": "/Lotus/Types/Items/Research/EnergyFragment", "ItemCount": 20, "ProductCategory": "MiscItems" }],
"RegularPrice": [1, 1],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": { "$date": { "$numberLong": "604800000" } },
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2797325750,
@ -77,17 +53,11 @@
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Guild/GuildAdvertisementGhost",
"ItemPrices": [
{
"ItemType": ["/Lotus/Types/Items/Research/BioFragment", "/Lotus/Types/Items/Research/ChemComponent", "/Lotus/Types/Items/Research/EnergyFragment"],
"ItemCount": 10,
"ProductCategory": "MiscItems"
}
],
"ItemPrices": [{ "ItemType": "/Lotus/Types/Items/Research/EnergyFragment", "ItemCount": 10, "ProductCategory": "MiscItems" }],
"RegularPrice": [1, 1],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": { "$date": { "$numberLong": "604800000" } },
"Expiry": { "$date": { "$numberLong": "9999999000000" } },
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 554932310,
@ -96,6 +66,6 @@
],
"PropertyTextHash": "255AFE2169BAE4130B4B20D7C55D14FA",
"RandomSeedType": "VRST_FLAVOUR_TEXT",
"Expiry": { "$date": { "$numberLong": "604800000" } }
"Expiry": { "$date": { "$numberLong": "9999999000000" } }
}
}

View File

@ -18,7 +18,7 @@
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "604800000"
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
@ -39,7 +39,7 @@
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "604800000"
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
@ -61,7 +61,7 @@
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "604800000"
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
@ -83,7 +83,7 @@
"QuantityMultiplier": 35000,
"Expiry": {
"$date": {
"$numberLong": "604800000"
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
@ -105,7 +105,7 @@
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "604800000"
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
@ -118,7 +118,7 @@
"PropertyTextHash": "62B64A8065B7C0FA345895D4BC234621",
"Expiry": {
"$date": {
"$numberLong": "604800000"
"$numberLong": "9999999000000"
}
}
}

View File

@ -561,7 +561,7 @@
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "604800000"
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 25,
@ -583,7 +583,7 @@
"QuantityMultiplier": 10000,
"Expiry": {
"$date": {
"$numberLong": "604800000"
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 25,
@ -596,7 +596,7 @@
"PropertyTextHash": "0A0F20AFA748FBEE490510DBF5A33A0D",
"Expiry": {
"$date": {
"$numberLong": "604800000"
"$numberLong": "2051240400000"
}
}
}

View File

@ -299,12 +299,6 @@
<div class="card mb-3" style="height: 400px;">
<h5 class="card-header" data-loc="inventory_operatorAmps"></h5>
<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">
<tbody id="OperatorAmps-list"></tbody>
</table>
@ -315,13 +309,6 @@
<div class="card mb-3" style="height: 400px;">
<h5 class="card-header" data-loc="inventory_hoverboards"></h5>
<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">
<tbody id="Hoverboards-list"></tbody>
</table>
@ -617,6 +604,7 @@
<datalist id="datalist-SpaceMelee"></datalist>
<datalist id="datalist-SentinelWeapons"></datalist>
<datalist id="datalist-Sentinels"></datalist>
<datalist id="datalist-ModularParts"></datalist>
<datalist id="datalist-MechSuits"></datalist>
<datalist id="datalist-Syndicates"></datalist>
<datalist id="datalist-miscitems"></datalist>
@ -625,14 +613,6 @@
<option data-key="/Lotus/Upgrades/CosmeticEnhancers/Peculiars/CyoteMod" value="Traumatic Peculiar"></option>
</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/whirlpool-js.min.js"></script>
<script src="/webui/libs/single.js"></script>

View File

@ -233,30 +233,6 @@ function fetchItemList() {
if (type == "Syndicates" && item.uniqueName.startsWith("RadioLegion")) {
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") {
const option = document.createElement("option");
option.setAttribute("data-key", item.uniqueName);
@ -646,61 +622,6 @@ 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 () {
$(this).removeClass("is-invalid");
});