Item search kinda

This commit is contained in:
b 2021-01-26 03:17:11 -06:00
parent 151e847c81
commit f84d8b5958
9 changed files with 318 additions and 177 deletions

File diff suppressed because one or more lines are too long

View file

@ -1,21 +0,0 @@
.items {
grid-column: 1;
padding: 0%;
display: grid;
grid-template-columns: repeat(auto-fill, 1fr);
width: 100%;
gap: 5px;
}
.itemsearch {
padding: 0%;
display: grid;
grid-template-columns: 1fr;
width: 100%;
gap: 5px;
grid-template-rows: masonry;
}
.search {
grid-column: 1;
}

View file

@ -1,24 +0,0 @@
.items {
grid-column: 2;
padding: 0%;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
width: 100%;
gap: 5px;
grid-template-rows: masonry;
}
.itemsearch {
padding: 0%;
display: grid;
grid-template-columns: 1fr 4fr;
width: 100%;
gap: 5px;
}
.search {
grid-column: 1;
position: sticky;
margin-bottom: auto;
top: 10px;
}

View file

@ -9,6 +9,7 @@
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="items.css">
<link rel="stylesheet" media="screen and (min-width: 1100px)" href="items-wide.css"/>
<link rel="stylesheet" media="screen and (max-width: 1099px)" href="items-narrow.css"/>
<link rel="icon" href="favicon.png">
@ -48,26 +49,86 @@
<br>
<br>
<div class="itemsearch">
<div class="search">
<div class="center" id="credits">
<a href="translations.txt" class="link">CLICK FOR ID mapping</a>
<div class="searchbox">
<div class="left">
<label for="name-choice">Name:</label><br>
<input class="searchinput" type="text" id="name-choice" name="name-choice" placeholder="Item name (case insensitive)" tabindex="1"/>
<p class="error"></p>
</div>
<div class="left">
<label for="category-choice">Category:</label><br>
<input class="searchinput" list="category-items" id="category-choice" name="category-choice" placeholder="ALL" tabindex="2"/>
<datalist id="category-items">
<option value="ALL">
<option value="armor">
<option value="helmet">
<option value="chestplate">
<option value="leggings">
<option value="boots">
<option value="accessory">
<option value="ring">
<option value="bracelet">
<option value="necklace">
<option value="weapon">
<option value="wand">
<option value="spear">
<option value="bow">
<option value="dagger">
<option value="relik">
</datalist>
<p class="error"></p>
</div>
<div class="left">
<label for="rarity-choice">Rarity:</label><br>
<input class="searchinput" list="rarity-items" id="rarity-choice" name="rarity-choice" placeholder="ANY" tabindex="3"/>
<datalist id="rarity-items">
<option value="ANY">
<option value="Normal">
<option value="Unique">
<option value="Rare">
<option value="Legendary">
<option value="Fabled">
<option value="Mythic">
<option value="Sane">
</datalist>
<p class="error"></p>
</div>
<div class="left">
<label for="level-choice">Level:</label><br>
<input class="searchinput" type="text" id="level-choice" name="level-choice" value="1-106" tabindex="4"/>
<p class="error"></p>
</div>
<datalist id="filter-items">
</datalist>
<div class="left">
<label for="filter1-choice">Filter 1:</label><br>
<input class="searchinput" list="filter-items" id="filter1-choice" name="filter1-choice" placeholder="ANY" tabindex="5"/>
<p class="error"></p>
</div>
<div class="left">
<label for="filter2-choice">Filter 2:</label><br>
<input class="searchinput" list="filter-items" id="filter2-choice" name="filter2-choice" placeholder="ANY" tabindex="6"/>
<p class="error"></p>
</div>
<div class="left">
<label for="filter3-choice">Filter 3:</label><br>
<input class="searchinput" list="filter-items" id="filter3-choice" name="filter3-choice" placeholder="ANY" tabindex="7"/>
<p class="error"></p>
</div>
<div class="left">
<label for="filter4-choice">Filter 4:</label><br>
<input class="searchinput" list="filter-items" id="filter4-choice" name="filter4-choice" placeholder="ANY" tabindex="8"/>
<p class="error"></p>
</div>
<div class="right" style="grid-column:1/span 2">
<button class = "button" id = "search-button" onclick = "doItemSearch()" tabindex="9">
Search!
</button>
</div>
<div id="summary" class="left" style="grid-column:3/span 2">
Hello!
</div>
<p>Basic Dumb JSON search</p>
<p>Query types:</p>
<p>name, type, category, stat</p>
<textarea name="query-json" id="query-json" cols="25" rows="25" tabindex="1">
[
{
"queryType": "name",
"value": ""
}
]
</textarea>
<br>
<button class = "button" id = "search-button" onclick = "doItemSearch()" tabindex="2">
Search Items
</button>
<p id="summary">hello</p>
</div>
<div class="center items" id="main">
</div>

162
items.js
View file

@ -1,4 +1,123 @@
const translate_mappings = {
//"Name": "name",
//"Display Name": "displayName",
//"tier"Tier": ",
//"Set": "set",
"Powder Slots": "slots",
//"Type": "type",
//"armorType", (deleted)
//"color", (deleted)
//"lore", (deleted)
//"material", (deleted)
"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)": new SumQuery(["str", "dex", "int", "def", "agi"]),
"Sum (Mana Sustain)": new SumQuery(["mr", "ms"]),
"Sum (Life Sustain)": new SumQuery(["hpr", "ls"]),
"Sum (Health + Health Bonus)": new SumQuery(["hp", "hpBonus"]),
"No Req Strength": new NegateQuery("strReq"),
"No Req Dexterity": new NegateQuery("dexReq"),
"No Req Intelligence": new NegateQuery("intReq"),
"No Req Agility": new NegateQuery("agiReq"),
"No Req Defense": new NegateQuery("defReq"),
};
let itemFilters = document.getElementById("filter-items");
for (let x in translate_mappings) {
let el = document.createElement("option");
el.value = x;
itemFilters.appendChild(el);
}
for (let x in special_mappings) {
let el = document.createElement("option");
el.value = x;
itemFilters.appendChild(el);
}
let itemTypes = [ "helmet", "chestplate", "leggings", "boots", "ring", "bracelet", "necklace", "wand", "spear", "bow", "dagger", "relik" ];
let itemCategories = [ "armor", "accessory", "weapon" ];
function applyQuery(items, query) {
return items.filter(query.filter, query).sort(query.compare);
}
@ -17,12 +136,47 @@ function displayItems(items_copy) {
function doItemSearch() {
window.scrollTo(0, 0);
let input_json = document.getElementById("query-json").value;
let input = JSON.parse(input_json);
let queries = [];
queries.push(new NameQuery(document.getElementById("name-choice").value));
let categoryOrType = document.getElementById("category-choice").value;
if (itemTypes.includes(categoryOrType)) {
queries.push(new IdMatchQuery("type", categoryOrType));
}
else if (itemCategories.includes(categoryOrType)) {
queries.push(new IdMatchQuery("category", categoryOrType));
}
let rarity = document.getElementById("rarity-choice").value;
if (rarity) {
if (rarity === "ANY") {
}
else {
queries.push(new IdMatchQuery("tier", rarity));
}
}
let level_dat = document.getElementById("level-choice").value.split("-");
queries.push(new LevelRangeQuery(parseInt(level_dat[0]), parseInt(level_dat[1])));
for (let i = 1; i <= 4; ++i) {
let raw_dat = document.getElementById("filter"+i+"-choice").value;
let filter_dat = translate_mappings[raw_dat];
if (filter_dat !== undefined) {
queries.push(new IdQuery(filter_dat));
continue;
}
filter_dat = special_mappings[raw_dat];
if (filter_dat !== undefined) {
queries.push(filter_dat);
continue;
}
}
let items_copy = items.slice();
document.getElementById("main").textContent = "";
for (const _query of input) {
const query = queryTypeMap.get(_query.queryType)(_query.value, _query.value2);
for (const query of queries) {
items_copy = applyQuery(items_copy, query);
}
document.getElementById("summary").textContent = items_copy.length + " results."

View file

@ -1,4 +1,4 @@
const DB_VERSION = 28;
const DB_VERSION = 29;
// @See https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/video-store/index.js
let db;

View file

@ -14,33 +14,30 @@ class NameQuery {
}
queryTypeMap.set("name", function(s) { return new NameQuery(s); } );
class TypeQuery {
constructor(type) { this.type = type; }
class LevelRangeQuery {
constructor(min, max) { this.min = min; this.max = max; }
filter(item) {
if (item.remapID === undefined) {
return (item.type === this.type);
return (item.lvl <= this.max && item.lvl >= this.min);
}
return false;
}
compare(a, b) { return a < b; }
compare(a, b) { return a > b; }
}
queryTypeMap.set("type", function(s) { return new TypeQuery(s); } );
class CategoryQuery {
constructor(category) { this.category = category; }
filter(item) {
if (item.remapID === undefined) {
return (item.category === this.category);
}
return false;
class NegateQuery {
constructor(id) {
this.id = id;
this.compare = function(a, b) { return 0; };
}
compare(a, b) { return a < b; }
filter(item) {
return (!(this.id in item)) || (item[this.id] == 0);
}
}
queryTypeMap.set("category", function(s) { return new CategoryQuery(s); } );
queryTypeMap.set("null", function(s) { return new IdQuery(s); } );
class IdQuery {
constructor(id) {
@ -55,3 +52,34 @@ class IdQuery {
}
}
queryTypeMap.set("stat", function(s) { return new IdQuery(s); } );
class IdMatchQuery {
constructor(id, value) {
this.id = id;
this.value = value;
this.compare = function(a, b) {
return 0;
};
}
filter(item) {
return (this.id in item) && (item[this.id] == this.value);
}
}
class SumQuery {
constructor(ids) {
this.compare = function(a, b) {
let balance = 0;
for (const id of ids) {
if (a[id]) { balance -= a[id]; }
if (b[id]) { balance += b[id]; }
}
return balance;
};
}
filter(item) {
return true;
}
}

View file

@ -5,6 +5,18 @@
flex-direction: row;
justify-content: center;
}
.error {
color: red;
top: 30px;
font-size: 10px;
padding: 0;
margin: 0;
height: 5px;
font-family: 'Nunito', sans-serif;
white-space: nowrap;
}
.headericon {
/* JANK FIX IF CAN */
max-height: 48px;

View file

@ -70943,77 +70943,37 @@
"drop": "NORMAL"
},
{
"name": "Enduzskam",
"tier": "Unique",
"type": "boots",
"name": "Enduzskam",
"displayName": "Enduzskam",
"set": null,
"quest": null,
"poison": 0,
"thorns": 0,
"sprint": 0,
"category": "armor",
"slots": 2,
"drop": "NORMAL",
"hp": 1950,
"fDef": 0,
"wDef": 50,
"aDef": 0,
"tDef": 80,
"eDef": -90,
"lvl": 83,
"classReq": null,
"fixID": false,
"strReq": 0,
"dexReq": 45,
"intReq": 45,
"agiReq": 0,
"dexReq": 35,
"intReq": 35,
"defReq": 0,
"hprPct": 0,
"mr": 1,
"sdPct": 7,
"mdPct": 0,
"ls": 0,
"ms": 0,
"xpb": 0,
"lb": 0,
"ref": 0,
"agiReq": 0,
"category": "armor",
"lvl": 83,
"hp": 1950,
"eDef": -90,
"tDef": 80,
"wDef": 50,
"slots": 2,
"str": 0,
"dex": 4,
"dex": 9,
"int": 0,
"agi": 0,
"def": 0,
"expd": 0,
"spd": 0,
"atkTier": 0,
"hpBonus": 0,
"spRegen": 0,
"eSteal": 0,
"hprRaw": 0,
"sdRaw": 0,
"mdRaw": 0,
"fDamPct": 0,
"wDamPct": 12,
"aDamPct": 0,
"tDamPct": 16,
"agi": 0,
"mr": 1,
"sdPct": 14,
"eDamPct": -14,
"fDefPct": 0,
"wDefPct": 0,
"aDefPct": 0,
"tDefPct": 0,
"tDamPct": 16,
"wDamPct": 12,
"eDefPct": -10,
"spPct1": 0,
"spRaw1": 0,
"spPct2": 0,
"spRaw2": 0,
"spPct3": 0,
"spRaw3": 0,
"spPct4": 0,
"spRaw4": 0,
"rainbowRaw": 0,
"sprintReg": 0,
"jh": 0,
"lq": 0,
"gXp": 0,
"gSpd": 0,
"id": 986
},
{
@ -256754,38 +256714,9 @@
"remapID": 586
},
{
"tier": "Unique",
"type": "boots",
"name": "Enduzkam",
"displayName": "Enduzkam",
"set": null,
"quest": null,
"classReq": null,
"fixID": false,
"strReq": 0,
"dexReq": 35,
"intReq": 35,
"defReq": 0,
"agiReq": 0,
"category": "armor",
"lvl": 83,
"hp": 1950,
"eDef": -90,
"tDef": 80,
"wDef": 50,
"slots": 2,
"str": 0,
"dex": 9,
"int": 0,
"def": 0,
"agi": 0,
"mr": 1,
"sdPct": 14,
"eDamPct": -14,
"tDamPct": 16,
"wDamPct": 12,
"eDefPct": -10,
"id": 3592
"id": 3592,
"name": "3592",
"remapID": 986
},
{
"tier": "Unique",
@ -258891,7 +258822,7 @@
"displayName": "Cursed Jackboots"
},
{
"displayName": "Cinfras Souvenir T-Shirt",
"name": "Cinfras Souvenir T-Shirt",
"tier": "Normal",
"type": "chestplate",
"set": null,