diff --git a/builder/index.html b/builder/index.html index 283d301..2084f43 100644 --- a/builder/index.html +++ b/builder/index.html @@ -619,7 +619,7 @@ Spell Damage %:
- +
Original Value: 0 @@ -630,7 +630,7 @@ Spell Damage Raw:
- +
Original Value: 0 @@ -641,7 +641,7 @@ Melee Damage %:
- +
Original Value: 0 @@ -652,7 +652,7 @@ Melee Damage Raw:
- +
Original Value: 0 @@ -665,7 +665,7 @@ Poison:
- +
Original Value: 0 @@ -676,7 +676,7 @@ Damage %:
- +
Original Value: 0 @@ -687,7 +687,7 @@ Damage %:
- +
Original Value: 0 @@ -698,7 +698,7 @@ Damage %:
- +
Original Value: 0 @@ -711,7 +711,7 @@ Damage %:
- +
Original Value: 0 @@ -722,7 +722,7 @@ Damage %:
- +
Original Value: 0 @@ -733,7 +733,7 @@ + Tier:
- +
Original Value: 0 @@ -752,7 +752,7 @@ Defense %:
- +
Original Value: 0 @@ -763,7 +763,7 @@ Defense %:
- +
Original Value: 0 @@ -774,7 +774,7 @@ Defense %:
- +
Original Value: 0 @@ -785,7 +785,7 @@ Defense %:
- +
Original Value: 0 @@ -798,7 +798,7 @@ Defense %:
- +
Original Value: 0 @@ -809,7 +809,7 @@ Health Regen Raw:
- +
Original Value: 0 @@ -820,7 +820,7 @@ Health Regen %:
- +
Original Value: 0 @@ -831,7 +831,7 @@ Health Bonus:
- +
Original Value: 0 @@ -847,7 +847,7 @@ 1st Spell Cost %:
- +
Original Value: 0 @@ -858,7 +858,7 @@ 2nd Spell Cost %:
- +
Original Value: 0 @@ -869,7 +869,7 @@ 3rd Spell Cost %:
- +
Original Value: 0 @@ -880,7 +880,7 @@ 4th Spell Cost %:
- +
Original Value: 0 @@ -893,7 +893,7 @@ 1st Spell Cost Raw:
- +
Original Value: 0 @@ -904,7 +904,7 @@ 2nd Spell Cost Raw:
- +
Original Value: 0 @@ -915,7 +915,7 @@ 3rd Spell Cost Raw:
- +
Original Value: 0 @@ -926,7 +926,7 @@ 4th Spell Cost Raw:
- +
Original Value: 0 diff --git a/js/build.js b/js/build.js index a655290..78cf2ac 100644 --- a/js/build.js +++ b/js/build.js @@ -149,64 +149,6 @@ class Build{ return [this.equipment,this.weapon,this.tomes].flat(); } - /* Getters */ - - getSpellCost(spellIdx, cost) { - return Math.max(1, this.getBaseSpellCost(spellIdx, cost)); - } - - getBaseSpellCost(spellIdx, cost) { - // old intelligence: - cost = Math.ceil(cost * (1 - skillPointsToPercentage(this.total_skillpoints[2]))); - cost += this.statMap.get("spRaw"+spellIdx); - return Math.floor(cost * (1 + this.statMap.get("spPct"+spellIdx) / 100)); - } - - - /* Get melee stats for build. - Returns an array in the order: - */ - getMeleeStats(){ - const stats = this.statMap; - 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){ - adjAtkSpd = 6; - }else if(adjAtkSpd < 0){ - adjAtkSpd = 0; - } - - let damage_mult = 1; - 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"), 0, this.weapon.statMap, this.total_skillpoints, damage_mult * this.damageMultiplier); - - let dex = this.total_skillpoints[1]; - - let totalDamNorm = results[0]; - let totalDamCrit = results[1]; - totalDamNorm.push(1-skillPointsToPercentage(dex)); - totalDamCrit.push(skillPointsToPercentage(dex)); - let damages_results = results[2]; - - let singleHitTotal = ((totalDamNorm[0]+totalDamNorm[1])*(totalDamNorm[2]) - +(totalDamCrit[0]+totalDamCrit[1])*(totalDamCrit[2]))/2; - - //Now do math - let normDPS = (totalDamNorm[0]+totalDamNorm[1])/2 * baseDamageMultiplier[adjAtkSpd]; - let critDPS = (totalDamCrit[0]+totalDamCrit[1])/2 * baseDamageMultiplier[adjAtkSpd]; - let avgDPS = (normDPS * (1 - skillPointsToPercentage(dex))) + (critDPS * (skillPointsToPercentage(dex))); - //[[n n n n] [e e e e] [t t t t] [w w w w] [f f f f] [a a a a] [lowtotal hightotal normalChance] [critlowtotal crithightotal critChance] normalDPS critCPS averageDPS adjAttackSpeed, singleHit] - return damages_results.concat([totalDamNorm,totalDamCrit,normDPS,critDPS,avgDPS,adjAtkSpd, singleHitTotal]).concat(results[3]); - } - /* Get all stats for this build. Stores in this.statMap. @pre The build itself should be valid. No checking of validity of pieces is done here. diff --git a/js/builder_graph.js b/js/builder_graph.js index d1b7292..29ec4d6 100644 --- a/js/builder_graph.js +++ b/js/builder_graph.js @@ -260,7 +260,6 @@ class PowderInputNode extends InputNode { } input = input.slice(2); } - //console.log("POWDERING: " + powdering); return powdering; } } @@ -407,7 +406,7 @@ class SpellDisplayNode extends ComputeNode { } compute_func(input_map) { - const build = input_map.get('build'); + const stats = input_map.get('stats'); const spell_info = input_map.get('spell-info'); const damages = input_map.get('spell-damage'); const spell = spell_info[0]; @@ -416,10 +415,60 @@ class SpellDisplayNode extends ComputeNode { const i = this.spell_idx; let parent_elem = document.getElementById("spell"+i+"-info"); let overallparent_elem = document.getElementById("spell"+i+"-infoAvg"); - displaySpellDamage(parent_elem, overallparent_elem, build, spell, i+1, spell_parts, damages); + displaySpellDamage(parent_elem, overallparent_elem, stats, spell, i+1, spell_parts, damages); } } +/* Get melee stats for build. + Returns an array in the order: +*/ +function getMeleeStats(stats, weapon) { + const weapon_stats = weapon.statMap; + const skillpoints = [ + stats.get('str'), + stats.get('dex'), + stats.get('int'), + stats.get('def'), + stats.get('agi') + ]; + 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){ + adjAtkSpd = 6; + }else if(adjAtkSpd < 0){ + adjAtkSpd = 0; + } + + let damage_mult = 1; + 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"), 0, weapon_stats, skillpoints, damage_mult); + + let dex = skillpoints[1]; + + let totalDamNorm = results[0]; + let totalDamCrit = results[1]; + totalDamNorm.push(1-skillPointsToPercentage(dex)); + totalDamCrit.push(skillPointsToPercentage(dex)); + let damages_results = results[2]; + + let singleHitTotal = ((totalDamNorm[0]+totalDamNorm[1])*(totalDamNorm[2]) + +(totalDamCrit[0]+totalDamCrit[1])*(totalDamCrit[2]))/2; + + //Now do math + let normDPS = (totalDamNorm[0]+totalDamNorm[1])/2 * baseDamageMultiplier[adjAtkSpd]; + let critDPS = (totalDamCrit[0]+totalDamCrit[1])/2 * baseDamageMultiplier[adjAtkSpd]; + let avgDPS = (normDPS * (1 - skillPointsToPercentage(dex))) + (critDPS * (skillPointsToPercentage(dex))); + //[[n n n n] [e e e e] [t t t t] [w w w w] [f f f f] [a a a a] [lowtotal hightotal normalChance] [critlowtotal crithightotal critChance] normalDPS critCPS averageDPS adjAttackSpeed, singleHit] + return damages_results.concat([totalDamNorm,totalDamCrit,normDPS,critDPS,avgDPS,adjAtkSpd, singleHitTotal]).concat(results[3]); +} + /** * Display build stats. * @@ -434,7 +483,9 @@ class BuildDisplayNode extends ComputeNode { displayBuildStats('overall-stats', build, build_all_display_commands, stats); displayBuildStats("offensive-stats", build, build_offensive_display_commands, stats); displaySetBonuses("set-info", build); - let meleeStats = build.getMeleeStats(); + 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); @@ -541,7 +592,6 @@ class DisplayBuildWarningsNode extends ComputeNode { } for (const [setName, count] of build.activeSetCounts) { const bonus = sets.get(setName).bonuses[count-1]; - // console.log(setName); if (bonus["illegal"]) { let setWarning = document.createElement("p"); setWarning.classList.add("itemp"); @@ -606,7 +656,6 @@ class SkillPointSetterNode extends ComputeNode { } compute_func(input_map) { - console.log("mmm"); 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()) { @@ -656,6 +705,7 @@ class SumNumberInputNode extends InputNode { let item_nodes = []; let powder_nodes = []; let spelldmg_nodes = []; +let edit_input_nodes = []; function builder_graph_init() { // Phase 1/2: Set up item input, propagate updates, etc. @@ -714,7 +764,6 @@ function builder_graph_init() { // Create one node that will be the "aggregator node" (listen to all the editable id nodes, as well as the build_node (for non editable stats) and collect them into one statmap) let stat_agg_node = new AggregateStatsNode(); stat_agg_node.link_to(build_node, 'build').link_to(item_nodes[8], 'weapon'); - let edit_input_nodes = []; for (const field of editable_item_fields) { // Create nodes that listens to each editable id input, the node name should match the "id" const elem = document.getElementById(field); @@ -753,7 +802,7 @@ function builder_graph_init() { spelldmg_nodes.push(calc_node); let display_node = new SpellDisplayNode(i); - display_node.link_to(build_node, 'build'); // TODO: same here.. + display_node.link_to(stat_agg_node, 'stats'); // TODO: same here.. display_node.link_to(spell_node, 'spell-info'); display_node.link_to(calc_node, 'spell-damage'); } diff --git a/js/damage_calc.js b/js/damage_calc.js index 9149a13..eef3825 100644 --- a/js/damage_calc.js +++ b/js/damage_calc.js @@ -105,7 +105,7 @@ function calculateSpellDamage(stats, spellConversions, rawModifier, pctModifier, let staticBoost = (pctModifier / 100.); let skillBoost = [0]; for (let i in total_skillpoints) { - skillBoost.push(skillPointsToPercentage(total_skillpoints[i]) + buildStats.get("damageBonus")[i] / 100.); + skillBoost.push(skillPointsToPercentage(total_skillpoints[i]) + buildStats.get(skp_elements[i]+"DamPct") / 100.); } for (let i in damages) { diff --git a/js/display.js b/js/display.js index 30175c8..c87f689 100644 --- a/js/display.js +++ b/js/display.js @@ -941,46 +941,45 @@ function displayExpandedIngredient(ingred, parent_id) { } } -function displayNextCosts(spell, build, weapon) { - let int = build.total_skillpoints[2]; - let spells = spell_table[weapon.get("type")]; +function displayNextCosts(_stats, spell, spellIdx) { + let stats = new Map(_stats); + let intel = stats.get('int'); let row = document.createElement("div"); row.classList.add("spellcost-tooltip"); let init_cost = document.createElement("b"); - init_cost.textContent = build.getSpellCost(spells.indexOf(spell) + 1, spell.cost); + init_cost.textContent = getSpellCost(stats, spellIdx, spell.cost); init_cost.classList.add("Mana"); let arrow = document.createElement("b"); arrow.textContent = "\u279C"; let next_cost = document.createElement("b"); - next_cost.textContent = (init_cost.textContent === "1" ? 1 : build.getSpellCost(spells.indexOf(spell) + 1, spell.cost) - 1); + next_cost.textContent = (init_cost.textContent === "1" ? 1 : getSpellCost(stats, spellIdx, spell.cost) - 1); next_cost.classList.add("Mana"); let int_needed = document.createElement("b"); if (init_cost.textContent === "1") { int_needed.textContent = ": n/a (+0)"; }else { //do math - let target = build.getSpellCost(spells.indexOf(spell) + 1, spell.cost) - 1; - let needed = int; + let target = getSpellCost(stats, spellIdx, spell.cost) - 1; + let needed = intel; let noUpdate = false; //forgive me... I couldn't inverse ceil, floor, and max. - while (build.getSpellCost(spells.indexOf(spell) + 1, spell.cost) > target) { + while (getSpellCost(stats, spellIdx, spell.cost) > target) { if(needed > 150) { noUpdate = true; break; } needed++; - build.total_skillpoints[2] = needed; + stats.set('int', stats.get('int') + 1); } - let missing = needed - int; + let missing = needed - intel; //in rare circumstances, the next spell cost can jump. if (noUpdate) { - next_cost.textContent = (init_cost.textContent === "1" ? 1 : build.getSpellCost(spells.indexOf(spell) + 1, spell.cost)-1); + next_cost.textContent = (init_cost.textContent === "1" ? 1 : getSpellCost(stats, spellIdx, spell.cost)-1); }else { - next_cost.textContent = (init_cost.textContent === "1" ? 1 : build.getSpellCost(spells.indexOf(spell) + 1, spell.cost)); + next_cost.textContent = (init_cost.textContent === "1" ? 1 : getSpellCost(stats, spellIdx, spell.cost)); } - build.total_skillpoints[2] = int;//forgive me pt 2 int_needed.textContent = ": " + (needed > 150 ? ">150" : needed) + " int (+" + (needed > 150 ? "n/a" : missing) + ")"; } @@ -1583,12 +1582,23 @@ function displayPowderSpecials(parent_elem, powderSpecials, build) { } } -function displaySpellDamage(parent_elem, overallparent_elem, build, spell, spellIdx, spell_parts, damages) { +function getSpellCost(stats, spellIdx, cost) { + return Math.max(1, getBaseSpellCost(stats, spellIdx, cost)); +} + +function getBaseSpellCost(stats, spellIdx, cost) { + // old intelligence: + cost = Math.ceil(cost * (1 - skillPointsToPercentage(stats.get('int')))); + cost += stats.get("spRaw"+spellIdx); + return Math.floor(cost * (1 + stats.get("spPct"+spellIdx) / 100)); +} + + +function displaySpellDamage(parent_elem, overallparent_elem, stats, spell, spellIdx, spell_parts, damages) { // TODO: remove spellIdx (just used to flag melee and cost) // TODO: move cost calc out parent_elem.textContent = ""; - const stats = build.statMap; let title_elem = document.createElement("p"); overallparent_elem.textContent = ""; @@ -1601,21 +1611,15 @@ function displaySpellDamage(parent_elem, overallparent_elem, build, spell, spell title_elemavg.appendChild(first); let second = document.createElement("span"); - second.textContent = build.getSpellCost(spellIdx, spell.cost); + second.textContent = getSpellCost(stats, spellIdx, spell.cost); second.classList.add("Mana"); - let int_redux = skillPointsToPercentage(build.total_skillpoints[2]).toFixed(2); - let spPct_redux = (build.statMap.get("spPct" + spellIdx)/100).toFixed(2); - let spRaw_redux = (build.statMap.get("spRaw" + spellIdx)).toFixed(2); - spPct_redux >= 0 ? spPct_redux = "+ " + spPct_redux : spPct_redux = "- " + Math.abs(spPct_redux); - spRaw_redux >= 0 ? spRaw_redux = "+ " + spRaw_redux : spRaw_redux = "- " + Math.abs(spRaw_redux); - title_elem.appendChild(second.cloneNode(true)); title_elemavg.appendChild(second); let third = document.createElement("span"); - third.textContent = ") [Base: " + build.getBaseSpellCost(spellIdx, spell.cost) + " ]"; + third.textContent = ") [Base: " + getBaseSpellCost(stats, spellIdx, spell.cost) + " ]"; title_elem.appendChild(third); let third_summary = document.createElement("span"); third_summary.textContent = ")"; @@ -1629,9 +1633,9 @@ function displaySpellDamage(parent_elem, overallparent_elem, build, spell, spell parent_elem.append(title_elem); overallparent_elem.append(title_elemavg); - overallparent_elem.append(displayNextCosts(spell, build, build.weapon.statMap)); + overallparent_elem.append(displayNextCosts(stats, spell, spellIdx)); - let critChance = skillPointsToPercentage(build.total_skillpoints[1]); + let critChance = skillPointsToPercentage(stats.get('dex')); let save_damages = []; @@ -1650,7 +1654,6 @@ function displaySpellDamage(parent_elem, overallparent_elem, build, spell, spell part_div.append(subtitle_elem); if (part.type === "damage") { - //console.log(build.expandedStats); let _results = damage; let totalDamNormal = _results[0]; let totalDamCrit = _results[1]; diff --git a/js/optimize.js b/js/optimize.js index 6185edd..fdce392 100644 --- a/js/optimize.js +++ b/js/optimize.js @@ -40,7 +40,7 @@ function optimizeStrDex() { for (const part of spell_parts) { if (part.type === "damage") { let _results = calculateSpellDamage(stats, part.conversion, - stats.get("sdRaw"), stats.get("sdPct") + player_build.externalStats.get("sdPct"), + stats.get("sdRaw"), stats.get("sdPct"), part.multiplier / 100, player_build.weapon, total_skillpoints, player_build.damageMultiplier, player_build.externalStats); let totalDamNormal = _results[0];