diff --git a/builder/index.html b/builder/index.html index d0ab71a..73e20b1 100644 --- a/builder/index.html +++ b/builder/index.html @@ -313,7 +313,7 @@
- +
@@ -1291,7 +1291,7 @@
-
+
diff --git a/js/build_constants.js b/js/build_constants.js index 2983328..820beb7 100644 --- a/js/build_constants.js +++ b/js/build_constants.js @@ -85,7 +85,7 @@ let tome_names = [ "Guild Tome", ] let equipmentInputs = equipment_fields.map(x => x + "-choice"); -let buildFields = equipment_fields.map(x => x+"-tooltip").concat(tome_fields.map(x => x + "-tooltip")); +let build_fields = equipment_fields.map(x => x+"-tooltip"); let tomeInputs = tome_fields.map(x => x + "-choice"); let powder_inputs = [ @@ -100,7 +100,7 @@ let weapon_keys = ['dagger', 'wand', 'bow', 'relik', 'spear']; let armor_keys = ['helmet', 'chestplate', 'leggings', 'boots']; let accessory_keys= ['ring1', 'ring2', 'bracelet', 'necklace']; let powderable_keys = ['helmet', 'chestplate', 'leggings', 'boots', 'weapon']; -let equipment_keys = ['helmet', 'chestplate', 'leggings', 'boots', 'ring1', 'ring2', 'bracelet', 'necklace', 'weapon'].concat(tome_keys); +let equipment_keys = ['helmet', 'chestplate', 'leggings', 'boots', 'ring1', 'ring2', 'bracelet', 'necklace', 'weapon']; let spell_disp = ['spell0-info', 'spell1-info', 'spell2-info', 'spell3-info']; let other_disp = ['build-order', 'set-info', 'int-info']; diff --git a/js/build_encode_decode.js b/js/build_encode_decode.js index 0929e4e..12b45b1 100644 --- a/js/build_encode_decode.js +++ b/js/build_encode_decode.js @@ -137,7 +137,7 @@ function decodeBuild(url_tag) { /* Stores the entire build in a string using B64 encoding and adds it to the URL. */ -function encodeBuild(build) { +function encodeBuild(build, powders) { if (build) { let build_string; @@ -147,19 +147,15 @@ function encodeBuild(build) { build_string = ""; tome_string = ""; - let crafted_idx = 0; - let custom_idx = 0; for (const item of build.items) { - if (item.get("custom")) { - let custom = "CI-"+encodeCustom(build.customItems[custom_idx],true); + if (item.statMap.get("custom")) { + let custom = "CI-"+encodeCustom(item, true); build_string += Base64.fromIntN(custom.length, 3) + custom; - custom_idx += 1; build_version = Math.max(build_version, 5); - } else if (item.get("crafted")) { - build_string += "CR-"+encodeCraft(build.craftedItems[crafted_idx]); - crafted_idx += 1; - } else if (item.get("category") === "tome") { + } else if (item.statMap.get("crafted")) { + build_string += "CR-"+encodeCraft(item); + } else if (item.statMap.get("category") === "tome") { let tome_id = item.get("id"); if (tome_id <= 60) { // valid normal tome. ID 61-63 is for NONE tomes. @@ -167,7 +163,7 @@ function encodeBuild(build) { } tome_string += Base64.fromIntN(tome_id, 1); } else { - build_string += Base64.fromIntN(item.get("id"), 3); + build_string += Base64.fromIntN(item.statMap.get("id"), 3); } } @@ -175,7 +171,7 @@ function encodeBuild(build) { build_string += Base64.fromIntN(getValue(skp + "-skp"), 2); // Maximum skillpoints: 2048 } build_string += Base64.fromIntN(build.level, 2); - for (const _powderset of build.powders) { + for (const _powderset of powders) { let n_bits = Math.ceil(_powderset.length / 6); build_string += Base64.fromIntN(n_bits, 1); // Hard cap of 378 powders. // Slice copy. @@ -196,26 +192,24 @@ function encodeBuild(build) { } } -function copyBuild(build) { - if (build) { - copyTextToClipboard(url_base+location.hash); - document.getElementById("copy-button").textContent = "Copied!"; - } +function copyBuild() { + copyTextToClipboard(url_base+location.hash); + document.getElementById("copy-button").textContent = "Copied!"; } function shareBuild(build) { if (build) { let text = url_base+location.hash+"\n"+ "WynnBuilder build:\n"+ - "> "+build.helmet.get("displayName")+"\n"+ - "> "+build.chestplate.get("displayName")+"\n"+ - "> "+build.leggings.get("displayName")+"\n"+ - "> "+build.boots.get("displayName")+"\n"+ - "> "+build.ring1.get("displayName")+"\n"+ - "> "+build.ring2.get("displayName")+"\n"+ - "> "+build.bracelet.get("displayName")+"\n"+ - "> "+build.necklace.get("displayName")+"\n"+ - "> "+build.weapon.get("displayName")+" ["+build.weapon.get("powders").map(x => powderNames.get(x)).join("")+"]"; + "> "+build.helmet.statMap.get("displayName")+"\n"+ + "> "+build.chestplate.statMap.get("displayName")+"\n"+ + "> "+build.leggings.statMap.get("displayName")+"\n"+ + "> "+build.boots.statMap.get("displayName")+"\n"+ + "> "+build.ring1.statMap.get("displayName")+"\n"+ + "> "+build.ring2.statMap.get("displayName")+"\n"+ + "> "+build.bracelet.statMap.get("displayName")+"\n"+ + "> "+build.necklace.statMap.get("displayName")+"\n"+ + "> "+build.weapon.statMap.get("displayName")+" ["+build_powders[4].map(x => powderNames.get(x)).join("")+"]"; copyTextToClipboard(text); document.getElementById("share-button").textContent = "Copied!"; } diff --git a/js/builder.js b/js/builder.js index 1ce6a3f..0251fef 100644 --- a/js/builder.js +++ b/js/builder.js @@ -1,3 +1,5 @@ +let build_powders; + function getItemNameFromID(id) { if (redirectMap.has(id)) { return getItemNameFromID(redirectMap.get(id)); @@ -142,15 +144,263 @@ function show_tab(tab) { document.getElementById("tab-" + tab.split("-")[0] + "-btn").classList.add("selected-btn"); } +// autocomplete initialize +function init_autocomplete() { + let dropdowns = new Map(); + for (const eq of equipment_keys) { + if (tome_keys.includes(eq)) { + continue; + } + // build dropdown + let item_arr = []; + if (eq == 'weapon') { + for (const weaponType of weapon_keys) { + for (const weapon of itemLists.get(weaponType)) { + let item_obj = itemMap.get(weapon); + if (item_obj["restrict"] && item_obj["restrict"] === "DEPRECATED") { + continue; + } + if (item_obj["name"] == 'No '+ eq.charAt(0).toUpperCase() + eq.slice(1)) { + continue; + } + item_arr.push(weapon); + } + } + } else { + for (const item of itemLists.get(eq.replace(/[0-9]/g, ''))) { + let item_obj = itemMap.get(item); + if (item_obj["restrict"] && item_obj["restrict"] === "DEPRECATED") { + continue; + } + if (item_obj["name"] == 'No '+ eq.charAt(0).toUpperCase() + eq.slice(1)) { + continue; + } + item_arr.push(item) + } + } + + // create dropdown + dropdowns.set(eq, new autoComplete({ + data: { + src: item_arr + }, + selector: "#"+ eq +"-choice", + wrapper: false, + resultsList: { + maxResults: 1000, + tabSelect: true, + noResults: true, + class: "search-box dark-7 rounded-bottom px-2 fw-bold dark-shadow-sm", + element: (list, data) => { + // dynamic result loc + let position = document.getElementById(eq+'-dropdown').getBoundingClientRect(); + list.style.top = position.bottom + window.scrollY +"px"; + list.style.left = position.x+"px"; + list.style.width = position.width+"px"; + list.style.maxHeight = position.height * 2 +"px"; + + if (!data.results.length) { + message = document.createElement('li'); + message.classList.add('scaled-font'); + message.textContent = "No results found!"; + list.prepend(message); + } + }, + }, + resultItem: { + class: "scaled-font search-item", + selected: "dark-5", + element: (item, data) => { + item.classList.add(itemMap.get(data.value).tier); + }, + }, + events: { + input: { + selection: (event) => { + if (event.detail.selection.value) { + event.target.value = event.detail.selection.value; + } + event.target.dispatchEvent(new Event('input')); + }, + }, + } + })); + } + + for (const eq of tome_keys) { + // build dropdown + let tome_arr = []; + for (const tome of tomeLists.get(eq.replace(/[0-9]/g, ''))) { + let tome_obj = tomeMap.get(tome); + if (tome_obj["restrict"] && tome_obj["restrict"] === "DEPRECATED") { + continue; + } + //this should suffice for tomes - jank + if (tome_obj["name"].includes('No ' + eq.charAt(0).toUpperCase())) { + continue; + } + let tome_name = tome; + tome_arr.push(tome_name); + } + + // create dropdown + dropdowns.set(eq, new autoComplete({ + data: { + src: tome_arr + }, + selector: "#"+ eq +"-choice", + wrapper: false, + resultsList: { + maxResults: 1000, + tabSelect: true, + noResults: true, + class: "search-box dark-7 rounded-bottom px-2 fw-bold dark-shadow-sm", + element: (list, data) => { + // dynamic result loc + let position = document.getElementById(eq+'-dropdown').getBoundingClientRect(); + list.style.top = position.bottom + window.scrollY +"px"; + list.style.left = position.x+"px"; + list.style.width = position.width+"px"; + list.style.maxHeight = position.height * 2 +"px"; + + if (!data.results.length) { + message = document.createElement('li'); + message.classList.add('scaled-font'); + message.textContent = "No results found!"; + list.prepend(message); + } + }, + }, + resultItem: { + class: "scaled-font search-item", + selected: "dark-5", + element: (tome, data) => { + tome.classList.add(tomeMap.get(data.value).tier); + }, + }, + events: { + input: { + selection: (event) => { + if (event.detail.selection.value) { + event.target.value = event.detail.selection.value; + } + }, + }, + } + })); + } + + let filter_loc = ["filter1", "filter2", "filter3", "filter4"]; + for (const i of filter_loc) { + dropdowns.set(i+"-choice", new autoComplete({ + data: { + src: sq2ItemFilters, + }, + selector: "#"+i+"-choice", + wrapper: false, + resultsList: { + tabSelect: true, + noResults: true, + class: "search-box dark-7 rounded-bottom px-2 fw-bold dark-shadow-sm", + element: (list, data) => { + // dynamic result loc + console.log(i); + list.style.zIndex = "100"; + let position = document.getElementById(i+"-dropdown").getBoundingClientRect(); + window_pos = document.getElementById("search-container").getBoundingClientRect(); + list.style.top = position.bottom - window_pos.top + 5 +"px"; + list.style.left = position.x - window_pos.x +"px"; + list.style.width = position.width+"px"; + + if (!data.results.length) { + message = document.createElement('li'); + message.classList.add('scaled-font'); + message.textContent = "No filters found!"; + list.prepend(message); + } + }, + }, + resultItem: { + class: "scaled-font search-item", + selected: "dark-5", + }, + events: { + input: { + selection: (event) => { + if (event.detail.selection.value) { + event.target.value = event.detail.selection.value; + } + }, + }, + } + })); + } +} + +function collapse_element(elmnt) { + elem_list = document.querySelector(elmnt).children; + if (elem_list) { + for (elem of elem_list) { + if (elem.classList.contains("no-collapse")) { continue; } + if (elem.style.display == "none") { + elem.style.display = ""; + } else { + elem.style.display = "none"; + } + } + } + // macy quirk + window.dispatchEvent(new Event('resize')); + // weird bug where display: none overrides?? + document.querySelector(elmnt).style.removeProperty('display'); +} // TODO: Learn and use await function init() { console.log("builder.js init"); init_autocomplete(); + + // Other "main" stuff + // Spell dropdowns + for (const i of spell_disp) { + document.querySelector("#"+i+"Avg").addEventListener("click", () => toggle_spell_tab(i)); + } + for (const eq of equipment_keys) { + document.querySelector("#"+eq+"-tooltip").addEventListener("click", () => collapse_element('#'+eq+'-tooltip')); + } + + // Masonry setup + let masonry = Macy({ + container: "#masonry-container", + columns: 1, + mobileFirst: true, + breakAt: { + 1200: 4, + }, + margin: { + x: 20, + y: 20, + } + + }); + + let search_masonry = Macy({ + container: "#search-results", + columns: 1, + mobileFirst: true, + breakAt: { + 1200: 4, + }, + margin: { + x: 20, + y: 20, + } + + }); decodeBuild(url_tag); + builder_graph_init(); } -//load_init(init3); (async function() { let load_promises = [ load_init(), load_ing_init(), load_tome_init() ]; await Promise.all(load_promises); diff --git a/js/builder_graph.js b/js/builder_graph.js index 4fcd47b..083eb32 100644 --- a/js/builder_graph.js +++ b/js/builder_graph.js @@ -1,22 +1,180 @@ - - -class BuildEncodeNode extends ComputeNode { - constructor() { - super("builder-encode"); +/** + * Node for getting an item's stats from an item input field. + * + * Signature: ItemInputNode() => Item | null + */ +class ItemInputNode extends InputNode { + /** + * Make an item stat pulling compute node. + * + * @param name: Name of this node. + * @param item_input_field: Input field (html element) to listen for item names from. + * @param none_item: Item object to use as the "none" for this field. + */ + constructor(name, item_input_field, none_item) { + super(name, item_input_field); + this.none_item = new Item(none_item); + this.none_item.statMap.set('NONE', true); } compute_func(input_map) { - if (input_map.size !== 1) { throw "BuildEncodeNode accepts exactly one input (build)"; } - const [build] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element - return encodeBuild(build); + // built on the assumption of no one will type in CI/CR letter by letter + + let item_text = this.input_field.value; + if (!item_text) { + return this.none_item; + } + + let item; + + if (item_text.slice(0, 3) == "CI-") { + item = getCustomFromHash(item_text); + } + else if (item_text.slice(0, 3) == "CR-") { + item = getCraftFromHash(item_text); + } + else if (itemMap.has(item_text)) { + item = new Item(itemMap.get(item_text)); + } + else if (tomeMap.has(item_text)) { + item = new Item(tomeMap.get(item_text)); + } + + if (item) { + let type_match; + if (this.none_item.statMap.get('category') === 'weapon') { + type_match = item.statMap.get('category') === 'weapon'; + } else { + type_match = item.statMap.get('type') === this.none_item.statMap.get('type'); + } + if (type_match) { return item; } + } + return null; } } -class URLUpdateNode extends ComputeNode { - constructor() { - super("builder-url-update"); +/** + * Node for updating item input fields from parsed items. + * + * Signature: ItemInputDisplayNode(item: Item) => null + */ +class ItemInputDisplayNode extends ComputeNode { + + constructor(name, eq, item_image) { + super(name); + this.input_field = document.getElementById(eq+"-choice"); + this.health_field = document.getElementById(eq+"-health"); + this.level_field = document.getElementById(eq+"-lv"); + this.image = item_image; + this.fail_cb = true; } + compute_func(input_map) { + if (input_map.size !== 1) { throw "ItemInputDisplayNode accepts exactly one input (item)"; } + const [item] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element + + this.input_field.classList.remove("text-light", "is-invalid", 'Normal', 'Unique', 'Rare', 'Legendary', 'Fabled', 'Mythic', 'Set', 'Crafted', 'Custom'); + this.input_field.classList.add("text-light"); + this.image.classList.remove('Normal-shadow', 'Unique-shadow', 'Rare-shadow', 'Legendary-shadow', 'Fabled-shadow', 'Mythic-shadow', 'Set-shadow', 'Crafted-shadow', 'Custom-shadow'); + + if (!item) { + this.input_field.classList.add("is-invalid"); + return null; + } + + if (item.statMap.has('NONE')) { + return null; + } + const tier = item.statMap.get('tier'); + this.input_field.classList.add(tier); + if (this.health_field) { + // Doesn't exist for weapons. + this.health_field.textContent = item.statMap.get('hp'); + } + this.level_field.textContent = item.statMap.get('lvl'); + this.image.classList.add(tier + "-shadow"); + return null; + } +} + +/** + * Node for rendering an item. + * + * Signature: ItemDisplayNode(item: Item) => null + */ +class ItemDisplayNode extends ComputeNode { + constructor(name, target_elem) { + super(name); + this.target_elem = target_elem; + } + + compute_func(input_map) { + if (input_map.size !== 1) { throw "ItemInputDisplayNode accepts exactly one input (item)"; } + const [item] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element + + displayExpandedItem(item.statMap, this.target_elem); + collapse_element("#"+this.target_elem); + } +} + +/** + * Change the weapon to match correct type. + * + * Signature: WeaponInputDisplayNode(item: Item) => null + */ +class WeaponInputDisplayNode extends ComputeNode { + + constructor(name, image_field) { + super(name); + this.image = image_field; + } + + compute_func(input_map) { + if (input_map.size !== 1) { throw "WeaponDisplayNode accepts exactly one input (item)"; } + const [item] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element + + const type = item.statMap.get('type'); + this.image.setAttribute('src', '../media/items/new/generic-'+type+'.png'); + } +} + +/** + * Encode the build into a url-able string. + * + * Signature: BuildEncodeNode(build: Build, + helmet-powder: List[powder], + chestplate-powder: List[powder], + leggings-powder: List[powder], + boots-powder: List[powder], + weapon-powder: List[powder]) => str + */ +class BuildEncodeNode extends ComputeNode { + constructor() { super("builder-encode"); } + + compute_func(input_map) { + const build = input_map.get('build'); + let powders = [ + input_map.get('helmet-powder'), + input_map.get('chestplate-powder'), + input_map.get('leggings-powder'), + input_map.get('boots-powder'), + input_map.get('weapon-powder') + ]; + // TODO: grr global state for copy button.. + player_build = build; + build_powders = powders; + return encodeBuild(build, powders); + } +} + +/** + * Update the window's URL. + * + * Signature: URLUpdateNode(build_str: str) => null + */ +class URLUpdateNode extends ComputeNode { + constructor() { super("builder-url-update"); } + compute_func(input_map) { if (input_map.size !== 1) { throw "URLUpdateNode accepts exactly one input (build_str)"; } const [build_str] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element @@ -24,10 +182,25 @@ class URLUpdateNode extends ComputeNode { } } +/** + * Create a "build" object from a set of equipments. + * Returns a new Build object, or null if all items are NONE items. + * + * TODO: add tomes + * + * Signature: BuildAssembleNode(helmet-input: Item, + * chestplate-input: Item, + * leggings-input: Item, + * boots-input: Item, + * ring1-input: Item, + * ring2-input: Item, + * bracelet-input: Item, + * necklace-input: Item, + * weapon-input: Item, + * level-input: int) => Build | null + */ class BuildAssembleNode extends ComputeNode { - constructor() { - super("builder-make-build"); - } + constructor() { super("builder-make-build"); } compute_func(input_map) { let equipments = [ @@ -54,11 +227,15 @@ class BuildAssembleNode extends ComputeNode { } } +/** + * Read an input field and parse into a list of powderings. + * Every two characters makes one powder. If parsing fails, NULL is returned. + * + * Signature: PowderInputNode() => List[powder] | null + */ class PowderInputNode extends InputNode { - constructor(name, input_field) { - super(name, input_field); - } + constructor(name, input_field) { super(name, input_field); } compute_func(input_map) { // TODO: haha improve efficiency to O(n) dumb @@ -81,6 +258,13 @@ class PowderInputNode extends InputNode { } } +/** + * Select a spell+spell "variation" based on a build / spell idx. + * Right now this isn't much logic and is only used to abstract away major id interactions + * but will become significantly more complex in wynn2. + * + * Signature: SpellSelectNode(build: Build) => [Spell, SpellParts] + */ class SpellSelectNode extends ComputeNode { constructor(spell_num) { super("builder-spell"+spell_num+"-select"); @@ -111,10 +295,18 @@ class SpellSelectNode extends ComputeNode { } } +/** + * Compute spell damage of spell parts. + * Currently kinda janky / TODO while we rework the internal rep. of spells. + * + * Signature: SpellDamageCalcNode(weapon-input: Item, + * build: Build, + * weapon-powder: List[powder], + * spell-info: [Spell, SpellParts]) => List[SpellDamage] + */ class SpellDamageCalcNode extends ComputeNode { constructor(spell_num) { super("builder-spell"+spell_num+"-calc"); - this.spell_idx = spell_num; } compute_func(input_map) { @@ -148,6 +340,15 @@ class SpellDamageCalcNode extends ComputeNode { } } + +/** + * Display spell damage from spell parts. + * Currently kinda janky / TODO while we rework the internal rep. of spells. + * + * Signature: SpellDisplayNode(build: Build, + * spell-info: [Spell, SpellParts], + * spell-damage: List[SpellDamage]) => null + */ class SpellDisplayNode extends ComputeNode { constructor(spell_num) { super("builder-spell"+spell_num+"-display"); @@ -168,26 +369,44 @@ class SpellDisplayNode extends ComputeNode { } } +/** + * Display build stats. + * + * Signature: BuildDisplayNode(build: Build) => null + */ +class BuildDisplayNode extends ComputeNode { + constructor(spell_num) { super("builder-stats-display"); } + + compute_func(input_map) { + if (input_map.size !== 1) { throw "BuildDisplayNode accepts exactly one input (build)"; } + const [build] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element + displayBuildStats('overall-stats', build, build_all_display_commands); + displayBuildStats("offensive-stats", build, build_offensive_display_commands); + displaySetBonuses("set-info", build); + } +} + let item_nodes = []; let powder_nodes = []; let spelldmg_nodes = []; -document.addEventListener('DOMContentLoaded', function() { +function builder_graph_init() { // Bind item input fields to input nodes, and some display stuff (for auto colorizing stuff). - for (const [eq, none_item] of zip(equipment_fields, none_items)) { + for (const [eq, display_elem, none_item] of zip3(equipment_fields, build_fields, none_items)) { let input_field = document.getElementById(eq+"-choice"); let item_image = document.getElementById(eq+"-img"); let item_input = new ItemInputNode(eq+'-input', input_field, none_item); item_nodes.push(item_input); - new ItemInputDisplayNode(eq+'-display', input_field, item_image).link_to(item_input); + new ItemInputDisplayNode(eq+'-input-display', eq, item_image).link_to(item_input); + new ItemDisplayNode(eq+'-item-display', display_elem).link_to(item_input); //new PrintNode(eq+'-debug').link_to(item_input); //document.querySelector("#"+eq+"-tooltip").setAttribute("onclick", "collapse_element('#"+ eq +"-tooltip');"); //toggle_plus_minus('" + eq + "-pm'); } // weapon image changer node. let weapon_image = document.getElementById("weapon-img"); - new WeaponDisplayNode('weapon-type', weapon_image).link_to(item_nodes[8]); + new WeaponInputDisplayNode('weapon-type', weapon_image).link_to(item_nodes[8]); // Level input node. let level_input = new InputNode('level-input', document.getElementById('level-choice')); @@ -198,10 +417,19 @@ document.addEventListener('DOMContentLoaded', function() { build_node.link_to(input); } build_node.link_to(level_input); + new BuildDisplayNode().link_to(build_node, 'build'); + + let build_encode_node = new BuildEncodeNode(); + build_encode_node.link_to(build_node, 'build'); + + let url_update_node = new URLUpdateNode(); + url_update_node.link_to(build_encode_node, 'build-str'); for (const input of powder_inputs) { - powder_nodes.push(new PowderInputNode(input, document.getElementById(input))); + let powder_node = new PowderInputNode(input, document.getElementById(input)); + powder_nodes.push(powder_node); + build_encode_node.link_to(powder_node, input); } for (let i = 0; i < 4; ++i) { @@ -222,234 +450,5 @@ document.addEventListener('DOMContentLoaded', function() { } console.log("Set up graph"); - - // Other "main" stuff - // TODO: consolidate and comment - - // Spell dropdowns - for (const i of spell_disp) { - document.querySelector("#"+i+"Avg").addEventListener("click", () => toggle_spell_tab(i)); - } - - // Masonry setup - let masonry = Macy({ - container: "#masonry-container", - columns: 1, - mobileFirst: true, - breakAt: { - 1200: 4, - }, - margin: { - x: 20, - y: 20, - } - - }); - - let search_masonry = Macy({ - container: "#search-results", - columns: 1, - mobileFirst: true, - breakAt: { - 1200: 4, - }, - margin: { - x: 20, - y: 20, - } - - }); -}); - -// autocomplete initialize -function init_autocomplete() { - let dropdowns = new Map(); - for (const eq of equipment_keys) { - if (tome_keys.includes(eq)) { - continue; - } - // build dropdown - let item_arr = []; - if (eq == 'weapon') { - for (const weaponType of weapon_keys) { - for (const weapon of itemLists.get(weaponType)) { - let item_obj = itemMap.get(weapon); - if (item_obj["restrict"] && item_obj["restrict"] === "DEPRECATED") { - continue; - } - if (item_obj["name"] == 'No '+ eq.charAt(0).toUpperCase() + eq.slice(1)) { - continue; - } - item_arr.push(weapon); - } - } - } else { - for (const item of itemLists.get(eq.replace(/[0-9]/g, ''))) { - let item_obj = itemMap.get(item); - if (item_obj["restrict"] && item_obj["restrict"] === "DEPRECATED") { - continue; - } - if (item_obj["name"] == 'No '+ eq.charAt(0).toUpperCase() + eq.slice(1)) { - continue; - } - item_arr.push(item) - } - } - - // create dropdown - dropdowns.set(eq, new autoComplete({ - data: { - src: item_arr - }, - selector: "#"+ eq +"-choice", - wrapper: false, - resultsList: { - maxResults: 1000, - tabSelect: true, - noResults: true, - class: "search-box dark-7 rounded-bottom px-2 fw-bold dark-shadow-sm", - element: (list, data) => { - // dynamic result loc - let position = document.getElementById(eq+'-dropdown').getBoundingClientRect(); - list.style.top = position.bottom + window.scrollY +"px"; - list.style.left = position.x+"px"; - list.style.width = position.width+"px"; - list.style.maxHeight = position.height * 2 +"px"; - - if (!data.results.length) { - message = document.createElement('li'); - message.classList.add('scaled-font'); - message.textContent = "No results found!"; - list.prepend(message); - } - }, - }, - resultItem: { - class: "scaled-font search-item", - selected: "dark-5", - element: (item, data) => { - item.classList.add(itemMap.get(data.value).tier); - }, - }, - events: { - input: { - selection: (event) => { - if (event.detail.selection.value) { - event.target.value = event.detail.selection.value; - } - event.target.dispatchEvent(new Event('input')); - }, - }, - } - })); - } - - for (const eq of tome_keys) { - // build dropdown - let tome_arr = []; - for (const tome of tomeLists.get(eq.replace(/[0-9]/g, ''))) { - let tome_obj = tomeMap.get(tome); - if (tome_obj["restrict"] && tome_obj["restrict"] === "DEPRECATED") { - continue; - } - //this should suffice for tomes - jank - if (tome_obj["name"].includes('No ' + eq.charAt(0).toUpperCase())) { - continue; - } - let tome_name = tome; - tome_arr.push(tome_name); - } - - // create dropdown - dropdowns.set(eq, new autoComplete({ - data: { - src: tome_arr - }, - selector: "#"+ eq +"-choice", - wrapper: false, - resultsList: { - maxResults: 1000, - tabSelect: true, - noResults: true, - class: "search-box dark-7 rounded-bottom px-2 fw-bold dark-shadow-sm", - element: (list, data) => { - // dynamic result loc - let position = document.getElementById(eq+'-dropdown').getBoundingClientRect(); - list.style.top = position.bottom + window.scrollY +"px"; - list.style.left = position.x+"px"; - list.style.width = position.width+"px"; - list.style.maxHeight = position.height * 2 +"px"; - - if (!data.results.length) { - message = document.createElement('li'); - message.classList.add('scaled-font'); - message.textContent = "No results found!"; - list.prepend(message); - } - }, - }, - resultItem: { - class: "scaled-font search-item", - selected: "dark-5", - element: (tome, data) => { - tome.classList.add(tomeMap.get(data.value).tier); - }, - }, - events: { - input: { - selection: (event) => { - if (event.detail.selection.value) { - event.target.value = event.detail.selection.value; - } - }, - }, - } - })); - } - - let filter_loc = ["filter1", "filter2", "filter3", "filter4"]; - for (const i of filter_loc) { - dropdowns.set(i+"-choice", new autoComplete({ - data: { - src: sq2ItemFilters, - }, - selector: "#"+i+"-choice", - wrapper: false, - resultsList: { - tabSelect: true, - noResults: true, - class: "search-box dark-7 rounded-bottom px-2 fw-bold dark-shadow-sm", - element: (list, data) => { - // dynamic result loc - console.log(i); - list.style.zIndex = "100"; - let position = document.getElementById(i+"-dropdown").getBoundingClientRect(); - window_pos = document.getElementById("search-container").getBoundingClientRect(); - list.style.top = position.bottom - window_pos.top + 5 +"px"; - list.style.left = position.x - window_pos.x +"px"; - list.style.width = position.width+"px"; - - if (!data.results.length) { - message = document.createElement('li'); - message.classList.add('scaled-font'); - message.textContent = "No filters found!"; - list.prepend(message); - } - }, - }, - resultItem: { - class: "scaled-font search-item", - selected: "dark-5", - }, - events: { - input: { - selection: (event) => { - if (event.detail.selection.value) { - event.target.value = event.detail.selection.value; - } - }, - }, - } - })); - } } + diff --git a/js/computation_graph.js b/js/computation_graph.js index fc5ad46..11113bd 100644 --- a/js/computation_graph.js +++ b/js/computation_graph.js @@ -22,10 +22,10 @@ class ComputeNode { * Request update of this compute node. Pushes updates to children. */ update() { - if (!this.dirty) { + if (this.inputs_dirty_count != 0) { return; } - if (this.inputs_dirty_count != 0) { + if (!this.dirty) { return; } let calc_inputs = new Map(); @@ -128,6 +128,9 @@ class PrintNode extends ComputeNode { /** * Node for getting an input from an input field. + * Fires updates whenever the input field is updated. + * + * Signature: InputNode() => str */ class InputNode extends ComputeNode { constructor(name, input_field) { @@ -141,110 +144,3 @@ class InputNode extends ComputeNode { return this.input_field.value; } } - -/** - * Node for getting an item's stats from an item input field. - */ -class ItemInputNode extends InputNode { - /** - * Make an item stat pulling compute node. - * - * @param name: Name of this node. - * @param item_input_field: Input field (html element) to listen for item names from. - * @param none_item: Item object to use as the "none" for this field. - */ - constructor(name, item_input_field, none_item) { - super(name, item_input_field); - this.none_item = new Item(none_item); - this.none_item.statMap.set('NONE', true); - } - - compute_func(input_map) { - // built on the assumption of no one will type in CI/CR letter by letter - - let item_text = this.input_field.value; - if (!item_text) { - return this.none_item; - } - - let item; - - if (item_text.slice(0, 3) == "CI-") { - item = getCustomFromHash(item_text); - } - else if (item_text.slice(0, 3) == "CR-") { - item = getCraftFromHash(item_text); - } - else if (itemMap.has(item_text)) { - item = new Item(itemMap.get(item_text)); - } - else if (tomeMap.has(item_text)) { - item = new Item(tomeMap.get(item_text)); - } - - if (item) { - let type_match; - if (this.none_item.statMap.get('category') === 'weapon') { - type_match = item.statMap.get('category') === 'weapon'; - } else { - type_match = item.statMap.get('type') === this.none_item.statMap.get('type'); - } - if (type_match) { return item; } - } - return null; - } -} - -/** - * Node for updating item input fields from parsed items. - */ -class ItemInputDisplayNode extends ComputeNode { - - constructor(name, item_input_field, item_image) { - super(name); - this.input_field = item_input_field; - this.image = item_image; - this.fail_cb = true; - } - - compute_func(input_map) { - if (input_map.size !== 1) { throw "ItemInputDisplayNode accepts exactly one input (item)"; } - const [item] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element - - this.input_field.classList.remove("text-light", "is-invalid", 'Normal', 'Unique', 'Rare', 'Legendary', 'Fabled', 'Mythic', 'Set', 'Crafted', 'Custom'); - this.input_field.classList.add("text-light"); - this.image.classList.remove('Normal-shadow', 'Unique-shadow', 'Rare-shadow', 'Legendary-shadow', 'Fabled-shadow', 'Mythic-shadow', 'Set-shadow', 'Crafted-shadow', 'Custom-shadow'); - - if (!item) { - this.input_field.classList.add("is-invalid"); - return null; - } - - if (item.statMap.has('NONE')) { - return null; - } - const tier = item.statMap.get('tier'); - this.input_field.classList.add(tier); - this.image.classList.add(tier + "-shadow"); - return null; - } -} - -/** - * Change the weapon to match correct type. - */ -class WeaponDisplayNode extends ComputeNode { - - constructor(name, image_field) { - super(name); - this.image = image_field; - } - - compute_func(input_map) { - if (input_map.size !== 1) { throw "WeaponDisplayNode accepts exactly one input (item)"; } - const [item] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element - - const type = item.statMap.get('type'); - this.image.setAttribute('src', '../media/items/new/generic-'+type+'.png'); - } -} diff --git a/js/display.js b/js/display.js index 0ef1c02..76f85cf 100644 --- a/js/display.js +++ b/js/display.js @@ -46,7 +46,7 @@ function displaySetBonuses(parent_id,build) { } for (const [setName, count] of build.activeSetCounts) { - const active_set = sets[setName]; + const active_set = sets.get(setName); if (active_set["hidden"]) { continue; } let set_elem = document.createElement('p'); @@ -353,12 +353,12 @@ function displayExpandedItem(item, parent_id){ */ //allow the plus minus element to toggle upon click: ➕➖ - let plusminus = document.createElement("div"); - plusminus.id = parent_div.id.split("-")[0] + "-pm"; - plusminus.classList.add("col", "plus_minus", "text_end"); - plusminus.style.flexGrow = 0; - plusminus.textContent = "\u2795"; - row.appendChild(plusminus); + //let plusminus = document.createElement("div"); + //plusminus.id = parent_div.id.split("-")[0] + "-pm"; + //plusminus.classList.add("col", "plus_minus", "text_end"); + //plusminus.style.flexGrow = 0; + //plusminus.textContent = "\u2795"; + //row.appendChild(plusminus); if (item.get("custom")) { a_elem.href = "../custom/#" + item.get("hash"); @@ -595,12 +595,17 @@ function displayExpandedItem(item, parent_id){ } } -/* Displays stats about a recipe that are NOT displayed in the craft stats. -* Includes: mat name and amounts -* ingred names in an "array" with ingred effectiveness +/* +* Displays stats about a recipe that are NOT displayed in the craft stats. +* Includes: mat name and amounts, ingred names in an "array" with ingred effectiveness */ function displayRecipeStats(craft, parent_id) { let elem = document.getElementById(parent_id); + if (!elem.classList.contains("col")) { + elem.classList.add("col"); + } + + //local vars elem.textContent = ""; recipe = craft["recipe"]; mat_tiers = craft["mat_tiers"]; @@ -610,30 +615,33 @@ function displayRecipeStats(craft, parent_id) { } let effectiveness = craft["statMap"].get("ingredEffectiveness"); - let ldiv = document.createElement("div"); - ldiv.classList.add("itemleft"); - let title = document.createElement("p"); - title.classList.add("smalltitle"); + let title = document.createElement("div"); + title.classList.add("row", "box-title", "fw-bold", "justify-content-center"); title.textContent = "Recipe Stats"; - ldiv.appendChild(title); - let mats = document.createElement("p"); - mats.classList.add("itemp"); + elem.appendChild(title); + + let mats = document.createElement("div"); + mats.classList.add("row"); mats.textContent = "Crafting Materials: "; + elem.appendChild(mats); + for (let i = 0; i < 2; i++) { let tier = mat_tiers[i]; - let row = document.createElement("p"); - row.classList.add("left"); - let b = document.createElement("b"); + let row = document.createElement("div"); + row.classList.add("row", "px-0", "mx-0"); + let b = document.createElement("div"); let mat = recipe.get("materials")[i]; b.textContent = "- " + mat.get("amount") + "x " + mat.get("item").split(" ").slice(1).join(" "); - b.classList.add("space"); - let starsB = document.createElement("b"); - starsB.classList.add("T1-bracket"); - starsB.textContent = "["; + b.classList.add("col"); row.appendChild(b); + + let starsB = document.createElement("div"); + starsB.classList.add("T1-bracket", "col-auto", "px-0"); + starsB.textContent = "["; row.appendChild(starsB); for(let j = 0; j < 3; j ++) { - let star = document.createElement("b"); + let star = document.createElement("div"); + star.classList.add("col-auto", "px-0"); star.textContent = "\u272B"; if(j < tier) { star.classList.add("T1"); @@ -642,51 +650,57 @@ function displayRecipeStats(craft, parent_id) { } row.append(star); } - let starsE = document.createElement("b"); - starsE.classList.add("T1-bracket"); + let starsE = document.createElement("div"); + starsE.classList.add("T1-bracket", "col-auto", "px-0"); starsE.textContent = "]"; row.appendChild(starsE); - mats.appendChild(row); - } - ldiv.appendChild(mats); - let ingredTable = document.createElement("table"); - ingredTable.classList.add("itemtable"); - ingredTable.classList.add("ingredTable"); + elem.appendChild(row); + } + + let ingredTable = document.createElement("div"); + ingredTable.classList.add("row"); + for (let i = 0; i < 3; i++) { - let row = document.createElement("tr"); + let row = document.createElement("div"); + row.classList.add("row", "g-1", "justify-content-center"); + + for (let j = 0; j < 2; j++) { + if (j == 1) { + let spacer = document.createElement("div"); + spacer.classList.add("col-1"); + row.appendChild(spacer); + } let ingredName = ingreds[2 * i + j]; - let cell = document.createElement("td"); - cell.style.minWidth = "50%"; - cell.classList.add("center"); - cell.classList.add("box"); - cell.classList.add("tooltip"); - let b = document.createElement("b"); - b.textContent = ingredName; - b.classList.add("space"); - let eff = document.createElement("b"); + let col = document.createElement("div"); + col.classList.add("col-5", "rounded", "dark-6", "border", "border-3", "dark-shadow"); + + let temp_row = document.createElement("div"); + temp_row.classList.add("row"); + col.appendChild(temp_row); + + let ingred_div = document.createElement("div"); + ingred_div.classList.add("col"); + ingred_div.textContent = ingredName; + temp_row.appendChild(ingred_div); + + let eff_div = document.createElement("div"); + eff_div.classList.add("col-auto"); let e = effectiveness[2 * i + j]; if (e > 0) { - eff.classList.add("positive"); + eff_div.classList.add("positive"); } else if (e < 0) { - eff.classList.add("negative"); + eff_div.classList.add("negative"); } - eff.textContent = "[" + e + "%]"; - cell.appendChild(b); - cell.appendChild(eff); - row.appendChild(cell); + eff_div.textContent = "[" + e + "%]"; - let tooltip = document.createElement("div"); - tooltip.classList.add("tooltiptext"); - tooltip.classList.add("ing-tooltip"); - tooltip.classList.add("center"); - tooltip.id = "tooltip-" + (2*i + j); - cell.appendChild(tooltip); + temp_row.appendChild(eff_div); + + row.appendChild(col); } ingredTable.appendChild(row); } - elem.appendChild(ldiv); elem.appendChild(ingredTable); } @@ -696,23 +710,14 @@ function displayCraftStats(craft, parent_id) { displayExpandedItem(mock_item,parent_id); } -//Displays an ingredient in item format. However, an ingredient is too far from a normal item to display as one. +/* +* Displays an ingredient in item format. +* However, an ingredient is too far from a normal item to display as one. +*/ function displayExpandedIngredient(ingred, parent_id) { let parent_elem = document.getElementById(parent_id); parent_elem.textContent = ""; - let display_order = [ - "#cdiv", - "displayName", //tier will be displayed w/ name - "#table", - "ids", - "#ldiv", - "posMods", - "itemIDs", - "consumableIDs", - "#ldiv", - "lvl", - "skills", - ] + let item_order = [ "dura", "strReq", @@ -787,83 +792,85 @@ function displayExpandedIngredient(ingred, parent_id) { let active_elem; let elemental_format = false; let style; - for (const command of display_order) { - if (command.charAt(0) === "#") { - if (command === "#cdiv") { - active_elem = document.createElement('div'); - active_elem.classList.add('itemcenter'); + for (const command of sq2_ing_display_order) { + if (command.charAt(0) === "!") { + // TODO: This is sooo incredibly janky..... + if (command === "!elemental") { + elemental_format = !elemental_format; } - else if (command === "#ldiv") { - active_elem = document.createElement('div'); - active_elem.classList.add('itemleft'); + else if (command === "!spacer") { + let spacer = document.createElement('div'); + spacer.classList.add("row", "my-2"); + parent_elem.appendChild(spacer); + continue; } - else if (command === "#table") { - active_elem = document.createElement('table'); - active_elem.classList.add('itemtable'); - } - parent_elem.appendChild(active_elem); - }else { - let p_elem = document.createElement("p"); - p_elem.classList.add("left"); + } else { + let div = document.createElement("div"); + div.classList.add("row"); if (command === "displayName") { - p_elem.classList.add("title"); - p_elem.classList.remove("left"); - let title_elem = document.createElement("b"); + div.classList.add("box-title"); + let title_elem = document.createElement("div"); + title_elem.classList.add("col-auto", "justify-content-center", "pr-1"); title_elem.textContent = ingred.get("displayName"); - p_elem.appendChild(title_elem); - - let space = document.createElement("b"); - space.classList.add("space"); - p_elem.appendChild(space); + div.appendChild(title_elem); let tier = ingred.get("tier"); //tier in [0,3] let begin = document.createElement("b"); - begin.classList.add("T"+tier+"-bracket"); + begin.classList.add("T"+tier+"-bracket", "col-auto", "px-0"); begin.textContent = "["; - p_elem.appendChild(begin); + div.appendChild(begin); for (let i = 0; i < 3; i++) { let tier_elem = document.createElement("b"); - if(i < tier) {tier_elem.classList.add("T"+tier)} - else {tier_elem.classList.add("T0")} + if (i < tier) { + tier_elem.classList.add("T"+tier); + } else { + tier_elem.classList.add("T0"); + } + tier_elem.classList.add("px-0", "col-auto"); tier_elem.textContent = "\u272B"; - p_elem.appendChild(tier_elem); + div.appendChild(tier_elem); } let end = document.createElement("b"); - end.classList.add("T"+tier+"-bracket"); + end.classList.add("T"+tier+"-bracket", "px-0", "col-auto"); end.textContent = "]"; - p_elem.appendChild(end); + div.appendChild(end); }else if (command === "lvl") { - p_elem.textContent = "Crafting Lvl Min: " + ingred.get("lvl"); + div.textContent = "Crafting Lvl Min: " + ingred.get("lvl"); }else if (command === "posMods") { for (const [key,value] of ingred.get("posMods")) { - let p = document.createElement("p"); - p.classList.add("nomarginp"); + let posModRow = document.createElement("div"); + posModRow.classList.add("row"); if (value != 0) { - let title = document.createElement("b"); - title.textContent = posModPrefixes[key]; - let val = document.createElement("b"); + let posMod = document.createElement("div"); + posMod.classList.add("col-auto"); + posMod.textContent = posModPrefixes[key]; + posModRow.appendChild(posMod); + + let val = document.createElement("div"); + val.classList.add("col-auto", "px-0"); val.textContent = value + posModSuffixes[key]; if(value > 0) { val.classList.add("positive"); } else { val.classList.add("negative"); } - p.appendChild(title); - p.appendChild(val); - p_elem.appendChild(p); + posModRow.appendChild(val); + div.appendChild(posModRow); } } } else if (command === "itemIDs") { //dura, reqs for (const [key,value] of ingred.get("itemIDs")) { - let p = document.createElement("p"); - p.classList.add("nomarginp"); + let idRow = document.createElement("div"); + idRow.classList.add("row"); if (value != 0) { - let title = document.createElement("b"); + let title = document.createElement("div"); + title.classList.add("col-auto"); title.textContent = itemIDPrefixes[key]; - p.appendChild(title); + idRow.appendChild(title); } - let desc = document.createElement("b"); + let desc = document.createElement("div"); + desc.classList.add("col-auto"); if(value > 0) { if(key !== "dura") { desc.classList.add("negative"); @@ -880,20 +887,22 @@ function displayExpandedIngredient(ingred, parent_id) { desc.textContent = value; } if(value != 0){ - p.appendChild(desc); + idRow.appendChild(desc); } - p_elem.append(p); + div.appendChild(idRow); } } else if (command === "consumableIDs") { //dura, charges for (const [key,value] of ingred.get("consumableIDs")) { - let p = document.createElement("p"); - p.classList.add("nomarginp"); + let idRow = document.createElement("div"); + idRow.classList.add("row"); if (value != 0) { - let title = document.createElement("b"); + let title = document.createElement("div"); + title.classList.add("col-auto"); title.textContent = consumableIDPrefixes[key]; - p.appendChild(title); + idRow.appendChild(title); } - let desc = document.createElement("b"); + let desc = document.createElement("div"); + desc.classList.add("col-auto"); if(value > 0) { desc.classList.add("positive"); desc.textContent = "+"+value; @@ -902,32 +911,41 @@ function displayExpandedIngredient(ingred, parent_id) { desc.textContent = value; } if(value != 0){ - p.appendChild(desc); - let suffix = document.createElement("b"); + idRow.appendChild(desc); + let suffix = document.createElement("div"); + suffix.classList.add("col-auto"); suffix.textContent = consumableIDSuffixes[key]; - p.appendChild(suffix); + idRow.appendChild(suffix); } - p_elem.append(p); + div.appendChild(idRow); } }else if (command === "skills") { - p_elem.textContent = "Used in:"; + let row = document.createElement("div"); + row.classList.add("row"); + let title = document.createElement("div"); + title.classList.add("row"); + title.textContent = "Used in:"; + row.appendChild(title); for(const skill of ingred.get("skills")) { - let p = document.createElement("p"); - p.textContent = skill.charAt(0) + skill.substring(1).toLowerCase(); - p.classList.add("left"); - p_elem.append(p); + let skill_div = document.createElement("div"); + skill_div.classList.add("row"); + skill_div.textContent = skill.charAt(0) + skill.substring(1).toLowerCase(); + row.appendChild(skill_div); } + div.appendChild(row); } else if (command === "ids") { //warp for (let [key,value] of ingred.get("ids").get("maxRolls")) { if (value !== undefined && value != 0) { - let row = displayRolledID(ingred.get("ids"), key, false, "auto"); - active_elem.appendChild(row); + let row = displayRolledID(ingred.get("ids"), key, elemental_format); + row.classList.remove("col"); + row.classList.remove("col-12"); + div.appendChild(row); } } } else {//this shouldn't be happening } - active_elem.appendChild(p_elem); + parent_elem.appendChild(div); } } } @@ -1083,29 +1101,21 @@ function displayPoisonDamage(overallparent_elem, build) { overallparent_elem.append(overallpoisonDamage); } -function displayEquipOrder(parent_elem,buildOrder){ +function displayEquipOrder(parent_elem, buildOrder){ parent_elem.textContent = ""; const order = buildOrder.slice(); - let title_elem = document.createElement("p"); + let title_elem = document.createElement("b"); title_elem.textContent = "Equip order "; - title_elem.classList.add("title"); - title_elem.classList.add("Normal"); - title_elem.classList.add("itemp"); + title_elem.classList.add("Normal", "text-center"); parent_elem.append(title_elem); - parent_elem.append(document.createElement("br")); for (const item of order) { - let p_elem = document.createElement("p"); - p_elem.classList.add("itemp"); - p_elem.classList.add("left"); + let p_elem = document.createElement("b"); p_elem.textContent = item.get("displayName"); parent_elem.append(p_elem); } } - -function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){ - console.log("Melee Stats"); - console.log(meleeStats); +function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats) { let tooltipinfo = meleeStats[13]; let attackSpeeds = ["Super Slow", "Very Slow", "Slow", "Normal", "Fast", "Very Fast", "Super Fast"]; //let damagePrefixes = ["Neutral Damage: ","Earth Damage: ","Thunder Damage: ","Water Damage: ","Fire Damage: ","Air Damage: "]; @@ -1123,7 +1133,7 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){ stats[i][j] = stats[i][j].toFixed(2); } } - for (let i = 8; i < 11; ++i){ + for (let i = 8; i < 11; ++i) { stats[i] = stats[i].toFixed(2); } //tooltipelem, tooltiptext @@ -1132,24 +1142,18 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){ //title let title_elem = document.createElement("p"); title_elem.classList.add("title"); - title_elem.classList.add("Normal"); - title_elem.classList.add("itemp"); title_elem.textContent = "Melee Stats"; parent_elem.append(title_elem); parent_elem.append(document.createElement("br")); //overall title - let title_elemavg = document.createElement("p"); - title_elemavg.classList.add("smalltitle"); - title_elemavg.classList.add("Normal"); + let title_elemavg = document.createElement("b"); title_elemavg.textContent = "Melee Stats"; overallparent_elem.append(title_elemavg); //average DPS let averageDamage = document.createElement("p"); averageDamage.classList.add("left"); - averageDamage.classList.add("itemp"); - averageDamage.classList.add("tooltip"); averageDamage.textContent = "Average DPS: " + stats[10]; tooltiptext = `= ((${stats[8]} * ${(stats[6][2]).toFixed(2)}) + (${stats[9]} * ${(stats[7][2]).toFixed(2)}))` tooltip = createTooltip(tooltip, "p", tooltiptext, averageDamage, ["melee-tooltip"]); @@ -1158,14 +1162,12 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){ //overall average DPS let overallaverageDamage = document.createElement("p"); - overallaverageDamage.classList.add("itemp"); - let overallaverageDamageFirst = document.createElement("b"); + let overallaverageDamageFirst = document.createElement("span"); overallaverageDamageFirst.textContent = "Average DPS: " - let overallaverageDamageSecond = document.createElement("b"); + let overallaverageDamageSecond = document.createElement("span"); overallaverageDamageSecond.classList.add("Damage"); overallaverageDamageSecond.textContent = stats[10]; - tooltip = createTooltip(tooltip, "p", tooltiptext, overallaverageDamage, ["melee-tooltip", "summary-tooltip"]); overallaverageDamage.appendChild(overallaverageDamageFirst); overallaverageDamage.appendChild(overallaverageDamageSecond); @@ -1175,18 +1177,15 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){ //attack speed let atkSpd = document.createElement("p"); atkSpd.classList.add("left"); - atkSpd.classList.add("itemp"); atkSpd.textContent = "Attack Speed: " + attackSpeeds[stats[11]]; parent_elem.append(atkSpd); parent_elem.append(document.createElement("br")); //overall attack speed let overallatkSpd = document.createElement("p"); - overallatkSpd.classList.add("center"); - overallatkSpd.classList.add("itemp"); - let overallatkSpdFirst = document.createElement("b"); + let overallatkSpdFirst = document.createElement("span"); overallatkSpdFirst.textContent = "Attack Speed: "; - let overallatkSpdSecond = document.createElement("b"); + let overallatkSpdSecond = document.createElement("span"); overallatkSpdSecond.classList.add("Damage"); overallatkSpdSecond.textContent = attackSpeeds[stats[11]]; overallatkSpd.appendChild(overallatkSpdFirst); @@ -1196,11 +1195,10 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){ //Non-Crit: n->elem, total dmg, DPS let nonCritStats = document.createElement("p"); nonCritStats.classList.add("left"); - nonCritStats.classList.add("itemp"); nonCritStats.textContent = "Non-Crit Stats: "; nonCritStats.append(document.createElement("br")); - for (let i = 0; i < 6; i++){ - if(stats[i][1] != 0){ + for (let i = 0; i < 6; i++) { + if (stats[i][1] != 0) { let dmg = document.createElement("p"); dmg.textContent = stats[i][0] + " \u2013 " + stats[i][1]; dmg.classList.add(damageClasses[i]); @@ -1213,7 +1211,6 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){ let normalDamage = document.createElement("p"); normalDamage.textContent = "Total: " + stats[6][0] + " \u2013 " + stats[6][1]; - normalDamage.classList.add("itemp"); let tooltiparr = ["Min: = ", "Max: = "] let arr = []; let arr2 = []; for (let i = 0; i < 6; i++) { @@ -1228,7 +1225,6 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){ let normalDPS = document.createElement("p"); normalDPS.textContent = "Normal DPS: " + stats[8]; - normalDPS.classList.add("itemp"); normalDPS.classList.add("tooltip"); tooltiptext = ` = ((${stats[6][0]} + ${stats[6][1]}) / 2) * ${baseDamageMultiplier[stats[11]]}`; tooltip = createTooltip(tooltip, "p", tooltiptext, normalDPS, ["melee-tooltip"]); @@ -1236,14 +1232,13 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){ //overall average DPS let singleHitDamage = document.createElement("p"); - singleHitDamage.classList.add("itemp"); - let singleHitDamageFirst = document.createElement("b"); + let singleHitDamageFirst = document.createElement("span"); singleHitDamageFirst.textContent = "Single Hit Average: "; - let singleHitDamageSecond = document.createElement("b"); + let singleHitDamageSecond = document.createElement("span"); singleHitDamageSecond.classList.add("Damage"); singleHitDamageSecond.textContent = stats[12].toFixed(2); tooltiptext = ` = ((${stats[6][0]} + ${stats[6][1]}) / 2) * ${stats[6][2].toFixed(2)} + ((${stats[7][0]} + ${stats[7][1]}) / 2) * ${stats[7][2].toFixed(2)}`; - tooltip = createTooltip(tooltip, "p", tooltiptext, singleHitDamage, ["melee-tooltip", "summary-tooltip"]); + // tooltip = createTooltip(tooltip, "p", tooltiptext, singleHitDamage, ["melee-tooltip", "summary-tooltip"]); singleHitDamage.appendChild(singleHitDamageFirst); singleHitDamage.appendChild(singleHitDamageSecond); @@ -1251,7 +1246,6 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){ let normalChance = document.createElement("p"); normalChance.textContent = "Non-Crit Chance: " + (stats[6][2]*100).toFixed(2) + "%"; - normalChance.classList.add("itemp"); normalChance.append(document.createElement("br")); normalChance.append(document.createElement("br")); nonCritStats.append(normalChance); @@ -1262,7 +1256,6 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){ //Crit: n->elem, total dmg, DPS let critStats = document.createElement("p"); critStats.classList.add("left"); - critStats.classList.add("itemp"); critStats.textContent = "Crit Stats: "; critStats.append(document.createElement("br")); for (let i = 0; i < 6; i++){ @@ -1278,7 +1271,6 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){ } let critDamage = document.createElement("p"); critDamage.textContent = "Total: " + stats[7][0] + " \u2013 " + stats[7][1]; - critDamage.classList.add("itemp"); tooltiparr = ["Min: = ", "Max: = "] arr = []; arr2 = []; for (let i = 0; i < 6; i++) { @@ -1294,14 +1286,12 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){ let critDPS = document.createElement("p"); critDPS.textContent = "Crit DPS: " + stats[9]; - critDPS.classList.add("itemp"); tooltiptext = ` = ((${stats[7][0]} + ${stats[7][1]}) / 2) * ${baseDamageMultiplier[stats[11]]}`; tooltip = createTooltip(tooltip, "p", tooltiptext, critDPS, ["melee-tooltip"]); critStats.append(critDPS); let critChance = document.createElement("p"); critChance.textContent = "Crit Chance: " + (stats[7][2]*100).toFixed(2) + "%"; - critChance.classList.add("itemp"); critChance.append(document.createElement("br")); critChance.append(document.createElement("br")); critStats.append(critChance); @@ -2249,6 +2239,7 @@ function stringPDF(id,val,base,amp) { document.getElementById(id + "-pdf").appendChild(b2); document.getElementById(id + "-pdf").appendChild(b3); } + function stringCDF(id,val,base,amp) { let p; let min; let max; let minr; let maxr; let minround; let maxround; if (base > 0) { diff --git a/js/utils.js b/js/utils.js index 164543d..5691ac9 100644 --- a/js/utils.js +++ b/js/utils.js @@ -1,7 +1,8 @@ let getUrl = window.location; const url_base = getUrl.protocol + "//" + getUrl.host + "/" + getUrl.pathname.split('/')[1]; -const zip = (a, b) => a.map((k, i) => [k, b[i]]); +const zip2 = (a, b) => a.map((k, i) => [k, b[i]]); +const zip3 = (a, b, c) => a.map((k, i) => [k, b[i], c[i]]); function clamp(num, low, high){ return Math.min(Math.max(num, low), high);