From 7ebcbaaf918da4b8ad1161d982f69e00b81efbf5 Mon Sep 17 00:00:00 2001 From: ferricles Date: Sun, 10 Jan 2021 02:02:23 -0800 Subject: [PATCH] visual things + defense Stats --- build.js | 54 +++++++++++++++++------ display.js | 123 +++++++++++++++++++++++++++++++++++++++++++++++------ index.html | 22 +++++----- styles.css | 80 +++++++++++++++++++++++++++------- test.js | 18 ++++---- utils.js | 15 +++++++ 6 files changed, 252 insertions(+), 60 deletions(-) diff --git a/build.js b/build.js index 13579a4..d41e5fa 100644 --- a/build.js +++ b/build.js @@ -1,3 +1,8 @@ + +const baseDamageMultiplier = [ 0.51, 0.83, 1.5, 2.05, 2.5, 3.1, 4.3 ]; +const attackSpeeds = ["SUPER_SLOW", "VERY_SLOW", "SLOW", "NORMAL", "FAST", "VERY_FAST", "SUPER_FAST"]; +const classDefenseMultipliers = new Map([ ["relik",0.60], ["bow",0.60], ["wand", 0.80], ["assassin", 1.0], ["spear",1.20] ]); + /*Turns the input amount of skill points into a float precision percentage. * @param skp - the integer skillpoint count to be converted */ @@ -39,10 +44,6 @@ function levelToHPBase(level){ } } - -const baseDamageMultiplier = [ 0.51, 0.83, 1.5, 2.05, 2.5, 3.1, 4.3 ]; -const attackSpeeds = ["SUPER_SLOW", "VERY_SLOW", "SLOW", "NORMAL", "FAST", "VERY_FAST", "SUPER_FAST"]; - /*Class that represents a wynn player's build. */ class Build{ @@ -151,14 +152,6 @@ class Build{ /* Get total health for build. */ - getHealth(){ - let health = this.statMap.get("hp") + this.statMap.get("hpBonus"); - if(health<5){ - return 5; - }else{ - return health; - } - } getSpellCost(spellIdx, cost) { cost = Math.ceil(cost * (1 - skillPointsToPercentage(this.total_skillpoints[2]))); @@ -195,10 +188,45 @@ class Build{ let critDPS = (totalDamCrit[0]+totalDamCrit[1])/2 * baseDamageMultiplier[adjAtkSpd]; let avgDPS = (normDPS * (1 - skillPointsToPercentage(dex))) + (critDPS * (skillPointsToPercentage(dex))); //console.log([nDamAdj,eDamAdj,tDamAdj,wDamAdj,fDamAdj,aDamAdj,totalDamNorm,totalDamCrit,normDPS,critDPS,avgDPS]); - console.log(damages_results.concat([totalDamNorm,totalDamCrit,normDPS,critDPS,avgDPS,adjAtkSpd])); return damages_results.concat([totalDamNorm,totalDamCrit,normDPS,critDPS,avgDPS,adjAtkSpd]); } + /* + Get all defensive stats for this build. + */ + getDefenseStats(){ + const stats = this.statMap; + let defenseStats = []; + let def_pct = skillPointsToPercentage(this.total_skillpoints[3]); + let agi_pct = skillPointsToPercentage(this.total_skillpoints[4]); + //total hp + let totalHp = stats.get("hp") + stats.get("hpBonus"); + defenseStats.push(totalHp); + //EHP + let ehp = totalHp; + let defMult = classDefenseMultipliers.get(this.weapon.get("type")); + ehp /= ((1-def_pct)*(1-agi_pct)*(2-defMult)); + defenseStats.push(ehp); + //HPR + let totalHpr = rawToPct(stats.get("hprRaw"), stats.get("hprPct")/100.); + defenseStats.push(totalHpr); + //EHPR + let ehpr = totalHpr; + ehp /= ((1-def_pct)*(1-agi_pct)*(2-defMult)); + defenseStats.push(ehpr); + //skp stats + defenseStats.push([def_pct*100, agi_pct*100]); + //eledefs - TODO POWDERS + let eledefs = [0, 0, 0, 0, 0]; + for(const i in skp_elements){ //kinda jank but ok + eledefs[i] = rawToPct(stats.get(skp_elements[i] + "Def"), stats.get(skp_elements[i] + "DefPct")/100.); + } + defenseStats.push(eledefs); + + //[total hp, ehp, total hpr, ehpr, [def%, agi%], [edef,tdef,wdef,fdef,adef]] + return defenseStats; + } + /* 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/display.js b/display.js index 6209571..7e548b6 100644 --- a/display.js +++ b/display.js @@ -310,8 +310,12 @@ function displayExpandedItem(item, parent_id){ let p_elem = displayFixedID(active_elem, id, item.get(id), elemental_format); if (id === "slots") { // HACK TO MAKE POWDERS DISPLAY NICE!! TODO + //let powderMap = new Map([ ["e", "Earth"], ["t", "Thunder"], ["w", "Water"], ["f", "Fire"], ["a", "Air"]]); p_elem.textContent = idPrefixes[id].concat(item.get(id), idSuffixes[id]) + " [ " + item.get("powders").map(x => powderNames.get(x)) + " ]"; + }else if(id === "displayName"){ + p_elem.classList.add("title"); + p_elem.classList.add(item.get("tier")); } } else if (rolledIDs.includes(id) && item.get("minRolls").get(id)){ // && item.get("maxRolls").get(id) ){//rolled ID & non-0/non-null/non-und ID @@ -355,6 +359,7 @@ function displayExpandedItem(item, parent_id){ let item_desc_elem = document.createElement('p'); item_desc_elem.classList.add('itemp'); item_desc_elem.classList.add('left'); + item_desc_elem.classList.add(item.get("tier")); item_desc_elem.textContent = item.get("tier")+" "+item.get("type"); parent_div.append(item_desc_elem); } @@ -398,6 +403,21 @@ function displayFixedID(active, id, value, elemental_format, style) { return p_elem; } } +function displayEquipOrder(parent_elem,buildOrder){ + parent_elem.textContent = ""; + const order = buildOrder.slice(); + let title_elem = document.createElement("p"); + title_elem.textContent = "Equip order "; + title_elem.classList.add("title"); + parent_elem.append(title_elem); + for (const item of order) { + let p_elem = document.createElement("p"); + p_elem.classList.add("itemp"); + p_elem.classList.add("left"); + p_elem.textContent = item.get("displayName"); + parent_elem.append(p_elem); + } +} function displayMeleeDamage(parent_elem, meleeStats){ let attackSpeeds = ["Super Slow", "Very Slow", "Slow", "Normal", "Fast", "Very Fast", "Super Fast"]; //let damagePrefixes = ["Neutral Damage: ","Earth Damage: ","Thunder Damage: ","Water Damage: ","Fire Damage: ","Air Damage: "]; @@ -420,7 +440,7 @@ function displayMeleeDamage(parent_elem, meleeStats){ //title let title_elem = document.createElement("p"); - title_elem.classList.add("center"); + title_elem.classList.add("title"); title_elem.textContent = "Melee Stats"; parent_elem.append(title_elem); parent_elem.append(document.createElement("br")); @@ -428,12 +448,14 @@ function displayMeleeDamage(parent_elem, meleeStats){ //average DPS let averageDamage = document.createElement("p"); averageDamage.classList.add("center"); + averageDamage.classList.add("itemp"); averageDamage.textContent = "Average DPS: " + stats[10]; parent_elem.append(averageDamage); //attack speed let atkSpd = document.createElement("p"); atkSpd.classList.add("center"); + atkSpd.classList.add("itemp"); atkSpd.textContent = "Attack Speed: " + attackSpeeds[stats[11]]; parent_elem.append(atkSpd); parent_elem.append(document.createElement("br")); @@ -441,6 +463,7 @@ function displayMeleeDamage(parent_elem, meleeStats){ //Non-Crit: n->elem, total dmg, DPS let nonCritStats = document.createElement("p"); nonCritStats.classList.add("center"); + nonCritStats.classList.add("itemp"); nonCritStats.textContent = "Non-Crit Stats: "; nonCritStats.append(document.createElement("br")); for (let i = 0; i < 6; i++){ @@ -448,17 +471,20 @@ function displayMeleeDamage(parent_elem, meleeStats){ let dmg = document.createElement("p"); dmg.textContent = stats[i][0] + " - " + stats[i][1]; dmg.classList.add(damageClasses[i]); + dmg.classList.add("itemp"); nonCritStats.append(dmg); } } let normalDamage = document.createElement("p"); - normalDamage.textContent = "Total Damage: " + stats[6][0] + " - " + stats[6][1]; + normalDamage.textContent = "Total: " + stats[6][0] + " - " + stats[6][1]; + normalDamage.classList.add("itemp"); nonCritStats.append(normalDamage); let normalDPS = document.createElement("p"); normalDPS.textContent = "Normal DPS: " + stats[8]; normalDPS.append(document.createElement("br")); normalDPS.append(document.createElement("br")); + normalDPS.classList.add("itemp"); nonCritStats.append(normalDPS); parent_elem.append(nonCritStats); @@ -467,6 +493,7 @@ function displayMeleeDamage(parent_elem, meleeStats){ //Crit: n->elem, total dmg, DPS let critStats = document.createElement("p"); critStats.classList.add("center"); + critStats.classList.add("itemp"); critStats.textContent = "Crit Stats: "; critStats.append(document.createElement("br")); for (let i = 0; i < 6; i++){ @@ -474,22 +501,94 @@ function displayMeleeDamage(parent_elem, meleeStats){ dmg = document.createElement("p"); dmg.textContent = stats[i][2] + " - " + stats[i][3]; dmg.classList.add(damageClasses[i]); + dmg.classList.add("itemp"); critStats.append(dmg); } } - normalDamage = document.createElement("p"); - normalDamage.textContent = "Total Damage: " + stats[7][0] + " - " + stats[7][1]; - critStats.append(normalDamage); + let critDamage = document.createElement("p"); + critDamage.textContent = "Total: " + stats[7][0] + " - " + stats[7][1]; + critDamage.classList.add("itemp"); + critStats.append(critDamage); - normalDPS = document.createElement("p"); - normalDPS.textContent = "Crit DPS: " + stats[9]; - normalDPS.append(document.createElement("br")); - normalDPS.append(document.createElement("br")); - critStats.append(normalDPS); + let critDPS = document.createElement("p"); + critDPS.textContent = "Crit DPS: " + stats[9]; + critDPS.classList.add("itemp"); + critDPS.append(document.createElement("br")); + critDPS.append(document.createElement("br")); + critStats.append(critDPS); parent_elem.append(critStats); +} +function displayDefenseStats(parent_elem,defenseStats){ + parent_elem.textContent = ""; + const stats = defenseStats.slice(); + let title_elem = document.createElement("p"); + title_elem.textContent = "Defense Stats"; + title_elem.classList.add("title"); + parent_elem.append(title_elem); parent_elem.append(document.createElement("br")); - + + //[total hp, ehp, total hpr, ehpr, [def%, agi%], [edef,tdef,wdef,fdef,adef]] + for(const i in stats){ + if(typeof stats[i] === "number"){ + stats[i] = stats[i].toFixed(2); + }else{ + for(const j in stats[i]){ + stats[i][j] = stats[i][j].toFixed(2); + } + } + } + //total HP + let hpElem = document.createElement("p"); + hpElem.textContent = "HP: " + stats[0]; + hpElem.classList.add("left"); + hpElem.classList.add("Health"); + parent_elem.append(hpElem); + //EHP + let ehpElem = document.createElement("p"); + ehpElem.textContent = "Effective HP: " + stats[1]; + ehpElem.classList.add("left"); + parent_elem.append(ehpElem); + //total HPR + let hprElem = document.createElement("p"); + hprElem.textContent = "HP Regen: " + stats[2]; + hprElem.classList.add("left"); + hprElem.classList.add("Health"); + parent_elem.append(hprElem); + //EHPR + let ehprElem = document.createElement("p"); + ehprElem.textContent = "Effective HP Regen: " + stats[3]; + ehprElem.classList.add("left"); + parent_elem.append(ehprElem); + //eledefs + let eledefs = stats[5]; + for (let i = 0; i < eledefs.length; i++){ + /* TODO: make this comment work + let eledefElem = document.createElement("p"); + let ele = document.createElement("b"); + ele.classList.add(damageClasses[i+1]); + ele.textContent = damageClasses[i+1]; + eledefElem.textContent = " Defense: " + eledefs[i]; + //eledefElem.classList.add(damageClasses[i+1]); + eledefElem.classList.add("left"); + parent_elem.append(ele); + parent_elem.append(eledefElem); + */ + let eledefElem = document.createElement("p"); + eledefElem.textContent = damageClasses[i+1] + " Defense: " + eledefs[i]; + eledefElem.classList.add(damageClasses[i+1]); + eledefElem.classList.add("left"); + parent_elem.append(eledefElem); + } + //skp + let defElem = document.createElement("p"); + defElem.textContent = "Damage Absorbed %: " + stats[4][0] + "%"; + defElem.classList.add("left"); + parent_elem.append(defElem); + let agiElem = document.createElement("p"); + agiElem.textContent = "Dodge Chance %: " + stats[4][1] + "%"; + agiElem.classList.add("left"); + parent_elem.append(agiElem); } @@ -498,7 +597,7 @@ function displaySpellDamage(parent_elem, build, spell, spellIdx) { const stats = build.statMap; let title_elem = document.createElement("p"); - title_elem.classList.add('center'); + title_elem.classList.add('title'); if (spellIdx != 0) { title_elem.textContent = spell.title + " (" + build.getSpellCost(spellIdx, spell.cost) + ")"; } diff --git a/index.html b/index.html index 415c36d..fe220ba 100644 --- a/index.html +++ b/index.html @@ -35,21 +35,21 @@
- +

- +

- +
@@ -63,14 +63,14 @@
- +

- +
@@ -101,7 +101,7 @@ X slots
- +
X slots @@ -118,8 +118,8 @@
X slots
-
- +
+








@@ -250,11 +250,11 @@
-
-
-
+
+
+
diff --git a/styles.css b/styles.css index f3abdeb..b28b536 100644 --- a/styles.css +++ b/styles.css @@ -24,7 +24,7 @@ grid-auto-rows: minmax(60px, auto); } .equipment, .skillpoints, .center, .header, .all{ - background: #110110; + background: #121516; color: #aaa; } .hppeng{ @@ -36,6 +36,10 @@ a.link{ color: #A5FDFF; } +.title{ + text-align: center; + font-size: 150%; +} .center { text-align: center; } @@ -45,6 +49,7 @@ a.link{ } .left { + margin: 2px 2%; text-align: left; } @@ -55,12 +60,12 @@ a.link{ gap: 20px; grid-auto-rows: minmax(60px, auto); width: 94%; - background: #110110; + background: #121516; } -.build-helmet, .build-chestplate, .build-leggings, .build-boots, .build-ring1, .build-ring2, .build-bracelet, .build-necklace, .build-weapon, .build-order, .build-overall, .build-melee-stats, .spell-info, .set-info { +.build-helmet, .build-chestplate, .build-leggings, .build-boots, .build-ring1, .build-ring2, .build-bracelet, .build-necklace, .build-weapon, .build-order, .build-overall, .build-melee-stats, .build-defense-stats, .spell-info, .set-info { color: #aaa; - background: #110110; + background: #121516; border: 3px solid #BCBCBC; border-radius: 3px; width: 96%; @@ -172,20 +177,65 @@ a.link{ width: 10px; } - /* Track */ - ::-webkit-scrollbar-track { +/* Track */ +::-webkit-scrollbar-track { box-shadow: inset 0 0 5px #BCBCBC; border: #BCBCBC; border-radius: 5px; - } - - /* Handle */ - ::-webkit-scrollbar-thumb { +} + +/* Handle */ +::-webkit-scrollbar-thumb { background: #aaa; border-radius: 10px; - } +} - /* Ugly Corner */ - ::-webkit-scrollbar-corner{ - background: #110110; - } +/* Ugly Corner */ +::-webkit-scrollbar-corner{ + background: #110110; +} +button { + background-color: #666; + border: 2px solid #444; + border-radius: 5px; + color: #ddd; + text-align: center; + text-decoration: none; + font-family: 'Nunito',sans-serif; + font-weight: 700; + font-size: 120%; + display: inline-block; +} +input { + background-color: #666; + border: 2px solid #444; + border-radius: 5px; + color: #ddd; + text-align: center; + text-decoration: none; + font-family: 'Nunito',sans-serif; + font-weight: 700; + display: inline-block; +} +/* Tier colors tier colors */ +.Normal{ + color: #fff; +} +.Unique{ + color:#ff5; +} +.Rare{ + color:#f5f; +} +.Legendary{ + color:#5ff; +} +.Fabled{ + color:#f55; +} +.Mythic{ + color:#a0a; +} +.Set{ + color:#5f5 +} \ No newline at end of file diff --git a/test.js b/test.js index 3a6e027..3a1a979 100644 --- a/test.js +++ b/test.js @@ -24,6 +24,7 @@ let weaponTypes = [ "wand", "spear", "bow", "dagger", "relik" ]; let item_fields = [ "name", "displayName", "tier", "set", "slots", "type", "material", "drop", "quest", "restrict", "nDam", "fDam", "wDam", "aDam", "tDam", "eDam", "atkSpd", "hp", "fDef", "wDef", "aDef", "tDef", "eDef", "lvl", "classReq", "strReq", "dexReq", "intReq", "defReq", "agiReq", "hprPct", "mr", "sdPct", "mdPct", "ls", "ms", "xpb", "lb", "ref", "str", "dex", "int", "agi", "def", "thorns", "expd", "spd", "atkTier", "poison", "hpBonus", "spRegen", "eSteal", "hprRaw", "sdRaw", "mdRaw", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "fixID", "category", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4", "rainbowRaw", "sprint", "sprintReg", "jh", "lq", "gXp", "gSpd", "id" ]; let skp_order = ["str","dex","int","def","agi"]; +let skp_elements = ["e","t","w","f","a"]; let skpReqs = skp_order.map(x => x + "Req"); let equipment_fields = [ @@ -54,7 +55,7 @@ let buildFields = equipment_fields.map(x => "build-"+x); let powderIDs = new Map(); let powderNames = new Map(); let _powderID = 0; -for (const x of ['e', 't', 'w', 'f', 'a']) { +for (const x of skp_elements) { for (let i = 1; i <= 6; ++i) { // Support both upper and lowercase, I guess. powderIDs.set(x.toUpperCase()+i, _powderID); @@ -125,7 +126,7 @@ function init() { ["accessory", "ring", "No Ring 2"], ["accessory", "bracelet", "No Bracelet"], ["accessory", "necklace", "No Necklace"], - ["weapon", "wand", "No Weapon"], + ["weapon", "dagger", "No Weapon"], ]; for (let i = 0; i < 9; i++) { let item = Object(); @@ -354,12 +355,9 @@ function calculateBuild(save_skp, skp){ console.log(equipment); player_build = new Build(106, equipment, powderings); console.log(player_build.toString()); + displayEquipOrder(document.getElementById("build-order"),player_build.equip_order); - let equip_order_text = "Equip order:
"; - for (const item of player_build.equip_order) { - equip_order_text += item.get("displayName") + "
"; - } - setHTML("build-order", equip_order_text); + const assigned = player_build.base_skillpoints; const skillpoints = player_build.total_skillpoints; @@ -426,9 +424,11 @@ function calculateBuildStats() { displayBuildStats(player_build, "build-overall-stats"); displaySetBonuses(player_build, "set-info"); - let parent_elem = document.getElementById("build-melee-stats"); let meleeStats = player_build.getMeleeStats(); - displayMeleeDamage(parent_elem,meleeStats); + displayMeleeDamage(document.getElementById("build-melee-stats") ,meleeStats); + + let defenseStats = player_build.getDefenseStats(); + displayDefenseStats(document.getElementById("build-defense-stats"),defenseStats); //let defenseStats = ""; diff --git a/utils.js b/utils.js index c00a2a0..fbd2a2f 100644 --- a/utils.js +++ b/utils.js @@ -97,3 +97,18 @@ Base64 = (function () { // Base64.fromInt(-2147483648); // gives "200000" // Base64.toInt("200000"); // gives -2147483648 + +/* + Turns a raw stat and a % stat into a final stat on the basis that - raw and >= 100% becomes 0 and + raw and <=-100% becomes 0. + Pct would be 0.80 for 80%, -1.20 for 120%, etc +*/ +function rawToPct(raw, pct){ + final = 0; + if (raw < 0){ + final = (Math.min(0, raw - (raw * pct) )); + }else if(raw > 0){ + final = (Math.max(0, raw + (raw * pct))); + }else{ //do nothing - final's already 0 + } + return final; +} \ No newline at end of file