Consolidate constants/utils files, start working on new builder file

This commit is contained in:
hppeng 2022-05-22 00:57:47 -07:00
parent 0234101262
commit 06f745c158
8 changed files with 405 additions and 364 deletions

View file

@ -1379,6 +1379,7 @@
<script src="https://cdn.jsdelivr.net/npm/macy@2"></script> <script src="https://cdn.jsdelivr.net/npm/macy@2"></script>
<script type="text/javascript" src="../js/utils.js"></script> <script type="text/javascript" src="../js/utils.js"></script>
<script type="text/javascript" src="../js/build_utils.js"></script> <script type="text/javascript" src="../js/build_utils.js"></script>
<script type="text/javascript" src="../js/computation_graph.js"></script>
<!-- <script type="text/javascript" src="../js/icons.js"></script> --> <!-- <script type="text/javascript" src="../js/icons.js"></script> -->
<script type="text/javascript" src="../js/sq2icons.js"></script> <script type="text/javascript" src="../js/sq2icons.js"></script>
<script type="text/javascript" src="../js/powders.js"></script> <script type="text/javascript" src="../js/powders.js"></script>
@ -1399,7 +1400,8 @@
<script type="text/javascript" src="../js/custom.js"></script> <script type="text/javascript" src="../js/custom.js"></script>
<script type="text/javascript" src="../js/craft.js"></script> <script type="text/javascript" src="../js/craft.js"></script>
<script type="text/javascript" src="../js/sq2build.js"></script> <script type="text/javascript" src="../js/sq2build.js"></script>
<script type="text/javascript" src="../js/sq2builder.js"></script> <script type="text/javascript" src="../js/build_constants.js"></script>
<script type="text/javascript" src="../js/builder.js"></script>
<script type="text/javascript" src="../js/expr_parser.js"></script> <script type="text/javascript" src="../js/expr_parser.js"></script>
<script type="text/javascript" src="../js/items.js"></script> <script type="text/javascript" src="../js/items.js"></script>
<script type="text/javascript" src="../js/sq2items.js"></script> <script type="text/javascript" src="../js/sq2items.js"></script>

106
js/build_constants.js Normal file
View file

@ -0,0 +1,106 @@
/**
* I kinda lied. Theres some listener stuff in here
* but its mostly constants for builder page specifically.
*/
const url_tag = location.hash.slice(1);
const BUILD_VERSION = "7.0.19";
let player_build;
// THIS IS SUPER DANGEROUS, WE SHOULD NOT BE KEEPING THIS IN SO MANY PLACES
let editable_item_fields = [ "sdPct", "sdRaw", "mdPct", "mdRaw", "poison",
"fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct",
"fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct",
"hprRaw", "hprPct", "hpBonus", "atkTier",
"spPct1", "spRaw1", "spPct2", "spRaw2",
"spPct3", "spRaw3", "spPct4", "spRaw4" ];
let editable_elems = [];
for (let i of editable_item_fields) {
let elem = document.getElementById(i);
elem.addEventListener("change", (event) => {
elem.classList.add("highlight");
});
editable_elems.push(elem);
}
for (let i of skp_order) {
let elem = document.getElementById(i+"-skp");
elem.addEventListener("change", (event) => {
elem.classList.add("highlight");
});
editable_elems.push(elem);
}
function clear_highlights() {
for (let i of editable_elems) {
i.classList.remove("highlight");
}
}
let equipment_fields = [
"helmet",
"chestplate",
"leggings",
"boots",
"ring1",
"ring2",
"bracelet",
"necklace",
"weapon"
];
let tome_fields = [
"weaponTome1",
"weaponTome2",
"armorTome1",
"armorTome2",
"armorTome3",
"armorTome4",
"guildTome1",
]
let equipment_names = [
"Helmet",
"Chestplate",
"Leggings",
"Boots",
"Ring 1",
"Ring 2",
"Bracelet",
"Necklace",
"Weapon"
];
let tome_names = [
"Weapon Tome",
"Weapon Tome",
"Armor Tome",
"Armor Tome",
"Armor Tome",
"Armor Tome",
"Guild Tome",
]
let equipmentInputs = equipment_fields.map(x => x + "-choice");
let buildFields = equipment_fields.map(x => x+"-tooltip").concat(tome_fields.map(x => x + "-tooltip"));
let tomeInputs = tome_fields.map(x => x + "-choice");
let powderInputs = [
"helmet-powder",
"chestplate-powder",
"leggings-powder",
"boots-powder",
"weapon-powder",
];
let weapon_keys = ['dagger', 'wand', 'bow', 'relik', 'spear'];
let armor_keys = ['helmet', 'chestplate', 'leggings', 'boots'];
let accessory_keys= ['ring1', 'ring2', 'bracelet', 'necklace'];
let powderable_keys = ['helmet', 'chestplate', 'leggings', 'boots', 'weapon'];
let equipment_keys = ['helmet', 'chestplate', 'leggings', 'boots', 'ring1', 'ring2', 'bracelet', 'necklace', 'weapon'].concat(tome_keys);
let spell_disp = ['spell0-info', 'spell1-info', 'spell2-info', 'spell3-info'];
let other_disp = ['build-order', 'set-info', 'int-info'];

View file

@ -138,6 +138,7 @@ let rolledIDs = [
"gXp", "gXp",
"gSpd" "gSpd"
]; ];
let reversedIDs = [ "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4" ];
/** /**
* Take an item with id list and turn it into a set of minrolls and maxrolls. * Take an item with id list and turn it into a set of minrolls and maxrolls.
@ -186,7 +187,7 @@ function expandItem(item) {
} }
expandedItem.set("minRolls",minRolls); expandedItem.set("minRolls",minRolls);
expandedItem.set("maxRolls",maxRolls); expandedItem.set("maxRolls",maxRolls);
expandedItem.set("powders", powders); expandedItem.set("powders", []);
return expandedItem; return expandedItem;
} }

View file

@ -1,182 +1,3 @@
const url_tag = location.hash.slice(1);
// console.log(url_base);
// console.log(url_tag);
const BUILD_VERSION = "7.0.19";
function setTitle() {
let text;
if (url_base.includes("hppeng-wynn")) {
text = "WynnBuilder UNSTABLE version "+BUILD_VERSION+" (db version "+DB_VERSION+")";
}
else {
text = "WynnBuilder version "+BUILD_VERSION+" (db version "+DB_VERSION+")";
document.getElementById("header").classList.add("funnynumber");
}
document.getElementById("header").textContent = text;
}
setTitle();
let player_build;
let editable_item_fields = [ "sdPct", "sdRaw", "mdPct", "mdRaw", "poison", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "hprRaw", "hprPct", "hpBonus", "atkTier", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4" ];
let editable_elems = [];
for (let i of editable_item_fields) {
let elem = document.getElementById(i);
elem.addEventListener("change", (event) => {
elem.classList.add("highlight");
});
editable_elems.push(elem);
}
for (let i of skp_order) {
let elem = document.getElementById(i+"-skp");
elem.addEventListener("change", (event) => {
elem.classList.add("highlight");
});
editable_elems.push(elem);
}
function clear_highlights() {
for (let i of editable_elems) {
i.classList.remove("highlight");
}
}
let equipment_fields = [
"helmet",
"chestplate",
"leggings",
"boots",
"ring1",
"ring2",
"bracelet",
"necklace",
"weapon"
];
let equipment_names = [
"Helmet",
"Chestplate",
"Leggings",
"Boots",
"Ring 1",
"Ring 2",
"Bracelet",
"Necklace",
"Weapon"
];
let equipmentInputs = equipment_fields.map(x => x + "-choice");
let buildFields = equipment_fields.map(x => "build-"+x);
let powderInputs = [
"helmet-powder",
"chestplate-powder",
"leggings-powder",
"boots-powder",
"weapon-powder",
];
/*
* Function that takes an item list and populates its corresponding dropdown.
* Used for armors and bracelet/necklace.
*/
function populateItemList(type) {
let item_list = document.getElementById(type+"-items");
for (const item of itemLists.get(type)) {
let item_obj = itemMap.get(item);
if (item_obj["restrict"] && item_obj["restrict"] === "DEPRECATED") {
continue;
}
let el = document.createElement("option");
el.value = item;
item_list.appendChild(el);
}
}
/*
* Populate dropdowns, add listeners, etc.
*/
function init() {
console.log("builder.js init");
for (const armorType of armorTypes) {
populateItemList(armorType);
// Add change listener to update armor slots.
document.getElementById(armorType+"-choice").addEventListener("change", (event) => {
let item_name = event.target.value;
let nSlots = undefined;
if (itemMap.has(item_name)) {
let item = itemMap.get(item_name);
nSlots = item["slots"];
//console.log(item);
}
else {
let crafted_custom_item = getCraftFromHash(item_name) !== undefined ? getCraftFromHash(item_name) : (getCustomFromHash(item_name) !== undefined ? getCustomFromHash(item_name) : undefined);
if (crafted_custom_item !== undefined) {
nSlots = crafted_custom_item.statMap.get("slots");
}
}
if (nSlots !== undefined) {
document.getElementById(armorType+"-slots").textContent = nSlots + " slots";
}
else {
document.getElementById(armorType+"-slots").textContent = "X slots";
}
});
}
let ring1_list = document.getElementById("ring1-items");
let ring2_list = document.getElementById("ring2-items");
for (const ring of itemLists.get("ring")) {
let item_obj = itemMap.get(ring);
if (item_obj["restrict"] && item_obj["restrict"] === "DEPRECATED") {
continue;
}
let el1 = document.createElement("option");
let el2 = document.createElement("option");
el1.value = ring;
el2.value = ring;
ring1_list.appendChild(el1);
ring2_list.appendChild(el2);
}
populateItemList("bracelet");
populateItemList("necklace");
let weapon_list = document.getElementById("weapon-items");
for (const weaponType of weaponTypes) {
for (const weapon of itemLists.get(weaponType)) {
let item_obj = itemMap.get(weapon);
if (item_obj["restrict"] && item_obj["restrict"] === "DEPRECATED") {
continue;
}
let el = document.createElement("option");
el.value = weapon;
weapon_list.appendChild(el);
}
}
// Add change listener to update weapon slots.
document.getElementById("weapon-choice").addEventListener("change", (event) => {
let item_name = event.target.value;
let item = itemMap.has(item_name) ? itemMap.get(item_name) : (getCraftFromHash(item_name) ? getCraftFromHash(item_name) : (getCustomFromHash(item_name) ? getCustomFromHash(item_name) : undefined));
if (item !== undefined && event.target.value !== "") {
document.getElementById("weapon-slots").textContent = (item["slots"] ? item["slots"] : (item.statMap !== undefined ? ( item.statMap.has("slots") ? item.statMap.get("slots") : 0): 0) )+ " slots";
} else {
document.getElementById("weapon-slots").textContent = "X slots";
}
});
decodeBuild(url_tag);
populateBuildList();
}
function getItemNameFromID(id) { function getItemNameFromID(id) {
if (redirectMap.has(id)) { if (redirectMap.has(id)) {
@ -185,13 +6,20 @@ function getItemNameFromID(id) {
return idMap.get(id); return idMap.get(id);
} }
function getTomeNameFromID(id) {
if (tomeRedirectMap.has(id)) {
return getTomeNameFromID(tomeRedirectMap.get(id));
}
return tomeIDMap.get(id);
}
function parsePowdering(powder_info) { function parsePowdering(powder_info) {
// TODO: Make this run in linear instead of quadratic time... ew // TODO: Make this run in linear instead of quadratic time... ew
let powdering = []; let powdering = [];
for (let i = 0; i < 5; ++i) { for (let i = 0; i < 5; ++i) {
let powders = ""; let powders = "";
let n_blocks = Base64.toInt(powder_info.charAt(0)); let n_blocks = Base64.toInt(powder_info.charAt(0));
console.log(n_blocks + " blocks"); // console.log(n_blocks + " blocks");
powder_info = powder_info.slice(1); powder_info = powder_info.slice(1);
for (let j = 0; j < n_blocks; ++j) { for (let j = 0; j < n_blocks; ++j) {
let block = powder_info.slice(0,5); let block = powder_info.slice(0,5);
@ -205,7 +33,7 @@ function parsePowdering(powder_info) {
} }
powdering[i] = powders; powdering[i] = powders;
} }
return powdering; return [powdering, powder_info];
} }
/* /*
@ -213,14 +41,20 @@ function parsePowdering(powder_info) {
*/ */
function decodeBuild(url_tag) { function decodeBuild(url_tag) {
if (url_tag) { if (url_tag) {
//default values
let equipment = [null, null, null, null, null, null, null, null, null]; let equipment = [null, null, null, null, null, null, null, null, null];
let tomes = [null, null, null, null, null, null, null];
let powdering = ["", "", "", "", ""]; let powdering = ["", "", "", "", ""];
let info = url_tag.split("_"); let info = url_tag.split("_");
let version = info[0]; let version = info[0];
let save_skp = false; let save_skp = false;
let skillpoints = [0, 0, 0, 0, 0]; let skillpoints = [0, 0, 0, 0, 0];
let level = 106; let level = 106;
if (version === "0" || version === "1" || version === "2" || version === "3") {
version_number = parseInt(version)
//equipment (items)
// TODO: use filters
if (version_number < 4) {
let equipments = info[1]; let equipments = info[1];
for (let i = 0; i < 9; ++i ) { for (let i = 0; i < 9; ++i ) {
let equipment_str = equipments.slice(i*3,i*3+3); let equipment_str = equipments.slice(i*3,i*3+3);
@ -228,7 +62,7 @@ function decodeBuild(url_tag) {
} }
info[1] = equipments.slice(27); info[1] = equipments.slice(27);
} }
if (version === "4") { else if (version_number == 4) {
let info_str = info[1]; let info_str = info[1];
let start_idx = 0; let start_idx = 0;
for (let i = 0; i < 9; ++i ) { for (let i = 0; i < 9; ++i ) {
@ -244,7 +78,7 @@ function decodeBuild(url_tag) {
} }
info[1] = info_str.slice(start_idx); info[1] = info_str.slice(start_idx);
} }
if (version === "5") { else if (version_number <= 6) {
let info_str = info[1]; let info_str = info[1];
let start_idx = 0; let start_idx = 0;
for (let i = 0; i < 9; ++i ) { for (let i = 0; i < 9; ++i ) {
@ -263,10 +97,17 @@ function decodeBuild(url_tag) {
} }
info[1] = info_str.slice(start_idx); info[1] = info_str.slice(start_idx);
} }
if (version === "1") { //constant in all versions
for (let i in equipment) {
setValue(equipmentInputs[i], equipment[i]);
}
//level, skill point assignments, and powdering
if (version_number == 1) {
let powder_info = info[1]; let powder_info = info[1];
powdering = parsePowdering(powder_info); let res = parsePowdering(powder_info);
} else if (version === "2") { powdering = res[0];
} else if (version_number == 2) {
save_skp = true; save_skp = true;
let skillpoint_info = info[1].slice(0, 10); let skillpoint_info = info[1].slice(0, 10);
for (let i = 0; i < 5; ++i ) { for (let i = 0; i < 5; ++i ) {
@ -274,8 +115,9 @@ function decodeBuild(url_tag) {
} }
let powder_info = info[1].slice(10); let powder_info = info[1].slice(10);
powdering = parsePowdering(powder_info); let res = parsePowdering(powder_info);
} else if (version === "3" || version === "4" || version === "5"){ powdering = res[0];
} else if (version_number <= 6){
level = Base64.toInt(info[1].slice(10,12)); level = Base64.toInt(info[1].slice(10,12));
setValue("level-choice",level); setValue("level-choice",level);
save_skp = true; save_skp = true;
@ -286,126 +128,101 @@ function decodeBuild(url_tag) {
let powder_info = info[1].slice(12); let powder_info = info[1].slice(12);
powdering = parsePowdering(powder_info); let res = parsePowdering(powder_info);
powdering = res[0];
info[1] = res[1];
}
// Tomes.
if (version == 6) {
//tome values do not appear in anything before v6.
for (let i = 0; i < 7; ++i) {
let tome_str = info[1].charAt(i);
for (let i in tomes) {
setValue(tomeInputs[i], getTomeNameFromID(Base64.toInt(tome_str)));
}
}
info[1] = info[1].slice(7);
} }
for (let i in powderInputs) { for (let i in powderInputs) {
setValue(powderInputs[i], powdering[i]); setValue(powderInputs[i], powdering[i]);
} }
for (let i in equipment) {
setValue(equipmentInputs[i], equipment[i]);
}
calculateBuild(save_skp, skillpoints); calculateBuild(save_skp, skillpoints);
} }
} }
/* Stores the entire build in a string using B64 encryption and adds it to the URL. /* Stores the entire build in a string using B64 encoding and adds it to the URL.
*/ */
function encodeBuild() { function encodeBuild() {
if (player_build) { if (player_build) {
let build_string; let build_string;
if (player_build.customItems.length > 0) { //v5 encoding
build_string = "5_"; //V6 encoding - Tomes
let crafted_idx = 0; build_version = 4;
let custom_idx = 0; build_string = "";
for (const item of player_build.items) { tome_string = "";
if (item.get("custom")) { let crafted_idx = 0;
let custom = "CI-"+encodeCustom(player_build.customItems[custom_idx],true); let custom_idx = 0;
build_string += Base64.fromIntN(custom.length, 3) + custom; for (const item of player_build.items) {
custom_idx += 1;
} else if (item.get("crafted")) { if (item.get("custom")) {
build_string += "CR-"+encodeCraft(player_build.craftedItems[crafted_idx]); let custom = "CI-"+encodeCustom(player_build.customItems[custom_idx],true);
crafted_idx += 1; build_string += Base64.fromIntN(custom.length, 3) + custom;
} else { custom_idx += 1;
build_string += Base64.fromIntN(item.get("id"), 3); build_version = Math.max(build_version, 5);
} } else if (item.get("crafted")) {
} build_string += "CR-"+encodeCraft(player_build.craftedItems[crafted_idx]);
crafted_idx += 1;
for (const skp of skp_order) { } else if (item.get("category") === "tome") {
build_string += Base64.fromIntN(getValue(skp + "-skp"), 2); // Maximum skillpoints: 2048 let tome_id = item.get("id");
} if (tome_id <= 60) {
build_string += Base64.fromIntN(player_build.level, 2); // valid normal tome. ID 61-63 is for NONE tomes.
for (const _powderset of player_build.powders) { build_version = Math.max(build_version, 6);
let n_bits = Math.ceil(_powderset.length / 6);
build_string += Base64.fromIntN(n_bits, 1); // Hard cap of 378 powders.
// Slice copy.
let powderset = _powderset.slice();
while (powderset.length != 0) {
let firstSix = powderset.slice(0,6).reverse();
let powder_hash = 0;
for (const powder of firstSix) {
powder_hash = (powder_hash << 5) + 1 + powder; // LSB will be extracted first.
}
build_string += Base64.fromIntN(powder_hash, 5);
powderset = powderset.slice(6);
}
}
} else { //v4 encoding
build_string = "4_";
let crafted_idx = 0;
for (const item of player_build.items) {
if (item.get("crafted")) {
build_string += "-"+encodeCraft(player_build.craftedItems[crafted_idx]);
crafted_idx += 1;
} else {
build_string += Base64.fromIntN(item.get("id"), 3);
}
}
for (const skp of skp_order) {
build_string += Base64.fromIntN(getValue(skp + "-skp"), 2); // Maximum skillpoints: 2048
}
build_string += Base64.fromIntN(player_build.level, 2);
for (const _powderset of player_build.powders) {
let n_bits = Math.ceil(_powderset.length / 6);
build_string += Base64.fromIntN(n_bits, 1); // Hard cap of 378 powders.
// Slice copy.
let powderset = _powderset.slice();
while (powderset.length != 0) {
let firstSix = powderset.slice(0,6).reverse();
let powder_hash = 0;
for (const powder of firstSix) {
powder_hash = (powder_hash << 5) + 1 + powder; // LSB will be extracted first.
}
build_string += Base64.fromIntN(powder_hash, 5);
powderset = powderset.slice(6);
} }
tome_string += Base64.fromIntN(tome_id, 1);
} else {
build_string += Base64.fromIntN(item.get("id"), 3);
} }
} }
return build_string;
for (const skp of skp_order) {
build_string += Base64.fromIntN(getValue(skp + "-skp"), 2); // Maximum skillpoints: 2048
}
build_string += Base64.fromIntN(player_build.level, 2);
for (const _powderset of player_build.powders) {
let n_bits = Math.ceil(_powderset.length / 6);
build_string += Base64.fromIntN(n_bits, 1); // Hard cap of 378 powders.
// Slice copy.
let powderset = _powderset.slice();
while (powderset.length != 0) {
let firstSix = powderset.slice(0,6).reverse();
let powder_hash = 0;
for (const powder of firstSix) {
powder_hash = (powder_hash << 5) + 1 + powder; // LSB will be extracted first.
}
build_string += Base64.fromIntN(powder_hash, 5);
powderset = powderset.slice(6);
}
}
build_string += tome_string;
return build_version.toString() + "_" + build_string;
} }
// this.equipment = [ this.helmet, this.chestplate, this.leggings, this.boots, this.ring1, this.ring2, this.bracelet, this.necklace ];
// let build_string = "3_" + Base64.fromIntN(player_build.helmet.get("id"), 3) +
// Base64.fromIntN(player_build.chestplate.get("id"), 3) +
// Base64.fromIntN(player_build.leggings.get("id"), 3) +
// Base64.fromIntN(player_build.boots.get("id"), 3) +
// Base64.fromIntN(player_build.ring1.get("id"), 3) +
// Base64.fromIntN(player_build.ring2.get("id"), 3) +
// Base64.fromIntN(player_build.bracelet.get("id"), 3) +
// Base64.fromIntN(player_build.necklace.get("id"), 3) +
// Base64.fromIntN(player_build.weapon.get("id"), 3);
return "";
} }
function calculateBuild(save_skp, skp){ function calculateBuild(save_skp, skp){
try { try {
let specialNames = ["Quake", "Chain_Lightning", "Curse", "Courage", "Wind_Prison"]; resetEditableIDs();
for (const sName of specialNames) { if (player_build) {
for (let i = 1; i < 6; i++) { reset_powder_specials();
let elem = document.getElementById(sName + "-" + i);
let name = sName.replace("_", " ");
if (elem.classList.contains("toggleOn")) { //toggle the pressed button off
elem.classList.remove("toggleOn");
}
}
}
if(player_build){
updateBoosts("skip", false); updateBoosts("skip", false);
updatePowderSpecials("skip", false); updatePowderSpecials("skip", false);
} }
let weaponName = getValue(equipmentInputs[8]); let weaponName = getValue(equipmentInputs[8]);
//bruh @hpp
if (weaponName.startsWith("Morph-")) { if (weaponName.startsWith("Morph-")) {
let equipment = [ "Morph-Stardust", "Morph-Steel", "Morph-Iron", "Morph-Gold", "Morph-Topaz", "Morph-Emerald", "Morph-Amethyst", "Morph-Ruby", weaponName.substring(6) ]; let equipment = [ "Morph-Stardust", "Morph-Steel", "Morph-Iron", "Morph-Gold", "Morph-Topaz", "Morph-Emerald", "Morph-Amethyst", "Morph-Ruby", weaponName.substring(6) ];
for (let i in equipment) { for (let i in equipment) {
@ -440,7 +257,6 @@ function calculateBuild(save_skp, skp){
while (input) { while (input) {
let first = input.slice(0, 2); let first = input.slice(0, 2);
let powder = powderIDs.get(first); let powder = powderIDs.get(first);
console.log(powder);
if (powder === undefined) { if (powder === undefined) {
errorederrors.push(first); errorederrors.push(first);
} else { } else {
@ -457,11 +273,24 @@ function calculateBuild(save_skp, skp){
//console.log("POWDERING: " + powdering); //console.log("POWDERING: " + powdering);
powderings.push(powdering); powderings.push(powdering);
} }
let tomes = [ null, null, null, null, null, null, null];
for (let i in tomes) {
let equip = getValue(tomeInputs[i]).trim();
if (equip === "") {
equip = "No " + tome_names[i]
}
else {
setValue(tomeInputs[i], equip);
}
tomes[i] = equip;
}
let level = document.getElementById("level-choice").value; let level = document.getElementById("level-choice").value;
player_build = new Build(level, equipment, powderings, new Map(), errors); player_build = new Build(level, equipment, powderings, new Map(), errors, tomes);
console.log(player_build); console.log(player_build);
//isn't this deprecated?
for (let i of document.getElementsByClassName("hide-container-block")) { for (let i of document.getElementsByClassName("hide-container-block")) {
i.style.display = "block"; i.style.display = "block";
} }
@ -470,21 +299,14 @@ function calculateBuild(save_skp, skp){
} }
console.log(player_build.toString()); console.log(player_build.toString());
displayEquipOrder(document.getElementById("build-order"),player_build.equip_order); displaysq2EquipOrder(document.getElementById("build-order"),player_build.equip_order);
const assigned = player_build.base_skillpoints; const assigned = player_build.base_skillpoints;
const skillpoints = player_build.total_skillpoints; const skillpoints = player_build.total_skillpoints;
for (let i in skp_order){ //big bren for (let i in skp_order){ //big bren
setText(skp_order[i] + "-skp-base", "Original Value: " + skillpoints[i]); setText(skp_order[i] + "-skp-base", "Original: " + skillpoints[i]);
} }
for (let id of editable_item_fields) {
setValue(id, player_build.statMap.get(id));
setText(id+"-base", "Original Value: " + player_build.statMap.get(id));
}
if (save_skp) { if (save_skp) {
// TODO: reduce duplicated code, @updateStats // TODO: reduce duplicated code, @updateStats
let skillpoints = player_build.total_skillpoints; let skillpoints = player_build.total_skillpoints;
@ -499,14 +321,13 @@ function calculateBuild(save_skp, skp){
player_build.assigned_skillpoints += delta_total; player_build.assigned_skillpoints += delta_total;
} }
updateEditableIDs();
calculateBuildStats(); calculateBuildStats();
setTitle();
if (player_build.errored) if (player_build.errored)
throw new ListError(player_build.errors); throw new ListError(player_build.errors);
} }
catch (error) { catch (error) {
handleBuilderError(error); console.log(error);
} }
} }
@ -586,7 +407,7 @@ function updateStats() {
let delta_total = 0; let delta_total = 0;
for (let i in skp_order) { for (let i in skp_order) {
let value = document.getElementById(skp_order[i] + "-skp").value; let value = document.getElementById(skp_order[i] + "-skp").value;
if (value === ""){value = "0"; setValue(skp_order[i] + "-skp", value)} if (value === ""){value = 0; setValue(skp_order[i] + "-skp", value)}
let manual_assigned = 0; let manual_assigned = 0;
if (value.includes("+")) { if (value.includes("+")) {
let skp = value.split("+"); let skp = value.split("+");
@ -604,15 +425,58 @@ function updateStats() {
player_build.assigned_skillpoints += delta_total; player_build.assigned_skillpoints += delta_total;
if(player_build){ if(player_build){
updatePowderSpecials("skip", false); updatePowderSpecials("skip", false);
updateArmorPowderSpecials("skip", false);
updateBoosts("skip", false); updateBoosts("skip", false);
} for (let id of editable_item_fields) {
for (let id of editable_item_fields) { player_build.statMap.set(id, parseInt(getValue(id)));
player_build.statMap.set(id, parseInt(getValue(id))); }
} }
player_build.aggregateStats(); player_build.aggregateStats();
console.log(player_build.statMap); console.log(player_build.statMap);
calculateBuildStats(); calculateBuildStats();
} }
/* Updates all IDs in the edit IDs section. Resets each input and original value text to the correct text according to the current build.
*/
function updateEditableIDs() {
if (player_build) {
for (const id of editable_item_fields) {
let edit_input = document.getElementById(id);
let val = player_build.statMap.get(id);
edit_input.value = val;
edit_input.placeholder = val;
let value_label = document.getElementById(id + "-base");
value_label.textContent = "Original Value: " + val;
//a hack to make resetting easier
value_label.value = val;
}
}
}
/* Resets all IDs in the edit IDs section to their "original" values.
*/
function resetEditableIDs() {
if (player_build) {
for (const id of editable_item_fields) {
let edit_input = document.getElementById(id);
let value_label = document.getElementById(id + "-base");
edit_input.value = value_label.value;
edit_input.placeholder = value_label.value;
}
} else {
//no player build, reset to 0
for (const id of editable_item_fields) {
let edit_input = document.getElementById(id);
edit_input.value = 0;
edit_input.placeholder = 0;
}
}
}
/* Updates all spell boosts /* Updates all spell boosts
*/ */
function updateBoosts(buttonId, recalcStats) { function updateBoosts(buttonId, recalcStats) {
@ -655,7 +519,7 @@ function updateBoosts(buttonId, recalcStats) {
} }
} }
/* Updates all powder special boosts /* Updates ACTIVE powder special boosts (weapons)
*/ */
function updatePowderSpecials(buttonId, recalcStats) { function updatePowderSpecials(buttonId, recalcStats) {
//console.log(player_build.statMap); //console.log(player_build.statMap);
@ -740,8 +604,76 @@ function updatePowderSpecials(buttonId, recalcStats) {
if (recalcStats) { if (recalcStats) {
calculateBuildStats(); calculateBuildStats();
} }
displayPowderSpecials(document.getElementById("powder-special-stats"), powderSpecials, player_build); displaysq2PowderSpecials(document.getElementById("powder-special-stats"), powderSpecials, player_build, true);
} }
/* Updates PASSIVE powder special boosts (armors)
*/
function updateArmorPowderSpecials(elem_id, recalc_stats) {
//we only update the powder special + external stats if the player has a build
if (elem_id !== "skip") {
if (player_build !== undefined && player_build.weapon !== undefined && player_build.weapon.get("name") !== "No Weapon") {
let wynn_elem = elem_id.split("_")[0]; //str, dex, int, def, agi
//update the label associated w/ the slider
let elem = document.getElementById(elem_id);
let label = document.getElementById(elem_id + "_label");
let prev_label = document.getElementById(elem_id + "_prev");
let value = elem.value;
//for use in editing build stats
let prev_value = prev_label.value;
let value_diff = value - prev_value;
//update the "previous" label
prev_label.value = value;
label.textContent = label.textContent.split(":")[0] + ": " + value;
let dmg_id = elem_chars[skp_names.indexOf(wynn_elem)] + "DamPct";
let new_dmgboost = player_build.externalStats.get(dmg_id) + value_diff;
//update build external stats - the second one is the relevant one for damage calc purposes
player_build.externalStats.set(dmg_id, new_dmgboost);
player_build.externalStats.get("damageBonus")[skp_names.indexOf(wynn_elem)] = new_dmgboost;
//update the slider's graphics
let bg_color = elem_colors[skp_names.indexOf(wynn_elem)];
let pct = Math.round(100 * value / powderSpecialStats[skp_names.indexOf(wynn_elem)].cap);
elem.style.background = `linear-gradient(to right, ${bg_color}, ${bg_color} ${pct}%, #AAAAAA ${pct}%, #AAAAAA 100%)`;
}
} else {
if (player_build !== undefined) {
for (let i = 0; i < skp_names.length; ++i) {
skp_name = skp_names[i];
skp_char = elem_chars[i];
player_build.externalStats.set(skp_char + "DamPct", player_build.externalStats.get(skp_char + "DamPct") - document.getElementById(skp_name+"_boost_armor").value);
player_build.externalStats.get("damageBonus")[i] -= document.getElementById(skp_name+"_boost_armor").value;
}
}
}
if (recalc_stats && player_build) {
//calc build stats and display powder special
calculateBuildStats();
// displaysq2PowderSpecials(document.getElementById("powder-special-stats"), powderSpecials, player_build, true);
}
}
function resetArmorPowderSpecials() {
for (const skp of skp_names) {
document.getElementById(skp + "_boost_armor").value = 0;
document.getElementById(skp + "_boost_armor_prev").value = 0;
document.getElementById(skp + "_boost_armor").style.background = `linear-gradient(to right, #AAAAAA, #AAAAAA 0%, #AAAAAA 100%)`;
document.getElementById(skp + "_boost_armor_label").textContent = `% ${capitalizeFirst(elem_names[skp_names.indexOf(skp)])} Damage Boost: 0`
}
}
/* Calculates all build statistics and updates the entire display. /* Calculates all build statistics and updates the entire display.
*/ */
function calculateBuildStats() { function calculateBuildStats() {
@ -749,27 +681,29 @@ function calculateBuildStats() {
const skillpoints = player_build.total_skillpoints; const skillpoints = player_build.total_skillpoints;
let skp_effects = ["% more damage dealt.","% chance to crit.","% spell cost reduction.","% less damage taken.","% chance to dodge."]; let skp_effects = ["% more damage dealt.","% chance to crit.","% spell cost reduction.","% less damage taken.","% chance to dodge."];
for (let i in skp_order){ //big bren for (let i in skp_order){ //big bren
setText(skp_order[i] + "-skp-assign", "Manually Assigned: " + assigned[i]); setText(skp_order[i] + "-skp-assign", "Assign: " + assigned[i]);
setValue(skp_order[i] + "-skp", skillpoints[i]); setValue(skp_order[i] + "-skp", skillpoints[i]);
let linebreak = document.createElement("br"); let linebreak = document.createElement("br");
linebreak.classList.add("itemp"); linebreak.classList.add("itemp");
document.getElementById(skp_order[i] + "-skp-label"); document.getElementById(skp_order[i] + "-skp-label");
setText(skp_order[i] + "-skp-pct", (skillPointsToPercentage(skillpoints[i])*100).toFixed(1).concat(skp_effects[i])); setText(skp_order[i] + "-skp-pct", (skillPointsToPercentage(skillpoints[i])*100).toFixed(1).concat(skp_effects[i]));
document.getElementById(skp_order[i]+"-warnings").textContent = ''
if (assigned[i] > 100) { if (assigned[i] > 100) {
let skp_warning = document.createElement("p"); let skp_warning = document.createElement("p");
skp_warning.classList.add("warning"); skp_warning.classList.add("warning");
skp_warning.textContent += "WARNING: Cannot assign " + assigned[i] + " skillpoints in " + ["Strength","Dexterity","Intelligence","Defense","Agility"][i] + " manually."; skp_warning.classList.add("small-text")
document.getElementById(skp_order[i]+"-skp-pct").appendChild(skp_warning); skp_warning.textContent += "Cannot assign " + assigned[i] + " skillpoints in " + ["Strength","Dexterity","Intelligence","Defense","Agility"][i] + " manually.";
document.getElementById(skp_order[i]+"-warnings").textContent = ''
document.getElementById(skp_order[i]+"-warnings").appendChild(skp_warning);
} }
} }
let summarybox = document.getElementById("summary-box"); let summarybox = document.getElementById("summary-box");
summarybox.textContent = ""; summarybox.textContent = "";
let skpRow = document.createElement("p"); let skpRow = document.createElement("p");
let td = document.createElement("p");
let remainingSkp = document.createElement("p"); let remainingSkp = document.createElement("p");
remainingSkp.classList.add("center"); remainingSkp.classList.add("scaled-font");
let remainingSkpTitle = document.createElement("b"); let remainingSkpTitle = document.createElement("b");
remainingSkpTitle.textContent = "Assigned " + player_build.assigned_skillpoints + " skillpoints. Remaining skillpoints: "; remainingSkpTitle.textContent = "Assigned " + player_build.assigned_skillpoints + " skillpoints. Remaining skillpoints: ";
let remainingSkpContent = document.createElement("b"); let remainingSkpContent = document.createElement("b");
@ -783,13 +717,12 @@ function calculateBuildStats() {
summarybox.append(skpRow); summarybox.append(skpRow);
summarybox.append(remainingSkp); summarybox.append(remainingSkp);
if(player_build.assigned_skillpoints > levelToSkillPoints(player_build.level)){ if(player_build.assigned_skillpoints > levelToSkillPoints(player_build.level)){
let skpWarning = document.createElement("p"); let skpWarning = document.createElement("span");
//skpWarning.classList.add("itemp"); //skpWarning.classList.add("itemp");
skpWarning.classList.add("warning"); skpWarning.classList.add("warning");
skpWarning.classList.add("itemp");
skpWarning.textContent = "WARNING: Too many skillpoints need to be assigned!"; skpWarning.textContent = "WARNING: Too many skillpoints need to be assigned!";
let skpCount = document.createElement("p"); let skpCount = document.createElement("p");
skpCount.classList.add("itemp"); skpCount.classList.add("warning");
skpCount.textContent = "For level " + (player_build.level>101 ? "101+" : player_build.level) + ", there are only " + levelToSkillPoints(player_build.level) + " skill points available."; skpCount.textContent = "For level " + (player_build.level>101 ? "101+" : player_build.level) + ", there are only " + levelToSkillPoints(player_build.level) + " skill points available.";
summarybox.append(skpWarning); summarybox.append(skpWarning);
summarybox.append(skpCount); summarybox.append(skpCount);
@ -826,7 +759,6 @@ function calculateBuildStats() {
const bonus = sets[setName].bonuses[count-1]; const bonus = sets[setName].bonuses[count-1];
// console.log(setName); // console.log(setName);
if (bonus["illegal"]) { if (bonus["illegal"]) {
console.log("mmmm");
let setWarning = document.createElement("p"); let setWarning = document.createElement("p");
setWarning.classList.add("itemp"); setWarning.classList.add("itemp");
setWarning.classList.add("warning"); setWarning.classList.add("warning");
@ -836,30 +768,32 @@ function calculateBuildStats() {
} }
for (let i in player_build.items) { for (let i in player_build.items) {
displayExpandedItem(player_build.items[i], buildFields[i]); displaysq2ExpandedItem(player_build.items[i], buildFields[i]);
collapse_element("#"+equipment_keys[i]+"-tooltip");
} }
displayBuildStats("build-overall-stats",player_build); displaysq2ArmorStats(player_build);
displaySetBonuses("set-info",player_build); displaysq2BuildStats('overall-stats', player_build, build_all_display_commands);
displayNextCosts("int-info",player_build); displaysq2BuildStats("offensive-stats",player_build, build_offensive_display_commands);
displaysq2SetBonuses("set-info",player_build);
displaysq2WeaponStats(player_build);
let meleeStats = player_build.getMeleeStats(); let meleeStats = player_build.getMeleeStats();
displayMeleeDamage(document.getElementById("build-melee-stats"), document.getElementById("build-melee-statsAvg"), meleeStats); displaysq2MeleeDamage(document.getElementById("build-melee-stats"), document.getElementById("build-melee-statsAvg"), meleeStats);
displayDefenseStats(document.getElementById("build-defense-stats"),player_build); displaysq2DefenseStats(document.getElementById("defensive-stats"),player_build);
displayPoisonDamage(document.getElementById("build-poison-stats"),player_build); displaysq2PoisonDamage(document.getElementById("build-poison-stats"),player_build);
let spells = spell_table[player_build.weapon.get("type")]; let spells = spell_table[player_build.weapon.get("type")];
for (let i = 0; i < 4; ++i) { for (let i = 0; i < 4; ++i) {
let parent_elem = document.getElementById("spell"+i+"-info"); let parent_elem = document.getElementById("spell"+i+"-info");
let overallparent_elem = document.getElementById("spell"+i+"-infoAvg"); let overallparent_elem = document.getElementById("spell"+i+"-infoAvg");
displaySpellDamage(parent_elem, overallparent_elem, player_build, spells[i], i+1); displaysq2SpellDamage(parent_elem, overallparent_elem, player_build, spells[i], i+1);
} }
location.hash = encodeBuild(); location.hash = encodeBuild();
clear_highlights(); clear_highlights();
updateOGP();
} }
function copyBuild() { function copyBuild() {
@ -971,7 +905,21 @@ function toggleID() {
} }
} }
function toggleButton(button_id) {
let button = document.getElementById(button_id);
if (button) {
if (button.classList.contains("toggleOn")) {
button.classList.remove("toggleOn");
} else {
button.classList.add("toggleOn");
}
}
}
function optimizeStrDex() { function optimizeStrDex() {
if (!player_build) {
return;
}
const remaining = levelToSkillPoints(player_build.level) - player_build.assigned_skillpoints; const remaining = levelToSkillPoints(player_build.level) - player_build.assigned_skillpoints;
const base_skillpoints = player_build.base_skillpoints; const base_skillpoints = player_build.base_skillpoints;
const max_str_boost = 100 - base_skillpoints[0]; const max_str_boost = 100 - base_skillpoints[0];
@ -1061,7 +1009,6 @@ function optimizeStrDex() {
try { try {
calculateBuildStats(); calculateBuildStats();
setTitle();
if (player_build.errored) if (player_build.errored)
throw new ListError(player_build.errors); throw new ListError(player_build.errors);
} }
@ -1071,8 +1018,20 @@ function optimizeStrDex() {
} }
// TODO: Learn and use await // TODO: Learn and use await
function init() {
console.log("builder.js init");
init_autocomplete();
decodeBuild(url_tag);
for (const i of equipment_keys) {
update_field(i);
}
}
function init2() { function init2() {
load_ing_init(init); load_ing_init(init);
} }
load_init(init2); function init3() {
updateOGP(); load_tome_init(init2)
}
load_init(init3);

View file

@ -1,5 +1,3 @@
let _ALL_NODES = new Map();
class ComputeNode { class ComputeNode {
/** /**
* Make a generic compute node. * Make a generic compute node.
@ -8,10 +6,6 @@ class ComputeNode {
* @param name : Name of the node (string). Must be unique. Must "fit in" a JS string (terminated by single quotes). * @param name : Name of the node (string). Must be unique. Must "fit in" a JS string (terminated by single quotes).
*/ */
constructor(name) { constructor(name) {
if (_ALL_NODES.has(name)) {
throw 'Duplicate node name: ' + name;
}
_ALL_NODES.set(name, this)
this.inputs = []; this.inputs = [];
this.children = []; this.children = [];
this.value = 0; this.value = 0;
@ -65,10 +59,9 @@ class ComputeNode {
/** /**
* Schedule a ComputeNode to be updated. * Schedule a ComputeNode to be updated.
* *
* @param node_name : ComputeNode name to schedule an update for. * @param node : ComputeNode to schedule an update for.
*/ */
function calcSchedule(node_name) { function calcSchedule(node) {
node = _ALL_NODES.get(node_name);
if (node.update_task !== null) { if (node.update_task !== null) {
clearTimeout(node.update_task); clearTimeout(node.update_task);
} }
@ -92,7 +85,7 @@ class ItemInputNode extends ComputeNode {
*/ */
constructor(name, item_input_field, none_item) { constructor(name, item_input_field, none_item) {
super(name); super(name);
this.input_field.setAttribute("onInput", "calcSchedule('"+name+"');"); this.input_field.setAttribute("input", () => calcSchedule(this));
this.input_field = item_input_field; this.input_field = item_input_field;
this.none_item = expandItem(none_item); this.none_item = expandItem(none_item);
} }

View file

@ -1,4 +1,3 @@
let reversedIDs = [ "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4" ];
let colorMap = new Map( let colorMap = new Map(
[ [
["Normal", "#fff"], ["Normal", "#fff"],

View file

@ -1,13 +1,3 @@
let weapon_keys = ['dagger', 'wand', 'bow', 'relik', 'spear'];
let armor_keys = ['helmet', 'chestplate', 'leggings', 'boots'];
let skp_keys = ['str', 'dex', 'int', 'def', 'agi'];
let accessory_keys= ['ring1', 'ring2', 'bracelet', 'necklace'];
let powderable_keys = ['helmet', 'chestplate', 'leggings', 'boots', 'weapon'];
let equipment_keys = ['helmet', 'chestplate', 'leggings', 'boots', 'ring1', 'ring2', 'bracelet', 'necklace', 'weapon'].concat(tome_keys);
let powder_keys = ['e', 't', 'w', 'f', 'a'];
let spell_disp = ['spell0-info', 'spell1-info', 'spell2-info', 'spell3-info'];
let other_disp = ['build-order', 'set-info', 'int-info'];
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
@ -202,7 +192,7 @@ function update_field(field) {
document.querySelector("#"+field+"-powder").classList.add("is-invalid"); document.querySelector("#"+field+"-powder").classList.add("is-invalid");
} else { } else {
for (i = 0; i < powder_string.length / 2; i++) { for (i = 0; i < powder_string.length / 2; i++) {
if (powder_keys.includes(powder_string.substring(i*2, i*2+2).split("")[0]) == false || isNaN(powder_string.substring(i*2, i*2+2).split("")[1]) || parseInt(powder_string.substring(i*2, i*2+2).split("")[1]) < 1 || parseInt(powder_string.substring(i*2, i*2+2).split("")[1]) > 6) { if (skp_elements.includes(powder_string.substring(i*2, i*2+2).split("")[0]) == false || isNaN(powder_string.substring(i*2, i*2+2).split("")[1]) || parseInt(powder_string.substring(i*2, i*2+2).split("")[1]) < 1 || parseInt(powder_string.substring(i*2, i*2+2).split("")[1]) > 6) {
document.querySelector("#"+field+"-powder").classList.add("is-invalid"); document.querySelector("#"+field+"-powder").classList.add("is-invalid");
} }
} }
@ -239,7 +229,7 @@ function toggle_spell_tab(tab) {
} }
function toggle_boost_tab(tab) { function toggle_boost_tab(tab) {
for (const i of skp_keys) { for (const i of skp_order) {
document.querySelector("#"+i+"-boost").style.display = "none"; document.querySelector("#"+i+"-boost").style.display = "none";
document.getElementById(i + "-boost-tab").classList.remove("selected-btn"); document.getElementById(i + "-boost-tab").classList.remove("selected-btn");
} }

View file

@ -5,25 +5,16 @@ const url_tag = location.hash.slice(1);
const BUILD_VERSION = "7.0.19"; const BUILD_VERSION = "7.0.19";
// function setTitle() {
// let text;
// if (url_base.includes("hppeng-wynn")) {
// text = "WynnBuilder UNSTABLE version "+BUILD_VERSION+" (db version "+DB_VERSION+")";
// }
// else {
// text = "WynnBuilder version "+BUILD_VERSION+" (db version "+DB_VERSION+")";
// document.getElementById("header").classList.add("funnynumber");
// }
// document.getElementById("header").textContent = text;
// }
//
// setTitle();
let player_build; let player_build;
// THIS IS SUPER DANGEROUS, WE SHOULD NOT BE KEEPING THIS IN SO MANY PLACES // THIS IS SUPER DANGEROUS, WE SHOULD NOT BE KEEPING THIS IN SO MANY PLACES
let editable_item_fields = [ "sdPct", "sdRaw", "mdPct", "mdRaw", "poison", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "hprRaw", "hprPct", "hpBonus", "atkTier", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4" ]; let editable_item_fields = [ "sdPct", "sdRaw", "mdPct", "mdRaw", "poison",
"fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct",
"fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct",
"hprRaw", "hprPct", "hpBonus", "atkTier",
"spPct1", "spRaw1", "spPct2", "spRaw2",
"spPct3", "spRaw3", "spPct4", "spRaw4" ];
let editable_elems = []; let editable_elems = [];