UNPKG

bdo-shopping-cart-package

Version:
453 lines 20.7 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ItemManager = exports.Recipe = exports.Item = exports.RecipeData = exports.MarketPrice = exports.getShoppingCartDataForItem = exports.getMarketPriceForItem = void 0; var ShoppingCart_1 = require("./ShoppingCart"); var Action_1 = require("../optimizers/Action"); var PPSOptimizer_1 = require("./../optimizers/PPSOptimizer"); exports.getMarketPriceForItem = function (item) { return (item.overrideMarketPrice || (item.marketData && item.marketData["Market Price"]) || 0); }; exports.getShoppingCartDataForItem = function (item, recipePath) { return item.shoppingCartData[recipePath]; }; var MarketPrice = /** @class */ (function () { function MarketPrice() { } return MarketPrice; }()); exports.MarketPrice = MarketPrice; ; var RecipeData = /** @class */ (function () { function RecipeData() { } return RecipeData; }()); exports.RecipeData = RecipeData; ; var Item = /** @class */ (function () { /** * Create a new Item object * @param initialItemData e.g {Action: string, Ingredients: [], Market Data: {}, Name: string, Quantity Produced: float, Recipe: [], Time to Produce: float} */ function Item(initialItemData) { var _this = this; this.resetUses = function (recipePath) { if (recipePath == null) { _this.usedInRecipes = {}; } else { delete _this.usedInRecipes[recipePath]; delete _this.shoppingCartData[recipePath]; } // console.log("Reset Use: ", this.name, 'Recipe Path:', recipePath, 'Used in Recipes:', JSON.stringify(this.usedInRecipes, null, 4), JSON.stringify(this.shoppingCartData, null, 4)) if (Object.keys(_this.usedInRecipes).length == 0) _this.activeRecipeId = ""; }; // console.log("Initial Item Data", initialItemData) this.name = initialItemData["Name"]; this.marketData = initialItemData["Market Data"]; this.shoppingCartData = {}; this.recipes = {}; this.usedInRecipes = {}; this.activeRecipeId = ""; this.depth = initialItemData["depth"] || -1; this.overrideMarketPrice = null; this.isSymbolic = false; // A symbolic recipe is not meant to be bought this.image = initialItemData["Image"]; this.addRecipe(initialItemData["_id"], initialItemData["Name"], initialItemData["Recipe"], initialItemData["Quantity Produced"], initialItemData["Time to Produce"], initialItemData["Action"], initialItemData["Image"]); } /** * * @param _id * @param productName * @param recipe * @param quantityProduced * @param timeToProduce * @param action * @param image */ Item.prototype.addRecipe = function (_id, productName, recipe, quantityProduced, timeToProduce, action, image) { if (this.recipes[_id] == null) { this.recipes[_id] = new Recipe(productName, recipe, quantityProduced, timeToProduce, action, image); if (action == "Symbolic") { this.isSymbolic = true; } } // this.printRecipes() }; /** * * @param actionTaken // Craft or Buy * @param parentName // What recipe is this item used in? * @param parentRecipeId // What recipe is this item used in? * @param activeRecipeId // One of the recipes to craft this item * @param recipePath // One of the recipes to craft this item */ Item.prototype.addUse = function (actionTaken, parentName, parentRecipeId, activeRecipeId, recipePath) { this.usedInRecipes[recipePath] = { actionTaken: actionTaken, parentName: parentName, parentRecipeId: parentRecipeId, }; if (this.activeRecipeId == "") this.selectRecipe(activeRecipeId); else if (activeRecipeId != this.activeRecipeId) { console.log("POSSIBLE ERROR: Recursive recipe OR recipe needs to be bought/crafted at the same time... or crafted using multiple recipes. \nItem name:", this.name, "\nActive recipe:", this.activeRecipeId, "\nTarget recipe:", activeRecipeId); } }; /** * * @param recipePath * @param data */ Item.prototype.addShoppingCartData = function (recipePath, data) { this.shoppingCartData[recipePath] = data; }; Item.prototype.selectRecipe = function (recipeId) { if (this.recipes[recipeId] != null) { this.activeRecipeId = recipeId; } else if (recipeId == "" || recipeId == null) { this.activeRecipeId = ""; } }; Item.prototype.setDepth = function (depth) { if (this.depth == -1 || depth < this.depth) { this.depth = depth; } }; Item.prototype.applyBuffs = function (buffs) { for (var _i = 0, _a = Object.values(this.recipes); _i < _a.length; _i++) { var recipe = _a[_i]; recipe.applyBuffs(buffs); } }; Item.prototype.printRecipes = function () { console.log("Recipes:", this.recipes); }; return Item; }()); exports.Item = Item; var Recipe = /** @class */ (function () { /** * * @param productName * @param ingredients * @param quantityProduced * @param timeToProduce * @param action */ function Recipe(productName, ingredients, quantityProduced, timeToProduce, action, image) { this.productName = productName; this.ingredients = ingredients; this.quantityProduced = quantityProduced; this.timeToProduce = timeToProduce; this.originalTimeToProduce = timeToProduce; this.action = action; this.image = image; } Recipe.prototype.printIngredients = function () { console.log("Ingredients:", this.ingredients); }; Recipe.prototype.applyBuffs = function (buffs) { if (this.action in buffs) { this.timeToProduce = Math.max(this.originalTimeToProduce - buffs[this.action].timeReduction, 0); } }; return Recipe; }()); exports.Recipe = Recipe; var ItemManager = /** @class */ (function () { function ItemManager() { var _this = this; this.officialProductName = ""; /** * Starting at the recipe path, remove all references pointing to that item. * In other words, all paths branching off that recipePath provided will have their 'usedInRecipes' dictionary reset * @param itemName // Name of the item * @param recipePath // Path to reach the item (ingredient) */ this.resetRecipePath = function (itemName, recipePath) { // Parse path variables var pathArr = recipePath.split("/"); var parentName = pathArr.length >= 2 ? pathArr[pathArr.length - 2] : null; if (parentName == "") parentName = null; var parentPath = pathArr.slice(0, -1).join("/"); if (parentPath == "") parentPath = null; // console.log('Reset', pathArr, parentName, parentPath) // Reset items that were dependent on the previous recipe _this.startRecursiveReset(_this.items[itemName], _this.items, parentPath); }; /** * Callback function for RecipesTable.onRecipeClick * Updates the 'this.items' object in this component's state, which updates the RecipesTable(s) * @param itemName The name of the item * @param recipeId The id of the recipe selected */ this.selectRecipe = function (itemName, recipeId, recipePath) { var items = _this.items; // Step 1: Parse recipe Path and get the parent Recipe Id for later var _a = _this.splitPath(recipePath), parentName = _a.parentName, parentPath = _a.parentPath; var parentRecipeId = _this.items[parentName] != null ? _this.items[parentName].activeRecipeId : ""; // Step 2: Select the recipe // console.log("ITEMS", items); // console.log("ITEM NAME", itemName); if (items[itemName] == null) return; items[itemName].selectRecipe(recipeId); // console.log('recipesDashboard.jsx | items after recursive reset', items) // Step 2: Find the best way to make money using the new decision _this.shoppingCart.optimizer.setItems(items, _this.officialProductName); var optimalActions = _this.shoppingCart.optimizer.startCalculatingOptimalActions(itemName, recipeId); // console.log("optimalActions", optimalActions); var chosenAction = recipeId == "" ? Action_1.ActionTaken.Buy : Action_1.ActionTaken.Craft; // Step 3: Using the new optimal actions calculated, update the items object so that the corresponding tables are displayed _this.cascadeActiveRecipeWithOptimalActions(optimalActions, itemName, chosenAction, items, { parentRecipeId: parentRecipeId, parentName: parentName, parentPath: parentPath, }); // Step 4: Recalculate all the costs! _this.recalculate(); }; /** * * @param overrides * { * craftCount: int * } */ this.recalculate = function (overrides) { if (overrides === void 0) { overrides = null; } // Step 1: Calculate the costs associated with the desired action tree. (TODO: Move to separate function?) // console.log("THIS PROPS PRODUCT = ", this.officialProductName, this.items); if (overrides != null) { _this.shoppingCart.calculateCosts(_this.officialProductName, overrides.craftCount, _this.items); } else { _this.shoppingCart.calculateCosts(_this.officialProductName, _this.defaultCraftCount, _this.items); } }; this.items = {}; this.alreadyResetPath = {}; // To keep track of paths reset when calling 'startRecursiveReset' this.shoppingCart = new ShoppingCart_1.ShoppingCart(new PPSOptimizer_1.PPSOptimizer()); this.defaultCraftCount = 100; } /** * Parses the information retrieved from the backend to produce the state object 'items' * @param {} recipes */ ItemManager.prototype.parseRecipes = function (recipes) { // console.log("Original Recipes Data: ", recipes); this.items = {}; if (recipes == null) return this.items; // Get the official name of the item being produced this.officialProductName = ""; if (recipes.length > 0) this.officialProductName = recipes[0]["Name"]; // Parse Recipe and prep for the display in table format for (var _i = 0, recipes_1 = recipes; _i < recipes_1.length; _i++) { var recipe = recipes_1[_i]; this.addItem(this.items, recipe); for (var _a = 0, _b = recipe.Ingredients; _a < _b.length; _a++) { var ingredient = _b[_a]; this.addItem(this.items, ingredient); } } return this.items; }; ItemManager.prototype.applyBuffs = function (buffs) { if (!buffs) return; for (var _i = 0, _a = Object.values(this.items); _i < _a.length; _i++) { var item = _a[_i]; item.applyBuffs(buffs); } }; /** * * @param items {key: item name, value: Item object} * @param item */ ItemManager.prototype.addItem = function (items, item) { var _a, _b; if (item == null || items == null) return; if (items[item["Name"]] == null) { items[item["Name"]] = new Item(item); } else { items[item["Name"]].addRecipe(item["_id"], item["Name"], item["Recipe"], item["Quantity Produced"] || 0, item["Time to Produce"] || 0, item["Action"], (_a = item["Image"]) !== null && _a !== void 0 ? _a : ""); if (item["Name"] != this.officialProductName) items[item["Name"]].setDepth((_b = item["depth"]) !== null && _b !== void 0 ? _b : -1); } // console.log('item name', item.Name) }; /** * * @param item Instance of the Item object * @param items Dictionary of Item objects. This is used to referenced Items used in the recipe */ ItemManager.prototype.startRecursiveReset = function (item, items, parentPath) { this.alreadyResetPath = {}; // console.log("recipesDashboard.jsx | Starting recursive reset:", parentPath, item); this.recursivelyResetItemUses(item, items, parentPath); }; /** * * @param item Instance of the Item object * @param items Dictionary of Item objects. This is used to referenced Items used in the recipe */ ItemManager.prototype.recursivelyResetItemUses = function (item, items, parentPath) { if (parentPath === void 0) { parentPath = null; } if (item == null || items == null) return; var recipeId = item.activeRecipeId; var currentPath = (parentPath || "") + "/" + item.name; if (this.alreadyResetPath[currentPath]) { console.log("Already reset", item.name); return; } if (item.usedInRecipes[currentPath] == null) { // console.log('No recipe data available for item/path', item.name, currentPath, JSON.stringify(item.usedInRecipes,null, 4)); return; } this.alreadyResetPath[currentPath] = true; if (recipeId != "") { for (var _i = 0, _a = item.recipes[recipeId].ingredients; _i < _a.length; _i++) { var ingredient = _a[_i]; var ingredientName = ingredient["Item Name"]; // console.log( // "Ingredient reset:", // ingredient["Item Name"], parentPath // ); // const newPath = `${currentPath || ''}/${ingredientName}` this.recursivelyResetItemUses(items[ingredientName], items, currentPath); } } // items[ingredientName].resetUses(newPath); item.resetUses(currentPath); items[item.name] = item; }; /** * Splits it into /parentPath/parentName * @param path */ ItemManager.prototype.splitPath = function (path) { var pathArr = path.split("/"); var currentItemName = pathArr.length >= 2 ? pathArr[pathArr.length - 1] : ""; var parentName = pathArr.length >= 2 ? pathArr[pathArr.length - 2] : ""; var parentPath = pathArr.slice(0, -1).join("/"); // console.log('Select', pathArr, parentName, parentPath) return { parentPath: parentPath, parentName: parentName, currentItemName: currentItemName }; }; ItemManager.prototype.resetToOptimal = function () { if (this.officialProductName == null) { return this.items; } for (var _i = 0, _a = Object.values(this.items); _i < _a.length; _i++) { var item = _a[_i]; item.resetUses(); item.selectRecipe(""); } // Get optimal action for each recipe of the root product this.shoppingCart.optimizer.setItems(this.items, this.officialProductName); var bestRecipeActions = this.shoppingCart.optimizer.findOptimalActionSets(); var product = this.officialProductName; // Choose most optimal recipe and the optimal actions for profit var bestActionSet = null; for (var actionSetIdx in bestRecipeActions) { var actionSet = bestRecipeActions[actionSetIdx]; if (bestActionSet == null) { bestActionSet = actionSet; continue; } var oldCraftAction = bestActionSet.optimalActions[product].Craft; var newCraftAction = actionSet.optimalActions[product].Craft; var marketPrice = exports.getMarketPriceForItem(this.items[product]); if (oldCraftAction != null && newCraftAction != null && oldCraftAction.calculateProfit(marketPrice) < newCraftAction.calculateProfit(marketPrice)) bestActionSet = actionSet; } if (bestActionSet != null) { var craftAction = bestActionSet["optimalActions"][product].Craft; if (craftAction != null) { this.selectRecipe(product, craftAction.recipe_id, "/" + product); } else if (bestActionSet.optimalActions[product].Buy != null) { this.selectRecipe(product, bestActionSet.optimalActions[product].Buy.recipe_id, "/" + product); } } return this.items; }; /** * Selects the RecipeTables that should be active by modifying the 'this.items' object * @param optimalActions The set of actions determined by the user * @param currentItem Name of the item * @param actionTaken 'Buy' or 'Craft' * @param items this.items */ ItemManager.prototype.cascadeActiveRecipeWithOptimalActions = function (optimalActions, currentItemName, actionTaken, items, parent) { if (items === void 0) { items = __assign({}, this.items); } var parentRecipeId = parent.parentRecipeId, parentName = parent.parentName, parentPath = parent.parentPath; // console.log("Optimal Actions", JSON.stringify(optimalActions, null, 4)); // console.log("Active Item:", currentItemName); // console.log("Action Taken:", actionTaken); // console.log("Parent Path:", parentPath); if (items[currentItemName].isSymbolic) actionTaken = Action_1.ActionTaken.Craft; var action = optimalActions[currentItemName][actionTaken]; if (action == null) return items; // Base case. Return when there is no valid action var currentPath = (parentPath || "") + "/" + currentItemName; var recipePathArr = currentPath.split("/"); var containsLoop = new Set(recipePathArr).size !== recipePathArr.length; if (containsLoop) { actionTaken = Action_1.ActionTaken.Buy; } if (items[currentItemName] != null) { items[currentItemName].addUse(actionTaken, parentName, parentRecipeId, action.recipe_id, currentPath); // e.g. Item.addUse('Craft', parentRecipeId, action's recipe Id which may be null if Buying) } else { console.log("ERROR: '" + currentItemName + "' does not have a recipe entry in the database. Request a FIX by sending a DM on discord to @Kitsune#1040"); } if (actionTaken === Action_1.ActionTaken.Buy) return items; // Recursively update activeRecipes dictionary using more calls to cascadeActiveRecipeWithOptimalActions for (var ingredientIdx in action.recipe.ingredients) { var ingredient = action.recipe.ingredients[ingredientIdx]; var name_1 = ingredient["Item Name"]; var ingredientAction = action.actionSequence[ingredientIdx]; var newParent = { parentRecipeId: action.recipe_id, parentName: currentItemName, parentPath: currentPath, }; this.cascadeActiveRecipeWithOptimalActions(optimalActions, name_1, ingredientAction, items, newParent); } return items; }; return ItemManager; }()); exports.ItemManager = ItemManager; //# sourceMappingURL=ShoppingCartCore.js.map