+
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);