This commit is contained in:
Master 2024-06-29 13:40:41 +08:00
commit 6771578d2c
29 changed files with 571 additions and 594 deletions

View File

@ -1 +1,2 @@
static/webui/libs/ static/webui/libs/
*.html

View File

@ -0,0 +1,66 @@
import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { getInventory } from "@/src/services/inventoryService";
import { WeaponTypeInternal } from "@/src/services/itemDataService";
import { ArtifactPolarity, EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
const modularWeaponCategory: (WeaponTypeInternal | "Hoverboards")[] = [
"LongGuns",
"Pistols",
"Melee",
"OperatorAmps",
"Hoverboards" // Not sure about hoverboards just coppied from modual crafting
];
interface IGildWeaponRequest {
ItemName: string;
Recipe: string; // /Lotus/Weapons/SolarisUnited/LotusGildKitgunBlueprint
PolarizeSlot?: number;
PolarizeValue?: ArtifactPolarity;
ItemId: string;
Category: WeaponTypeInternal | "Hoverboards";
}
// In export there no recipes for gild action, so reputation and ressources only consumed visually
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const gildWeaponController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const data: IGildWeaponRequest = getJSONfromString(String(req.body));
data.ItemId = String(req.query.ItemId);
if (!modularWeaponCategory.includes(req.query.Category as WeaponTypeInternal | "Hoverboards")) {
throw new Error(`Unknown modular weapon Category: ${req.query.Category}`);
}
data.Category = req.query.Category as WeaponTypeInternal | "Hoverboards";
const inventory = await getInventory(accountId);
if (!inventory[data.Category]) {
throw new Error(`Category ${req.query.Category} not found in inventory`);
}
const weaponIndex = inventory[data.Category].findIndex(x => String(x._id) === data.ItemId);
if (weaponIndex === -1) {
throw new Error(`Weapon with ${data.ItemId} not found in category ${req.query.Category}`);
}
const weapon = inventory[data.Category][weaponIndex];
weapon.Features = EquipmentFeatures.GILDED; // maybe 9 idk if DOUBLE_CAPACITY is also given
weapon.ItemName = data.ItemName;
weapon.XP = 0;
if (data.Category != "OperatorAmps" && data.PolarizeSlot && data.PolarizeValue) {
weapon.Polarity = [
{
Slot: data.PolarizeSlot,
Value: data.PolarizeValue
}
];
}
inventory[data.Category][weaponIndex] = weapon;
await inventory.save();
res.json({
InventoryChanges: {
[data.Category]: [weapon]
}
});
};

View File

@ -7,7 +7,7 @@ import { IGiveKeyChainTriggeredItemsRequest } from "@/src/types/questTypes";
// eslint-disable-next-line @typescript-eslint/no-misused-promises // eslint-disable-next-line @typescript-eslint/no-misused-promises
const giveKeyChainTriggeredItemsController: RequestHandler = async (req, res) => { const giveKeyChainTriggeredItemsController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
const payload = getJSONfromString(req.body as string) as IGiveKeyChainTriggeredItemsRequest; const payload = getJSONfromString(String(req.body)) as IGiveKeyChainTriggeredItemsRequest;
const result = await giveKeyChainTriggeredItems(accountId, payload.KeyChain, payload.ChainStage); const result = await giveKeyChainTriggeredItems(accountId, payload.KeyChain, payload.ChainStage);
if (result) res.json(result); if (result) res.json(result);
else res.json({}); else res.json({});

View File

@ -7,7 +7,7 @@ import { IGiveKeyChainTriggeredMessageRequest } from "@/src/types/questTypes";
// eslint-disable-next-line @typescript-eslint/no-misused-promises // eslint-disable-next-line @typescript-eslint/no-misused-promises
const giveKeyChainTriggeredMessageController: RequestHandler = async (req, res) => { const giveKeyChainTriggeredMessageController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
const payload = getJSONfromString(req.body as string) as IGiveKeyChainTriggeredMessageRequest; const payload = getJSONfromString(String(req.body)) as IGiveKeyChainTriggeredMessageRequest;
const result = giveKeyChainTriggeredMessage(accountId, payload.KeyChain, payload.ChainStage); const result = giveKeyChainTriggeredMessage(accountId, payload.KeyChain, payload.ChainStage);
if (result != null) res.json(result); if (result != null) res.json(result);
else res.status(200).end(); else res.status(200).end();

View File

@ -7,7 +7,7 @@ import { ISession } from "@/src/types/session";
// eslint-disable-next-line @typescript-eslint/no-misused-promises // eslint-disable-next-line @typescript-eslint/no-misused-promises
const hostSessionController: RequestHandler = async (req, res) => { const hostSessionController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
const hostSessionRequest = JSON.parse(req.body as string) as ISession; const hostSessionRequest = JSON.parse(String(req.body)) as ISession;
logger.debug("HostSession Request", { hostSessionRequest }); logger.debug("HostSession Request", { hostSessionRequest });
const session = createNewSession(hostSessionRequest, accountId); const session = createNewSession(hostSessionRequest, accountId);
logger.debug(`New Session Created`, { session }); logger.debug(`New Session Created`, { session });

View File

@ -21,7 +21,7 @@ import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
// eslint-disable-next-line @typescript-eslint/no-misused-promises // eslint-disable-next-line @typescript-eslint/no-misused-promises
export const inventorySlotsController: RequestHandler = async (req, res) => { export const inventorySlotsController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
//const body = JSON.parse(req.body as string) as IInventorySlotsRequest; //const body = JSON.parse(String(req.body)) as IInventorySlotsRequest;
//console.log(body); //console.log(body);

View File

@ -10,7 +10,7 @@ export const saveLoadoutController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
try { try {
const body: ISaveLoadoutRequest = JSON.parse(req.body as string) as ISaveLoadoutRequest; const body: ISaveLoadoutRequest = JSON.parse(String(req.body)) as ISaveLoadoutRequest;
// console.log(util.inspect(body, { showHidden: false, depth: null, colors: true })); // console.log(util.inspect(body, { showHidden: false, depth: null, colors: true }));
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars

View File

@ -6,7 +6,7 @@ import { RequestHandler } from "express";
// eslint-disable-next-line @typescript-eslint/no-misused-promises // eslint-disable-next-line @typescript-eslint/no-misused-promises
export const setShipCustomizationsController: RequestHandler = async (req, res) => { export const setShipCustomizationsController: RequestHandler = async (req, res) => {
try { try {
const setShipCustomizationsRequest = JSON.parse(req.body as string) as ISetShipCustomizationsRequest; const setShipCustomizationsRequest = JSON.parse(String(req.body)) as ISetShipCustomizationsRequest;
const setShipCustomizationsResponse = await setShipCustomizations(setShipCustomizationsRequest); const setShipCustomizationsResponse = await setShipCustomizations(setShipCustomizationsRequest);
res.json(setShipCustomizationsResponse); res.json(setShipCustomizationsResponse);

View File

@ -7,7 +7,7 @@ import { handleSetShipDecorations } from "@/src/services/shipCustomizationsServi
// eslint-disable-next-line @typescript-eslint/no-misused-promises // eslint-disable-next-line @typescript-eslint/no-misused-promises
export const shipDecorationsController: RequestHandler = async (req, res) => { export const shipDecorationsController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
const shipDecorationsRequest = JSON.parse(req.body as string) as IShipDecorationsRequest; const shipDecorationsRequest = JSON.parse(String(req.body)) as IShipDecorationsRequest;
try { try {
const placedDecoration = await handleSetShipDecorations(accountId, shipDecorationsRequest); const placedDecoration = await handleSetShipDecorations(accountId, shipDecorationsRequest);

View File

@ -12,7 +12,7 @@ export interface IUnlockShipFeatureRequest {
export const unlockShipFeatureController: RequestHandler = async (req, res) => { export const unlockShipFeatureController: RequestHandler = async (req, res) => {
const accountId = parseString(req.query.accountId); const accountId = parseString(req.query.accountId);
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
const shipFeatureRequest = JSON.parse(req.body as string) as IUnlockShipFeatureRequest; const shipFeatureRequest = JSON.parse(String(req.body)) as IUnlockShipFeatureRequest;
await unlockShipFeature(accountId, shipFeatureRequest.Feature); await unlockShipFeature(accountId, shipFeatureRequest.Feature);
res.send([]); res.send([]);
}; };

View File

@ -7,7 +7,7 @@ import { updateQuest } from "@/src/services/questService";
// eslint-disable-next-line @typescript-eslint/no-misused-promises // eslint-disable-next-line @typescript-eslint/no-misused-promises
const updateQuestController: RequestHandler = async (req, res) => { const updateQuestController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req); const accountId = await getAccountIdForRequest(req);
const payload = getJSONfromString(req.body as string) as IUpdateQuestRequest; const payload = getJSONfromString(String(req.body)) as IUpdateQuestRequest;
const result = await updateQuest(accountId, payload); const result = await updateQuest(accountId, payload);
res.json(result); res.json(result);
}; };

View File

@ -3,7 +3,6 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
import { Inventory } from "@/src/models/inventoryModels/inventoryModel"; import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
import { IStatsView } from "@/src/types/statTypes"; import { IStatsView } from "@/src/types/statTypes";
import { config } from "@/src/services/configService"; import { config } from "@/src/services/configService";
import view from "@/static/fixed_responses/view.json";
import allScans from "@/static/fixed_responses/allScans.json"; import allScans from "@/static/fixed_responses/allScans.json";
// eslint-disable-next-line @typescript-eslint/no-misused-promises // eslint-disable-next-line @typescript-eslint/no-misused-promises
@ -15,7 +14,7 @@ const viewController: RequestHandler = async (req, res) => {
return; return;
} }
const responseJson: IStatsView = view; const responseJson: IStatsView = {};
responseJson.Weapons = []; responseJson.Weapons = [];
for (const item of inventory.XPInfo) { for (const item of inventory.XPInfo) {
responseJson.Weapons.push({ responseJson.Weapons.push({

View File

@ -36,9 +36,10 @@ import {
IPeriodicMissionCompletionDatabase, IPeriodicMissionCompletionDatabase,
IPeriodicMissionCompletionResponse, IPeriodicMissionCompletionResponse,
ILoreFragmentScan, ILoreFragmentScan,
IEvolutionProgress IEvolutionProgress,
} from "../../types/inventoryTypes/inventoryTypes"; IDefaultUpgrade
import { IOid } from "../../types/commonTypes"; } from "@/src/types/inventoryTypes/inventoryTypes";
import { IOid } from "@/src/types/commonTypes";
import { import {
IAbilityOverride, IAbilityOverride,
IColor, IColor,
@ -634,6 +635,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
DailyAffiliationNecraloid: Number, DailyAffiliationNecraloid: Number,
DailyAffiliationZariman: Number, DailyAffiliationZariman: Number,
DailyAffiliationKahl: Number, DailyAffiliationKahl: Number,
DailyAffiliationCavia: Number,
//Daily Focus limit //Daily Focus limit
DailyFocus: Number, DailyFocus: Number,
@ -966,7 +968,7 @@ type InventoryDocumentProps = {
OperatorAmps: Types.DocumentArray<IEquipmentDatabase>; OperatorAmps: Types.DocumentArray<IEquipmentDatabase>;
FlavourItems: Types.DocumentArray<IFlavourItem>; FlavourItems: Types.DocumentArray<IFlavourItem>;
RawUpgrades: Types.DocumentArray<IRawUpgrade>; RawUpgrades: Types.DocumentArray<IRawUpgrade>;
Upgrades: Types.DocumentArray<ICrewShipSalvagedWeaponSkin>; Upgrades: Types.DocumentArray<IDefaultUpgrade>;
MiscItems: Types.DocumentArray<IMiscItem>; MiscItems: Types.DocumentArray<IMiscItem>;
Boosters: Types.DocumentArray<IBooster>; Boosters: Types.DocumentArray<IBooster>;
OperatorLoadOuts: Types.DocumentArray<IOperatorConfigClient>; OperatorLoadOuts: Types.DocumentArray<IOperatorConfigClient>;

View File

@ -27,13 +27,16 @@ const EquipmentSelectionSchema = new Schema<IEquipmentSelection>(
const loadoutConfigSchema = new Schema<ILoadoutConfigDatabase>( const loadoutConfigSchema = new Schema<ILoadoutConfigDatabase>(
{ {
FocusSchool: String,
PresetIcon: String, PresetIcon: String,
Favorite: Boolean, Favorite: Boolean,
n: String, n: String, // Loadout name
s: EquipmentSelectionSchema, s: EquipmentSelectionSchema, // Suit
p: EquipmentSelectionSchema, l: EquipmentSelectionSchema, // Primary weapon
l: EquipmentSelectionSchema, p: EquipmentSelectionSchema, // Secondary weapon
m: EquipmentSelectionSchema m: EquipmentSelectionSchema, // Melee weapon
h: EquipmentSelectionSchema, // Gravimag weapon
a: EquipmentSelectionSchema // Necromech exalted weapon
}, },
{ {
id: false id: false

View File

@ -64,6 +64,7 @@ import { updateQuestController } from "@/src/controllers/api/updateQuestControll
import { updateSessionGetController, updateSessionPostController } from "@/src/controllers/api/updateSessionController"; import { updateSessionGetController, updateSessionPostController } from "@/src/controllers/api/updateSessionController";
import { updateThemeController } from "@/src/controllers/api/updateThemeController"; import { updateThemeController } from "@/src/controllers/api/updateThemeController";
import { upgradesController } from "@/src/controllers/api/upgradesController"; import { upgradesController } from "@/src/controllers/api/upgradesController";
import { gildWeaponController } from "../controllers/api/gildWeaponController";
const apiRouter = express.Router(); const apiRouter = express.Router();
@ -111,6 +112,7 @@ apiRouter.post("/genericUpdate.php", genericUpdateController);
apiRouter.post("/getAlliance.php", getAllianceController); apiRouter.post("/getAlliance.php", getAllianceController);
apiRouter.post("/giveKeyChainTriggeredItems.php", giveKeyChainTriggeredItemsController); apiRouter.post("/giveKeyChainTriggeredItems.php", giveKeyChainTriggeredItemsController);
apiRouter.post("/giveKeyChainTriggeredMessage.php", giveKeyChainTriggeredMessageController); apiRouter.post("/giveKeyChainTriggeredMessage.php", giveKeyChainTriggeredMessageController);
apiRouter.post("/gildWeapon.php", gildWeaponController);
apiRouter.post("/guildTech.php", guildTechController); apiRouter.post("/guildTech.php", guildTechController);
apiRouter.post("/hostSession.php", hostSessionController); apiRouter.post("/hostSession.php", hostSessionController);
apiRouter.post("/infestedFoundry.php", infestedFoundryController); apiRouter.post("/infestedFoundry.php", infestedFoundryController);

View File

@ -19,15 +19,18 @@ webuiRouter.use("/webui", (req, res, next) => {
}); });
// Serve virtual routes // Serve virtual routes
webuiRouter.get("/webui/settings", (_req, res) => {
res.sendFile(path.join(rootDir, "static/webui/index.html"));
});
webuiRouter.get("/webui/inventory", (_req, res) => { webuiRouter.get("/webui/inventory", (_req, res) => {
res.sendFile(path.join(rootDir, "static/webui/index.html")); res.sendFile(path.join(rootDir, "static/webui/index.html"));
}); });
webuiRouter.get("/webui/mods", (_req, res) => { webuiRouter.get("/webui/mods", (_req, res) => {
res.sendFile(path.join(rootDir, "static/webui/index.html")); res.sendFile(path.join(rootDir, "static/webui/index.html"));
}); });
webuiRouter.get("/webui/settings", (_req, res) => {
res.sendFile(path.join(rootDir, "static/webui/index.html"));
});
webuiRouter.get("/webui/cheats", (_req, res) => {
res.sendFile(path.join(rootDir, "static/webui/index.html"));
});
// Serve static files // Serve static files
webuiRouter.use("/webui", express.static(path.join(rootDir, "static/webui"))); webuiRouter.use("/webui", express.static(path.join(rootDir, "static/webui")));

View File

@ -14,7 +14,10 @@ import {
ISeasonChallenge, ISeasonChallenge,
ITypeCount, ITypeCount,
InventorySlot, InventorySlot,
IWeaponSkinClient IWeaponSkinClient,
IDefaultUpgrade,
KubrowPetEggItemType,
IKubrowPetEgg
} from "@/src/types/inventoryTypes/inventoryTypes"; } from "@/src/types/inventoryTypes/inventoryTypes";
import { IGenericUpdate } from "../types/genericUpdate"; import { IGenericUpdate } from "../types/genericUpdate";
import { import {
@ -26,9 +29,10 @@ import {
import { logger } from "@/src/utils/logger"; import { logger } from "@/src/utils/logger";
import { WeaponTypeInternal, getWeaponType, getExalted } from "@/src/services/itemDataService"; import { WeaponTypeInternal, getWeaponType, getExalted } from "@/src/services/itemDataService";
import { ISyndicateSacrifice, ISyndicateSacrificeResponse } from "../types/syndicateTypes"; import { ISyndicateSacrifice, ISyndicateSacrificeResponse } from "../types/syndicateTypes";
import { IEquipmentClient } from "../types/inventoryTypes/commonInventoryTypes"; import { IEquipmentClient, IEquipmentDatabase } from "../types/inventoryTypes/commonInventoryTypes";
import { ExportCustoms, ExportFlavour, ExportRecipes, ExportResources } from "warframe-public-export-plus"; import { ExportArcanes, ExportCustoms, ExportFlavour, ExportFusionBundles, ExportRecipes, ExportResources, ExportSentinels, ExportUpgrades } from "warframe-public-export-plus";
import { updateQuestKeys } from "./questService"; import { updateQuestKeys } from "./questService";
import { toOid } from "../helpers/inventoryHelpers";
export const createInventory = async ( export const createInventory = async (
accountOwnerId: Types.ObjectId, accountOwnerId: Types.ObjectId,
@ -75,6 +79,7 @@ export const addItem = async (
): Promise<{ InventoryChanges: IInventoryChanges }> => { ): Promise<{ InventoryChanges: IInventoryChanges }> => {
// Strict typing // Strict typing
if (typeName in ExportRecipes) { if (typeName in ExportRecipes) {
const recipe = ExportRecipes[typeName];
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
const recipeChanges = [ const recipeChanges = [
{ {
@ -82,6 +87,13 @@ export const addItem = async (
ItemCount: quantity ItemCount: quantity
} satisfies ITypeCount } satisfies ITypeCount
]; ];
recipe.ingredients.forEach(ingredient => {
const itemType = ingredient.ItemType.replace("Component", "Blueprint");
recipeChanges.push({
ItemType: itemType,
ItemCount: ingredient.ItemCount
} satisfies ITypeCount);
});
addRecipes(inventory, recipeChanges); addRecipes(inventory, recipeChanges);
await inventory.save(); await inventory.save();
return { return {
@ -92,19 +104,55 @@ export const addItem = async (
} }
if (typeName in ExportResources) { if (typeName in ExportResources) {
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
const miscItemChanges = [ const resource = ExportResources[typeName];
{ switch (resource.productCategory) {
ItemType: typeName, case "MiscItems": {
ItemCount: quantity const miscItemChanges = [
} satisfies IMiscItem {
]; ItemType: typeName,
addMiscItems(inventory, miscItemChanges); ItemCount: quantity
await inventory.save(); } satisfies IMiscItem
return { ];
InventoryChanges: { addMiscItems(inventory, miscItemChanges);
MiscItems: miscItemChanges await inventory.save();
return {
InventoryChanges: {
MiscItems: miscItemChanges
}
};
} }
}; case "ShipDecorations": {
const changes = [
{
ItemType: typeName,
ItemCount: quantity
} satisfies IMiscItem
];
addShipDecorations(inventory, changes);
await inventory.save();
return {
InventoryChanges: {
ShipDecorations: changes
}
};
}
case "KubrowPetEggs": {
const changes = [
{
ItemId: toOid(new Types.ObjectId()),
ItemType: KubrowPetEggItemType.LotusTypesGameKubrowPetEggsKubrowEgg,
ExpirationDate: { $date: { $numberLong: "9999999999999" } }
} satisfies IKubrowPetEgg
];
inventory.KubrowPetEggs.push(...changes);
await inventory.save();
return {
InventoryChanges: {
KubrowPetEggs: changes
}
};
}
}
} }
if (typeName in ExportCustoms) { if (typeName in ExportCustoms) {
return { return {
@ -120,6 +168,53 @@ export const addItem = async (
} }
}; };
} }
if (typeName in ExportUpgrades) {
return {
InventoryChanges: {
Upgrades: [await addUpgrade(typeName, accountId)]
}
};
}
if (typeName in ExportFusionBundles) {
const inventory = await getInventory(accountId);
inventory.FusionPoints += ExportFusionBundles[typeName].fusionPoints;
await inventory.save();
return {
InventoryChanges: {
FusionPoints: inventory.FusionPoints
}
};
}
if (typeName in ExportArcanes) {
return {
InventoryChanges: {
Upgrades: [await addUpgrade(typeName, accountId)]
}
};
}
if (typeName in ExportSentinels) {
const inventory = await getInventory(accountId);
const sentinelData = ExportSentinels[typeName];
const sentinel = await addSentinel(typeName, accountId);
await updateSlots(accountId, InventorySlot.SENTINELS, 0, 1);
if (!inventory.SentinelWeapons.find(i => i.ItemType == (sentinelData.defaultWeapon as string))) {
const sentinelWeapon = await addSentinelWeapon(sentinelData.defaultWeapon as string, accountId);
return {
InventoryChanges: {
SentinelBin: { count: 1, platinum: 0, Slots: -1 },
Sentinels: [sentinel],
SentinelWeapons: [sentinelWeapon]
}
};
}
return {
InventoryChanges: {
SentinelBin: { count: 1, platinum: 0, Slots: -1 },
Sentinels: [sentinel]
}
};
}
// Path-based duck typing // Path-based duck typing
switch (typeName.substring(1).split("/")[1]) { switch (typeName.substring(1).split("/")[1]) {
@ -268,13 +363,20 @@ export const addItem = async (
}; };
//TODO: maybe genericMethod for all the add methods, they share a lot of logic //TODO: maybe genericMethod for all the add methods, they share a lot of logic
export const addSentinel = async (sentinelName: string, accountId: string) => { export const addSentinel = async (sentinelName: string, accountId: string): Promise<IEquipmentDatabase> => {
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
const sentinelIndex = inventory.Sentinels.push({ ItemType: sentinelName, Configs: [], XP: 0 }); const sentinelIndex = inventory.Sentinels.push({ ItemType: sentinelName, Configs: [], XP: 0 });
const changedInventory = await inventory.save(); const changedInventory = await inventory.save();
return changedInventory.Sentinels[sentinelIndex - 1].toJSON(); return changedInventory.Sentinels[sentinelIndex - 1].toJSON();
}; };
export const addSentinelWeapon = async (weaponName: string, accountId: string): Promise<IEquipmentDatabase> => {
const inventory = await getInventory(accountId);
const sentinelWeaponIndex = inventory.SentinelWeapons.push({ ItemType: weaponName, Configs: [], XP: 0 });
const changedInventory = await inventory.save();
return changedInventory.SentinelWeapons[sentinelWeaponIndex - 1].toJSON();
};
export const addPowerSuit = async (powersuitName: string, accountId: string): Promise<IEquipmentClient> => { export const addPowerSuit = async (powersuitName: string, accountId: string): Promise<IEquipmentClient> => {
const specialItems = getExalted(powersuitName); const specialItems = getExalted(powersuitName);
if (specialItems != false) { if (specialItems != false) {
@ -288,7 +390,7 @@ export const addPowerSuit = async (powersuitName: string, accountId: string): Pr
return changedInventory.Suits[suitIndex - 1].toJSON(); return changedInventory.Suits[suitIndex - 1].toJSON();
}; };
export const addMechSuit = async (mechsuitName: string, accountId: string) => { export const addMechSuit = async (mechsuitName: string, accountId: string): Promise<IEquipmentDatabase> => {
const specialItems = getExalted(mechsuitName); const specialItems = getExalted(mechsuitName);
if (specialItems != false) { if (specialItems != false) {
for await (const specialItem of specialItems) { for await (const specialItem of specialItems) {
@ -301,7 +403,7 @@ export const addMechSuit = async (mechsuitName: string, accountId: string) => {
return changedInventory.MechSuits[suitIndex - 1].toJSON(); return changedInventory.MechSuits[suitIndex - 1].toJSON();
}; };
export const addSpecialItem = async (itemName: string, accountId: string) => { export const addSpecialItem = async (itemName: string, accountId: string): Promise<IEquipmentDatabase> => {
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
const specialItemIndex = inventory.SpecialItems.push({ const specialItemIndex = inventory.SpecialItems.push({
ItemType: itemName, ItemType: itemName,
@ -314,7 +416,7 @@ export const addSpecialItem = async (itemName: string, accountId: string) => {
return changedInventory.SpecialItems[specialItemIndex - 1].toJSON(); return changedInventory.SpecialItems[specialItemIndex - 1].toJSON();
}; };
export const addSpaceSuit = async (spacesuitName: string, accountId: string) => { export const addSpaceSuit = async (spacesuitName: string, accountId: string): Promise<IEquipmentDatabase> => {
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
const suitIndex = inventory.SpaceSuits.push({ ItemType: spacesuitName, Configs: [], UpgradeVer: 101, XP: 0 }); const suitIndex = inventory.SpaceSuits.push({ ItemType: spacesuitName, Configs: [], UpgradeVer: 101, XP: 0 });
const changedInventory = await inventory.save(); const changedInventory = await inventory.save();
@ -756,3 +858,17 @@ export const upgradeMod = async (artifactsData: IArtifactsRequest, accountId: st
throw error; throw error;
} }
}; };
export const addHerse = async (ItemType: string, accountId: string): Promise<IEquipmentDatabase> => {
const inventory = await getInventory(accountId);
const herseIndex = inventory.Horses.push({ ItemType: ItemType, Configs: [], UpgradeVer: 101 });
const changedInventory = await inventory.save();
return changedInventory.Horses[herseIndex - 1].toJSON();
};
export const addUpgrade = async (ItemType: string, accountId: string): Promise<IDefaultUpgrade> => {
const inventory = await getInventory(accountId);
const upgradeIndex = inventory.Upgrades.push({ ItemType: ItemType, UpgradeFingerprint: "{}" });
const changedInventory = await inventory.save();
return changedInventory.Upgrades[upgradeIndex - 1].toJSON();
};

View File

@ -86,6 +86,7 @@ export enum EquipmentFeatures {
DOUBLE_CAPACITY = 1, DOUBLE_CAPACITY = 1,
UTILITY_SLOT = 2, UTILITY_SLOT = 2,
GRAVIMAG_INSTALLED = 4, GRAVIMAG_INSTALLED = 4,
GILDED = 8,
ARCANE_SLOT = 32, ARCANE_SLOT = 32,
INCARNON_GENESIS = 512 INCARNON_GENESIS = 512
} }

View File

@ -252,6 +252,7 @@ export interface IInventoryResponse {
DailyAffiliationZariman: number; DailyAffiliationZariman: number;
NemesisAbandonedRewards: string[]; NemesisAbandonedRewards: string[];
DailyAffiliationKahl: number; DailyAffiliationKahl: number;
DailyAffiliationCavia: number;
LastInventorySync: IOid; LastInventorySync: IOid;
NextRefill: IMongoDate; // Next time argon crystals will have a decay tick NextRefill: IMongoDate; // Next time argon crystals will have a decay tick
FoundToday?: IMiscItem[]; // for Argon Crystals FoundToday?: IMiscItem[]; // for Argon Crystals
@ -621,11 +622,11 @@ export interface ILoadoutConfigClient {
Favorite?: boolean; Favorite?: boolean;
n?: string; // Loadout name n?: string; // Loadout name
s?: IEquipmentSelection; // Suit s?: IEquipmentSelection; // Suit
p?: IEquipmentSelection; p?: IEquipmentSelection; // Secondary weapon
l?: IEquipmentSelection; // Primary weapon l?: IEquipmentSelection; // Primary weapon
m?: IEquipmentSelection; // Melee weapon m?: IEquipmentSelection; // Melee weapon
h?: IEquipmentSelection; // Gravimag weapon h?: IEquipmentSelection; // Gravimag weapon
a?: IEquipmentSelection; a?: IEquipmentSelection; // Necromech exalted weapon
ItemId: IOid; ItemId: IOid;
Remove?: boolean; // when client wants to remove a config, it only includes ItemId & Remove. Remove?: boolean; // when client wants to remove a config, it only includes ItemId & Remove.
} }
@ -807,6 +808,13 @@ export interface IQuestProgress {
b?: any[]; b?: any[];
} }
export interface IDefaultUpgrade {
ItemType: string;
UpgradeFingerprint?: string;
ItemId?: IOid;
_id?: Types.ObjectId;
}
export interface IRawUpgrade { export interface IRawUpgrade {
ItemType: string; ItemType: string;
ItemCount: number; ItemCount: number;

View File

@ -14,7 +14,7 @@ export interface IPurchaseParams {
ExpectedPrice: number; ExpectedPrice: number;
} }
export type IInventoryChanges = Record<string, IBinChanges | object[]>; export type IInventoryChanges = Record<string, IBinChanges | number | object[]>;
export type IBinChanges = { export type IBinChanges = {
count: number; count: number;

View File

@ -1 +0,0 @@
{}

View File

@ -101,6 +101,7 @@
"DailyAffiliationNecraloid": 16000, "DailyAffiliationNecraloid": 16000,
"DailyAffiliationZariman": 16000, "DailyAffiliationZariman": 16000,
"DailyAffiliationKahl": 16000, "DailyAffiliationKahl": 16000,
"DailyAffiliationCavia": 16000,
"DailyFocus": 250000, "DailyFocus": 250000,
"GiftsRemaining": 8, "GiftsRemaining": 8,
"LibraryAvailableDailyTaskInfo": { "LibraryAvailableDailyTaskInfo": {

View File

@ -29,6 +29,7 @@
"DailyAffiliationVentkids": 16000, "DailyAffiliationVentkids": 16000,
"DailyAffiliationVox": 16000, "DailyAffiliationVox": 16000,
"DailyAffiliationZariman": 16000, "DailyAffiliationZariman": 16000,
"DailyAffiliationCavia": 16000,
"DailyFocus": 250000, "DailyFocus": 250000,
"DuviriInfo": { "Seed": 5898912197983600352, "NumCompletions": 0 }, "DuviriInfo": { "Seed": 5898912197983600352, "NumCompletions": 0 },
"GiftsRemaining": 8, "GiftsRemaining": 8,

View File

@ -1,13 +0,0 @@
{
"InventoryChanges": {
"WeaponBin": { "count": 1, "platinum": 0, "Slots": -1 },
"Suits": [
{
"ItemType": "/Lotus/Powersuits/Ninja/Ninja",
"Configs": [],
"ItemId": { "$oid": "123123123123" }
}
],
"RegularCredits": -25000
}
}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1,273 +0,0 @@
// for https://www.warframe.com/ru/droptables
/* eslint-disable */
(() => {
const missionNames = {
"Mercury/Larunda Relay": "MercuryHUB",
"Venus/Vesper Relay": "VenusHUB",
"Earth/Strata Relay": "EarthHUB",
"Mars/Maroo's Bazaar": "TradeHUB1",
"Saturn/Kronia Relay": "SaturnHUB",
"Eris/Kuiper Relay": "ErisHUB",
"Europa/Leonov Relay": "EuropaHUB",
"Pluto/Orcus Relay": "PlutoHUB",
"Venus/Romula": "ClanNode0",
"Venus/Malva": "ClanNode1",
"Earth/Coba": "ClanNode2",
"Earth/Tikal": "ClanNode3",
"Jupiter/Sinai": "ClanNode4",
"Jupiter/Cameria": "ClanNode5",
"Europa/Larzac": "ClanNode6",
"Europa/Cholistan": "ClanNode7",
"Mars/Kadesh": "ClanNode8",
"Mars/Wahiba": "ClanNode9",
"Phobos/Memphis": "ClanNode10",
"Phobos/Zeugma": "ClanNode11",
"Saturn/Caracol": "ClanNode12",
"Saturn/Piscinas": "ClanNode13",
"Sedna/Amarna": "ClanNode14",
"Sedna/Sangeru": "ClanNode15",
"Uranus/Ur": "ClanNode16",
"Uranus/Assur": "ClanNode17",
"Eris/Akkad": "ClanNode18",
"Eris/Zabala": "ClanNode19",
"Neptune/Yursa": "ClanNode20",
"Neptune/Kelashin": "ClanNode21",
"Ceres/Seimeni": "ClanNode22",
"Ceres/Gabii": "ClanNode23",
"Pluto/Sechura": "ClanNode24",
"Pluto/Hieracon": "ClanNode25",
"Phobos/Roche": "SettlementNode1",
"Phobos/Skyresh": "SettlementNode2",
"Phobos/Stickney": "SettlementNode3",
"Phobos/Kepler": "SettlementNode10",
"Phobos/Gulliver": "SettlementNode11",
"Phobos/Monolith": "SettlementNode12",
"Phobos/Shklovsky": "SettlementNode14",
"Phobos/Sharpless": "SettlementNode15",
"Phobos/Iliad": "SettlementNode20",
"Neptune/Galatea": "SolNode1",
"Venus/Aphrodite": "SolNode2",
"Pluto/Acheron": "SolNode4",
"Neptune/Despina": "SolNode6",
"Uranus/Rosalind": "SolNode9",
"Jupiter/Thebe": "SolNode10",
"Mars/Tharsis": "SolNode11",
"Mercury/Elion": "SolNode12",
"Mars/Ultor": "SolNode14",
"Earth/Pacific": "SolNode15",
"Mars/Augustus": "SolNode16",
"Neptune/Proteus": "SolNode17",
"Saturn/Rhea": "SolNode18",
"Saturn/Enceladus": "SolNode19",
"Saturn/Telesto": "SolNode20",
"Pluto/Narcissus": "SolNode21",
"Venus/Tessera": "SolNode22",
"Venus/Cytherean": "SolNode23",
"Earth/Oro": "SolNode24",
"Jupiter/Callisto": "SolNode25",
"Earth/Lith": "SolNode26",
"Earth/E Prime": "SolNode27",
"Mercury/Terminus": "SolNode28",
"Mars/Olympus": "SolNode30",
"Saturn/Anthe": "SolNode31",
"Saturn/Tethys": "SolNode32",
"Uranus/Ariel": "SolNode33",
"Uranus/Sycorax": "SolNode34",
"Mars/Martialis": "SolNode36",
"Pluto/Minthe": "SolNode38",
"Earth/Everest": "SolNode39",
"Mars/Arval": "SolNode41",
"Saturn/Helene": "SolNode42",
"Pluto/Cerberus": "SolNode43",
"Mars/Ara": "SolNode45",
"Mars/Spear": "SolNode46",
"Pluto/Regna": "SolNode48",
"Neptune/Larissa": "SolNode49",
"Saturn/Numa": "SolNode50",
"Pluto/Hades": "SolNode51",
"Jupiter/Themisto": "SolNode53",
"Pluto/Cypress": "SolNode56",
"Neptune/Sao": "SolNode57",
"Mars/Hellas": "SolNode58",
"Earth/Eurasia": "SolNode59",
"Uranus/Caliban": "SolNode60",
"Venus/Ishtar": "SolNode61",
"Neptune/Neso": "SolNode62",
"Earth/Mantle": "SolNode63",
"Uranus/Umbriel": "SolNode64",
"Mars/Gradivus": "SolNode65",
"Venus/Unda": "SolNode66",
"Saturn/Dione": "SolNode67",
"Mars/Vallis": "SolNode68",
"Uranus/Ophelia": "SolNode69",
"Saturn/Cassini": "SolNode70",
"Pluto/Outer Terminus": "SolNode72",
"Jupiter/Ananke": "SolNode73",
"Jupiter/Carme": "SolNode74",
"Earth/Cervantes": "SolNode75",
"Pluto/Hydra": "SolNode76",
"Neptune/Triton": "SolNode78",
"Earth/Cambria": "SolNode79",
"Pluto/Palus": "SolNode81",
"Saturn/Calypso": "SolNode82",
"Uranus/Cressida": "SolNode83",
"Neptune/Nereid": "SolNode84",
"Earth/Gaia": "SolNode85",
"Jupiter/Ganymede": "SolNode87",
"Jupiter/Adrastea": "SolNode88",
"Earth/Mariana": "SolNode89",
"Saturn/Keeler": "SolNode93",
"Mercury/Apollodorus": "SolNode94",
"Saturn/Titan": "SolNode96",
"Jupiter/Amalthea": "SolNode97",
"Uranus/Desdemona": "SolNode98",
"Mars/War": "SolNode99",
"Jupiter/Elara": "SolNode100",
"Venus/Kiliken": "SolNode101",
"Pluto/Oceanum": "SolNode102",
"Mercury/M Prime": "SolNode103",
"Venus/Fossa": "SolNode104",
"Uranus/Titania": "SolNode105",
"Mars/Alator": "SolNode106",
"Venus/Venera": "SolNode107",
"Mercury/Tolstoj": "SolNode108",
"Venus/Linea": "SolNode109",
"Mars/Ares": "SolNode113",
"Uranus/Puck": "SolNode114",
"Neptune/Laomedeia": "SolNode118",
"Mercury/Caloris": "SolNode119",
"Jupiter/Carpo": "SolNode121",
"Uranus/Stephano": "SolNode122",
"Venus/V Prime": "SolNode123",
"Jupiter/Io": "SolNode125",
"Jupiter/Metis": "SolNode126",
"Neptune/Psamathe": "SolNode127",
"Venus/E Gate": "SolNode128",
"Venus/Orb Vallis": "SolNode129",
"Mercury/Lares": "SolNode130",
"Ceres/Pallas": "SolNode131",
"Ceres/Bode": "SolNode132",
"Ceres/Thon": "SolNode135",
"Ceres/Nuovo": "SolNode137",
"Ceres/Ludi": "SolNode138",
"Ceres/Lex": "SolNode139",
"Ceres/Kiste": "SolNode140",
"Ceres/Ker": "SolNode141",
"Ceres/Exta": "SolNode144",
"Ceres/Draco": "SolNode146",
"Ceres/Cinxia": "SolNode147",
"Ceres/Casta": "SolNode149",
"Eris/Brugia": "SolNode153",
"Eris/Isos": "SolNode162",
"Eris/Kala-azar": "SolNode164",
"Eris/Nimus": "SolNode166",
"Eris/Oestrus": "SolNode167",
"Eris/Saxis": "SolNode171",
"Eris/Xini": "SolNode172",
"Eris/Solium": "SolNode173",
"Eris/Naeglar": "SolNode175",
"Sedna/Kappa": "SolNode177",
"Sedna/Adaro": "SolNode181",
"Sedna/Vodyanoi": "SolNode183",
"Sedna/Rusalka": "SolNode184",
"Sedna/Berehynia": "SolNode185",
"Sedna/Selkie": "SolNode187",
"Sedna/Kelpie": "SolNode188",
"Sedna/Naga": "SolNode189",
"Sedna/Nakki": "SolNode190",
"Sedna/Marid": "SolNode191",
"Sedna/Merrow": "SolNode193",
"Sedna/Hydron": "SolNode195",
"Sedna/Charybdis": "SolNode196",
"Sedna/Yam": "SolNode199",
"Europa/Abaddon": "SolNode203",
"Europa/Armaros": "SolNode204",
"Europa/Baal": "SolNode205",
"Europa/Morax": "SolNode209",
"Europa/Naamah": "SolNode210",
"Europa/Ose": "SolNode211",
"Europa/Paimon": "SolNode212",
"Europa/Sorath": "SolNode214",
"Europa/Valac": "SolNode215",
"Europa/Valefor": "SolNode216",
"Europa/Orias": "SolNode217",
"Europa/Kokabiel": "SolNode220",
"Mercury/Boethius": "SolNode223",
"Mercury/Odin": "SolNode224",
"Mercury/Suisei": "SolNode225",
"Mercury/Pantheon": "SolNode226",
"Earth/Plains of Eidolon": "SolNode228",
"Deimos/Cambion Drift": "SolNode229",
"Lua/Plato": "SolNode300",
"Lua/Grimaldi": "SolNode301",
"Lua/Tycho": "SolNode302",
"Lua/Copernicus": "SolNode304",
"Lua/Stöfler": "SolNode305",
"Lua/Pavlov": "SolNode306",
"Lua/Zeipel": "SolNode307",
"Lua/Apollo": "SolNode308",
"Void/Teshub": "SolNode400",
"Void/Hepit": "SolNode401",
"Void/Taranis": "SolNode402",
"Void/Tiwaz": "SolNode403",
"Void/Stribog": "SolNode404",
"Void/Ani": "SolNode405",
"Void/Ukko": "SolNode406",
"Void/Oxomoco": "SolNode407",
"Void/Belenus": "SolNode408",
"Void/Mot": "SolNode409",
"Void/Aten": "SolNode410",
"Void/Marduk": "SolNode411",
"Void/Mithra": "SolNode412",
"undefined/Jordas Golem Assassinate": "SolNode701",
"undefined/Mutalist Alad V Assassinate": "SolNode705",
"Deimos/Horend": "SolNode706",
"Deimos/Hyf": "SolNode707",
"Deimos/Phlegyas": "SolNode708",
"Deimos/Dirus": "SolNode709",
"Deimos/Formido": "SolNode710",
"Deimos/Terrorem": "SolNode711",
"Deimos/Magnacidium": "SolNode712",
"Deimos/Exequias": "SolNode713",
"Jupiter/The Ropalolyst": "SolNode740",
"Kuva Fortress/Koro": "SolNode741",
"Kuva Fortress/Nabuk": "SolNode742",
"Kuva Fortress/Rotuma": "SolNode743",
"Kuva Fortress/Taveuni": "SolNode744",
"Kuva Fortress/Tamu": "SolNode745",
"Kuva Fortress/Dakata": "SolNode746",
"Kuva Fortress/Pago": "SolNode747",
"Kuva Fortress/Garus": "SolNode748",
"Venus/Montes": "SolNode902",
"Earth/Erpo": "SolNode903",
"Mars/Syrtis": "SolNode904",
"Jupiter/Galilea": "SolNode905",
"Saturn/Pandora": "SolNode906",
"Uranus/Caelus": "SolNode907"
};
const result = {};
let lastItem = [];
let lastItemIndex;
let rotation;
Array.from(document.querySelectorAll("table")[0].children[0].children).forEach(element => {
if (element.classList.contains("blank-row")) {
if (lastItemIndex) result[lastItemIndex] = lastItem;
lastItem = [];
lastItemIndex = undefined;
rotation = undefined;
} else if (element.children[0].getAttribute("colspan") == 2) {
if (!lastItemIndex) {
const mission = element.children[0].textContent;
const formatedMission = mission.substring(0, mission.indexOf(" ("));
lastItemIndex = missionNames[formatedMission];
} else {
rotation = element.children[0].textContent.replace("Rotation ", "");
}
} else {
const name = element.children[0].textContent;
const chance = parseFloat(element.children[1].textContent.match(/(\d+\.\d+)/)[0]);
lastItem.push({ chance, name, ...(rotation !== undefined && { rotation }) });
}
});
return JSON.stringify(result);
})();

View File

@ -1,286 +1,269 @@
<!doctype html> <!doctype html>
<html lang="en" data-bs-theme="dark"> <html lang="en" data-bs-theme="dark">
<head> <head>
<title>OpenWF WebUI</title> <title>OpenWF WebUI</title>
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="libs/bootstrap.min.css" /> <link rel="stylesheet" href="libs/bootstrap.min.css" />
<link rel="stylesheet" href="style.css" /> <link rel="stylesheet" href="style.css" />
</head> </head>
<body> <body>
<nav class="navbar sticky-top bg-body-tertiary"> <nav class="navbar sticky-top bg-body-tertiary">
<div class="container"> <div class="container">
<button class="navbar-toggler d-lg-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebar" aria-controls="sidebar" aria-label="Toggle sidebar">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand">OpenWF WebUI</a>
<div class="nav-item dropdown">
<button class="nav-link dropdown-toggle displayname" data-bs-toggle="dropdown" aria-expanded="false"></button>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="/webui/" onclick="logout();">Logout</a></li>
</ul>
</div>
</div>
</nav>
<div class="container pt-3 pb-3" id="main-view">
<div class="offcanvas-lg offcanvas-start" tabindex="-1" id="sidebar" aria-labelledby="sidebarLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="sidebarLabel">Sidebar</h5>
<button <button
class="navbar-toggler d-lg-none" type="button"
type="button" class="btn-close"
data-bs-toggle="offcanvas" data-bs-dismiss="offcanvas"
data-bs-target="#sidebar" data-bs-target="#sidebar"
aria-controls="sidebar" aria-label="Close"
aria-label="Toggle sidebar" ></button>
> </div>
<span class="navbar-toggler-icon"></span> <div class="offcanvas-body">
</button> <div class="navbar p-0">
<a class="navbar-brand">OpenWF WebUI</a> <ul class="navbar-nav justify-content-end">
<div class="nav-item dropdown"> <li class="nav-item">
<button <a class="nav-link" href="/webui/inventory" data-bs-dismiss="offcanvas" data-bs-target="#sidebar">Inventory</a>
class="nav-link dropdown-toggle displayname" </li>
data-bs-toggle="dropdown" <li class="nav-item">
aria-expanded="false" <a class="nav-link" href="/webui/mods" data-bs-dismiss="offcanvas" data-bs-target="#sidebar">Mods</a>
></button> </li>
<ul class="dropdown-menu dropdown-menu-end"> <li class="nav-item">
<li><a class="dropdown-item" href="/webui/" onclick="logout();">Logout</a></li> <a class="nav-link" href="/webui/cheats" data-bs-dismiss="offcanvas" data-bs-target="#sidebar">Cheats</a>
</li>
</ul> </ul>
</div> </div>
</div> </div>
</nav> </div>
<div class="container pt-3 pb-3" id="main-view"> <div class="w-100">
<div class="offcanvas-lg offcanvas-start" tabindex="-1" id="sidebar" aria-labelledby="sidebarLabel"> <div data-route="/webui/" data-title="Login | OpenWF WebUI">
<div class="offcanvas-header"> <p>Login using your OpenWF account credentials.</p>
<h5 class="offcanvas-title" id="sidebarLabel">Sidebar</h5> <form onsubmit="doLogin();return false;">
<button <label for="email">Email address</label>
type="button" <input class="form-control" type="email" id="email" required />
class="btn-close" <br />
data-bs-dismiss="offcanvas" <label for="password">Password</label>
data-bs-target="#sidebar" <input class="form-control" type="password" id="password" required />
aria-label="Close" <br />
></button> <button class="btn btn-primary" type="submit">Login</button>
</form>
</div>
<div data-route="/webui/inventory" data-title="Inventory | OpenWF WebUI">
<p id="refresh-note" class="mb-4">
Note: Changes made here will only be reflected in-game when the game re-downloads your
inventory. Visiting the navigation should be the easiest way to trigger that.
</p>
<div class="card mb-4">
<h5 class="card-header">Add Items</h5>
<form class="card-body input-group" onsubmit="doAcquireMiscItems();return false;">
<input class="form-control" id="miscitem-count" type="number" min="1" value="1" />
<input class="form-control" id="miscitem-type" list="datalist-miscitems" />
<button class="btn btn-primary" type="submit">Add</button>
</form>
</div> </div>
<div class="offcanvas-body"> <div class="row">
<div class="navbar p-0"> <div class="col-lg-6">
<ul class="navbar-nav justify-content-end"> <div class="card mb-4">
<li class="nav-item"> <h5 class="card-header">Warframes</h5>
<a <div class="card-body">
class="nav-link" <form class="input-group mb-3" onsubmit="doAcquireWarframe();return false;">
href="/webui/inventory" <input class="form-control" id="warframe-to-acquire" list="datalist-warframes" />
data-bs-dismiss="offcanvas" <button class="btn btn-primary" type="submit">Add</button>
data-bs-target="#sidebar" </form>
> <table class="table table-hover w-100">
Inventory <tbody id="warframe-list"></tbody>
</a> </table>
</li> </div>
<li class="nav-item"> </div>
<a </div>
class="nav-link" <div class="col-lg-6">
href="/webui/mods" <div class="card mb-4">
data-bs-dismiss="offcanvas" <h5 class="card-header">Weapons</h5>
data-bs-target="#sidebar" <div class="card-body">
> <form class="input-group mb-3" onsubmit="doAcquireWeapon();return false;">
Mods <input class="form-control" id="weapon-to-acquire" list="datalist-weapons" />
</a> <button class="btn btn-primary" type="submit">Add</button>
</li> </form>
<li class="nav-item"> <table class="table table-hover w-100">
<a <tbody id="weapon-list"></tbody>
class="nav-link" </table>
href="/webui/settings" </div>
data-bs-dismiss="offcanvas" </div>
data-bs-target="#sidebar"
>
Settings
</a>
</li>
</ul>
</div> </div>
</div> </div>
</div> </div>
<div> <div data-route="/webui/mods" data-title="Mods | OpenWF WebUI">
<div data-route="/webui/" data-title="Login | OpenWF WebUI"> <p id="refresh-note" class="mb-4">
<p>Login using your OpenWF account credentials.</p> Note: Changes made here will only be reflected in-game when the game re-downloads your
<form onsubmit="doLogin();return false;"> inventory. Visiting the navigation should be the easiest way to trigger that.
<label for="email">Email address</label> </p>
<input class="form-control" type="email" id="email" required /> <div class="row">
<br /> <div class="col-xxl-6">
<label for="password">Password</label> <div class="card mb-4">
<input class="form-control" type="password" id="password" required /> <h5 class="card-header">Add Riven</h5>
<br /> <form class="card-body" onsubmit="doAcquireRiven();return false;">
<button class="btn btn-primary" type="submit">Login</button> <select class="form-control mb-3" id="addriven-type">
</form> <option value="LotusArchgunRandomModRare">LotusArchgunRandomModRare</option>
</div> <option value="LotusModularMeleeRandomModRare">LotusModularMeleeRandomModRare</option>
<div data-route="/webui/inventory" data-title="Inventory | OpenWF WebUI"> <option value="LotusModularPistolRandomModRare">LotusModularPistolRandomModRare</option>
<p id="refresh-note" class="mb-4"> <option value="LotusPistolRandomModRare">LotusPistolRandomModRare</option>
Note: Changes made here will only be reflected in-game when the game re-downloads your <option value="LotusRifleRandomModRare" selected>LotusRifleRandomModRare</option>
inventory. Visiting the navigation should be the easiest way to trigger that. <option value="LotusShotgunRandomModRare">LotusShotgunRandomModRare</option>
</p> <option value="PlayerMeleeWeaponRandomModRare">PlayerMeleeWeaponRandomModRare</option>
<div class="card mb-4"> </select>
<h5 class="card-header">Add Items</h5> <textarea id="addriven-fingerprint" class="form-control mb-3" placeholder="Fingerprint"></textarea>
<form class="card-body input-group" onsubmit="doAcquireMiscItems();return false;"> <button class="btn btn-primary" style="margin-right: 5px" type="submit">Add</button>
<input class="form-control" id="miscitem-count" type="number" min="1" value="1" /> <a href="riven-tool/" target="_blank">Need help with the fingerprint?</a>
<input class="form-control" id="miscitem-type" list="datalist-miscitems" /> </form>
<button class="btn btn-primary" type="submit">Add</button>
</form>
</div>
<div class="row">
<div class="col-lg-6">
<div class="card mb-4">
<h5 class="card-header">Warframes</h5>
<div class="card-body">
<form class="input-group" onsubmit="doAcquireWarframe();return false;">
<input
class="form-control"
id="warframe-to-acquire"
list="datalist-warframes"
/>
<button class="btn btn-primary" type="submit">Add</button>
</form>
<table class="table table-hover w-100">
<tbody id="warframe-list"></tbody>
</table>
</div>
</div>
</div> </div>
<div class="col-lg-6"> <div class="card mb-4">
<div class="card mb-4"> <h5 class="card-header">Rivens</h5>
<h5 class="card-header">Weapons</h5> <div class="card-body">
<div class="card-body"> <table class="table table-hover w-100">
<form class="input-group" onsubmit="doAcquireWeapon();return false;"> <tbody id="riven-list"></tbody>
<input class="form-control" id="weapon-to-acquire" list="datalist-weapons" /> </table>
<button class="btn btn-primary" type="submit">Add</button>
</form>
<table class="table table-hover w-100">
<tbody id="weapon-list"></tbody>
</table>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> <div class="col-xxl-6">
<div data-route="/webui/mods" data-title="Mods | OpenWF WebUI"> <div class="card mb-4">
<p id="refresh-note" class="mb-4"> <h5 class="card-header">Mods</h5>
Note: Changes made here will only be reflected in-game when the game re-downloads your <div class="card-body">
inventory. Visiting the navigation should be the easiest way to trigger that. <form class="input-group mb-3" onsubmit="doAcquireMod();return false;">
</p> <input class="form-control" id="mod-to-acquire" list="datalist-mods" />
<div class="row"> <button class="btn btn-primary" type="submit">Add</button>
<div class="col-xxl-6">
<div class="card mb-4">
<h5 class="card-header">Add Riven</h5>
<form class="card-body" onsubmit="doAcquireRiven();return false;">
<select class="form-control mb-3" id="addriven-type">
<option value="LotusArchgunRandomModRare">LotusArchgunRandomModRare</option>
<option value="LotusModularMeleeRandomModRare">
LotusModularMeleeRandomModRare
</option>
<option value="LotusModularPistolRandomModRare">
LotusModularPistolRandomModRare
</option>
<option value="LotusPistolRandomModRare">LotusPistolRandomModRare</option>
<option value="LotusRifleRandomModRare" selected>
LotusRifleRandomModRare
</option>
<option value="LotusShotgunRandomModRare">LotusShotgunRandomModRare</option>
<option value="PlayerMeleeWeaponRandomModRare">
PlayerMeleeWeaponRandomModRare
</option>
</select>
<textarea
id="addriven-fingerprint"
class="form-control mb-3"
placeholder="Fingerprint"
></textarea>
<button class="btn btn-primary" style="margin-right: 5px" type="submit">Add</button>
<a href="riven-tool/" target="_blank">Need help with the fingerprint?</a>
</form> </form>
</div> <table class="table table-hover w-100">
<div class="card mb-4"> <tbody id="mods-list"></tbody>
<h5 class="card-header">Rivens</h5> </table>
<div class="card-body">
<table class="table table-hover w-100">
<tbody id="riven-list"></tbody>
</table>
</div>
</div>
</div>
<div class="col-xxl-6">
<div class="card mb-4">
<h5 class="card-header">Mods</h5>
<div class="card-body">
<form class="input-group" onsubmit="doAcquireMod();return false;">
<input class="form-control" id="mod-to-acquire" list="datalist-mods" />
<button class="btn btn-primary" type="submit">Add</button>
</form>
<table class="table table-hover w-100">
<tbody id="mods-list"></tbody>
</table>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div data-route="/webui/settings" data-title="Settings | OpenWF WebUI"> </div>
<form onsubmit="doChangeSettings();return false;"> <div data-route="/webui/cheats, /webui/settings" data-title="Cheats | OpenWF WebUI">
<div class="form-check"> <div class="row">
<input class="form-check-input" type="checkbox" id="skipStoryModeChoice" /> <div class="col-lg-4">
<label class="form-check-label" for="skipStoryModeChoice">Skip Story Mode Choice</label> <div class="card mb-4">
<h5 class="card-header">Server</h5>
<form class="card-body" onsubmit="doChangeSettings();return false;">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="skipStoryModeChoice" />
<label class="form-check-label" for="skipStoryModeChoice">Skip Story Mode Choice</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="skipTutorial" />
<label class="form-check-label" for="skipTutorial">Skip Tutorial</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllScans" />
<label class="form-check-label" for="unlockAllScans">Unlock All Scans</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllMissions" />
<label class="form-check-label" for="unlockAllMissions">Unlock All Missions</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllQuests" />
<label class="form-check-label" for="unlockAllQuests">Unlock All Quests</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="completeAllQuests" />
<label class="form-check-label" for="completeAllQuests">Complete All Quests</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="infiniteResources" />
<label class="form-check-label" for="infiniteResources">Infinite Credits and Platinum</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllShipFeatures" />
<label class="form-check-label" for="unlockAllShipFeatures">Unlock All Ship Features</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllShipDecorations" />
<label class="form-check-label" for="unlockAllShipDecorations">Unlock All Ship Decorations</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllFlavourItems" />
<label class="form-check-label" for="unlockAllFlavourItems">
Unlock All <abbr title="Animation Sets, Glyphs, Plattes, etc.">Flavor Items</abbr>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllSkins" />
<label class="form-check-label" for="unlockAllSkins">Unlock All Skins</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="universalPolarityEverywhere" />
<label class="form-check-label" for="universalPolarityEverywhere">
Universal Polarity Everywhere
</label>
</div>
<div class="form-group mt-2">
<label class="form-label" for="spoofMasteryRank">
Spoofed Mastery Rank (-1 to disable)
</label>
<input class="form-control" id="spoofMasteryRank" type="number" min="-1" />
</div>
<button class="btn btn-primary mt-3" type="submit">Save Settings</button>
</form>
</div> </div>
<div class="form-check"> </div>
<input class="form-check-input" type="checkbox" id="skipTutorial" /> <div class="col-lg-4">
<label class="form-check-label" for="skipTutorial">Skip Tutorial</label> <div class="card mb-4">
<h5 class="card-header">Account</h5>
<div class="card-body">
<button class="btn btn-primary" onclick="doUnlockAllFocusSchools();">Unlock All Focus Schools</button>
</div>
</div> </div>
<div class="form-check"> </div>
<input class="form-check-input" type="checkbox" id="unlockAllScans" /> <div class="col-lg-4">
<label class="form-check-label" for="unlockAllScans">Unlock All Scans</label> <div class="card mb-4">
<h5 class="card-header">Client</h5>
<div id="client-cheats-nok" class="card-body">
Client cheats are currently unavailable. This could be because your client is not running or using a DLL without an HTTP interface.
</div>
<div id="client-cheats-ok" class="card-body d-none">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="skip_mission_start_timer" />
<label class="form-check-label" for="skip_mission_start_timer">
Skip Mission Start Timer
</label>
</div>
<div class="form-group mt-3">
<label class="form-label" for="fov_override">FOV Override (0 to disable)</label>
<input id="fov_override" class="form-range" type="range" min="0" value="0" max="2260000" step="10000">
</div>
</div>
</div> </div>
<div class="form-check"> </div>
<input class="form-check-input" type="checkbox" id="unlockAllMissions" />
<label class="form-check-label" for="unlockAllMissions">Unlock All Missions</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllQuests" />
<label class="form-check-label" for="unlockAllQuests">Unlock All Quests</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="completeAllQuests" />
<label class="form-check-label" for="completeAllQuests">Complete All Quests</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="infiniteResources" />
<label class="form-check-label" for="infiniteResources">
Infinite Credits and Platinum
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllShipFeatures" />
<label class="form-check-label" for="unlockAllShipFeatures">Unlock All Ship Features</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllShipDecorations" />
<label class="form-check-label" for="unlockAllShipDecorations">
Unlock All Ship Decorations
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllFlavourItems" />
<label class="form-check-label" for="unlockAllFlavourItems">
Unlock All <abbr title="Animation Sets, Glyphs, Plattes, etc.">Flavor Items</abbr>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllSkins" />
<label class="form-check-label" for="unlockAllSkins">Unlock All Skins</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="universalPolarityEverywhere" />
<label class="form-check-label" for="universalPolarityEverywhere">
Universal Polarity Everywhere
</label>
</div>
<div class="form-group mt-2 mb-2">
<label class="form-label" for="spoofMasteryRank">
Spoofed Mastery Rank (-1 to disable)
</label>
<input class="form-control" id="spoofMasteryRank" type="number" min="-1" />
</div>
<button class="btn btn-primary mt-3" type="submit">Save Settings</button>
</form>
</div> </div>
</div> </div>
</div> </div>
<datalist id="datalist-warframes"></datalist> </div>
<datalist id="datalist-weapons"></datalist> <datalist id="datalist-warframes"></datalist>
<datalist id="datalist-miscitems"></datalist> <datalist id="datalist-weapons"></datalist>
<datalist id="datalist-mods"></datalist> <datalist id="datalist-miscitems"></datalist>
<script src="libs/jquery-3.6.0.min.js"></script> <datalist id="datalist-mods"></datalist>
<script src="libs/whirlpool-js.min.js"></script> <script src="libs/jquery-3.6.0.min.js"></script>
<script src="libs/single.js"></script> <script src="libs/whirlpool-js.min.js"></script>
<script src="riven-tool/RivenParser.js"></script> <script src="libs/single.js"></script>
<script src="script.js"></script> <script src="riven-tool/RivenParser.js"></script>
<script src="libs/bootstrap.bundle.min.js"></script> <script src="script.js"></script>
</body> <script src="libs/bootstrap.bundle.min.js"></script>
</body>
</html> </html>

View File

@ -701,3 +701,83 @@ function doChangeSettings() {
}); });
}); });
} }
// Cheats route
fetch("http://localhost:61558/ping", { mode: "no-cors" }).then(() => {
$("#client-cheats-nok").addClass("d-none");
$("#client-cheats-ok").removeClass("d-none");
fetch("http://localhost:61558/skip_mission_start_timer")
.then(res => res.text())
.then(res => {
document.getElementById("skip_mission_start_timer").checked = res == "1";
});
document.getElementById("skip_mission_start_timer").onchange = function () {
fetch("http://localhost:61558/skip_mission_start_timer?" + this.checked);
};
fetch("http://localhost:61558/fov_override")
.then(res => res.text())
.then(res => {
document.getElementById("fov_override").value = parseFloat(res) * 10000;
});
document.getElementById("fov_override").oninput = function () {
fetch("http://localhost:61558/fov_override?" + this.value);
};
});
function doUnlockAllFocusSchools() {
revalidateAuthz(() => {
$.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1").done(async data => {
const missingFocusUpgrades = {
"/Lotus/Upgrades/Focus/Attack/AttackFocusAbility": true,
"/Lotus/Upgrades/Focus/Tactic/TacticFocusAbility": true,
"/Lotus/Upgrades/Focus/Ward/WardFocusAbility": true,
"/Lotus/Upgrades/Focus/Defense/DefenseFocusAbility": true,
"/Lotus/Upgrades/Focus/Power/PowerFocusAbility": true
};
if (data.FocusUpgrades) {
for (const focusUpgrade of data.FocusUpgrades) {
if (focusUpgrade.ItemType in missingFocusUpgrades) {
delete missingFocusUpgrades[focusUpgrade.ItemType];
}
}
}
for (const upgradeType of Object.keys(missingFocusUpgrades)) {
await unlockFocusSchool(upgradeType);
}
if (Object.keys(missingFocusUpgrades).length == 0) {
alert("All focus schools are already unlocked.");
} else {
alert(
"Unlocked " +
Object.keys(missingFocusUpgrades).length +
" new focus schools! An inventory update will be needed for the changes to be reflected in-game. Visiting the navigation should be the easiest way to trigger that."
);
}
});
});
}
function unlockFocusSchool(upgradeType) {
return new Promise(resolve => {
// Deselect current FocusAbility so we will be able to unlock the way for free
$.post({
url: "/api/focus.php?" + window.authz + "&op=5",
contentType: "text/plain",
data: "{}"
}).done(function () {
// Unlock the way now
$.post({
url: "/api/focus.php?" + window.authz + "&op=2",
contentType: "text/plain",
data: JSON.stringify({
FocusType: upgradeType
})
}).done(function () {
resolve();
});
});
});
}