diff --git a/js/build_encode_decode.js b/js/build_encode_decode.js deleted file mode 100644 index 2c280b7..0000000 --- a/js/build_encode_decode.js +++ /dev/null @@ -1,340 +0,0 @@ -let player_build; -let build_powders; - -function getItemNameFromID(id) { return idMap.get(id); } -function getTomeNameFromID(id) { return tomeIDMap.get(id); } - -function parsePowdering(powder_info) { - // TODO: Make this run in linear instead of quadratic time... ew - let powdering = []; - for (let i = 0; i < 5; ++i) { - let powders = ""; - let n_blocks = Base64.toInt(powder_info.charAt(0)); - // console.log(n_blocks + " blocks"); - powder_info = powder_info.slice(1); - for (let j = 0; j < n_blocks; ++j) { - let block = powder_info.slice(0,5); - let six_powders = Base64.toInt(block); - for (let k = 0; k < 6 && six_powders != 0; ++k) { - powders += powderNames.get((six_powders & 0x1f) - 1); - six_powders >>>= 5; - } - powder_info = powder_info.slice(5); - } - powdering[i] = powders; - } - return [powdering, powder_info]; -} - -let atree_data = null; - -/* - * Populate fields based on url, and calculate build. - */ -function decodeBuild(url_tag) { - if (url_tag) { - //default values - let equipment = [null, null, null, null, null, null, null, null, null]; - let tomes = [null, null, null, null, null, null, null]; - let powdering = ["", "", "", "", ""]; - let info = url_tag.split("_"); - let version = info[0]; - let save_skp = false; - let skillpoints = [0, 0, 0, 0, 0]; - let level = 106; - - let version_number = parseInt(version) - //equipment (items) - // TODO: use filters - if (version_number < 4) { - let equipments = info[1]; - for (let i = 0; i < 9; ++i ) { - let equipment_str = equipments.slice(i*3,i*3+3); - equipment[i] = getItemNameFromID(Base64.toInt(equipment_str)); - } - info[1] = equipments.slice(27); - } - else if (version_number == 4) { - let info_str = info[1]; - let start_idx = 0; - for (let i = 0; i < 9; ++i ) { - if (info_str.charAt(start_idx) === "-") { - equipment[i] = "CR-"+info_str.slice(start_idx+1, start_idx+18); - start_idx += 18; - } - else { - let equipment_str = info_str.slice(start_idx, start_idx+3); - equipment[i] = getItemNameFromID(Base64.toInt(equipment_str)); - start_idx += 3; - } - } - info[1] = info_str.slice(start_idx); - } - else if (version_number <= 7) { - let info_str = info[1]; - let start_idx = 0; - for (let i = 0; i < 9; ++i ) { - if (info_str.slice(start_idx,start_idx+3) === "CR-") { - equipment[i] = info_str.slice(start_idx, start_idx+20); - start_idx += 20; - } else if (info_str.slice(start_idx+3,start_idx+6) === "CI-") { - let len = Base64.toInt(info_str.slice(start_idx,start_idx+3)); - equipment[i] = info_str.slice(start_idx+3,start_idx+3+len); - start_idx += (3+len); - } else { - let equipment_str = info_str.slice(start_idx, start_idx+3); - equipment[i] = getItemNameFromID(Base64.toInt(equipment_str)); - start_idx += 3; - } - } - info[1] = info_str.slice(start_idx); - } - //constant in all versions - for (let i in equipment) { - setValue(equipment_inputs[i], equipment[i]); - } - - //level, skill point assignments, and powdering - if (version_number == 1) { - let powder_info = info[1]; - let res = parsePowdering(powder_info); - powdering = res[0]; - } else if (version_number == 2) { - save_skp = true; - let skillpoint_info = info[1].slice(0, 10); - for (let i = 0; i < 5; ++i ) { - skillpoints[i] = Base64.toIntSigned(skillpoint_info.slice(i*2,i*2+2)); - } - - let powder_info = info[1].slice(10); - let res = parsePowdering(powder_info); - powdering = res[0]; - } else if (version_number <= 7){ - level = Base64.toInt(info[1].slice(10,12)); - setValue("level-choice",level); - save_skp = true; - let skillpoint_info = info[1].slice(0, 10); - for (let i = 0; i < 5; ++i ) { - skillpoints[i] = Base64.toIntSigned(skillpoint_info.slice(i*2,i*2+2)); - } - - let powder_info = info[1].slice(12); - - let res = parsePowdering(powder_info); - powdering = res[0]; - info[1] = res[1]; - } - // Tomes. - if (version >= 6 && version < 8) { - //tome values do not appear in anything before v6. - for (let i in tomes) { - let tome_str = info[1].charAt(i); - let tome_name = getTomeNameFromID(Base64.toInt(tome_str)); - setValue(tomeInputs[i], tome_name); - } - info[1] = info[1].slice(7); - } - - if (version == 7) { - // ugly af. only works since its the last thing. will be fixed with binary decode - atree_data = new BitVector(info[1]); - } - else { - atree_data = null; - } - - for (let i in powder_inputs) { - setValue(powder_inputs[i], powdering[i]); - } - for (let i in skillpoints) { - setValue(skp_order[i] + "-skp", skillpoints[i]); - } - } -} - -/* Stores the entire build in a string using B64 encoding and adds it to the URL. -*/ -function encodeBuild(build, powders, skillpoints, atree, atree_state) { - //currently on version 8 - a unified version for all build types using bit-level encoding - if (build) { - //final link will be [build_vers]_[len_string]_[build_string] - build_version = 8; - let len_string = ""; - let build_string = ""; - let build_bits = new BitVector(0, 0); - - //ITEMS - for (const item of build.items) { - if (item.statMap.get("NONE") && item.statMap.get("NONE") === true) { - build_bits.append(0, 2); //00 - } else if (item.statMap.get("custom")) { - build_bits.append(3, 2); //11 - //BitVector CI encoding TODO - - // let custom = "CI-"+encodeCustom(item, true); - // build_string += Base64.fromIntN(custom.length, 3) + custom; - // build_version = Math.max(build_version, 5); - } else if (item.statMap.get("crafted")) { - build_bits.append(2, 2); //10 - //BitVector CR encoding TODO - - // build_string += "CR-"+encodeCraft(item); - } else { - if (item.statMap.get("category") === "tome") { - //we will encode tomes later - continue; - } else { - build_bits.append(1, 2); //01 - build_bits.append(item.statMap.get("id"), 13); - - //powderable - if (powderable_keys.includes(item.statMap.get("type"))) { - if (item.statMap.get("powders") && item.statMap.get("powders").length !== 0) { - //has powders - build_bits.append(1, 1); - - //num of powders in 8 bits, then each powder (6 bits) - //Having more than 256 powders on a vanilla item is NOT HANDLED. - build_bits.append(item.statMap.get("powders").length, 8); - for (const powder of item.statMap.get("powders")) { - build_bits.append(powder, 6); - } - } else { - //no powders - build_bits.append(0, 1); - } - } - } - } - } - - //SKILL POINTS - - //the original schema included a flag to indicate whether or not skill points are included. - //any reason for having a flag isn't implemented yet, so for now every build will have the skill point flag set. - build_bits.append(1, 1); - - for (const skp of build.base_skillpoints) { - build_bits.append(skp, 8); // Maximum skillpoints: 255 (allows for manual assign up to 150) - } - - //BUILD LEVEL - - // [flag to indicate if level is not 106 (0/1)] - // [else: level (7 bits, allows for lv 1->127)] - if (player_build.level != 106) { - build_bits.append(1, 1); - build_bits.append(player_build.level, 7); - } else { - build_bits.append(0, 1); - } - - // TOMES - - // [flag to indicate if tomes are included (0/1)] - // [if set: 7 sequential tome IDs, each 6 bits unsigned] - if (build.tomes.length > 0) { - build_bits.append(1, 1); - //decoding will assume that tomes has length of 7. - for (const tome of build.tomes) { - build_bits.append(tome.id, 6); - } - } else { - build_bits.append(0, 1); - } - - // ATREE - - // [flag to indicate if atree data is present] - // [atree data: see existing encoding impl] //idk the impl - if (atree.length > 0 && atree_state.get(atree[0].ability.id).active) { - build_bits.append(1, 1); - const atree_bitvec = encode_atree(atree, atree_state); - build_bits.append(atree_bitvec); - } else { - build_bits.append(0, 1); - } - - //compute length and return final build hash - return build_version.toString() + "_" + len_string + "_" + build_string; - } -} - -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.items[0].statMap.get("displayName")+"\n"+ - "> "+build.items[1].statMap.get("displayName")+"\n"+ - "> "+build.items[2].statMap.get("displayName")+"\n"+ - "> "+build.items[3].statMap.get("displayName")+"\n"+ - "> "+build.items[4].statMap.get("displayName")+"\n"+ - "> "+build.items[5].statMap.get("displayName")+"\n"+ - "> "+build.items[6].statMap.get("displayName")+"\n"+ - "> "+build.items[7].statMap.get("displayName")+"\n"+ - "> "+build.items[15].statMap.get("displayName")+" ["+build_powders[4].map(x => powderNames.get(x)).join("")+"]"; - copyTextToClipboard(text); - document.getElementById("share-button").textContent = "Copied!"; - } -} - -/** - * Ability tree encode and decode functions - * - * Based on a traversal, basically only uses bits to represent the nodes that are on (and "dark" outgoing edges). - * credit: SockMower - */ - -/** - * Return: BitVector - */ -function encode_atree(atree, atree_state) { - let ret_vec = new BitVector(0, 0); - - function traverse(head, atree_state, visited, ret) { - for (const child of head.children) { - if (visited.has(child.ability.id)) { continue; } - visited.set(child.ability.id, true); - if (atree_state.get(child.ability.id).active) { - ret.append(1, 1); - traverse(child, atree_state, visited, ret); - } - else { - ret.append(0, 1); - } - } - } - - traverse(atree[0], atree_state, new Map(), ret_vec); - return ret_vec; -} - -/** - * Return: List of active nodes - */ -function decode_atree(atree, bits) { - let i = 0; - let ret = []; - ret.push(atree[0]); - function traverse(head, visited, ret) { - for (const child of head.children) { - if (visited.has(child.ability.id)) { continue; } - visited.set(child.ability.id, true); - if (bits.read_bit(i)) { - i += 1; - ret.push(child); - traverse(child, visited, ret); - } - else { - i += 1; - } - } - } - traverse(atree[0], new Map(), ret); - return ret; -}