Shareable Custom Items, still not usable in builds

This commit is contained in:
ferricles 2021-03-08 14:50:47 -08:00
parent 929942a6a2
commit 71a7b65a91
6 changed files with 197 additions and 56 deletions

View file

@ -9,7 +9,7 @@ console.log(ing_url_tag);
const ING_BUILD_VERSION = "6.9.40";
const ING_BUILD_VERSION = "6.9.41";
/*
* END testing section
*/
@ -262,6 +262,7 @@ function encodeCraft(craft) {
}
return "";
}
function decodeCraft(ing_url_tag) {
if (ing_url_tag) {
console.log(ing_url_tag);

View file

@ -1,14 +1,15 @@
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));
const 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
const types = armorTypes.concat(accessoryTypes).concat(weaponTypes).concat(consumableTypes).map(x => x.substring(0,1).toUpperCase() + x.substring(1));
const atkSpds = ["SUPER_SLOW","VERY_SLOW","SLOW","NORMAL","FAST","VERY_FAST","SUPER_FAST"];
const ci_save_order = ["name", "lore", "tier", "set", "slots", "type", "material", "drop", "quest", "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", "id", "skillpoints", "reqs", "nDam_", "fDam_", "wDam_", "aDam_", "tDam_", "eDam_", "majorIds", "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"];
//omitted restrict - it's always "Custom Item"
//omitted displayName - either it's the same as name (repetitive) or it's "Custom Item"
//omitted category - can always get this from type
//omitted fixId - we will denote this early in the string.
//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.
@ -40,21 +41,15 @@ class Custom{
}
}
//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");
this.statMap.set("hash",hash);
}
updateName(name) {
this.name = name;
this.displayName = name; //name overrides hash
this.displayName = name;
}
/* Get all stats for this CI.
@ -63,8 +58,11 @@ class Custom{
* TODO: Check if this is even useful
*/
initCustomStats(){
//this.setHashVerbose(); //do NOT move sethash from here please
this.statMap.set("custom", true);
if (this.statMap.get("tier") === "Crafted") {
this.statMap.set("Crafted", true);
this.statMap.set("crafted", true);
for (const e of skp_elements) {
this.statMap.set(e+"DamLow", this.statMap.get(e+"Dam"));
}
@ -87,11 +85,11 @@ class Custom{
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("displayName", "Custom Item");
}
this.statMap.set("reqs",[this.statMap.get("strReq"),this.statMap.get("dexReq"),this.statMap.get("intReq"),this.statMap.get("defReq"),this.statMap.get("agiReq")]);

View file

@ -105,13 +105,7 @@
<p class="error" style="color: red; top: 30px; font-size: 10px; padding: 0; margin: 0; height: 5px; font-family: 'Nunito', sans-serif;"></p>
</td>
</tr>
<tr>
<td class="left" id = "fixID">
<label for="fixID-choice">Fixed IDs:</label>
<button class = "fixID-choice" id = "fixID-choice" onclick = "toggleButton('fixID-choice'); toggleYN('fixID-choice'); toggleFixed({textContent})" tabindex="">no</button>
<p class="error" style="color: red; top: 30px; font-size: 10px; padding: 0; margin: 0; height: 5px; font-family: 'Nunito', sans-serif;"></p>
</td>
</tr>
<tr>
<td class="center">
@ -1842,25 +1836,36 @@
Create
</button>
</div>
<div class = "button copy-button" style = "grid-item-3">
<button class = "copy-button" id = "copy-button" onclick = "copyCustom()">
Copy
</button>
</div>
<div class = "button set-button center" style = "grid-item-4">
<div class = "">Fixed IDs:</div>
</div>
<div class = "button reset-button" style = "grid-item-2">
<button class = "reset-button" id = "reset-button" onclick = "resetFields()">
Reset
</button>
</div>
<div class = "button copy-button" style = "grid-item-3">
<!--button class = "copy-button" id = "copy-button" onclick = "copyCustom()">
//TODO
Copy
</button-->
<div class = "button copy-button-long" style = "grid-item-6">
<button class = "copy-button-long" id = "copy-button-long" onclick = "copyCustomLong()">
Copy Long
</button>
</div>
<div class = "button set-button" style = "grid-item-4">
<div class="button set-button center" id = "fixID" style = "grid-item-5">
<button class = "fixID-choice" id = "fixID-choice" onclick = "toggleButton('fixID-choice'); toggleYN('fixID-choice'); toggleFixed({textContent})" tabindex="">no</button>
<p class="error" style="color: red; top: 30px; font-size: 10px; padding: 0; margin: 0; height: 5px; font-family: 'Nunito', sans-serif;"></p>
</div>
<div class = "button set-button" style = "grid-item-7">
<div class = "">Base Item: </div>
</div>
<div class = "button set-button" style = "grid-item-5">
<div class = "button set-button" style = "grid-item-8">
<input class = "input" list = "base-list" id = "base-input" value = ""></input>
<datalist id = "base-list"></datalist>
</div>
<div class = "button set-button" style = "grid-item-6">
<div class = "button set-button" style = "grid-item-9">
<button class = "set-button" id = "set-button" onclick = "useBaseItem('base-input')">
Use
</button>

View file

@ -8,7 +8,7 @@ const custom_url_tag = location.hash.slice(1);
console.log(custom_url_base);
console.log(custom_url_tag);
const BUILD_VERSION = "6.9.40";
const BUILD_VERSION = "6.9.41";
function setTitle() {
let text = "WynnCustom version "+BUILD_VERSION;
@ -32,6 +32,7 @@ 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();
@ -120,10 +121,10 @@ function calculateCustom() {
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));
statMap.get("minRolls").set(id,Math.round(parseFloat(input.value)));
statMap.get("maxRolls").set(id,Math.round(parseFloat(input.value)));
} else {
statMap.set(id, parseFloat(input.value));
statMap.set(id, Math.round(parseFloat(input.value)));
}
}
} else if (input.classList.contains("string-input")) {
@ -134,16 +135,16 @@ function calculateCustom() {
statMap.set(id, input.value);
}
} else if (input.classList.contains("array-input")) {
statMap.set(id, input.value.split("-").map(x=>parseFloat(x)));
statMap.set(id, input.value.split("-").map(x=>Math.round(parseFloat(x))));
}
if(input.value === "" && input.placeholder && input.placeholder !== "") {
if (input.classList.contains("number-input") && parseFloat(input.placeholder)) {
statMap.set(id, parseFloat(input.placeholder));
statMap.set(id, Math.round(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(id, input.placeholder.split("-").map(x=>Math.round(parseFloat(x))));
}
}
}
@ -174,9 +175,9 @@ function calculateCustom() {
if (input.classList.contains("number-input")) {
if (parseFloat(input.value)) {
if (rolledIDs.includes(id)) {
statMap.get(rollMap).set(id, parseFloat(input.value));
statMap.get(rollMap).set(id, Math.round(parseFloat(input.value)));
} else {
statMap.set(id, parseFloat(input.value));
statMap.set(id, Math.round(parseFloat(input.value)));
}
}
} else if (input.classList.contains("string-input")) {
@ -186,15 +187,15 @@ function calculateCustom() {
statMap.set(id, input.value);
}
} else if (input.classList.contains("array-input")) {
statMap.set(id, input.value.split("-").map(x=>parseFloat(x)));
statMap.set(id, input.value.split("-").map(x=>Math.round(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));
statMap.get(rollMap).set(id, Math.round(parseFloat(input.placeholder)));
} else {
statMap.set(id, parseFloat(input.placeholder));
statMap.set(id, Math.round(parseFloat(input.placeholder)));
}
} else if (input.classList.contains("string-input")){
if (rolledIDs.includes(id)) {
@ -203,7 +204,7 @@ function calculateCustom() {
statMap.set(id, input.placeholder);
}
} else if (input.classList.contains("array-input")) {
statMap.set(id, input.placeholder.split("-").map(x=>parseFloat(x)));
statMap.set(id, input.placeholder.split("-").map(x=>Math.round(parseFloat(x))));
}
}
}
@ -212,8 +213,16 @@ function calculateCustom() {
player_custom_item = new Custom(statMap);
let custom_str = encodeCustom(player_custom_item.statMap, false);
location.hash = custom_str;
player_custom_item.setHash(custom_str);
console.log(player_custom_item.statMap.get("hash"));
displayExpandedItem(player_custom_item.statMap, "custom-stats");
console.log(player_custom_item.statMap);
//console.log(player_custom_item.statMap);
}catch (error) {
//USE THE ERROR <p>S!
@ -235,20 +244,123 @@ function calculateCustom() {
}
function encodeCustom(custom) {
/**
* @param {Map} custom - the statMap of the CI
* @param {boolean} verbose - if we want lore and majorIds to display
*/
function encodeCustom(custom, verbose) {
if (custom) {
let hash = "1";
//version 1
if (custom.has("fixID") && custom.get("fixID")) {
hash += "1";
} else {
hash += "0";
}
for (const i in ci_save_order) {
let id = ci_save_order[i];
if (rolledIDs.includes(id)) {
let val_min = custom.get("minRolls").has(id) ? custom.get("minRolls").get(id) : 0;
let val_max = custom.get("maxRolls").has(id) ? custom.get("maxRolls").get(id) : 0;
let min_len = Math.max(1,Math.ceil(log(64,Math.abs(val_min))));
let max_len = Math.max(1,Math.ceil(log(64,Math.abs(val_max))));
let len = Math.max(min_len,max_len);
if ( val_min != 0 || val_max != 0 ) {
//hash += Base64.fromIntN(i,2) + Base64.fromIntN(val_min,Math.max(1,Math.ceil(log(64,Math.abs(val_min))))) + ":" + Base64.fromIntN(val_max,Math.max(1,Math.ceil(log(64,Math.abs(val_min))))) + "_";
if (custom.get("fixID")) {
hash += Base64.fromIntN(i,2) + Base64.fromIntN(len,2) + Base64.fromIntN(val_min, len);
} else {
hash += Base64.fromIntN(i,2) + Base64.fromIntN(len,2) + Base64.fromIntN(val_min, len) + Base64.fromIntN(val_max,len);
}
}
} else {
let damages = ["nDam", "eDam", "tDam", "wDam", "fDam", "aDam","nDam_", "eDam_", "tDam_", "wDam_", "fDam_", "aDam_"];
let val = custom.get(id);
if (typeof(val) === "string" && val !== "") {
if ((damages.includes(id) && val === "0-0") || (!verbose && (id === "lore" || id === "majorIds"))) { continue; }
if (id === "type") {
hash += Base64.fromIntN(i,2) + Base64.fromIntN(types.indexOf(val.substring(0,1).toUpperCase()+val.slice(1)),1);
} else if (id === "tier") {
hash += Base64.fromIntN(i,2) + Base64.fromIntN(tiers.indexOf(val),1);
} else if (id === "atkSpd") {
hash += Base64.fromIntN(i,2) + Base64.fromIntN(atkSpds.indexOf(val),1);
} else {
hash += Base64.fromIntN(i,2) + Base64.fromIntN(val.replace(" ", "%20").length,2) + val.replace(" ", "%20"); //values cannot go above 4096 chars!!!! Is this ok?
}
} else if (typeof(val) === "number" && val != 0) {
let len = Math.max(1,Math.ceil(log(64,Math.abs(val))));
//hash += Base64.fromIntN(i,2) + Base64.fromIntN(val,Math.max(1,Math.ceil(log(64,Math.abs(val))))) + "_";
hash += Base64.fromIntN(i,2) + Base64.fromIntN(len,2) + Base64.fromIntN(val,len);
}
}
}
return hash;
}
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);
let fixID = Boolean(parseInt(custom_url_tag.charAt(1),10));
let tag = custom_url_tag.substring(2);
let statMap = new Map();
statMap.set("minRolls", new Map());
statMap.set("maxRolls", new Map());
if (version === "1") {
//do the things
if (fixID) {statMap.set("fixId", "true");}
while (tag !== "") {
let id = ci_save_order[Base64.toInt(tag.slice(0,2))];
let len = Base64.toInt(tag.slice(2,4));
if (rolledIDs.includes(id)) {
let minRoll = Base64.toInt(tag.slice(4,4+len));
if (!fixID) {
let maxRoll = Base64.toInt(tag.slice(4+len,4+2*len));
setValue(id+"-choice-min", minRoll);
setValue(id+"-choice-max", maxRoll);
statMap.get("minRolls").set(id,minRoll);
statMap.get("maxRolls").set(id,maxRoll);
tag = tag.slice(4+2*len);
} else {
setValue(id+"-choice-fixed", minRoll);
statMap.get("minRolls").set(id,minRoll);
statMap.get("maxRolls").set(id,minRoll);
tag = tag.slice(4+len);
}
} else {
let val;
let elem = document.getElementById(id+"-choice");
if (elem.classList.contains("number-input")) {
val = Base64.toInt(tag.slice(4,4+len));
} else if (elem.classList.contains("string-input") || classList.contains("array-input")) {
if (id === "tier") {
val = tiers[Base64.toInt(tag.charAt(2))];
len = -1;
} else if (id === "type") {
val = types[Base64.toInt(tag.charAt(2))];
len = -1;
}
else if (id === "atkSpd") {
val = atkSpds[Base64.toInt(tag.charAt(2))];
len = -1;
} else { //general case
val = tag.slice(4,4+len).replace("%20"," ");
}
} else {
val = "";
}
statMap.set(id, val);
setValue(id+"-choice", val);
tag = tag.slice(4+len);
}
}
statMap.set("hash",custom_url_tag);
calculateCustom();
player_custom_item.setHash(custom_url_tag);
}
}
}
@ -406,13 +518,22 @@ function useBaseItem(elem) {
/* Copy the link
*/
function copyCustom(){
function copyCustom() {
if (player_custom_item) {
copyTextToClipboard(custom_url_base+location.hash);
document.getElementById("copy-button").textContent = "Copied!";
}
}
function copyCustomLong() {
if (player_custom_item) {
let hash = encodeCustom(player_custom_item.statMap,true);
console.log(hash);
location.hash = hash;
copyTextToClipboard(custom_url_base+location.hash);
document.getElementById("copy-button-long").textContent = "Copied!";
}
}
/* Reset all fields

View file

@ -597,10 +597,22 @@ function displayExpandedItem(item, parent_id){
p_elem.classList.add('itemp');
p_elem.classList.add("smalltitle");
p_elem.classList.add(item.get("tier"));
p_elem.href = url_base + "crafter.html#" + item.get("hash");
p_elem.href = url_base.replace("crafter.html","").replace("customizer.html","") + "crafter.html#" + item.get("hash");
p_elem.target = "_blank";
p_elem.textContent = item.get(id);
active_elem.appendChild(p_elem);
}
if(item.get("custom")) {
p_elem.remove();
p_elem = document.createElement("a");
p_elem.classList.add('itemp');
p_elem.classList.add("smalltitle");
p_elem.classList.add(item.get("tier"));
p_elem.href = url_base.replace("crafter.html","").replace("customizer.html","") + "customizer.html#" + item.get("hash");
p_elem.target = "_blank";
p_elem.textContent = item.get("displayName");
active_elem.appendChild(p_elem);
}
let img = document.createElement("img");
img.src = "/media/items/generic-" + item.get("type") + ".png";
img.alt = item.get("type");

View file

@ -70,6 +70,10 @@ function getValue(id) {
return document.getElementById(id).value;
}
function log(b, n) {
return Math.log(n) / Math.log(b);
}
// Base 64 encoding tools
// https://stackoverflow.com/a/27696695
// Modified for fixed precision