Powder specials and potion boosts

This commit is contained in:
hppeng 2022-06-20 10:51:17 -07:00
parent f7a1f4fc7e
commit ebcdf9ae27
8 changed files with 391 additions and 194 deletions

View file

@ -307,7 +307,7 @@
<input class="equipment-input text-light form-control form-control-sm" id="level-choice" name="level-choice" value="106" placeholder="Build level" value="" tabindex="2"/>
</div>
<div class="col-auto px-1 text-nowrap scaled-font">
<button class="button fw-bold text-light dark-5 scaled-font rounded" id="reset-button" onclick="sq2ResetFields()">Reset</button>
<button class="button fw-bold text-light dark-5 scaled-font rounded" id="reset-button" onclick="resetFields()">Reset</button>
</div>
</div>
<div class="row align-items-center justify-content-center my-1">
@ -944,27 +944,27 @@
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
<div class="row row-cols-2 row-cols-xl-0 text-nowrap justify-content-center">
<div class="col-auto p-1">
<button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="vanish-boost" onclick="updateBoosts('vanish-boost', true)">
<button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="vanish-boost" onclick="updateBoosts('vanish-boost')">
Vanish (+80%)
</button>
</div>
<div class="col-auto p-1">
<button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="warscream-boost" onclick="updateBoosts('warscream-boost', true)">
<button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="warscream-boost" onclick="updateBoosts('warscream-boost')">
War Scream (+10%)
</button>
</div>
<div class="col-auto p-1">
<button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="yourtotem-boost" onclick="updateBoosts('yourtotem-boost', true)">
<button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="yourtotem-boost" onclick="updateBoosts('yourtotem-boost')">
Your Totem (+35%)
</button>
</div>
<div class="col-auto p-1">
<button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="allytotem-boost" onclick="updateBoosts('allytotem-boost', true)">
<button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="allytotem-boost" onclick="updateBoosts('allytotem-boost')">
Ally Totem (+15%)
</button>
</div>
<div class="col-auto p-1">
<button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="bash-boost" onclick="updateBoosts('bash-boost', true)">
<button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="bash-boost" onclick="updateBoosts('bash-boost')">
Bash (+50%)
</button>
</div>
@ -1001,27 +1001,27 @@
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
<div class="row row-cols-2 row-cols-xl-0 text-nowrap justify-content-center">
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-1" onclick = "updatePowderSpecials('Quake-1', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-1" onclick = "updatePowderSpecials('Quake-1')">
Lv.4 [e4e4]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-2" onclick = "updatePowderSpecials('Quake-2', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-2" onclick = "updatePowderSpecials('Quake-2')">
Lv.4.5 [e5e4]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-3" onclick = "updatePowderSpecials('Quake-3', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-3" onclick = "updatePowderSpecials('Quake-3')">
Lv.5 [e5e5]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-4" onclick = "updatePowderSpecials('Quake-4', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-4" onclick = "updatePowderSpecials('Quake-4')">
Lv.5.5 [e6e5]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-5" onclick = "updatePowderSpecials('Quake-5', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-5" onclick = "updatePowderSpecials('Quake-5')">
Lv.6 [e6e6]
</button>
</div>
@ -1031,7 +1031,7 @@
Rage (Passive)
</div>
<div class="col">
<input type = "range" class = "e_slider" id = "str_boost_armor" name = "str-boost-armor" autocomplete = "off" min = '0' max = '400' value = '0' step = '1' onchange = "updateArmorPowderSpecials('str_boost_armor', true)">
<input type = "range" class = "e_slider" id = "str_boost_armor" name = "str-boost-armor" autocomplete = "off" min = '0' max = '400' value = '0' step = '1' onchange = "updateArmorPowderSpecials('str_boost_armor')">
<input type="text" id="str_boost_armor_prev" autocomplete = "off" value="0" style = "display:none;">
<label id = "str_boost_armor_label" for="str-boost-armor">% Earth Dmg Boost: 0</label>
</div>
@ -1045,27 +1045,27 @@
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
<div class="row row-cols-2 row-cols-xl-0 text-nowrap justify-content-center">
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-1" onclick = "updatePowderSpecials('Chain_Lightning-1', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-1" onclick = "updatePowderSpecials('Chain_Lightning-1')">
Lv.4 [t4t4]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-2" onclick = "updatePowderSpecials('Chain_Lightning-2', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-2" onclick = "updatePowderSpecials('Chain_Lightning-2')">
Lv.4.5 [t5t4]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-3" onclick = "updatePowderSpecials('Chain_Lightning-3', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-3" onclick = "updatePowderSpecials('Chain_Lightning-3')">
Lv.5 [t5t5]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-4" onclick = "updatePowderSpecials('Chain_Lightning-4', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-4" onclick = "updatePowderSpecials('Chain_Lightning-4')">
Lv.5.5 [t6t5]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-5" onclick = "updatePowderSpecials('Chain_Lightning-5', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-5" onclick = "updatePowderSpecials('Chain_Lightning-5')">
Lv.6 [t6t6]
</button>
</div>
@ -1075,7 +1075,7 @@
Kill Streak (Passive)
</div>
<div class="col">
<input type = "range" class = "t_slider" id = "dex_boost_armor" name = "dex-boost-armor" autocomplete = "off" min = '0' max = '200' value = '0' step = '1' onchange = "updateArmorPowderSpecials('dex_boost_armor', true)">
<input type = "range" class = "t_slider" id = "dex_boost_armor" name = "dex-boost-armor" autocomplete = "off" min = '0' max = '200' value = '0' step = '1' onchange = "updateArmorPowderSpecials('dex_boost_armor')">
<input type="text" id="dex_boost_armor_prev" autocomplete = "off" value="0" style = "display:none;">
<label id = "dex_boost_armor_label" for="dex-boost-armor">% Thunder Dmg Boost: 0</label>
</div>
@ -1089,27 +1089,27 @@
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
<div class="row row-cols-2 row-cols-xl-0 text-nowrap justify-content-center">
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-1" onclick = "updatePowderSpecials('Curse-1', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-1" onclick = "updatePowderSpecials('Curse-1')">
Lv.4 [w4w4]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-2" onclick = "updatePowderSpecials('Curse-2', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-2" onclick = "updatePowderSpecials('Curse-2')">
Lv.4.5 [w5w4]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-3" onclick = "updatePowderSpecials('Curse-3', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-3" onclick = "updatePowderSpecials('Curse-3')">
Lv.5 [w5w5]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-4" onclick = "updatePowderSpecials('Curse-4', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-4" onclick = "updatePowderSpecials('Curse-4')">
Lv.5.5 [w6w5]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-5" onclick = "updatePowderSpecials('Curse-5', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-5" onclick = "updatePowderSpecials('Curse-5')">
Lv.6 [w6w6]
</button>
</div>
@ -1119,7 +1119,7 @@
Concentration (Passive)
</div>
<div class="col">
<input type = "range" class = "w_slider" id = "int_boost_armor" name = "dex-boost-armor" autocomplete = "off" min = '0' max = '150' value = '0' step = '1' onchange = "updateArmorPowderSpecials('int_boost_armor', true)">
<input type = "range" class = "w_slider" id = "int_boost_armor" name = "dex-boost-armor" autocomplete = "off" min = '0' max = '150' value = '0' step = '1' onchange = "updateArmorPowderSpecials('int_boost_armor')">
<input type="text" id="int_boost_armor_prev" autocomplete = "off" value="0" style = "display:none;">
<label id = "int_boost_armor_label" for="dex-boost-armor">% Water Dmg Boost: 0</label>
</div>
@ -1133,27 +1133,27 @@
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
<div class="row row-cols-2 row-cols-xl-0 text-nowrap justify-content-center">
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-1" onclick = "updatePowderSpecials('Courage-1', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-1" onclick = "updatePowderSpecials('Courage-1')">
Lv.4 [f4f4]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-2" onclick = "updatePowderSpecials('Courage-2', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-2" onclick = "updatePowderSpecials('Courage-2')">
Lv.4.5 [f5f4]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-3" onclick = "updatePowderSpecials('Courage-3', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-3" onclick = "updatePowderSpecials('Courage-3')">
Lv.5 [f5f5]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-4" onclick = "updatePowderSpecials('Courage-4', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-4" onclick = "updatePowderSpecials('Courage-4')">
Lv.5.5 [f6f5]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-5" onclick = "updatePowderSpecials('Courage-5', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-5" onclick = "updatePowderSpecials('Courage-5')">
Lv.6 [f6f6]
</button>
</div>
@ -1163,7 +1163,7 @@
Endurance (Passive)
</div>
<div class="col">
<input type = "range" class = "f_slider" id = "def_boost_armor" name = "def-boost-armor" autocomplete = "off" min = '0' max = '200' value = '0' step = '1' onchange = "updateArmorPowderSpecials('def_boost_armor', true)">
<input type = "range" class = "f_slider" id = "def_boost_armor" name = "def-boost-armor" autocomplete = "off" min = '0' max = '200' value = '0' step = '1' onchange = "updateArmorPowderSpecials('def_boost_armor')">
<input type="text" id="def_boost_armor_prev" autocomplete = "off" value="0" style = "display:none;">
<label id = "def_boost_armor_label" for="def-boost-armor">% Fire Dmg Boost: 0</label>
</div>
@ -1177,27 +1177,27 @@
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
<div class="row row-cols-2 row-cols-xl-0 text-nowrap justify-content-center">
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-1" onclick = "updatePowderSpecials('Wind_Prison-1', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-1" onclick = "updatePowderSpecials('Wind_Prison-1')">
Lv.4 [a4a4]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-2" onclick = "updatePowderSpecials('Wind_Prison-2', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-2" onclick = "updatePowderSpecials('Wind_Prison-2')">
Lv.4.5 [a5a4]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-3" onclick = "updatePowderSpecials('Wind_Prison-3', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-3" onclick = "updatePowderSpecials('Wind_Prison-3')">
Lv.5 [a5a5]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-4" onclick = "updatePowderSpecials('Wind_Prison-4', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-4" onclick = "updatePowderSpecials('Wind_Prison-4')">
Lv.5.5 [a6a5]
</button>
</div>
<div class="col-auto p-1">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-5" onclick = "updatePowderSpecials('Wind_Prison-5', true)">
<button class = "button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-5" onclick = "updatePowderSpecials('Wind_Prison-5')">
Lv.6 [a6a6]
</button>
</div>
@ -1207,7 +1207,7 @@
Dodge (Passive)
</div>
<div class="col">
<input type = "range" class = "a_slider" id = "agi_boost_armor" name = "agi-boost-armor" autocomplete = "off" min = '0' max = '150' value = '0' step = '1' onchange = "updateArmorPowderSpecials('agi_boost_armor', true)">
<input type = "range" class = "a_slider" id = "agi_boost_armor" name = "agi-boost-armor" autocomplete = "off" min = '0' max = '150' value = '0' step = '1' onchange = "updateArmorPowderSpecials('agi_boost_armor')">
<input type="text" id="agi_boost_armor_prev" autocomplete = "off" value="0" style = "display:none;">
<label id = "agi_boost_armor_label" for="agi-boost-armor">% Air Dmg Boost: 0</label>
</div>

View file

@ -84,7 +84,7 @@ let tome_names = [
"Armor Tome",
"Guild Tome",
]
let equipmentInputs = equipment_fields.map(x => x + "-choice");
let equipment_inputs = equipment_fields.map(x => x + "-choice");
let build_fields = equipment_fields.map(x => x+"-tooltip");
let tomeInputs = tome_fields.map(x => x + "-choice");

View file

@ -8,7 +8,6 @@ function parsePowdering(powder_info) {
powder_info = powder_info.slice(1);
for (let j = 0; j < n_blocks; ++j) {
let block = powder_info.slice(0,5);
console.log(block);
let six_powders = Base64.toInt(block);
for (let k = 0; k < 6 && six_powders != 0; ++k) {
powders += powderNames.get((six_powders & 0x1f) - 1);
@ -84,7 +83,7 @@ function decodeBuild(url_tag) {
}
//constant in all versions
for (let i in equipment) {
setValue(equipmentInputs[i], equipment[i]);
setValue(equipment_inputs[i], equipment[i]);
}
//level, skill point assignments, and powdering
@ -133,7 +132,6 @@ function decodeBuild(url_tag) {
setValue(powder_inputs[i], powdering[i]);
}
for (let i in skillpoints) {
console.log(skillpoints[i]);
setValue(skp_order[i] + "-skp", skillpoints[i]);
}
}
@ -147,7 +145,7 @@ function encodeBuild(build, powders, skillpoints) {
let build_string;
//V6 encoding - Tomes
build_version = 4;
build_version = 5;
build_string = "";
tome_string = "";

View file

@ -69,20 +69,48 @@ function loadBuild() {
}
function resetFields(){
for (let i in powderInputs) {
setValue(powderInputs[i], "");
for (const i of powder_inputs) {
setValue(i, "");
}
for (let i in equipmentInputs) {
setValue(equipmentInputs[i], "");
for (const i of equipment_inputs) {
setValue(i, "");
}
setValue("str-skp", "0");
setValue("dex-skp", "0");
setValue("int-skp", "0");
setValue("def-skp", "0");
setValue("agi-skp", "0");
for (const special_name of specialNames) {
for (let i = 1; i < 6; i++) { //toggle all pressed buttons of the same powder special off
//name is same, power is i
let elem = document.getElementById(special_name.replace(" ", "_")+'-'+i);
if (elem.classList.contains("toggleOn")) {
elem.classList.remove("toggleOn");
}
}
}
for (const [key, value] of damageMultipliers) {
let elem = document.getElementById(key + "-boost")
if (elem.classList.contains("toggleOn")) {
elem.classList.remove("toggleOn");
}
}
const nodes_to_reset = item_nodes.concat(powder_nodes.concat(edit_input_nodes));
for (const node of nodes_to_reset) {
node.mark_dirty();
}
powder_special_input.mark_dirty();
boosts_node.mark_dirty();
for (const node of nodes_to_reset) {
node.update();
}
powder_special_input.update();
boosts_node.update();
setValue("level-choice", "106");
location.hash = "";
calculateBuild();
}
function toggleID() {
@ -130,6 +158,15 @@ function toggle_spell_tab(tab) {
}
}
function toggle_boost_tab(tab) {
for (const i of skp_order) {
document.querySelector("#"+i+"-boost").style.display = "none";
document.getElementById(i + "-boost-tab").classList.remove("selected-btn");
}
document.querySelector("#"+tab+"-boost").style.display = "";
document.getElementById(tab + "-boost-tab").classList.add("selected-btn");
}
let tabs = ['overall-stats', 'offensive-stats', 'defensive-stats'];
function show_tab(tab) {

View file

@ -1,7 +1,136 @@
let boosts_node;
/* Updates all spell boosts
*/
function updateBoosts(buttonId) {
let elem = document.getElementById(buttonId);
if (elem.classList.contains("toggleOn")) {
elem.classList.remove("toggleOn");
} else {
elem.classList.add("toggleOn");
}
boosts_node.mark_dirty();
boosts_node.update();
}
class BoostsInputNode extends ComputeNode {
constructor() { super('builder-boost-input'); }
compute_func(input_map) {
let damage_boost = 0;
let def_boost = 0;
for (const [key, value] of damageMultipliers) {
let elem = document.getElementById(key + "-boost")
if (elem.classList.contains("toggleOn")) {
damage_boost += value;
if (key === "warscream") { def_boost += .20 }
if (key === "vanish") { def_boost += .15 }
}
}
return [damage_boost, def_boost];
}
}
let powder_special_input;
let specialNames = ["Quake", "Chain Lightning", "Curse", "Courage", "Wind Prison"];
function updatePowderSpecials(buttonId) {
//console.log(player_build.statMap);
let name = (buttonId).split("-")[0];
let power = (buttonId).split("-")[1]; // [1, 5]
let elem = document.getElementById(buttonId);
if (elem.classList.contains("toggleOn")) { //toggle the pressed button off
elem.classList.remove("toggleOn");
} else {
for (let i = 1;i < 6; i++) { //toggle all pressed buttons of the same powder special off
//name is same, power is i
if(document.getElementById(name.replace(" ", "_") + "-" + i).classList.contains("toggleOn")) {
document.getElementById(name.replace(" ", "_") + "-" + i).classList.remove("toggleOn");
}
}
//toggle the pressed button on
elem.classList.add("toggleOn");
}
powder_special_input.mark_dirty();
powder_special_input.update();
}
class PowderSpecialInputNode extends ComputeNode {
constructor() { super('builder-powder-special-input'); }
compute_func(input_map) {
let powder_specials = []; // [ [special, power], [special, power]]
for (const sName of specialNames) {
for (let i = 1;i < 6; i++) {
if (document.getElementById(sName.replace(" ","_") + "-" + i).classList.contains("toggleOn")) {
let powder_special = powderSpecialStats[specialNames.indexOf(sName.replace("_"," "))];
powder_specials.push([powder_special, i]);
break;
}
}
}
return powder_specials;
}
}
class PowderSpecialCalcNode extends ComputeNode {
constructor() { super('builder-powder-special-apply'); }
compute_func(input_map) {
const powder_specials = input_map.get('powder-specials');
let stats = new Map();
for (const [special, power] of powder_specials) {
if (special["weaponSpecialEffects"].has("Damage Boost")) {
let name = special["weaponSpecialName"];
if (name === "Courage" || name === "Curse") { //courage and curse are is universal damage boost
stats.set("sdPct", special.weaponSpecialEffects.get("Damage Boost")[power-1]);
stats.set("mdPct", special.weaponSpecialEffects.get("Damage Boost")[power-1]);
stats.set("poisonPct", special.weaponSpecialEffects.get("Damage Boost")[power-1]);
} else if (name === "Wind Prison") {
stats.set("aDamPct", special.weaponSpecialEffects.get("Damage Boost")[power-1]);
}
}
}
return stats;
}
}
class PowderSpecialDisplayNode extends ComputeNode {
constructor() {
super('builder-powder-special-display');
this.fail_cb = true;
}
compute_func(input_map) {
const powder_specials = input_map.get('powder-specials');
const stats = input_map.get('stats');
const weapon = input_map.get('weapon');
displayPowderSpecials(document.getElementById("powder-special-stats"), powder_specials, stats, weapon.statMap, true);
}
}
/**
* Apply armor powders.
* Encoding shortcut assumes that all powders give +def to one element
* and -def to the element "behind" it in cycle ETWFA, which is true
* as of now and unlikely to change in the near future.
*/
function applyArmorPowders(expandedItem, powders) {
for(const id of powders){
let powder = powderStats[id];
let name = powderNames.get(id).charAt(0);
let prevName = skp_elements[(skp_elements.indexOf(name) + 4 )% 5];
expandedItem.set(name+"Def", (expandedItem.get(name+"Def") || 0) + powder["defPlus"]);
expandedItem.set(prevName+"Def", (expandedItem.get(prevName+"Def") || 0) - powder["defMinus"]);
}
}
/**
* Node for getting an item's stats from an item input field.
*
* Signature: ItemInputNode() => Item | null
* Signature: ItemInputNode(powdering: Optional[list[powder]]) => Item | null
*/
class ItemInputNode extends InputNode {
/**
@ -18,36 +147,36 @@ class ItemInputNode extends InputNode {
}
compute_func(input_map) {
// built on the assumption of no one will type in CI/CR letter by letter
const powdering = input_map.get('powdering');
// built on the assumption of no one will type in CI/CR letter by letter
let item_text = this.input_field.value;
if (!item_text) {
return this.none_item;
}
let item;
if (item_text.slice(0, 3) == "CI-") {
item = getCustomFromHash(item_text);
}
else if (item_text.slice(0, 3) == "CR-") {
item = getCraftFromHash(item_text);
}
else if (itemMap.has(item_text)) {
item = new Item(itemMap.get(item_text));
}
else if (tomeMap.has(item_text)) {
item = new Item(tomeMap.get(item_text));
}
if (item_text.slice(0, 3) == "CI-") { item = getCustomFromHash(item_text); }
else if (item_text.slice(0, 3) == "CR-") { item = getCraftFromHash(item_text); }
else if (itemMap.has(item_text)) { item = new Item(itemMap.get(item_text)); }
else if (tomeMap.has(item_text)) { item = new Item(tomeMap.get(item_text)); }
if (item) {
if (powdering !== undefined) {
item.statMap.set('powders', powdering);
}
let type_match;
if (this.none_item.statMap.get('category') === 'weapon') {
type_match = item.statMap.get('category') === 'weapon';
} else {
type_match = item.statMap.get('type') === this.none_item.statMap.get('type');
}
if (type_match) { return item; }
if (type_match) {
if (item.statMap.get('category') === 'armor' && powdering !== undefined) {
applyArmorPowders(item.statMap, powdering);
}
return item;
}
}
return null;
}
@ -142,11 +271,11 @@ class WeaponInputDisplayNode extends ComputeNode {
* Encode the build into a url-able string.
*
* Signature: BuildEncodeNode(build: Build,
helmet-powder: List[powder],
chestplate-powder: List[powder],
leggings-powder: List[powder],
boots-powder: List[powder],
weapon-powder: List[powder]) => str
* helmet-powder: List[powder],
* chestplate-powder: List[powder],
* leggings-powder: List[powder],
* boots-powder: List[powder],
* weapon-powder: List[powder]) => str
*/
class BuildEncodeNode extends ComputeNode {
constructor() { super("builder-encode"); }
@ -227,7 +356,7 @@ class BuildAssembleNode extends ComputeNode {
for (const item of equipments) {
all_none = all_none && item.statMap.has('NONE');
}
if (all_none) {
if (all_none && !location.hash) {
return null;
}
return new Build(level, equipments, [], weapon);
@ -314,17 +443,17 @@ function getDefenseStats(stats) {
defenseStats.push(totalHp);
//EHP
let ehp = [totalHp, totalHp];
let defMult = stats.get("classDef");
ehp[0] /= (1-def_pct)*(1-agi_pct)*(2-defMult);
ehp[1] /= (1-def_pct)*(2-defMult);
let defMult = (2 - stats.get("classDef")) * (1 - stats.get("defBonus"));
ehp[0] /= (1-def_pct)*(1-agi_pct)*defMult;
ehp[1] /= (1-def_pct)*defMult;
defenseStats.push(ehp);
//HPR
let totalHpr = rawToPct(stats.get("hprRaw"), stats.get("hprPct")/100.);
defenseStats.push(totalHpr);
//EHPR
let ehpr = [totalHpr, totalHpr];
ehpr[0] /= (1-def_pct)*(1-agi_pct)*(2-defMult);
ehpr[1] /= (1-def_pct)*(2-defMult);
ehpr[0] /= (1-def_pct)*(1-agi_pct)*defMult;
ehpr[1] /= (1-def_pct)*defMult;
defenseStats.push(ehpr);
//skp stats
defenseStats.push([ def_pct*100, agi_pct*100]);
@ -345,7 +474,6 @@ function getDefenseStats(stats) {
*
* Signature: SpellDamageCalcNode(weapon-input: Item,
* stats: StatMap,
* weapon-powder: List[powder],
* spell-info: [Spell, SpellParts]) => List[SpellDamage]
*/
class SpellDamageCalcNode extends ComputeNode {
@ -355,11 +483,10 @@ class SpellDamageCalcNode extends ComputeNode {
compute_func(input_map) {
const weapon = new Map(input_map.get('weapon-input').statMap);
const weapon_powder = input_map.get('weapon-powder');
const damage_mult = 1; // TODO: hook up
const spell_info = input_map.get('spell-info');
const spell_parts = spell_info[1];
const stats = input_map.get('stats');
const damage_mult = stats.get('damageMultiplier');
const skillpoints = [
stats.get('str'),
stats.get('dex'),
@ -367,8 +494,6 @@ class SpellDamageCalcNode extends ComputeNode {
stats.get('def'),
stats.get('agi')
];
weapon.set("powders", weapon_powder);
let spell_results = []
for (const part of spell_parts) {
@ -441,7 +566,7 @@ function getMeleeStats(stats, weapon) {
adjAtkSpd = 0;
}
let damage_mult = 1;
let damage_mult = stats.get("damageMultiplier");
if (weapon_stats.get("type") === "relik") {
damage_mult = 0.99; // CURSE YOU WYNNCRAFT
//One day we will create WynnWynn and no longer have shaman 99% melee injustice.
@ -485,7 +610,6 @@ class BuildDisplayNode extends ComputeNode {
displaySetBonuses("set-info", build);
let meleeStats = getMeleeStats(stats, build.weapon);
// TODO: move weapon out?
console.log(meleeStats);
displayMeleeDamage(document.getElementById("build-melee-stats"), document.getElementById("build-melee-statsAvg"), meleeStats);
displayDefenseStats(document.getElementById("defensive-stats"), stats);
@ -576,13 +700,11 @@ class DisplayBuildWarningsNode extends ComputeNode {
if (build.level < item_lvl) {
if (!lvlWarning) {
lvlWarning = document.createElement("p");
lvlWarning.classList.add("itemp");
lvlWarning.classList.add("warning");
lvlWarning.classList.add("itemp"); lvlWarning.classList.add("warning");
lvlWarning.textContent = "WARNING: A level " + build.level + " player cannot use some piece(s) of this build."
}
let baditem = document.createElement("p");
baditem.classList.add("nocolor");
baditem.classList.add("itemp");
baditem.classList.add("nocolor"); baditem.classList.add("itemp");
baditem.textContent = item.get("displayName") + " requires level " + item_lvl + " to use.";
lvlWarning.appendChild(baditem);
}
@ -594,8 +716,7 @@ class DisplayBuildWarningsNode extends ComputeNode {
const bonus = sets.get(setName).bonuses[count-1];
if (bonus["illegal"]) {
let setWarning = document.createElement("p");
setWarning.classList.add("itemp");
setWarning.classList.add("warning");
setWarning.classList.add("itemp"); setWarning.classList.add("warning");
setWarning.textContent = "WARNING: illegal item combination: " + setName
summarybox.append(setWarning);
}
@ -612,15 +733,26 @@ class AggregateStatsNode extends ComputeNode {
constructor() { super("builder-aggregate-stats"); }
compute_func(input_map) {
const build = input_map.get('build');
const weapon = input_map.get('weapon');
const build = input_map.get('build'); input_map.delete('build');
const powder_boost = input_map.get('powder-boost'); input_map.delete('powder-boost');
const potion_boost = input_map.get('potion-boost'); input_map.delete('potion-boost');
const weapon = input_map.get('weapon'); input_map.delete('weapon');
const output_stats = new Map(build.statMap);
output_stats.set("damageMultiplier", 1 + potion_boost[0]);
output_stats.set("defBonus", potion_boost[1]);
for (const [k, v] of input_map.entries()) {
if (k === 'build') {
continue;
}
output_stats.set(k, v);
}
for (const [k, v] of powder_boost.entries()) {
if (output_stats.has(k)) {
output_stats.set(k, v + output_stats.get(k));
}
else {
output_stats.set(k, v);
}
}
output_stats.set('classDef', classDefenseMultipliers.get(weapon.statMap.get("type")));
return output_stats;
}
@ -656,6 +788,7 @@ class SkillPointSetterNode extends ComputeNode {
}
compute_func(input_map) {
console.log("a");
if (input_map.size !== 1) { throw "SkillPointSetterNode accepts exactly one input (build)"; }
const [build] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element
for (const [idx, elem] of skp_order.entries()) {
@ -750,6 +883,12 @@ function builder_graph_init() {
build_encode_node.link_to(powder_node, input);
}
item_nodes[0].link_to(powder_nodes[0], 'powdering');
item_nodes[1].link_to(powder_nodes[1], 'powdering');
item_nodes[2].link_to(powder_nodes[2], 'powdering');
item_nodes[3].link_to(powder_nodes[3], 'powdering');
item_nodes[8].link_to(powder_nodes[4], 'powdering');
// Edit IDs setter declared up here to set ids so they will be populated by default.
let edit_id_output = new EditableIDSetterNode();
edit_id_output.link_to(build_node);
@ -788,6 +927,19 @@ function builder_graph_init() {
}
level_input.update();
// Powder specials.
powder_special_input = new PowderSpecialInputNode();
let powder_special_calc = new PowderSpecialCalcNode().link_to(powder_special_input, 'powder-specials');
new PowderSpecialDisplayNode().link_to(powder_special_input, 'powder-specials')
.link_to(stat_agg_node, 'stats').link_to(item_nodes[8], 'weapon');
stat_agg_node.link_to(powder_special_calc, 'powder-boost');
powder_special_input.update();
// Potion boost.
boosts_node = new BoostsInputNode();
stat_agg_node.link_to(boosts_node, 'potion-boost');
boosts_node.update();
// Also do something similar for skill points
for (let i = 0; i < 4; ++i) {
@ -798,7 +950,7 @@ function builder_graph_init() {
let calc_node = new SpellDamageCalcNode(i);
calc_node.link_to(item_nodes[8], 'weapon-input').link_to(stat_agg_node, 'stats')
.link_to(powder_nodes[4], 'weapon-powder').link_to(spell_node, 'spell-info');
.link_to(spell_node, 'spell-info');
spelldmg_nodes.push(calc_node);
let display_node = new SpellDisplayNode(i);

View file

@ -72,9 +72,6 @@ function calculateSpellDamage(stats, spellConversions, rawModifier, pctModifier,
damages[element+1][1] += powder.max;
}
//console.log(tooltipinfo);
damages[0] = neutralRemainingRaw;
let damageMult = damageMultiplier;

View file

@ -1,18 +1,3 @@
/**
* Apply armor powders.
* Encoding shortcut assumes that all powders give +def to one element
* and -def to the element "behind" it in cycle ETWFA, which is true
* as of now and unlikely to change in the near future.
*/
function applyArmorPowders(expandedItem, powders) {
for(const id of powders){
let powder = powderStats[id];
let name = powderNames.get(id).charAt(0);
let prevName = skp_elements[(skp_elements.indexOf(name) + 4 )% 5];
expandedItem.set(name+"Def", (expandedItem.get(name+"Def") || 0) + powder["defPlus"]);
expandedItem.set(prevName+"Def", (expandedItem.get(prevName+"Def") || 0) - powder["defMinus"]);
}
}
function apply_elemental_format(p_elem, id, suffix) {
suffix = (typeof suffix !== 'undefined') ? suffix : "";
@ -192,6 +177,11 @@ function displayExpandedItem(item, parent_id){
if (item.get("category") === "weapon") {
let stats = new Map();
stats.set("atkSpd", item.get("atkSpd"));
stats.set("eDamPct", 0);
stats.set("tDamPct", 0);
stats.set("wDamPct", 0);
stats.set("fDamPct", 0);
stats.set("aDamPct", 0);
stats.set("damageBonus", [0, 0, 0, 0, 0]);
//SUPER JANK @HPP PLS FIX
@ -991,9 +981,15 @@ function displayNextCosts(_stats, spell, spellIdx) {
}
function displayRolledID(item, id, elemental_format) {
let row = document.createElement('tr');
let min_elem = document.createElement('td');
min_elem.classList.add('left');
let row = document.createElement('div');
row.classList.add('col');
let item_div = document.createElement('div');
item_div.classList.add('row');
let min_elem = document.createElement('div');
min_elem.classList.add('col', 'text-start');
min_elem.style.cssText += "flex-grow: 0";
let id_min = item.get("minRolls").get(id)
let style = id_min < 0 ? "negative" : "positive";
if(reversedIDs.includes(id)){
@ -1001,10 +997,11 @@ function displayRolledID(item, id, elemental_format) {
}
min_elem.classList.add(style);
min_elem.textContent = id_min + idSuffixes[id];
row.appendChild(min_elem);
item_div.appendChild(min_elem);
let desc_elem = document.createElement('td');
desc_elem.classList.add('center');
let desc_elem = document.createElement('div');
desc_elem.classList.add('col', 'text-center');//, 'text-nowrap');
desc_elem.style.cssText += "flex-grow: 1";
//TODO elemental format jank
if (elemental_format) {
apply_elemental_format(desc_elem, id);
@ -1012,18 +1009,20 @@ function displayRolledID(item, id, elemental_format) {
else {
desc_elem.textContent = idPrefixes[id];
}
row.appendChild(desc_elem);
item_div.appendChild(desc_elem);
let max_elem = document.createElement('td');
let max_elem = document.createElement('div');
let id_max = item.get("maxRolls").get(id)
max_elem.classList.add('right');
max_elem.classList.add('col', 'text-end');
max_elem.style.cssText += "flex-grow: 0";
style = id_max < 0 ? "negative" : "positive";
if(reversedIDs.includes(id)){
if (reversedIDs.includes(id)) {
style === "positive" ? style = "negative" : style = "positive";
}
max_elem.classList.add(style);
max_elem.textContent = id_max + idSuffixes[id];
row.appendChild(max_elem);
item_div.appendChild(max_elem);
row.appendChild(item_div);
return row;
}
@ -1458,55 +1457,60 @@ function displayDefenseStats(parent_elem, statMap, insertSummary){
}
}
function displayPowderSpecials(parent_elem, powderSpecials, build) {
parent_elem.textContent = "Powder Specials";
function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon, overall=false) {
const skillpoints = [
stats.get('str'),
stats.get('dex'),
stats.get('int'),
stats.get('def'),
stats.get('agi')
];
parent_elem.textContent = ""
let title = document.createElement("b");
title.textContent = "Powder Specials";
parent_elem.appendChild(title);
let specials = powderSpecials.slice();
let stats = build.statMap;
let expandedStats = new Map();
//each entry of powderSpecials is [ps, power]
for (special of specials) {
//iterate through the special and display its effects.
let powder_special = document.createElement("p");
powder_special.classList.add("left");
let specialSuffixes = new Map([ ["Duration", " sec"], ["Radius", " blocks"], ["Chains", ""], ["Damage", "%"], ["Damage Boost", "%"], ["Knockback", " blocks"] ]);
let specialTitle = document.createElement("p");
let specialEffects = document.createElement("p");
specialTitle.classList.add("left");
specialTitle.classList.add("itemp");
specialTitle.classList.add(damageClasses[powderSpecialStats.indexOf(special[0]) + 1]);
specialEffects.classList.add("left");
specialEffects.classList.add("itemp");
specialEffects.classList.add("nocolor");
let effects = special[0]["weaponSpecialEffects"];
let power = special[1];
specialTitle.textContent = special[0]["weaponSpecialName"] + " " + Math.floor((power-1)*0.5 + 4) + (power % 2 == 0 ? ".5" : "");
for (const [key,value] of effects) {
let effect = document.createElement("p");
effect.classList.add("itemp");
effect.textContent += key + ": " + value[power-1] + specialSuffixes.get(key);
if(key === "Damage"){
effect.textContent += elementIcons[powderSpecialStats.indexOf(special[0])];
}
if(special[0]["weaponSpecialName"] === "Wind Prison" && key === "Damage Boost") {
effect.textContent += " (only 1st hit)";
}
specialEffects.appendChild(effect);
}
if (!overall || powderSpecialStats.indexOf(special[0]) == 2 || powderSpecialStats.indexOf(special[0]) == 3 || powderSpecialStats.indexOf(special[0]) == 4) {
for (const [key,value] of effects) {
let effect = document.createElement("p");
effect.textContent += key + ": " + value[power-1] + specialSuffixes.get(key);
if(key === "Damage"){
effect.textContent += elementIcons[powderSpecialStats.indexOf(special[0])];
}
if(special[0]["weaponSpecialName"] === "Wind Prison" && key === "Damage Boost") {
effect.textContent += " (only 1st hit)";
}
specialEffects.appendChild(effect);
}
}
powder_special.appendChild(specialTitle);
powder_special.appendChild(specialEffects);
//if this special is an instant-damage special (Quake, Chain Lightning, Courage Burst), display the damage.
let specialDamage = document.createElement("p");
// specialDamage.classList.add("item-margin");
let spells = spell_table["powder"];
if (powderSpecialStats.indexOf(special[0]) == 0 || powderSpecialStats.indexOf(special[0]) == 1 || powderSpecialStats.indexOf(special[0]) == 3) { //Quake, Chain Lightning, or Courage
let spell = (powderSpecialStats.indexOf(special[0]) == 3 ? spells[2] : spells[powderSpecialStats.indexOf(special[0])]);
let part = spell["parts"][0];
let _results = calculateSpellDamage(stats, part.conversion,
stats.get("mdRaw"), stats.get("mdPct") + build.externalStats.get("mdPct"),
0, build.weapon, build.total_skillpoints, build.damageMultiplier * ((part.multiplier[power-1] / 100)), build.externalStats);//part.multiplier[power] / 100
stats.get("mdRaw"), stats.get("mdPct"),
0, weapon, skillpoints, stats.get('damageMultiplier') * ((part.multiplier[power-1] / 100)));//part.multiplier[power] / 100
let critChance = skillPointsToPercentage(build.total_skillpoints[1]);
let critChance = skillPointsToPercentage(skillpoints[1]);
let save_damages = [];
let totalDamNormal = _results[0];
@ -1521,59 +1525,69 @@ function displayPowderSpecials(parent_elem, powderSpecials, build) {
let critAverage = (totalDamCrit[0]+totalDamCrit[1])/2 || 0;
let averageDamage = (1-critChance)*nonCritAverage+critChance*critAverage || 0;
let averageLabel = document.createElement("p");
averageLabel.textContent = "Average: "+averageDamage.toFixed(2);
averageLabel.classList.add("damageSubtitle");
specialDamage.append(averageLabel);
let nonCritLabel = document.createElement("p");
nonCritLabel.textContent = "Non-Crit Average: "+nonCritAverage.toFixed(2);
nonCritLabel.classList.add("damageSubtitle");
specialDamage.append(nonCritLabel);
let averageWrap = document.createElement("p");
let averageLabel = document.createElement("span");
averageLabel.textContent = "Average: ";
for (let i = 0; i < 6; i++){
if (results[i][1] > 0){
let p = document.createElement("p");
p.classList.add("damagep");
p.classList.add(damageClasses[i]);
p.textContent = results[i][0]+"-"+results[i][1];
specialDamage.append(p);
}
}
let normalDamage = document.createElement("p");
normalDamage.textContent = "Total: " + totalDamNormal[0].toFixed(2) + "-" + totalDamNormal[1].toFixed(2);
normalDamage.classList.add("itemp");
specialDamage.append(normalDamage);
let averageLabelDmg = document.createElement("span");
averageLabelDmg.classList.add("Damage");
averageLabelDmg.textContent = averageDamage.toFixed(2);
let nonCritChanceLabel = document.createElement("p");
nonCritChanceLabel.textContent = "Non-Crit Chance: " + ((1-critChance)*100).toFixed(2) + "%";
specialDamage.append(nonCritChanceLabel);
let critLabel = document.createElement("p");
critLabel.textContent = "Crit Average: "+critAverage.toFixed(2);
critLabel.classList.add("damageSubtitle");
averageWrap.appendChild(averageLabel);
averageWrap.appendChild(averageLabelDmg);
specialDamage.appendChild(averageWrap);
specialDamage.append(critLabel);
for (let i = 0; i < 6; i++){
if (results[i][1] > 0){
let p = document.createElement("p");
p.classList.add("damagep");
p.classList.add(damageClasses[i]);
p.textContent = results[i][2]+"-"+results[i][3];
specialDamage.append(p);
if (!overall) {
let nonCritLabel = document.createElement("p");
nonCritLabel.textContent = "Non-Crit Average: "+nonCritAverage.toFixed(2);
nonCritLabel.classList.add("damageSubtitle");
nonCritLabel.classList.add("item-margin");
specialDamage.append(nonCritLabel);
for (let i = 0; i < 6; i++){
if (results[i][1] > 0){
let p = document.createElement("p");
p.classList.add("damagep");
p.classList.add(damageClasses[i]);
p.textContent = results[i][0]+"-"+results[i][1];
specialDamage.append(p);
}
}
let normalDamage = document.createElement("p");
normalDamage.textContent = "Total: " + totalDamNormal[0].toFixed(2) + "-" + totalDamNormal[1].toFixed(2);
normalDamage.classList.add("itemp");
specialDamage.append(normalDamage);
let nonCritChanceLabel = document.createElement("p");
nonCritChanceLabel.textContent = "Non-Crit Chance: " + ((1-critChance)*100).toFixed(2) + "%";
specialDamage.append(nonCritChanceLabel);
let critLabel = document.createElement("p");
critLabel.textContent = "Crit Average: "+critAverage.toFixed(2);
critLabel.classList.add("damageSubtitle");
critLabel.classList.add("item-margin");
specialDamage.append(critLabel);
for (let i = 0; i < 6; i++){
if (results[i][1] > 0){
let p = document.createElement("p");
p.classList.add("damagep");
p.classList.add(damageClasses[i]);
p.textContent = results[i][2]+"-"+results[i][3];
specialDamage.append(p);
}
}
let critDamage = document.createElement("p");
critDamage.textContent = "Total: " + totalDamCrit[0].toFixed(2) + "-" + totalDamCrit[1].toFixed(2);
critDamage.classList.add("itemp");
specialDamage.append(critDamage);
let critChanceLabel = document.createElement("p");
critChanceLabel.textContent = "Crit Chance: " + (critChance*100).toFixed(2) + "%";
specialDamage.append(critChanceLabel);
save_damages.push(averageDamage);
}
let critDamage = document.createElement("p");
critDamage.textContent = "Total: " + totalDamCrit[0].toFixed(2) + "-" + totalDamCrit[1].toFixed(2);
critDamage.classList.add("itemp");
specialDamage.append(critDamage);
let critChanceLabel = document.createElement("p");
critChanceLabel.textContent = "Crit Chance: " + (critChance*100).toFixed(2) + "%";
specialDamage.append(critChanceLabel);
save_damages.push(averageDamage);
powder_special.append(specialDamage);
}

View file

@ -25,7 +25,6 @@ async function load_tome_local() {
console.log("Successfully read local tome db.");
}
get_tx.oncomplete = function(event) {
console.log('b');
console.log(request.readyState);
tomes = request.result;
init_tome_maps();