const translate_mappings = { //"Name": "name", //"Display Name": "displayName", //"Tier": "tier", //"Set": "set", "Powder Slots": "slots", //"Type": "type", "Drop type": "drop", "Quest requirement": "quest", "Restriction": "restrict", //"Base Neutral Damage": "nDam", //"Base Fire Damage": "fDam", //"Base Water Damage": "wDam", //"Base Air Damage": "aDam", //"Base Thunder Damage": "tDam", //"Base Earth Damage": "eDam", //"Base Attack Speed": "atkSpd", "Health": "hp", "Raw Fire Defense": "fDef", "Raw Water Defense": "wDef", "Raw Air Defense": "aDef", "Raw Thunder Defense": "tDef", "Raw Earth Defense": "eDef", "Combat Level": "lvl", //"Class Requirement": "classReq", "Req Strength": "strReq", "Req Dexterity": "dexReq", "Req Intelligence": "intReq", "Req Agility": "agiReq", "Req Defense": "defReq", "% Health Regen": "hprPct", "Mana Regen": "mr", "% Spell Damage": "sdPct", "% Melee Damage": "mdPct", "Life Steal": "ls", "Mana Steal": "ms", "XP Bonus": "xpb", "Loot Bonus": "lb", "Reflection": "ref", "Strength": "str", "Dexterity": "dex", "Intelligence": "int", "Agility": "agi", "Defense": "def", "Thorns": "thorns", "Exploding": "expd", "Walk Speed": "spd", "Attack Speed Bonus": "atkTier", "Poison": "poison", "Health Bonus": "hpBonus", "Soul Point Regen": "spRegen", "Stealing": "eSteal", "Raw Health Regen": "hprRaw", "Raw Spell": "sdRaw", "Raw Melee": "mdRaw", "% Fire Damage": "fDamPct", "% Water Damage": "wDamPct", "% Air Damage": "aDamPct", "% Thunder Damage": "tDamPct", "% Earth Damage": "eDamPct", "% Fire Defense": "fDefPct", "% Water Defense": "wDefPct", "% Air Defense": "aDefPct", "% Thunder Defense": "tDefPct", "% Earth Defense": "eDefPct", "Fixed IDs": "fixID", "Custom Skin": "skin", //"Item Category": "category", "1st Spell Cost %": "-spPct1", "1st Spell Cost Raw": "-spRaw1", "2nd Spell Cost %": "-spPct2", "2nd Spell Cost Raw": "-spRaw2", "3rd Spell Cost %": "-spPct3", "3rd Spell Cost Raw": "-spRaw3", "4th Spell Cost %": "-spPct4", "4th Spell Cost Raw": "-spRaw4", "Rainbow Spell Damage": "rainbowRaw", "Sprint": "sprint", "Sprint Regen": "sprintReg", "Jump Height": "jh", "Loot Quality": "lq", "Gather XP Bonus": "gXp", "Gather Speed Bonus": "gSpd", }; const special_mappings = { "Sum (skill points)": "str+dex+int+def+agi", "Sum (Mana Sustain)": "mr+ms", "Sum (Life Sustain)": "hpr+ls", "Sum (Health + Health Bonus)": "hp+hpBonus", // "No Strength Req": "strReq=0", // "No Dexterity Req": "dexReq=0", // "No Intelligence Req": "intReq=0", // "No Agility Req": "agiReq=0", // "No Defense Req": "defReq=0", }; let item_filters = [] for (let x in translate_mappings) { item_filters.push(x); } for (let x in special_mappings) { item_filters.push(x); } let item_categories = ["armor", "accessory", "weapon"]; const types = {bow: false, spear: false, wand: false, dagger: false, relik: false, helmet: false, chestplate: false, leggings: false, boots: false, ring: false, bracelet: false, necklace: false}; const rarities = {normal: true, unique: true, set: true, rare: true, legendary: true, fabled: true, mythic: true}; const filters = []; let filter_id_counter = 0; function displayItems(items_copy) { let items_parent = document.getElementById("search-results"); for (let i in items_copy) { if (i > 200) {break;} let item = items_copy[i].itemExp; let box = make_elem('div', ['col-lg-3', 'col-sm-6', 'p-2'], {id: 'item'+i}); let bckgrdbox = make_elem("div", ["dark-7", "rounded", "px-2", "col-auto"], {id: 'item'+i+'b'}); box.append(bckgrdbox); items_parent.appendChild(box); item.set("powders", []); if (item.get("category") == "weapon") { apply_weapon_powders(item); } displayExpandedItem(item, bckgrdbox.id, true); } } let search_db; let expr_parser; function do_item_search() { window.scrollTo(0, 0); let queries = []; // name if (document.getElementById("item-name-choice").value != "") { queries.push("f:name?=\"" + document.getElementById("item-name-choice").value.trim() + "\""); } // types let allTypes = true, noTypes = true; let typeQuery = "f:(" for (const type of Object.keys(types)) { if (types[type]) { typeQuery += "type=\"" + type + "\"|"; noTypes = false; } else { allTypes = false; } } if (noTypes) { document.getElementById("summary").innerHTML = "Error: Cannot search without at least 1 type selected!"; return; } else if (!allTypes) { queries.push(typeQuery.substring(0, typeQuery.length - 1) + ")"); } // rarities let allRarities = true, noRarities = true; let rarityQuery = "f:(" for (const rarity of Object.keys(rarities)) { if (rarities[rarity]) { rarityQuery += "tiername=\"" + rarity + "\"|"; noRarities = false; } else { allRarities = false; } } if (noRarities) { document.getElementById("summary").innerHTML = "Error: Cannot search without at least 1 rarity selected!"; return; } else if (!allRarities) { queries.push(rarityQuery.substring(0, rarityQuery.length - 1) + ")"); } // filters for (const filter of filters) { let min = parseInt(filter.min_elem.value); let max = parseInt(filter.max_elem.value); if (min > max) { document.getElementById("summary").innerHTML = "Error: The minimum of filter " + filter.input_elem.value + " (" + min + ") is greater than its maximum (" + max + ")!"; return; } let zero_in_min_max = (isNaN(min) || min < 0) && (isNaN(max) || max > 0); let raw_name = filter.input_elem.value; let filter_name = translate_mappings[raw_name]; if (filter_name === undefined) { filter_name = special_mappings[raw_name]; if (filter_name === undefined) { continue; // not a valid filter } filter_name = "(" + filter_name + ")"; } if (!isNaN(min)) { queries.push("f:" + filter_name + ">=" + min); } if (!isNaN(max)) { queries.push("f:" + filter_name + "<=" + max); } if (zero_in_min_max) { queries.push("f:" + filter_name + "!=0"); } queries.push("s:" + (filter.ascending ? "0-" : "") + filter_name); } let filter_query = "true"; let sort_queries = []; console.log(queries); for (const query of queries) { if (query.startsWith("s:")) { sort_queries.push(query.slice(2)); } else if (query.startsWith("f:")) { filter_query = filter_query + "&" + query.slice(2); } } document.getElementById("search-results").textContent = ""; let results = []; try { const filter_expr = expr_parser.parse(filter_query); const sort_exprs = sort_queries.map(q => expr_parser.parse(q)); for (let i = 0; i < search_db.length; ++i) { const item = search_db[i][0]; const itemExp = search_db[i][1]; if (checkBool(filter_expr.resolve(item, itemExp))) { results.push({ item, itemExp, sortKeys: sort_exprs.map(e => e.resolve(item, itemExp)) }); } } results.sort((a, b) => { return compareLexico(a.item, a.sortKeys, b.item, b.sortKeys); }); } catch (e) { document.getElementById("summary").textContent = e.message; return; } document.getElementById("summary").textContent = results.length + " results:" displayItems(results); } function init_items() { search_db = items.filter( i => ! i.remapID ).map( i => [i, expandItem(i, [])] ); expr_parser = new ExprParser(itemQueryProps, itemQueryFuncs); // init type buttons for (const type of Object.keys(types)) { document.getElementById("type-" + type).addEventListener("click", function() { types[type] = !types[type]; this.classList.toggle("type-selected"); }); } document.getElementById("all-types").addEventListener("click", function() { for (const type of Object.keys(types)) { types[type] = true; document.getElementById("type-" + type).classList.add("type-selected"); } }); document.getElementById("none-types").addEventListener("click", function() { for (const type of Object.keys(types)) { types[type] = false; document.getElementById("type-" + type).classList.remove("type-selected"); } }); // init rarity buttons for (const rarity of Object.keys(rarities)) { document.getElementById("rarity-" + rarity).addEventListener("click", function() { rarities[rarity] = !rarities[rarity]; this.classList.toggle("rarity-selected"); }); } document.getElementById("all-rarities").addEventListener("click", function() { for (const rarity of Object.keys(rarities)) { rarities[rarity] = true; document.getElementById("rarity-" + rarity).classList.add("rarity-selected"); } }); document.getElementById("none-rarities").addEventListener("click", function() { for (const rarity of Object.keys(rarities)) { rarities[rarity] = false; document.getElementById("rarity-" + rarity).classList.remove("rarity-selected"); } }); // filters document.getElementById("add-filter").addEventListener("click", create_filter); create_filter(); filters[0].input_elem.value = "Combat Level"; init_filter_drag(); } function reset_item_search() { document.getElementById("item-name-choice").value = ""; document.getElementById("all-types").click(); document.getElementById("all-rarities").click(); } function create_filter() { let data = {ascending: false}; let row = make_elem("div", ["row", "filter-row"], {}); let col = make_elem("div", ["col"], {}); row.appendChild(col); data.div = row; let reorder_img = make_elem("img", ["reorder-filter"], {src: "../media/icons/3-lines.svg", draggable: "true"}); col.appendChild(reorder_img); let filter_input = make_elem("input", ["col", "border-dark", "text-light", "dark-5", "rounded", "scaled-font", "form-control", "form-control-sm", "filter-input"], {id: "filter-input-" + filter_id_counter, type: "text", placeholder: "Filter"} ); filter_id_counter++; col.appendChild(filter_input); data.input_elem = filter_input; let asc_desc = make_elem("div", [], {style: "cursor: pointer; display: inline-block;"}); asc_desc.appendChild(make_elem("img", ["desc-icon", "asc-sel"], {src: "../media/icons/triangle.svg"})); asc_desc.appendChild(make_elem("img", ["asc-icon"], {src: "../media/icons/triangle.svg"})); asc_desc.addEventListener("click", function() { data.ascending = !data.ascending; asc_desc.children[0].classList.toggle("asc-sel"); asc_desc.children[1].classList.toggle("asc-sel"); }); col.appendChild(asc_desc); let min = make_elem("input", ["col", "border-dark", "text-light", "dark-5", "rounded", "scaled-font", "form-control", "form-control-sm", "min-max-input"], {type: "number", placeholder: "-\u221E"} ); col.appendChild(min); data.min_elem = min; let to = make_elem("span", [], {innerHTML: " to "}); col.appendChild(to); let max = make_elem("input", ["col", "border-dark", "text-light", "dark-5", "rounded", "scaled-font", "form-control", "form-control-sm", "min-max-input"], {type: "number", placeholder: "\u221E"} ); col.appendChild(max); data.max_elem = max; document.getElementById("filter-container").insertBefore(row, document.getElementById("add-filter").parentElement); filters.push(data); init_filter_dropdown(data); } let currently_dragging = null; function init_filter_drag() { let container = document.getElementById("filter-container"); container.addEventListener("dragstart", function(e) { if (e.path[0].classList.contains("reorder-filter")) { currently_dragging = filters[Array.from(e.path[3].children).indexOf(e.path[2]) - 1]; } else { e.preventDefault(); } }); container.addEventListener("dragenter", function(e) { e.preventDefault(); }); container.addEventListener("dragleave", function(e) { e.preventDefault(); }); container.addEventListener("dragend", function(e) { e.preventDefault(); for (const el of document.getElementsByClassName("filter-dragged-over")) { el.classList.remove("filter-dragged-over"); } currently_dragging = null; }); container.addEventListener("dragover", function(e) { e.preventDefault(); for (const el of document.getElementsByClassName("filter-dragged-over")) { el.classList.remove("filter-dragged-over"); } if (!e.path.includes(currently_dragging.div)) { for (let i = 0; i < e.path.length; i++) { if (e.path[i].classList.contains("filter-row")) { e.path[i].classList.add("filter-dragged-over"); break; } } } }); container.addEventListener("drop", function(e) { e.preventDefault(); for (const el of document.getElementsByClassName("filter-dragged-over")) { el.classList.remove("filter-dragged-over"); } if (!e.path.includes(currently_dragging.div)) { for (let i = 0; i < e.path.length; i++) { if (e.path[i].classList.contains("filter-row")) { let old_index = filters.indexOf(currently_dragging); let new_index = Array.from(e.path[i + 1].children).indexOf(e.path[i]) - 1; filters.splice(old_index, 1); filters.splice(new_index, 0, currently_dragging); currently_dragging.div.remove(); container.insertBefore(currently_dragging.div, container.children[new_index + 1]); break; } } } currently_dragging = null; }); } function init_filter_dropdown(filter) { let field_choice = filter.input_elem; field_choice.onclick = function() {field_choice.dispatchEvent(new Event('input', {bubbles:true}));}; filter.autoComplete = new autoComplete({ data: { src: item_filters, }, threshold: 0, selector: "#" + field_choice.id, wrapper: false, resultsList: { maxResults: 100, tabSelect: true, noResults: true, class: "search-box dark-7 rounded-bottom px-2 fw-bold dark-shadow-sm", element: (list, data) => { let position = field_choice.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 * 4 +"px"; if (!data.results.length) { const message = make_elem('li', ['scaled-font'], {textContent: "No results 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; }; }, }, } }); } (async function() { await Promise.resolve(load_init()); init_items(); })();