From 8db34d68a75f6743308d19d928a756325c4426e8 Mon Sep 17 00:00:00 2001 From: hppeng Date: Sun, 19 Jun 2022 09:49:04 -0700 Subject: [PATCH] Almost working spell damage calculation --- js/build.js | 45 +++++++-------- js/build_constants.js | 2 +- js/build_encode_decode.js | 26 ++++++++- js/builder.js | 38 +++++-------- js/builder_graph.js | 113 +++++++++++++++++++++++++++++++++++--- js/computation_graph.js | 29 +++++----- js/damage_calc.js | 19 +------ js/load.js | 21 +++++-- js/skillpoints.js | 9 +-- js/sq2display.js | 24 ++++---- 10 files changed, 212 insertions(+), 114 deletions(-) diff --git a/js/build.js b/js/build.js index 447162d..00300c1 100644 --- a/js/build.js +++ b/js/build.js @@ -127,7 +127,9 @@ class Build{ this.weapon = weapon; this.items = this.equipment.concat([this.weapon]).concat(this.tomes); // return [equip_order, best_skillpoints, final_skillpoints, best_total]; - let result = calculate_skillpoints(this.equipment.concat(this.tomes), this.weapon); + + // calc skillpoints requires statmaps only + let result = calculate_skillpoints(this.equipment.concat(this.tomes).map((x) => x.statMap), this.weapon.statMap); console.log(result); this.equip_order = result[0]; // How many skillpoints the player had to assign (5 number) @@ -165,8 +167,9 @@ class Build{ */ getMeleeStats(){ const stats = this.statMap; - if (this.weapon.get("tier") === "Crafted") { - stats.set("damageBases", [this.weapon.get("nDamBaseHigh"),this.weapon.get("eDamBaseHigh"),this.weapon.get("tDamBaseHigh"),this.weapon.get("wDamBaseHigh"),this.weapon.get("fDamBaseHigh"),this.weapon.get("aDamBaseHigh")]); + const weapon_stats = this.weapon.statMap; + if (weapon_stats.get("tier") === "Crafted") { + stats.set("damageBases", [weapon_stats.get("nDamBaseHigh"),weapon_stats.get("eDamBaseHigh"),weapon_stats.get("tDamBaseHigh"),weapon_stats.get("wDamBaseHigh"),weapon_stats.get("fDamBaseHigh"),weapon_stats.get("aDamBaseHigh")]); } let adjAtkSpd = attackSpeeds.indexOf(stats.get("atkSpd")) + stats.get("atkTier"); if(adjAtkSpd > 6){ @@ -176,13 +179,13 @@ class Build{ } let damage_mult = 1; - if (this.weapon.get("type") === "relik") { + 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. //In all seriousness 99% is because wynn uses 0.33 to estimate dividing the damage by 3 to split damage between 3 beams. } // 0spellmult for melee damage. - let results = calculateSpellDamage(stats, [100, 0, 0, 0, 0, 0], stats.get("mdRaw"), stats.get("mdPct") + this.externalStats.get("mdPct"), 0, this.weapon, this.total_skillpoints, damage_mult * this.damageMultiplier, this.externalStats); + let results = calculateSpellDamage(stats, [100, 0, 0, 0, 0, 0], stats.get("mdRaw"), stats.get("mdPct"), 0, this.weapon.statMap, this.total_skillpoints, damage_mult * this.damageMultiplier); let dex = this.total_skillpoints[1]; @@ -217,8 +220,8 @@ class Build{ defenseStats.push(totalHp); //EHP let ehp = [totalHp, totalHp]; - let defMult = classDefenseMultipliers.get(this.weapon.get("type")); - ehp[0] /= ((1-def_pct)*(1-agi_pct)*(2-defMult)*(2-this.defenseMultiplier)); + let defMult = classDefenseMultipliers.get(this.weapon.statMap.get("type")); + ehp[0] /= ((1-def_pct)*(1-agi_pct)*(2-defMult)*(2-this.defenseMultiplier)); ehp[1] /= ((1-def_pct)*(2-defMult)*(2-this.defenseMultiplier)); defenseStats.push(ehp); //HPR @@ -259,26 +262,27 @@ class Build{ let major_ids = new Set(); for (const item of this.items){ - for (let [id, value] of item.get("maxRolls")) { + const item_stats = item.statMap; + for (let [id, value] of item_stats.get("maxRolls")) { if (staticIDs.includes(id)) { continue; } statMap.set(id,(statMap.get(id) || 0)+value); } for (const staticID of staticIDs) { - if (item.get(staticID)) { - statMap.set(staticID, statMap.get(staticID) + item.get(staticID)); + if (item_stats.get(staticID)) { + statMap.set(staticID, statMap.get(staticID) + item_stats.get(staticID)); } } - if (item.get("majorIds")) { - for (const major_id of item.get("majorIds")) { + if (item_stats.get("majorIds")) { + for (const major_id of item_stats.get("majorIds")) { major_ids.add(major_id); } } } statMap.set("activeMajorIDs", major_ids); for (const [setName, count] of this.activeSetCounts) { - const bonus = sets[setName].bonuses[count-1]; + const bonus = sets.get(setName).bonuses[count-1]; for (const id in bonus) { if (skp_order.includes(id)) { // pass. Don't include skillpoints in ids @@ -291,16 +295,8 @@ class Build{ statMap.set("poisonPct", 100); // The stuff relevant for damage calculation!!! @ferricles - statMap.set("atkSpd", this.weapon.get("atkSpd")); + statMap.set("atkSpd", this.weapon.statMap.get("atkSpd")); - for (const x of skp_elements) { - this.externalStats.set(x + "DamPct", 0); - } - this.externalStats.set("mdPct", 0); - this.externalStats.set("sdPct", 0); - this.externalStats.set("damageBonus", [0, 0, 0, 0, 0]); - this.externalStats.set("defBonus",[0, 0, 0, 0, 0]); - this.externalStats.set("poisonPct", 0); this.statMap = statMap; this.aggregateStats(); @@ -308,10 +304,11 @@ class Build{ aggregateStats() { let statMap = this.statMap; - statMap.set("damageRaw", [this.weapon.get("nDam"), this.weapon.get("eDam"), this.weapon.get("tDam"), this.weapon.get("wDam"), this.weapon.get("fDam"), this.weapon.get("aDam")]); + let weapon_stats = this.weapon.statMap; + statMap.set("damageRaw", [weapon_stats.get("nDam"), weapon_stats.get("eDam"), weapon_stats.get("tDam"), weapon_stats.get("wDam"), weapon_stats.get("fDam"), weapon_stats.get("aDam")]); statMap.set("damageBonus", [statMap.get("eDamPct"), statMap.get("tDamPct"), statMap.get("wDamPct"), statMap.get("fDamPct"), statMap.get("aDamPct")]); statMap.set("defRaw", [statMap.get("eDef"), statMap.get("tDef"), statMap.get("wDef"), statMap.get("fDef"), statMap.get("aDef")]); statMap.set("defBonus", [statMap.get("eDefPct"), statMap.get("tDefPct"), statMap.get("wDefPct"), statMap.get("fDefPct"), statMap.get("aDefPct")]); - statMap.set("defMult", classDefenseMultipliers.get(this.weapon.get("type"))); + statMap.set("defMult", classDefenseMultipliers.get(weapon_stats.get("type"))); } } diff --git a/js/build_constants.js b/js/build_constants.js index fbcbb3f..2983328 100644 --- a/js/build_constants.js +++ b/js/build_constants.js @@ -88,7 +88,7 @@ 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 = [ +let powder_inputs = [ "helmet-powder", "chestplate-powder", "leggings-powder", diff --git a/js/build_encode_decode.js b/js/build_encode_decode.js index 9b168b1..0929e4e 100644 --- a/js/build_encode_decode.js +++ b/js/build_encode_decode.js @@ -1,3 +1,25 @@ +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); + 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); + six_powders >>>= 5; + } + powder_info = powder_info.slice(5); + } + powdering[i] = powders; + } + return [powdering, powder_info]; +} /* * Populate fields based on url, and calculate build. @@ -107,8 +129,8 @@ function decodeBuild(url_tag) { info[1] = info[1].slice(7); } - for (let i in powderInputs) { - setValue(powderInputs[i], powdering[i]); + for (let i in powder_inputs) { + setValue(powder_inputs[i], powdering[i]); } } } diff --git a/js/builder.js b/js/builder.js index 249bf32..fcdf850 100644 --- a/js/builder.js +++ b/js/builder.js @@ -12,29 +12,6 @@ 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); - 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); - six_powders >>>= 5; - } - powder_info = powder_info.slice(5); - } - powdering[i] = powders; - } - return [powdering, powder_info]; -} - function populateBuildList() { const buildList = document.getElementById("build-choice"); const savedBuilds = window.localStorage.getItem("builds") === null ? {} : JSON.parse(window.localStorage.getItem("builds")); @@ -139,6 +116,21 @@ function toggle_tab(tab) { } } + +let tabs = ['overall-stats', 'offensive-stats', 'defensive-stats']; +function show_tab(tab) { + //console.log(itemFilters) + + //hide all tabs, then show the tab of the div clicked and highlight the correct button + for (const i in tabs) { + document.querySelector("#" + tabs[i]).style.display = "none"; + document.getElementById("tab-" + tabs[i].split("-")[0] + "-btn").classList.remove("selected-btn"); + } + document.querySelector("#" + tab).style.display = ""; + document.getElementById("tab-" + tab.split("-")[0] + "-btn").classList.add("selected-btn"); +} + + // TODO: Learn and use await function init() { console.log("builder.js init"); diff --git a/js/builder_graph.js b/js/builder_graph.js index 111cd92..c1d80d4 100644 --- a/js/builder_graph.js +++ b/js/builder_graph.js @@ -42,14 +42,71 @@ class BuildAssembleNode extends ComputeNode { ]; let weapon = input_map.get('weapon-input'); let level = input_map.get('level-input'); - console.log('build node run'); + + let all_none = weapon.statMap.has('NONE'); + for (const item of equipments) { + all_none = all_none && item.statMap.has('NONE'); + } + if (all_none) { + return null; + } return new Build(level, equipments, [], weapon); } } +class PowderInputNode extends InputNode { + + constructor(name, input_field) { + super(name, input_field); + } + + compute_func(input_map) { + // TODO: haha improve efficiency to O(n) dumb + // also, error handling is missing + let input = this.input_field.value.trim(); + let powdering = []; + let errorederrors = []; + while (input) { + let first = input.slice(0, 2); + let powder = powderIDs.get(first); + if (powder === undefined) { + return null; + } else { + powdering.push(powder); + } + input = input.slice(2); + } + //console.log("POWDERING: " + powdering); + return powdering; + } +} + +class SpellDamageCalcNode extends ComputeNode { + constructor(spell_num) { + super("builder-spell"+spell_num+"-calc"); + this.spell_idx = spell_num; + } + + compute_func(input_map) { + // inputs: + let weapon = new Map(input_map.get('weapon-input').statMap); + let build = input_map.get('build'); + let weapon_powder = input_map.get('weapon-powder'); + weapon.set("powders", weapon_powder); + const i = this.spell_idx; + let spell = spell_table[weapon.get("type")][i]; + let parent_elem = document.getElementById("spell"+i+"-info"); + let overallparent_elem = document.getElementById("spell"+i+"-infoAvg"); + displaysq2SpellDamage(parent_elem, overallparent_elem, build, spell, i+1, weapon); + } +} + let item_nodes = []; +let powder_nodes = []; +let spell_nodes = []; document.addEventListener('DOMContentLoaded', function() { + // Bind item input fields to input nodes, and some display stuff (for auto colorizing stuff). for (const [eq, none_item] of zip(equipment_fields, none_items)) { let input_field = document.getElementById(eq+"-choice"); let item_image = document.getElementById(eq+"-img"); @@ -57,28 +114,70 @@ document.addEventListener('DOMContentLoaded', function() { let item_input = new ItemInputNode(eq+'-input', input_field, none_item); item_nodes.push(item_input); new ItemInputDisplayNode(eq+'-display', input_field, item_image).link_to(item_input); - new PrintNode(eq+'-debug').link_to(item_input); + //new PrintNode(eq+'-debug').link_to(item_input); //document.querySelector("#"+eq+"-tooltip").setAttribute("onclick", "collapse_element('#"+ eq +"-tooltip');"); //toggle_plus_minus('" + eq + "-pm'); - } + + // weapon image changer node. let weapon_image = document.getElementById("weapon-img"); new WeaponDisplayNode('weapon-type', weapon_image).link_to(item_nodes[8]); - let level_input = new InputNode('level-input', document.getElementById('level-choice')); - new PrintNode('lvl-debug').link_to(level_input); + // Level input node. + let level_input = new InputNode('level-input', document.getElementById('level-choice')); + + // "Build" now only refers to equipment and level (no powders). Powders are injected before damage calculation / stat display. let build_node = new BuildAssembleNode(); for (const input of item_nodes) { build_node.link_to(input); } build_node.link_to(level_input); + + + for (const input of powder_inputs) { + powder_nodes.push(new PowderInputNode(input, document.getElementById(input))); + } + + for (let i = 0; i < 4; ++i) { + let spell_node = new SpellDamageCalcNode(i); + spell_node.link_to(item_nodes[8], 'weapon-input'); + spell_node.link_to(build_node, 'build'); + spell_node.link_to(powder_nodes[4], 'weapon-powder'); + spell_nodes.push(spell_node); + } + console.log("Set up graph"); + let masonry = Macy({ + container: "#masonry-container", + columns: 1, + mobileFirst: true, + breakAt: { + 1200: 4, + }, + margin: { + x: 20, + y: 20, + } + + }); + + let search_masonry = Macy({ + container: "#search-results", + columns: 1, + mobileFirst: true, + breakAt: { + 1200: 4, + }, + margin: { + x: 20, + y: 20, + } + + }); }); // autocomplete initialize function init_autocomplete() { - console.log("autocomplete init"); - console.log(itemLists) let dropdowns = new Map(); for (const eq of equipment_keys) { if (tome_keys.includes(eq)) { diff --git a/js/computation_graph.js b/js/computation_graph.js index 155d95a..45ba267 100644 --- a/js/computation_graph.js +++ b/js/computation_graph.js @@ -7,13 +7,14 @@ class ComputeNode { */ constructor(name) { this.inputs = []; // parent nodes + this.input_translation = new Map(); this.children = []; - this.value = 0; + this.value = null; this.name = name; this.update_task = null; this.update_time = Date.now(); this.fail_cb = false; // Set to true to force updates even if parent failed. - this.dirty = false; + this.dirty = true; this.inputs_dirty = new Map(); this.inputs_dirty_count = 0; } @@ -32,7 +33,7 @@ class ComputeNode { } let calc_inputs = new Map(); for (const input of this.inputs) { - calc_inputs.set(input.name, input.value); + calc_inputs.set(this.input_translation.get(input.name), input.value); } this.value = this.compute_func(calc_inputs); this.dirty = false; @@ -41,18 +42,6 @@ class ComputeNode { } } - /** - * Set this node's value directly. Notifies children. - */ - set_value(value) { - let timestamp = Date.now(); - this.update_time = timestamp; - this.value = value; - for (const child of this.children) { - child.set_input(this.name, this.value, timestamp); - } - } - /** * Mark parent as not dirty. Propagates calculation if all inputs are present. */ @@ -99,8 +88,10 @@ class ComputeNode { throw "no compute func specified"; } - link_to(parent_node) { + link_to(parent_node, link_name) { this.inputs.push(parent_node) + link_name = (link_name !== undefined) ? link_name : parent_node.name; + this.input_translation.set(parent_node.name, link_name); this.inputs_dirty.set(parent_node.name, parent_node.dirty); if (parent_node.dirty) { this.inputs_dirty_count += 1; @@ -147,6 +138,7 @@ class InputNode extends ComputeNode { super(name); this.input_field = input_field; this.input_field.addEventListener("input", () => calcSchedule(this)); + calcSchedule(this); } compute_func(input_map) { @@ -168,6 +160,7 @@ class ItemInputNode extends InputNode { constructor(name, item_input_field, none_item) { super(name, item_input_field); this.none_item = new Item(none_item); + this.none_item.statMap.set('NONE', true); } compute_func(input_map) { @@ -231,9 +224,13 @@ class ItemInputDisplayNode extends ComputeNode { return null; } + if (item.statMap.has('NONE')) { + return null; + } const tier = item.statMap.get('tier'); this.input_field.classList.add(tier); this.image.classList.add(tier + "-shadow"); + return null; } } diff --git a/js/damage_calc.js b/js/damage_calc.js index 564ab2e..6aa7c64 100644 --- a/js/damage_calc.js +++ b/js/damage_calc.js @@ -1,29 +1,12 @@ const damageMultipliers = new Map([ ["allytotem", .15], ["yourtotem", .35], ["vanish", 0.80], ["warscream", 0.10], ["bash", 0.50] ]); // Calculate spell damage given a spell elemental conversion table, and a spell multiplier. // If spell mult is 0, its melee damage and we don't multiply by attack speed. -// externalStats should be a map -function calculateSpellDamage(stats, spellConversions, rawModifier, pctModifier, spellMultiplier, weapon, total_skillpoints, damageMultiplier, externalStats) { +function calculateSpellDamage(stats, spellConversions, rawModifier, pctModifier, spellMultiplier, weapon, total_skillpoints, damageMultiplier) { let buildStats = new Map(stats); let tooltipinfo = new Map(); //6x for damages, normal min normal max crit min crit max let damageformulas = [["Min: = ","Max: = ","Min: = ","Max: = "],["Min: = ","Max: = ","Min: = ","Max: = "],["Min: = ","Max: = ","Min: = ","Max: = "],["Min: = ","Max: = ","Min: = ","Max: = "],["Min: = ","Max: = ","Min: = ","Max: = "],["Min: = ","Max: = ","Min: = ","Max: = "]]; - if(externalStats) { //if nothing is passed in, then this hopefully won't trigger - for (const entry of externalStats) { - const key = entry[0]; - const value = entry[1]; - if (typeof value === "number") { - buildStats.set(key, buildStats.get(key) + value); - } else if (Array.isArray(value)) { - arr = []; - for (let j = 0; j < value.length; j++) { - arr[j] = buildStats.get(key)[j] + value[j]; - } - buildStats.set(key, arr); - } - } - } - let powders = weapon.get("powders").slice(); // Array of neutral + ewtfa damages. Each entry is a pair (min, max). diff --git a/js/load.js b/js/load.js index 4f6e4b2..521765e 100644 --- a/js/load.js +++ b/js/load.js @@ -6,7 +6,7 @@ let reload = false; let load_complete = false; let load_in_progress = false; let items; -let sets; +let sets = new Map(); let itemMap; let idMap; let redirectMap; @@ -20,7 +20,6 @@ async function load_local() { let sets_store = get_tx.objectStore('set_db'); let get_store = get_tx.objectStore('item_db'); let request = get_store.getAll(); - let request2 = sets_store.getAll(); request.onerror = function(event) { reject("Could not read local item db..."); } @@ -28,15 +27,27 @@ async function load_local() { console.log("Successfully read local item db."); } + // key-value iteration (hpp don't break this again) + // https://stackoverflow.com/questions/47931595/indexeddb-getting-all-data-with-keys + let request2 = sets_store.openCursor(); request2.onerror = function(event) { reject("Could not read local set db..."); } request2.onsuccess = function(event) { - console.log("Successfully read local set db."); - } + let cursor = event.target.result; + if (cursor) { + let key = cursor.primaryKey; + let value = cursor.value; + sets.set(key, value); + cursor.continue(); + } + else { + // no more results + console.log("Successfully read local set db."); + } + }; get_tx.oncomplete = function(event) { items = request.result; - sets = request2.result; init_maps(); load_complete = true; db.close(); diff --git a/js/skillpoints.js b/js/skillpoints.js index 12c8805..fcf24b6 100644 --- a/js/skillpoints.js +++ b/js/skillpoints.js @@ -31,14 +31,15 @@ function calculate_skillpoints(equipment, weapon) { let setCount = activeSetCounts.get(setName); let old_bonus = {}; if (setCount) { - old_bonus = sets[setName].bonuses[setCount-1]; + old_bonus = sets.get(setName).bonuses[setCount-1]; activeSetCounts.set(setName, setCount + 1); } else { setCount = 0; activeSetCounts.set(setName, 1); } - const new_bonus = sets[setName].bonuses[setCount]; + console.log(sets); + const new_bonus = sets.get(setName).bonuses[setCount]; //let skp_order = ["str","dex","int","def","agi"]; for (const i in skp_order) { const delta = (new_bonus[skp_order[i]] || 0) - (old_bonus[skp_order[i]] || 0); @@ -74,8 +75,8 @@ function calculate_skillpoints(equipment, weapon) { if (setName) { // undefined/null means no set. const setCount = activeSetCounts.get(setName); if (setCount) { - const old_bonus = sets[setName].bonuses[setCount-1]; - const new_bonus = sets[setName].bonuses[setCount]; + const old_bonus = sets.get(setName).bonuses[setCount-1]; + const new_bonus = sets.get(setName).bonuses[setCount]; //let skp_order = ["str","dex","int","def","agi"]; for (const i in skp_order) { const set_delta = (new_bonus[skp_order[i]] || 0) - (old_bonus[skp_order[i]] || 0); diff --git a/js/sq2display.js b/js/sq2display.js index b6b588b..195aea5 100644 --- a/js/sq2display.js +++ b/js/sq2display.js @@ -41,7 +41,7 @@ function displaysq2BuildStats(parent_id,build,command_group){ // id instruction else { let id = command; - if (stats.get(id) || build.externalStats.get(id)) { + if (stats.get(id)) { let style = null; // TODO: add pos and neg style @@ -54,10 +54,6 @@ function displaysq2BuildStats(parent_id,build,command_group){ // ignore let id_val = stats.get(id); - if (build.externalStats.has(id)) { - id_val += build.externalStats.get(id); - } - if (reversedIDs.includes(id)) { style === "positive" ? style = "negative" : style = "positive"; } @@ -650,7 +646,7 @@ function displaysq2PoisonDamage(overallparent_elem, build) { let overallpoisonDamage = document.createElement("p"); let overallpoisonDamageFirst = document.createElement("span"); let overallpoisonDamageSecond = document.createElement("span"); - let poison_tick = Math.ceil(build.statMap.get("poison") * (1+skillPointsToPercentage(build.total_skillpoints[0])) * (build.statMap.get("poisonPct") + build.externalStats.get("poisonPct"))/100 /3); + let poison_tick = Math.ceil(build.statMap.get("poison") * (1+skillPointsToPercentage(build.total_skillpoints[0])) * (build.statMap.get("poisonPct"))/100 /3); overallpoisonDamageFirst.textContent = "Poison Tick: "; overallpoisonDamageSecond.textContent = Math.max(poison_tick,0); overallpoisonDamageSecond.classList.add("Damage"); @@ -1126,8 +1122,8 @@ function displaysq2PowderSpecials(parent_elem, powderSpecials, build, overall=fa 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, build.weapon, build.total_skillpoints, build.damageMultiplier * ((part.multiplier[power-1] / 100)));//part.multiplier[power] / 100 let critChance = skillPointsToPercentage(build.total_skillpoints[1]); let save_damages = []; @@ -1215,7 +1211,7 @@ function displaysq2PowderSpecials(parent_elem, powderSpecials, build, overall=fa } } -function displaysq2SpellDamage(parent_elem, overallparent_elem, build, spell, spellIdx) { +function displaysq2SpellDamage(parent_elem, overallparent_elem, build, spell, spellIdx, weapon) { parent_elem.textContent = ""; @@ -1264,7 +1260,7 @@ function displaysq2SpellDamage(parent_elem, overallparent_elem, build, spell, sp parent_elem.append(title_elem); overallparent_elem.append(title_elemavg); - overallparent_elem.append(displaysq2NextCosts(spell, build)); + overallparent_elem.append(displaysq2NextCosts(spell, build, weapon)); let critChance = skillPointsToPercentage(build.total_skillpoints[1]); @@ -1300,8 +1296,8 @@ function displaysq2SpellDamage(parent_elem, overallparent_elem, build, spell, sp if (part.type === "damage") { //console.log(build.expandedStats); let _results = calculateSpellDamage(stats, part.conversion, - stats.get("sdRaw") + stats.get("rainbowRaw"), stats.get("sdPct") + build.externalStats.get("sdPct"), - part.multiplier / 100, build.weapon, build.total_skillpoints, build.damageMultiplier, build.externalStats); + stats.get("sdRaw") + stats.get("rainbowRaw"), stats.get("sdPct"), + part.multiplier / 100, weapon, build.total_skillpoints, build.damageMultiplier); let totalDamNormal = _results[0]; let totalDamCrit = _results[1]; let results = _results[2]; @@ -1427,9 +1423,9 @@ function displaysq2EquipOrder(parent_elem, buildOrder){ } } -function displaysq2NextCosts(spell, build) { +function displaysq2NextCosts(spell, build, weapon) { let int = build.total_skillpoints[2]; - let spells = spell_table[build.weapon.get("type")]; + let spells = spell_table[weapon.get("type")]; let row = document.createElement("div"); row.classList.add("spellcost-tooltip");