Added WynnCustom Version 1, ATLAS, and minor fixes

This commit is contained in:
ferricles 2021-03-05 08:28:00 -08:00
parent fadd6700be
commit 3fea0ba00a
20 changed files with 2891 additions and 14 deletions

61
atlas.html Normal file
View file

@ -0,0 +1,61 @@
<!DOCTYPE html>
<html scroll-behavior="smooth">
<head>
<!-- nunito font, copying wynndata -->
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" media="screen and (min-width: 1100px)" href="wide.css"/>
<link rel="stylesheet" media="screen and (max-width: 1099px)" href="narrow.css"/>
<link rel="icon" href="favicon.png">
<link rel="manifest" href="manifest.json">
<title>ATLAS???</title>
</head>
<body class="all">
<div class="center">
<header class = "header nomarginp">
<div class = "headerleft">
<a href = "./" class = "nomarginp iconlink tooltip">
<img src = "/media/icons/builder.png" class = "left linkoptions headericon">
</img>
<div class = "tooltiptext center">WynnBuilder</div>
</a>
<a href = "./crafter.html" class = "nomarginp iconlink tooltip">
<img src = "/media/icons/crafter.png" class = "left linkoptions headericon">
</img>
<div class = "tooltiptext center">WynnCrafter</div>
</a>
<a href = "./items.html" class = "nomarginp iconlink tooltip">
<img src = "/media/icons/searcher.png" class = "left linkoptions headericon">
</img>
<div class = "tooltiptext center">WynnAtlas</div>
</a>
<a href = "./customizer.html" class = "nomarginp iconlink tooltip">
<img src = "/media/icons/custom.png" class = "left linkoptions headericon">
</img>
<div class = "tooltiptext center">WynnCustom</div>
</a>
</div>
<div class = "headercenter">
<div >
<p class = "itemp" id = "header">Atlas???</p>
</div>
</div>
<div class = "headerright">
<button class = "atlas" onclick = "atlasClick()">
<img src = "favicon.png"/>
</button>
</div>
</header>
</div>
<div class = "center" id = "flavortext">
...
</div>
<div class = "center bodydiv" id = "bodydiv">
</div>
<script type="text/javascript" src="atlas.js"></script>
</body>
</html>

139
atlas.js Normal file
View file

@ -0,0 +1,139 @@
function setTitle() {
let text = "ATLAS???";
document.getElementById("header").classList.add("funnynumber");
document.getElementById("header").classList.add("title");
document.getElementById("header").textContent = text;
}
setTitle();
const flavortexts = ["JALA?? \n ATLAS?? \n ANYONE??",
"this really do be a bruh moment.",
"OH, LOOK AT YOU. YOU FOUND THE FUNNY BUILDER GUILDER MEME PAGE. AREN'T YOU PROUD OF YOURSELF?",
"Downloading Atlas Inc Virus 2.0...",
"Any WynnBuilders in the chat?",
":sunglaso:",
"This says a lot about our society.",
"WynnCraft is overrated. Stay on this page forever!",
"Now trading Smash invite letters for Atlas Inc invites!",
"You have reached the customer support page of Wynnbuilder. Please call [REDACTED] to get your problems solved!",
"",
"Isn't this like that one game Amogus?",
"Mom, what does 'hppeng' mean?",
"| |I || |_",
"",
];
const dt = 10; //millis
const PIX_PER_SEC = 1000;
const EPSILON = 1E-7 * dt;
let atli = [];
function atlasClick() {
let atlas = document.createElement("div");
let atlas_img = document.createElement("img");
atlas_img.src = "favicon.png";
atlas_img.style.width = "100%";
atlas_img.style.height = "100%";
atlas_img.style.zIndex = 1;
atlas.classList.add("atlas");
atlas.appendChild(atlas_img);
atlas.style = "background-image: radial-gradient(closest-side, #" + Math.round(255*Math.random()).toString(16)+Math.round(255*Math.random()).toString(16)+Math.round(255*Math.random()).toString(16) + " 0%," + "#121516 120%);";
atlas.style.position = "absolute";
rect = document.getElementById("bodydiv").getBoundingClientRect(); //use rect.top, rect.left, rect.bottom, and rect.top
atlasrect = atlas.getBoundingClientRect();
atlas.style.left = Math.floor((rect.right - rect.left - 2*(atlasrect.right - atlasrect.left) ) * Math.random() + rect.left + (atlasrect.right - atlasrect.left) )+ "px";
atlas.style.top = Math.floor((rect.bottom - rect.top - 2*(atlasrect.bottom - atlasrect.top) ) * Math.random() + rect.top + (atlasrect.bottom - atlasrect.top) ) + "px";
//atlas.style.border = "3px solid white";
atlas.vx = (dt / 1000 * PIX_PER_SEC * Math.random()) - (dt / 2000 * PIX_PER_SEC);
atlas.vy = (dt / 1000 * PIX_PER_SEC * Math.random()) - (dt / 2000 * PIX_PER_SEC);
let temp = 2*Math.random()-1;
let sign = Math.round(temp/Math.abs(temp));
atlas.wx = sign*(150 + 60*Math.random())/dt;//using w for omega
atlas.theta = Math.random()*360;
atli.push(atlas);
document.getElementById("bodydiv").appendChild(atlas);
document.getElementById("flavortext").textContent = flavortexts[Math.floor(flavortexts.length*Math.random())];
}
function runAtlas() {
let rect = document.getElementById("bodydiv").getBoundingClientRect(); //use rect.top, rect.left, rect.bottom, and rect.top
//bounce off the walls - average slight damping
for (const atlas of atli) {
let atlasrect = atlas.getBoundingClientRect();
if(atlasrect.left + atlas.vx < rect.left || atlasrect.right + atlas.vx > rect.right) {
atlas.vx *= -1 + (.01 * Math.random() - .004)*dt;
if(Math.abs(atlas.vx) < EPSILON) {
atlas.vx += (.001 * Math.random() - .0005)*dt;
}
}
if(atlasrect.top + atlas.vy < rect.top || atlasrect.bottom + atlas.vy > rect.bottom) {
atlas.vy *= -1 + (.01 * Math.random() - .004)*dt;
if(Math.abs(atlas.vy) < EPSILON) {
atlas.vy += (.001 * Math.random() - .0005)*dt;
}
}
}
for(let i = 0; i < atli.length; i++) {
for(let j = 0; j < atli.length; j++) {
if(i != j) {
let temp;
let atlas1 = atli[i];
let atlas2 = atli[j];
let rect1 = atlas1.getBoundingClientRect(); //The bounding rects of both divs.
let rect2 = atlas2.getBoundingClientRect();
let at1 = [(rect1.left+rect1.right)/2, (rect1.top+rect1.bottom)/2]; //The center x,y coords of both divs
let at2 = [(rect2.left+rect2.right)/2, (rect2.top+rect2.bottom)/2];
let r = (rect2.bottom - rect2.top)/2; //The radius of the incircle of a div.
let dx = at2[0] - at1[0];
let dy = at2[1] - at1[1];
let center = [(at1[0]+at2[0])/2, (at1[1]+at2[1])/2 ];
if (Math.sqrt(((at2[1]+atlas2.vy) - (at1[1]+atlas1.vy))**2 + ((at2[0]+atlas2.vx) - (at1[0]+atlas1.vx))**2) < 2*r) {
if(Math.sqrt( (at2[1]-at1[1])**2 + (at2[0]-at1[0])**2 ) < 2*r ) {//check for collision
//Move both away slightly - correct alg this time :)
atlas1.style.left = parseFloat(atlas1.style.left.replace("px","")) + (at1[0]-center[0]) * 2 * r / Math.sqrt(dx**2 + dy**2) + "px";
atlas1.style.top = parseFloat(atlas1.style.top.replace("px","")) + (at1[1]-center[1]) * 2 * r / Math.sqrt(dx**2 + dy**2) + "px";
atlas2.style.left = parseFloat(atlas2.style.left.replace("px","")) + (at2[0]-center[0]) * 2 * r / Math.sqrt(dx**2 + dy**2) + "px";
atlas2.style.top = parseFloat(atlas2.style.top.replace("px","")) + (at2[1]-center[1]) * 2 * r / Math.sqrt(dx**2 + dy**2) + "px";
}
//Do conservation of momentum with an elastic collision. Masses are equal.
temp = atlas1.vy;
atlas1.vy = atlas2.vy;
atlas2.vy = temp;
temp = atlas1.vx;
atlas1.vx = atlas2.vx;
atlas2.vx = temp;
}
}
}
}
for(const atlas of atli) {
//move the atlas
atlas.style.left = parseFloat(atlas.style.left.replace("px",""))+atlas.vx+"px";
atlas.style.top = parseFloat(atlas.style.top.replace("px",""))+atlas.vy+"px";
//rotate the atlas - this is causing trouble with teleporting atli; probably has to do with messing with the corners of the bounding rects.
atlas.childNodes[0].style.transform = 'rotate(' + (atlas.theta)%360 + 'deg)';
atlas.theta = (atlas.theta+atlas.wx/dt)%360
//make sure the atlas is in bounds!!
let atlasrect = atlas.getBoundingClientRect();
if(atlasrect.right > rect.right || atlasrect.left < rect.left || atlasrect.top < rect.top || atlasrect.bottom > rect.bottom) {
atlas.style.left = Math.floor((rect.right - rect.left - 2*(atlasrect.right - atlasrect.left) ) * Math.random() + rect.left + (atlasrect.right - atlasrect.left) )+ "px";
atlas.style.top = Math.floor((rect.bottom - rect.top - 2*(atlasrect.bottom - atlasrect.top) ) * Math.random() + rect.top + (atlasrect.bottom - atlasrect.top) ) + "px";
}
}
}
setInterval(runAtlas, dt);

View file

@ -1,6 +1,5 @@
const baseDamageMultiplier = [ 0.51, 0.83, 1.5, 2.05, 2.5, 3.1, 4.3 ];
const attackSpeeds = ["SUPER_SLOW", "VERY_SLOW", "SLOW", "NORMAL", "FAST", "VERY_FAST", "SUPER_FAST"];
const classDefenseMultipliers = new Map([ ["relik",0.50], ["bow",0.60], ["wand", 0.80], ["dagger", 1.0], ["spear",1.20] ]);
/**

View file

@ -2,7 +2,7 @@ const url_tag = location.hash.slice(1);
console.log(url_base);
console.log(url_tag);
const BUILD_VERSION = "6.9.38";
const BUILD_VERSION = "6.9.40";
function setTitle() {
let text;
@ -911,4 +911,3 @@ function toggleID() {
}
load_init(init);

View file

@ -65,6 +65,7 @@ class Craft{
}
setHash(hash) {
this.hash = hash;
this.statMap.set("name", "CR-" + this.hash);
this.statMap.set("displayName", "CR-" + this.hash);
this.statMap.set("hash", this.hash);
}
@ -76,7 +77,8 @@ class Craft{
let statMap = new Map();
statMap.set("minRolls", new Map());
statMap.set("maxRolls", new Map());
statMap.set("displayName", "CR-" + this.hash); //TODO: DISPLAY THE HASH
statMap.set("name", "CR-" + this.hash);
statMap.set("displayName", "CR-" + this.hash);
statMap.set("tier", "Crafted");
statMap.set("type", this.recipe.get("type").toLowerCase());
statMap.set("duration", [this.recipe.get("duration")[0], this.recipe.get("duration")[1]]); //[low, high]

View file

@ -8,7 +8,7 @@
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" media="screen and (min-width: 1100px)" href="wide.css"/>
<link rel="stylesheet" media="screen and (max-width: 1099px)" href="narrow.css"/>
<link rel="icon" href="favicon.png">
<link rel="icon" href="./media/icons/crafter.png">
<link rel="manifest" href="manifest.json">
<title>WynnCrafter</title>
</head>
@ -31,6 +31,11 @@
</img>
<div class = "tooltiptext center">WynnAtlas</div>
</a>
<a href = "./customizer.html" class = "nomarginp iconlink tooltip">
<img src = "/media/icons/custom.png" class = "left linkoptions headericon">
</img>
<div class = "tooltiptext center">WynnCustom</div>
</a>
</div>
<div class = "headercenter">
<div >

View file

@ -9,7 +9,7 @@ console.log(ing_url_tag);
const ING_BUILD_VERSION = "6.9.21";
const ING_BUILD_VERSION = "6.9.40";
/*
* END testing section
*/
@ -29,7 +29,7 @@ function setTitle() {
document.getElementById("header").textContent = "WynnCrafter version "+ING_BUILD_VERSION+" (ingredient db version "+ING_DB_VERSION+")";
document.getElementById("header").classList.add("funnynumber");
let disclaimer = document.createElement("p");
disclaimer.textContent = "THIS CRAFTER IS NEARLY COMPLETE. The effect of material tiers on crafted items is not 100% tested and accurate. If you know how the math behind it works OR if you have a crafted item whose stats contradict this crafter, please contact ferricles on forums, discord, or ingame.";
disclaimer.textContent = "THIS CRAFTER IS NEARLY COMPLETE. The effect of powders on crafted weapons is not accurate. If you know how the math behind it works, please contact ferricles on forums, discord, or ingame.";
document.getElementById("header").append(disclaimer);
}

102
custom.js Normal file
View file

@ -0,0 +1,102 @@
tiers = ["Normal", "Unique", "Rare", "Legendary", "Fabled", "Mythic", "Set", "Crafted"] //I'm not sure why you would make a custom crafted but if you do you should be able to use it w/ the correct powder formula
types = armorTypes.concat(accessoryTypes).concat(weaponTypes).concat(consumableTypes).map(x => x.substring(0,1).toUpperCase() + x.substring(1));
//constructs a CI from a hash 'CI-qwoefsabaoe' or 'qwoefsaboe'
function getCustomFromHash(hash) {
}
/** An object representing a Custom Item. Mostly for vanity purposes.
* @dep Requires the use of nonRolledIDs and rolledIDs from display.js.
* @dep Requires the use of attackSpeeds from build.js.
*/
class Custom{
/**
* @description Construct a custom item (CI) from a statMap.
* @param {statMap}: A map with keys from rolledIDs or nonRolledIDs or minRolls/maxRolls and values befitting the keys. minRolls and maxRolls are their own maps and have the same keys, but with minimum and maximum values (for rolls).
*
*/
constructor(statMap){
this.statMap = statMap;
this.initCustomStats();
}
//Applies powders to the CI
applyPowders() {
if (this.statMap.get("category") === "armor") {
//double apply armor powders
for(const id of this.statMap.get("powders")){
let powder = powderStats[id];
let name = powderNames.get(id);
this.statMap.set(name.charAt(0) + "Def", (this.statMap.get(name.charAt(0)+"Def") || 0) + 2 * powder["defPlus"]);
this.statMap.set(skp_elements[(skp_elements.indexOf(name.charAt(0)) + 4 )% 5] + "Def", (this.statMap.get(skp_elements[(skp_elements.indexOf(name.charAt(0)) + 4 )% 5]+"Def") || 0) - 2 * powder["defMinus"]);
}
}else if (this.statMap.get("category") === "weapon") {
//do nothing - weapon powders are handled in displayExpandedItem
}
}
//Sets the "Hash" of the CI. YOU SHOULD NEVER BE CHANGING THE HASH.
setHash(hash) {
this.hash = hash;
//this.statMap.set("displayName", "CI-" + this.hash);
this.statMap.set("hash", this.hash);
}
//TODO
setHash() {
this.statMap.set("hash", "Custom Item");
}
updateName(name) {
this.name = name;
this.displayName = name; //name overrides hash
}
/* Get all stats for this CI.
* Stores in this.statMap.
* Follows the expandedItem item structure, similar to a crafted item.
* TODO: Check if this is even useful
*/
initCustomStats(){
if (this.statMap.get("tier") === "Crafted") {
this.statMap.set("Crafted", true);
for (const e of skp_elements) {
this.statMap.set(e+"DamLow", this.statMap.get(e+"Dam"));
}
this.statMap.set("nDamLow", this.statMap.get("nDam"));
}
if (this.statMap.get("type")) {
this.statMap.set("type",this.statMap.get("type").toLowerCase());
if (armorTypes.includes(this.statMap.get("type"))) {
this.statMap.set("category","armor");
} else if (accessoryTypes.includes(this.statMap.get("type"))) {
this.statMap.set("category","accessory");
} else if (weaponTypes.includes(this.statMap.get("type"))) {
this.statMap.set("category","weapon");
} else if (consumableTypes.includes(this.statMap.get("type"))) {
this.statMap.set("category","consumable")
}
}
if(this.statMap.get("category") !== "weapon") {
this.statMap.set("atkSpd", "");
}
this.setHash();
if (this.statMap.get("name") && this.statMap.get("name") !== "") {
this.statMap.set("displayName", this.statMap.get("name"));
} else {
this.statMap.set("displayName", this.statMap.get("hash"));
}
this.statMap.set("reqs",[this.statMap.get("strReq"),this.statMap.get("dexReq"),this.statMap.get("intReq"),this.statMap.get("defReq"),this.statMap.get("agiReq")]);
this.statMap.set("powders", []);
this.statMap.set("restrict", "Custom Item")
}
}

1903
customizer.html Normal file

File diff suppressed because it is too large Load diff

555
customizer.js Normal file
View file

@ -0,0 +1,555 @@
/*
* TESTING SECTION
*/
const custom_url_base = location.href.split("#")[0];
const custom_url_tag = location.hash.slice(1);
console.log(custom_url_base);
console.log(custom_url_tag);
const BUILD_VERSION = "6.9.40";
function setTitle() {
let text = "WynnCustom version "+BUILD_VERSION;
document.getElementById("header").classList.add("funnynumber");
document.getElementById("header").textContent = text;
}
setTitle();
/*
* END testing section
*/
let player_custom_item;
let base_item; //the item that a user starts from, if any
let pos_range = [0.3,1.3];
let neg_range = [1.3,0.7];
let itemMap = new Map();
/* Mapping from item names to set names. */
let idMap = new Map();
let redirectMap = new Map();
let roll_range_ids = ["neg_roll_range-choice-min","neg_roll_range-choice-max","pos_roll_range-choice-min","pos_roll_range-choice-max"];
function init() {
try {
//directly from builder.js. Removed irrelevant materials and no noneitems used here.
for (const item of items) {
if (item.remapID === undefined) {
itemMap.set(item.displayName, item);
idMap.set(item.id, item.displayName);
}
else {
redirectMap.set(item.id, item.remapID);
}
}
console.log(itemMap);
populateFields();
decodeCustom(custom_url_tag);
for (const id of rolledIDs) {
if (document.getElementById(id+"-choice-base")) {
let base_elem = document.getElementById(id+"-choice-base");
base_elem.addEventListener("focusout", (event) => {
base_to_range(id);
});
let min_elem = document.getElementById(id+"-choice-min");
min_elem.addEventListener("focusout", (event) => {
range_to_base(id,"min");
});
let max_elem = document.getElementById(id+"-choice-max");
max_elem.addEventListener("focusout", (event) => {
range_to_base(id,"max");
});
}
}
for (const id of roll_range_ids) {
document.getElementById(id).addEventListener("focusout", (event) => {
changeBaseValues();
});
}
} catch (error) {
console.log("If you are seeing this while building, do not worry. Oherwise, panic! (jk contact ferricles)");
console.log(error);
}
}
/** Create a custom item based on data input into the fields.
*
*/
function calculateCustom() {
try {
//Make things display.
for (let i of document.getElementsByClassName("hide-container-block")) {
i.style.display = "block";
}
for (let i of document.getElementsByClassName("hide-container-grid")) {
i.style.display = "grid";
}
let statMap = new Map();
statMap.set("minRolls", new Map());
statMap.set("maxRolls", new Map());
let inputs = document.getElementsByTagName("input");
if (document.getElementById("fixID-choice").textContent === "yes") {//Fixed IDs
for (const input of inputs) {
if (input.id.includes("-min") || input.id.includes("-max")) {
continue;
}
let id = input.id.replace("-choice", "");
id = id.replace("-fixed", "");
id = id.replace("-min", "");
id = id.replace("-max", "");
if (input.classList.contains("number-input")) {
if (parseFloat(input.value)) {
if(rolledIDs.includes(id)) {
statMap.get("minRolls").set(id,parseFloat(input.value));
statMap.get("maxRolls").set(id,parseFloat(input.value));
} else {
statMap.set(id, parseFloat(input.value));
}
}
} else if (input.classList.contains("string-input")) {
if(rolledIDs.includes(id)) {
statMap.get("minRolls").set(id,input.value);
statMap.get("maxRolls").set(id,input.value);
} else {
statMap.set(id, input.value);
}
} else if (input.classList.contains("array-input")) {
statMap.set(id, input.value.split("-").map(x=>parseFloat(x)));
}
if(input.value === "" && input.placeholder && input.placeholder !== "") {
if (input.classList.contains("number-input") && parseFloat(input.placeholder)) {
statMap.set(id, parseFloat(input.placeholder));
} else if (input.classList.contains("string-input")) {
statMap.set(id, input.placeholder);
} else if (input.classList.contains("array-input")) {
statMap.set(id, input.placeholder.split("-").map(x=>parseFloat(x)));
}
}
}
statMap.set("fixID", true);
} else { //rolled IDs!
for (const input of inputs) {
if (input.id.includes("-fixed")) {
continue;
}
//FIXs
let id = input.id.replace("-choice", "");
let rollMap = "";
//If it's a minimum, it's -min
if(id.includes("-min")) {
rollMap = "minRolls";
}
//If it's a maximum, it's -max
else if(id.includes("-max")) {
rollMap = "maxRolls";
}
id = id.replace("-fixed", "");
id = id.replace("-min", "");
id = id.replace("-max", "");
if (input.classList.contains("number-input")) {
if (parseFloat(input.value)) {
if (rolledIDs.includes(id)) {
statMap.get(rollMap).set(id, parseFloat(input.value));
} else {
statMap.set(id, parseFloat(input.value));
}
}
} else if (input.classList.contains("string-input")) {
if(rolledIDs.includes(id)) {
statMap.get(rollMap).set(id, input.value);
} else {
statMap.set(id, input.value);
}
} else if (input.classList.contains("array-input")) {
statMap.set(id, input.value.split("-").map(x=>parseFloat(x)));
}
if(input.value === "" && input.placeholder && input.placeholder !== "") {
if (input.classList.contains("number-input")) {
if (rolledIDs.includes(id)) {
statMap.get(rollMap).set(id, parseFloat(input.placeholder));
} else {
statMap.set(id, parseFloat(input.placeholder));
}
} else if (input.classList.contains("string-input")){
if (rolledIDs.includes(id)) {
statMap.get(rollMap).set(id, input.placeholder);
} else {
statMap.set(id, input.placeholder);
}
} else if (input.classList.contains("array-input")) {
statMap.set(id, input.placeholder.split("-").map(x=>parseFloat(x)));
}
}
}
}
player_custom_item = new Custom(statMap);
displayExpandedItem(player_custom_item.statMap, "custom-stats");
console.log(player_custom_item.statMap);
}catch (error) {
//USE THE ERROR <p>S!
let msg = error.stack;
let lines = msg.split("\n");
let header = document.getElementById("header");
header.textContent = "";
for (const line of lines) {
let p = document.createElement("p");
p.classList.add("itemp");
p.textContent = line;
header.appendChild(p);
}
let p2 = document.createElement("p");
p2.textContent = "If you believe this is an error, contact hppeng on forums or discord.";
header.appendChild(p2);
}
}
function encodeCustom(custom) {
return "";
}
function decodeCustom(custom_url_tag) {
if (custom_url_tag) {
console.log(custom_url_tag);
let version = custom_url_tag.charAt(0);
let tag = custom_url_tag.substring(1);
if (version === "1") {
//do the things
calculateCustom();
}
}
}
function populateFields() {
/*Ex
let recipe_list = document.getElementById("recipe-choices");
for (const recipe of recipeTypes) {
let el = document.createElement("option");
el.value = recipe.charAt(0) + recipe.substring(1).toLowerCase();
recipe_list.appendChild(el);
}
*/
let tier_list = document.getElementById("tier-list");
for (const tier of tiers) {
let el = document.createElement("option");
el.value = tier;
tier_list.appendChild(el);
}
let type_list = document.getElementById("type-list");
for (const type of types) {
let el = document.createElement("option");
el.value = type;
type_list.appendChild(el);
}
let atkSpd_list = document.getElementById("atkSpd-list");
for (const atkSpd of attackSpeeds) {
let el = document.createElement("option");
el.value = atkSpd;
atkSpd_list.appendChild(el);
}
let class_list = document.getElementById("class-list");
for (const className of classes) {
let el = document.createElement("option");
el.value = className;
class_list.appendChild(el);
}
let item_list = document.getElementById("base-list");
for (const [baseItem,value] of itemMap) {
let el = document.createElement("option");
el.value = baseItem;
item_list.appendChild(el);
}
}
/* Toggles ONE button
*/
function toggleButton(buttonId) {
let elem = document.getElementById(buttonId);
if (elem.classList.contains("toggleOn")) {
elem.classList.remove("toggleOn");
} else{
elem.classList.add("toggleOn");
}
}
/* Changes an element's text content from yes to no or vice versa
*/
function toggleYN(elemId) {
let elem = document.getElementById(elemId);
if (elem.textContent && elem.textContent === "no") {
elem.textContent = "yes";
} else if (elem.textContent === "yes") {
elem.textContent = "no";
} else {
elem.textContent = "no";
}
}
/**
* @param fixed : a boolean for the state of the fixID button. True -> make all the variable IDs 2 inputs, False -> make them all 1 input
*/
function toggleFixed(fixed) {
for (const id of rolledIDs) {
let elem = document.getElementById(id);
if (elem) {
if (fixed.textContent === "yes") { //now fixed IDs -> go to 1 input
document.getElementById(id+"-choice-fixed-container").style = "";
document.getElementById(id+"-choice-container").style = "display:none";
} else { //now rollable -> go to 2 inputs
document.getElementById(id+"-choice-fixed-container").style = "display:none";
document.getElementById(id+"-choice-container").style = "";
}
}
}
}
/** Make a custom item
*
* @param {elem} : The elem with value item to base off of. A string input.
*/
function useBaseItem(elem) {
let itemName = getValue(elem);
let baseItem;
//Check items db.
for (const [name,itemObj] of itemMap) {
if (itemName === name) {
baseItem = expandItem(itemObj, []);
break;
}
}
//If it starts with CR-, try creating a craft
if(!baseItem) {
baseItem = getCraftFromHash(itemName).statMap;
console.log(baseItem);
}
//If it starts with CI-, try creating a custom (TODO)
//If the item exists, go through stats and assign to values!
if(baseItem) {
resetFields();
//Rolled IDs
if (document.getElementById("fixID-choice").textContent === "yes") { //fixed IDs
for (const id of rolledIDs) { //use maxrolls
if (baseItem.get("maxRolls").get(id) && document.getElementById(id+"-choice-fixed")) {
setValue(id+"-choice-fixed", baseItem.get("maxRolls").get(id));
setValue(id+"-choice-min", baseItem.get("maxRolls").get(id));
setValue(id+"-choice-max", baseItem.get("maxRolls").get(id));
}
}
} else { //use both
for (const id of rolledIDs) {
if (baseItem.get("maxRolls").get(id) && document.getElementById(id+"-choice-fixed")) {
setValue(id+"-choice-fixed", baseItem.get("maxRolls").get(id));
setValue(id+"-choice-min", baseItem.get("minRolls").get(id));
setValue(id+"-choice-max", baseItem.get("maxRolls").get(id));
}
}
}
//Static IDs
for (const id of nonRolledIDs) {
if (baseItem.get(id) && document.getElementById(id+"-choice")) {
setValue(id+"-choice", baseItem.get(id));
}
}
//Take care of durability, duration, and charges.
if (baseItem.get("tier") === "Crafted") {
let specialIDs = ["duration", "durability"];
setValue("charges-choice", baseItem.get("charges"));
for (const id of specialIDs) {
setValue(id+"-choice", baseItem.get(id)[0]+"-"+baseItem.get(id)[1]);
}
}
}
//Don't do anything if nothing is met
calculateCustom();
}
/* Copy the link
*/
function copyCustom(){
if (player_custom_item) {
copyTextToClipboard(custom_url_base+location.hash);
document.getElementById("copy-button").textContent = "Copied!";
}
}
/* Reset all fields
*/
function resetFields() {
let inputs = document.getElementsByTagName('input');
for (const input of inputs) {
input.textContent = "";
input.value = "";
}
let elem = document.getElementById("fixID-choice")
if (elem.textContent === "yes") {
elem.textContent = "no";
elem.classList.remove("toggleOn");
}
}
/** Takes the base value for an id and attempts to autofill the corresponding min and maxes.
*
* @param {String} id - the id to do the math for (ex: hprPct)
*/
function base_to_range(id) {
let base = parseFloat(getValue(id+"-choice-base"));
if(base) {
//This version allows overriding of min and max.
if (base < 0) {
setValue(id+"-choice-min", Math.min(Math.round(neg_range[0]*base),-1));
} else {
setValue(id+"-choice-min", Math.max(Math.round(pos_range[0]*base),1));
}
if (base < 0) {
setValue(id+"-choice-max", Math.min(Math.round(neg_range[1]*base),-1));
} else {
setValue(id+"-choice-max", Math.max(Math.round(pos_range[1]*base),1));
}
/* No overiding min/max version
if (!getValue(id+"-choice-min")) {
if (base < 0) {
setValue(id+"-choice-min", Math.min(Math.round(neg_range[0]*base),-1));
} else {
setValue(id+"-choice-min", Math.max(Math.round(pos_range[0]*base),1));
}
}
if (!getValue(id+"-choice-max")) {
if (base < 0) {
setValue(id+"-choice-max", Math.min(Math.round(neg_range[1]*base),-1));
} else {
setValue(id+"-choice-max", Math.max(Math.round(pos_range[1]*base),1));
}
}
*/
}
}
/** Takes min/max value(s) and attempts to autofill the corresponding base and min/max
*
* @param {String} id - the id to do the math for (ex: hprPct)
* @param {String} mode - the tabbed value (min or max)
*/
function range_to_base(id, mode) {
let value;
try {
value = parseFloat(getValue(id+"-choice-"+mode));
} catch (error) {
console.log("Error in range_to_base.");
console.log(error);
}
if (mode === "min") { //base and max
if (value && !getValue(id+"-choice-base")) {
if (value < 0) {
setValue(id+"-choice-base", Math.min(Math.round(1/neg_range[0]*value),-1));
} else {
setValue(id+"-choice-base", Math.max(Math.round(1/pos_range[0]*value),1));
}
}
if (value && !getValue(id+"-choice-max")) {
if (value < 0) {
setValue(id+"-choice-max", Math.min(Math.round(neg_range[1]/neg_range[0]*value),-1));
} else {
setValue(id+"-choice-max", Math.max(Math.round(pos_range[1]/pos_range[0]*value),1));
}
}
} else if (mode === "max") { //min and base
if (value && !getValue(id+"-choice-base")) {
if (value < 0) {
setValue(id+"-choice-base", Math.min(Math.round(1/neg_range[1]*value),-1));
} else {
setValue(id+"-choice-base", Math.max(Math.round(1/pos_range[1]*value),1));
}
}
if (value && !getValue(id+"-choice-min")) {
if (value < 0) {
setValue(id+"-choice-min", Math.min(Math.round(neg_range[0]/neg_range[1]*value),-1));
} else {
setValue(id+"-choice-min", Math.max(Math.round(pos_range[0]/pos_range[1]*value),1));
}
}
}
}
/** Uses the base value input fields and changes the base values.
*
*/
function changeBaseValues() {
for (const id of roll_range_ids) {
if (getValue(id)) {
if (id.includes("neg")) {
if (id.includes("min")) {
neg_range[0] = parseFloat(getValue(id));
} else {
neg_range[1] = parseFloat(getValue(id));
}
} else {
if (id.includes("min")) {
pos_range[0] = parseFloat(getValue(id));
} else {
pos_range[1] = parseFloat(getValue(id));
}
}
}
}
for (const identification of rolledIDs) {
if (document.getElementById(identification)) {
base_to_range(identification);
}
}
}
function resetBaseValues() {
pos_range = [0.3,1.3];
neg_range = [1.3,0.7];
for (const id of roll_range_ids) {
setValue(id,"");
}
}
load_init(init);
load_ing_init(init);

33
customnarrow.css Normal file
View file

@ -0,0 +1,33 @@
.container{
width: 95%;
border: 3px solid #BCBCBC;
border-radius: 3px;
padding: 2% 4% 4%;
}
.overall-container {
padding: 2%;
}
.customchoices{
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: 5px;
grid-auto-rows: minmax(60px, auto);
}
.button-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 5px;
grid-auto-rows: minmax(30px, auto);
margin-bottom: 5px;
padding-bottom: 5px;
}
.title{
text-align: center;
font-size: 150%;
}
.smalltitle{
text-align: center;
font-size: 125%;
margin-top: 10px;
margin-bottom: 4px;
}

46
customwide.css Normal file
View file

@ -0,0 +1,46 @@
.container {
width: 95%;
border: 3px solid #BCBCBC;
border-radius: 3px;
}
.overall-container {
width: 100%;
display: grid;
grid-template-columns: 2.3fr 1fr;
gap: 5px;
grid-auto-rows: minmax(60px, auto);
}
.customchoices {
width: 100%;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 5px;
grid-auto-rows: minmax(60px, auto);
}
.title{
text-align: center;
font-size: 150%;
}
.smalltitle{
text-align: center;
font-size: 125%;
margin-top: 10px;
margin-bottom: 4px;
}
.button-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 5px;
grid-auto-rows: minmax(30px, auto);
margin-bottom: 5px;
padding-bottom: 5px;
}
.button {
padding: 2%;
}
.sticky-box {
position: -webkit-sticky; /* Safari */
position: sticky;
top: 10px;
}

View file

@ -1,4 +1,4 @@
let nonRolledIDs = ["name", "displayName", "tier", "set", "slots", "type", "material", "drop", "quest", "restrict", "nDam", "fDam", "wDam", "aDam", "tDam", "eDam", "atkSpd", "hp", "fDef", "wDef", "aDef", "tDef", "eDef", "lvl", "classReq", "strReq", "dexReq", "intReq", "defReq", "agiReq","str", "dex", "int", "agi", "def", "fixID", "category", "id", "skillpoints", "reqs", "nDam_", "fDam_", "wDam_", "aDam_", "tDam_", "eDam_", "majorIds"];
let nonRolledIDs = ["name", "lore", "displayName", "tier", "set", "slots", "type", "material", "drop", "quest", "restrict", "nDam", "fDam", "wDam", "aDam", "tDam", "eDam", "atkSpd", "hp", "fDef", "wDef", "aDef", "tDef", "eDef", "lvl", "classReq", "strReq", "dexReq", "intReq", "defReq", "agiReq","str", "dex", "int", "agi", "def", "fixID", "category", "id", "skillpoints", "reqs", "nDam_", "fDam_", "wDam_", "aDam_", "tDam_", "eDam_", "majorIds"];
let rolledIDs = ["hprPct", "mr", "sdPct", "mdPct", "ls", "ms", "xpb", "lb", "ref", "thorns", "expd", "spd", "atkTier", "poison", "hpBonus", "spRegen", "eSteal", "hprRaw", "sdRaw", "mdRaw", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4", "rainbowRaw", "sprint", "sprintReg", "jh", "lq", "gXp", "gSpd"];
let reversedIDs = [ "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4" ];
let colorMap = new Map(
@ -139,8 +139,8 @@ function idRound(id){
}
//Used for item IDs and ingredient id field IDs
let idPrefixes = {"displayName": "", "lvl":"Combat Level Min: ", "classReq":"Class Req: ","strReq":"Strength Min: ","dexReq":"Dexterity Min: ","intReq":"Intelligence Min: ","defReq":"Defense Min: ","agiReq":"Agility Min: ", "nDam_":"Neutral Damage: ", "eDam_":"Earth Damage: ", "tDam_":"Thunder Damage: ", "wDam_":"Water Damage: ", "fDam_":"Fire Damage: ", "aDam_":"Air Damage: ", "atkSpd":"Attack Speed: ", "hp":"Health : ", "eDef":"Earth Defense: ", "tDef":"Thunder Defense: ", "wDef":"Water Defense: ", "fDef":"Fire Defense: ", "aDef":"Air Defense: ", "str":"Strength: ", "dex":"Dexterity: ", "int":"Intelligence: ", "def":"Defense: ","agi":"Agility: ", "hpBonus":"Health Bonus: ", "hprRaw":"Health Regen Raw: ", "hprPct":"Health Regen %: ", "sdRaw":"Raw Spell Damage: ", "sdPct":"Spell Damage %: ", "mdRaw":"Raw Melee Damage: ", "mdPct":"Melee Damage %: ", "mr":"Mana Regen: ", "ms":"Mana Steal: ", "ref":"Reflection: ", "ls":"Life Steal: ", "poison":"Poison: ", "thorns":"Thorns: ", "expd":"Exploding: ", "spd":"Walk Speed Bonus: ", "atkTier":"Attack Speed Bonus: ", "eDamPct":"Earth Damage %: ", "tDamPct":"Thunder Damage %: ", "wDamPct":"Water Damage %: ", "fDamPct":"Fire Damage %: ", "aDamPct":"Air Damage %: ", "eDefPct":"Earth Defense %: ", "tDefPct":"Thunder Defense %: ", "wDefPct":"Water Defense %: ", "fDefPct":"Fire Defense %: ", "aDefPct":"Air Defense %: ", "spPct1":"1st Spell Cost %: ", "spRaw1":"1st Spell Cost Raw: ", "spPct2":"2nd Spell Cost %: ", "spRaw2":"2nd Spell Cost Raw: ", "spPct3":"3rd Spell Cost %: ", "spRaw3":"3rd Spell Cost Raw: ", "spPct4":"4th Spell Cost %: ", "spRaw4":"4th Spell Cost Raw: ", "rainbowRaw":"Rainbow Spell Damage Raw: ", "sprint":"Sprint Bonus: ", "sprintReg":"Sprint Regen Bonus: ", "jh":"Jump Height: ", "xpb":"Combat XP Bonus: ", "lb":"Loot Bonus: ", "lq":"Loot Quality: ", "spRegen":"Soul Point Regen: ", "eSteal":"Stealing: ", "gXp":"Gathering XP Bonus: ", "gSpd":"Gathering Speed Bonus: ", "slots":"Powder Slots: ", "set":"Set: ", "quest":"Quest Req: ", "restrict":""};
let idSuffixes = {"displayName": "", "lvl":"", "classReq":"","strReq":"","dexReq":"","intReq":"","defReq":"","agiReq":"", "nDam_":"", "eDam_":"", "tDam_":"", "wDam_":"", "fDam_":"", "aDam_":"", "atkSpd":"", "hp":"", "eDef":"", "tDef":"", "wDef":"", "fDef":"", "aDef":"", "str":"", "dex":"", "int":"", "def":"","agi":"", "hpBonus":"", "hprRaw":"", "hprPct":"%", "sdRaw":"", "sdPct":"%", "mdRaw":"", "mdPct":"%", "mr":"/4s", "ms":"/4s", "ref":"%", "ls":"/4s", "poison":"/3s", "thorns":"%", "expd":"%", "spd":"%", "atkTier":" tier", "eDamPct":"%", "tDamPct":"%", "wDamPct":"%", "fDamPct":"%", "aDamPct":"%", "eDefPct":"%", "tDefPct":"%", "wDefPct":"%", "fDefPct":"%", "aDefPct":"%", "spPct1":"%", "spRaw1":"", "spPct2":"%", "spRaw2":"", "spPct3":"%", "spRaw3":"", "spPct4":"%", "spRaw4":"", "rainbowRaw":"", "sprint":"%", "sprintReg":"%", "jh":"", "xpb":"%", "lb":"%", "lq":"%", "spRegen":"%", "eSteal":"%", "gXp":"%", "gSpd":"%", "slots":"", "set":" set.", "quest":"", "restrict":""};
let idPrefixes = {"displayName": "", "lvl":"Combat Level Min: ", "classReq":"Class Req: ","strReq":"Strength Min: ","dexReq":"Dexterity Min: ","intReq":"Intelligence Min: ","defReq":"Defense Min: ","agiReq":"Agility Min: ", "nDam_":"Neutral Damage: ", "eDam_":"Earth Damage: ", "tDam_":"Thunder Damage: ", "wDam_":"Water Damage: ", "fDam_":"Fire Damage: ", "aDam_":"Air Damage: ", "atkSpd":"Attack Speed: ", "hp":"Health : ", "eDef":"Earth Defense: ", "tDef":"Thunder Defense: ", "wDef":"Water Defense: ", "fDef":"Fire Defense: ", "aDef":"Air Defense: ", "str":"Strength: ", "dex":"Dexterity: ", "int":"Intelligence: ", "def":"Defense: ","agi":"Agility: ", "hpBonus":"Health Bonus: ", "hprRaw":"Health Regen Raw: ", "hprPct":"Health Regen %: ", "sdRaw":"Raw Spell Damage: ", "sdPct":"Spell Damage %: ", "mdRaw":"Raw Melee Damage: ", "mdPct":"Melee Damage %: ", "mr":"Mana Regen: ", "ms":"Mana Steal: ", "ref":"Reflection: ", "ls":"Life Steal: ", "poison":"Poison: ", "thorns":"Thorns: ", "expd":"Exploding: ", "spd":"Walk Speed Bonus: ", "atkTier":"Attack Speed Bonus: ", "eDamPct":"Earth Damage %: ", "tDamPct":"Thunder Damage %: ", "wDamPct":"Water Damage %: ", "fDamPct":"Fire Damage %: ", "aDamPct":"Air Damage %: ", "eDefPct":"Earth Defense %: ", "tDefPct":"Thunder Defense %: ", "wDefPct":"Water Defense %: ", "fDefPct":"Fire Defense %: ", "aDefPct":"Air Defense %: ", "spPct1":"1st Spell Cost %: ", "spRaw1":"1st Spell Cost Raw: ", "spPct2":"2nd Spell Cost %: ", "spRaw2":"2nd Spell Cost Raw: ", "spPct3":"3rd Spell Cost %: ", "spRaw3":"3rd Spell Cost Raw: ", "spPct4":"4th Spell Cost %: ", "spRaw4":"4th Spell Cost Raw: ", "rainbowRaw":"Rainbow Spell Damage Raw: ", "sprint":"Sprint Bonus: ", "sprintReg":"Sprint Regen Bonus: ", "jh":"Jump Height: ", "xpb":"Combat XP Bonus: ", "lb":"Loot Bonus: ", "lq":"Loot Quality: ", "spRegen":"Soul Point Regen: ", "eSteal":"Stealing: ", "gXp":"Gathering XP Bonus: ", "gSpd":"Gathering Speed Bonus: ", "slots":"Powder Slots: ", "set":"Set: ", "quest":"Quest Req: ", "restrict":"", "lore": ""};
let idSuffixes = {"displayName": "", "lvl":"", "classReq":"","strReq":"","dexReq":"","intReq":"","defReq":"","agiReq":"", "nDam_":"", "eDam_":"", "tDam_":"", "wDam_":"", "fDam_":"", "aDam_":"", "atkSpd":"", "hp":"", "eDef":"", "tDef":"", "wDef":"", "fDef":"", "aDef":"", "str":"", "dex":"", "int":"", "def":"","agi":"", "hpBonus":"", "hprRaw":"", "hprPct":"%", "sdRaw":"", "sdPct":"%", "mdRaw":"", "mdPct":"%", "mr":"/4s", "ms":"/4s", "ref":"%", "ls":"/4s", "poison":"/3s", "thorns":"%", "expd":"%", "spd":"%", "atkTier":" tier", "eDamPct":"%", "tDamPct":"%", "wDamPct":"%", "fDamPct":"%", "aDamPct":"%", "eDefPct":"%", "tDefPct":"%", "wDefPct":"%", "fDefPct":"%", "aDefPct":"%", "spPct1":"%", "spRaw1":"", "spPct2":"%", "spRaw2":"", "spPct3":"%", "spRaw3":"", "spPct4":"%", "spRaw4":"", "rainbowRaw":"", "sprint":"%", "sprintReg":"%", "jh":"", "xpb":"%", "lb":"%", "lq":"%", "spRegen":"%", "eSteal":"%", "gXp":"%", "gSpd":"%", "slots":"", "set":" set.", "quest":"", "restrict":"", "lore": ""};
//Used for ingredient IDs - name, lvl, tier. As of now, not used.
/*let ingPrefixes = {"name": "", "lvl": "", "tier": ""};
let ingSuffixes = {"name": "", "lvl": "", "tier": ""}*/
@ -504,6 +504,7 @@ function displayExpandedItem(item, parent_id){
"majorIds",
"slots",
"set",
"lore",
"quest",
"restrict"
];
@ -536,7 +537,7 @@ function displayExpandedItem(item, parent_id){
// TODO: This is sooo incredibly janky.....
if (command === "!elemental") {
elemental_format = !elemental_format;
}
}
}
else {
let id = command; //warp
@ -610,6 +611,8 @@ function displayExpandedItem(item, parent_id){
bckgrd.classList.add("itemp");
active_elem.appendChild(bckgrd);
bckgrd.appendChild(img);
} else if (id === "lore") {
p_elem.style = "font-style: italic";
} else if (skp_order.includes(id)) { //id = str, dex, int, def, or agi
if ( item.get("tier") !== "Crafted" && active_elem.nodeName === "DIV") {
p_elem.textContent = "";

View file

@ -11,7 +11,7 @@
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" media="screen and (min-width: 1100px)" href="wide.css"/>
<link rel="stylesheet" media="screen and (max-width: 1099px)" href="narrow.css"/>
<link rel="icon" href="favicon.png">
<link rel="icon" href="./media/icons/builder.png">
<link rel="manifest" href="manifest.json">
<title>WynnBuilder</title>
</head>
@ -34,6 +34,11 @@
</img>
<div class = "tooltiptext center">WynnAtlas</div>
</a>
<a href = "./customizer.html" class = "nomarginp iconlink tooltip">
<img src = "/media/icons/custom.png" class = "left linkoptions headericon">
</img>
<div class = "tooltiptext center">WynnCustom</div>
</a>
</div>
<div class = "headercenter">
<div >

View file

@ -12,7 +12,7 @@
<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">
<link rel="icon" href="./media/icons/searcher.png">
<link rel="manifest" href="manifest.json">
<title>Wynn Clientside</title>
</head>
@ -35,6 +35,11 @@
</img>
<div class = "tooltiptext center">WynnAtlas</div>
</a>
<a href = "./customizer.html" class = "nomarginp iconlink tooltip">
<img src = "/media/icons/custom.png" class = "left linkoptions headericon">
</img>
<div class = "tooltiptext center">WynnCustom</div>
</a>
</div>
<div class = "headercenter">
<div >

View file

@ -6,7 +6,7 @@
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles.css">
<link rel="icon" href="favicon.png">
<link rel="icon" href="./media/icons/searcher.png">
<link rel="manifest" href="manifest.json">
<title>WynnAtlas</title>
</head>
@ -28,6 +28,11 @@
</img>
<div class = "tooltiptext center">WynnAtlas</div>
</a>
<a href = "./customizer.html" class = "nomarginp iconlink tooltip">
<img src = "/media/icons/custom.png" class = "left linkoptions headericon">
</img>
<div class = "tooltiptext center">WynnCustom</div>
</a>
</div>
<div class = "headercenter">
<div >

BIN
media/icons/custom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 B

View file

@ -335,6 +335,9 @@ input {
font-weight: 700;
display: inline-block;
}
.small-input {
width: max(4vw,60px);
}
::placeholder{
color: #aaa;
}
@ -465,3 +468,12 @@ button.toggleOn:hover {
.tooltip:hover .tooltiptext {
visibility: visible;
}
.bodydiv{
height: 100vh;
}
.atlas{
height: 48px;
width: 48px;
}

View file

@ -10,6 +10,8 @@ let armorTypes = [ "helmet", "chestplate", "leggings", "boots" ];
let accessoryTypes = [ "ring", "bracelet", "necklace" ];
let weaponTypes = [ "wand", "spear", "bow", "dagger", "relik" ];
let consumableTypes = [ "potion", "scroll", "food"];
const attackSpeeds = ["SUPER_SLOW", "VERY_SLOW", "SLOW", "NORMAL", "FAST", "VERY_FAST", "SUPER_FAST"];
let classes = ["Warrior", "Assassin", "Mage", "Archer", "Shaman"];
let elementIcons = ["\u2724","\u2726", "\u2749", "\u2739", "\u274b" ];
let skpReqs = skp_order.map(x => x + "Req");

View file

@ -14,6 +14,7 @@
grid-template-rows: min-content min-content auto;
}
.sticky-box {
position: -webkit-sticky; /* Safari */
position: sticky;
top: 10px;
}