From a1ab532ba164af62b31c2e64074148e3e842806b Mon Sep 17 00:00:00 2001 From: ferricles Date: Thu, 7 Jan 2021 18:34:07 -0800 Subject: [PATCH] statMap functional, melee damage calc functional but overestimates elemental damage --- build.js | 161 +++++++++++++++++++++++++++++++++++++++++++---------- index.html | 10 ++++ test.js | 65 +++++++++++++++++++-- 3 files changed, 201 insertions(+), 35 deletions(-) diff --git a/build.js b/build.js index e8f7d50..dbf7c8a 100644 --- a/build.js +++ b/build.js @@ -104,7 +104,6 @@ class Build{ this.items = [helmet, chestplate, leggings, boots, ring1, ring2, bracelet, necklace, weapon]; // return [equip_order, best_skillpoints, final_skillpoints, best_total]; let result = calculate_skillpoints(this.equipment, weapon); - console.log(result); this.equip_order = result[0]; this.base_skillpoints = result[1]; this.total_skillpoints = result[2]; @@ -129,22 +128,93 @@ class Build{ return health; } } - /* Get total melee dps for build. + /* Get melee stats for build. + Returns an array in the order: + */ - getMeleeDPS(){ - let meleeMult = { - "SUPER_SLOW":"0.51", - "VERY_SLOW":"0.83", - "SLOW":"1.5", - "NORMAL":"2.05", - "FAST":"2.5", - "VERY_FAST":"3.1", - "SUPER_FAST":"4.3", - } - let stats = this.getBuildStats(); - let nDam = stats.get("nDam"); + getMeleeStats(){ + //Establish vars + let meleeMult = new Map(); + meleeMult.set("SUPER_SLOW",0.51); + meleeMult.set("VERY_SLOW",0.83); + meleeMult.set("SLOW",1.5); + meleeMult.set("NORMAL",2.05); + meleeMult.set("FAST",2.5); + meleeMult.set("VERY_FAST",3.1); + meleeMult.set("SUPER_FAST",4.3); + let atkSpdToNum = new Map(); + atkSpdToNum.set("SUPER_SLOW",-3); + atkSpdToNum.set("VERY_SLOW",-2); + atkSpdToNum.set("SLOW",-1); + atkSpdToNum.set("NORMAL",0); + atkSpdToNum.set("FAST",1); + atkSpdToNum.set("VERY_FAST",2); + atkSpdToNum.set("SUPER_FAST",3); + let numToAtkSpd = new Map(); + numToAtkSpd.set(-3,"SUPER_SLOW"); + numToAtkSpd.set(-2,"VERY_SLOW"); + numToAtkSpd.set(-1,"SLOW"); + numToAtkSpd.set(0,"NORMAL"); + numToAtkSpd.set(1,"FAST"); + numToAtkSpd.set(2,"VERY_FAST"); + numToAtkSpd.set(3,"SUPER_FAST"); - return []; + let stats = this.getBuildStats(); + let nDam = stats.get("nDam").split("-").map(Number); + let eDam = stats.get("eDam").split("-").map(Number); + let tDam = stats.get("tDam").split("-").map(Number); + let wDam = stats.get("wDam").split("-").map(Number); + let fDam = stats.get("fDam").split("-").map(Number); + let aDam = stats.get("aDam").split("-").map(Number); + let mdRaw = stats.get("maxStats").get("mdRaw"); + + let mdPct = stats.get("maxStats").get("mdPct"); + let eDamPct = stats.get("maxStats").get("eDamPct"); + let tDamPct = stats.get("maxStats").get("tDamPct"); + let wDamPct = stats.get("maxStats").get("wDamPct"); + let fDamPct = stats.get("maxStats").get("fDamPct"); + let aDamPct = stats.get("maxStats").get("aDamPct"); + + let baseAtkTier = stats.get("atkSpd"); + let atkTier = stats.get("maxStats").get("atkTier"); + let adjAtkSpd = atkSpdToNum.get(baseAtkTier) + atkTier; + if(adjAtkSpd > 3){ + adjAtkSpd = 3; + }else if(adjAtkSpd < -3){ + adjAtkSpd = -3; + } + adjAtkSpd = numToAtkSpd.get(adjAtkSpd); + let str = stats.get("str"); + let strReq = stats.get("strReq"); + str = str + strReq; + let dex = stats.get("dex"); + let dexReq = stats.get("dexReq"); + dex = dex + dexReq; + let int = stats.get("int"); + let intReq = stats.get("intReq"); + int = int + intReq; + let def = stats.get("def"); + let defReq = stats.get("defReq"); + def = def + defReq; + let agi = stats.get("agi"); + let agiReq = stats.get("agiReq"); + agi = agi + agiReq; + let poison = stats.get("maxStats").get("poison"); + + //Now do math + let nDamAdj = [Math.round(nDam[0] * ((100 + mdPct + skillPointsToPercentage(str) * 100) / 100.) + mdRaw), Math.round(nDam[1] * ((100 + mdPct + skillPointsToPercentage(str) * 100) / 100.) + mdRaw), Math.round(nDam[0] * ((200 + mdPct + skillPointsToPercentage(str) * 100) / 100.) + mdRaw), Math.round(nDam[1] * ((200 + mdPct + skillPointsToPercentage(str) * 100) / 100.) + mdRaw)]; + let eDamAdj = [Math.round(eDam[0] * ((100 + mdPct + eDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(str) * 100) / 100.)), Math.round(eDam[1] * ((100 + mdPct + eDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(str) * 100) / 100.)), Math.round(eDam[0] * ((200 + mdPct + eDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(str) * 100) / 100.)), Math.round(eDam[1] * ((200 + mdPct + eDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(str) * 100) / 100.))]; + let tDamAdj = [Math.round(tDam[0] * ((100 + mdPct + tDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(dex) * 100) / 100.)), Math.round(tDam[1] * ((100 + mdPct + tDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(dex) * 100) / 100.)), Math.round(tDam[0] * ((200 + mdPct + tDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(dex) * 100) / 100.)), Math.round(tDam[1] * ((200 + mdPct + tDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(dex) * 100) / 100.))]; + let wDamAdj = [Math.round(wDam[0] * ((100 + mdPct + wDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(int) * 100) / 100.)), Math.round(wDam[1] * ((100 + mdPct + wDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(int) * 100) / 100.)), Math.round(wDam[0] * ((200 + mdPct + wDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(int) * 100) / 100.)), Math.round(wDam[1] * ((200 + mdPct + wDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(int) * 100) / 100.))]; + let fDamAdj = [Math.round(fDam[0] * ((100 + mdPct + fDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(def) * 100) / 100.)), Math.round(fDam[1] * ((100 + mdPct + fDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(def) * 100) / 100.)), Math.round(fDam[0] * ((200 + mdPct + fDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(def) * 100) / 100.)), Math.round(fDam[1] * ((200 + mdPct + fDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(def) * 100) / 100.))]; + let aDamAdj = [Math.round(aDam[0] * ((100 + mdPct + aDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(agi) * 100) / 100.)), Math.round(aDam[1] * ((100 + mdPct + aDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(agi) * 100) / 100.)), Math.round(aDam[0] * ((200 + mdPct + aDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(agi) * 100) / 100.)), Math.round(aDam[1] * ((200 + mdPct + aDamPct + skillPointsToPercentage(str) * 100 + skillPointsToPercentage(agi) * 100) / 100.))]; + let totalDamNorm = [nDamAdj[0]+eDamAdj[0]+tDamAdj[0]+wDamAdj[0]+fDamAdj[0]+aDamAdj[0], nDamAdj[1]+eDamAdj[1]+tDamAdj[1]+wDamAdj[1]+fDamAdj[1]+aDamAdj[1]]; + let totalDamCrit = [nDamAdj[2]+eDamAdj[2]+tDamAdj[2]+wDamAdj[2]+fDamAdj[2]+aDamAdj[2], nDamAdj[3]+eDamAdj[3]+tDamAdj[3]+wDamAdj[3]+fDamAdj[3]+aDamAdj[3]]; + let normDPS = (totalDamNorm[0]+totalDamNorm[1])/2 * meleeMult.get(adjAtkSpd); + let critDPS = (totalDamCrit[0]+totalDamCrit[1])/2 * meleeMult.get(adjAtkSpd); + let avgDPS = (normDPS * (1 - skillPointsToPercentage(dex))) + (critDPS * (skillPointsToPercentage(dex))) + (poison / 3.0 * (1 + skillPointsToPercentage(str))); + //console.log([nDamAdj,eDamAdj,tDamAdj,wDamAdj,fDamAdj,aDamAdj,totalDamNorm,totalDamCrit,normDPS,critDPS,avgDPS]); + return [nDamAdj,eDamAdj,tDamAdj,wDamAdj,fDamAdj,aDamAdj,totalDamNorm,totalDamCrit,normDPS,critDPS,avgDPS]; } /* Get all stats for this build. Returns a map w/ sums of all IDs. @@ -159,28 +229,61 @@ class Build{ //Create a map of this build's stats //This is universal for every possible build, so it's possible to move this elsewhere. let statMap = new Map(); + let minStats = new Map(); //for rolled mins + let maxStats = new Map(); //for rolled maxs for (const i in item_fields){ let id = item_fields[i]; - if(stackingIDs.includes(id)){ //IDs stack - make it number - statMap.set(id,0); - }else if(standaloneIDs.includes(id)){ //IDs do not stack - string - statMap.set(id,""); - } + if(rolledIDs.includes(id)){ //ID is rolled - put the min and max rolls in min and max stats + if(stackingIDs.includes(id)){ //IDs stack - make it number + minStats.set(id,0); + maxStats.set(id,0); + }//if standaloneIDs includes id, something's wrong. + }else{ //ID is not rolled - just set w/ default + if(stackingIDs.includes(id)){//stacking but not rolled: ex skill points + statMap.set(id,0); + }else if(standaloneIDs.includes(id)){ + statMap.set(id,""); + }else if(skpReqs.includes(id)){ + statMap.set(id,0); + } + } } + statMap.set("minStats",minStats); + statMap.set("maxStats",maxStats); + for (const i in this.items){ let item = expandItem(this.items[i]); - console.log(item,type(item)); - if(item.has("fixID") && item.get("fixID")){//item has fixed IDs - for(const [key,value] in item.entries()){ - console.log(key,value); + for(const [key,value] of item){ //for each key:value pair in item + if(key === "minRolls"){ + for (const [id,roll] of value){ //for each id:roll pair in minRolls + statMap.get("minStats").set(id,statMap.get("minStats").get(id) + roll); //we know they must stack + } + }else if(key==="maxRolls"){ + for (const [id,roll] of value){ //for each id:roll pair in maxRolls + statMap.get("maxStats").set(id,statMap.get("maxStats").get(id) + roll); //we know they must stack + } + }else if(typeof value === "undefined"){ //does not stack - convert to string + statMap.set(key,statMap.get(key).concat("undefined,")); + }else if(typeof value === "null"){ //does not stack - convert to string + statMap.set(key,statMap.get(key).concat("null,")); + }else if(typeof value === "number"){ //although the value is not rolled, it stacks b/c it's a number. + if(key === "strReq" || key === "dexReq" || key === "intReq" || key === "defReq" || key === "agiReq" ){ + if(value > statMap.get(key)){ + statMap.set(key,value); + } + }else{ + statMap.set(key,statMap.get(key)+value); + } + }else if(typeof value === "string"){ //does not stack + if(key === "nDam" || key === "eDam" || key === "tDam" || key === "wDam" || key === "fDam" || key === "aDam" || key === "atkSpd"){ + statMap.set(key,statMap.get(key).concat(value)); + }else{ + statMap.set(key,statMap.get(key).concat(value.concat(","))); + } } - }else{//item does not have fixed IDs - for (const i in item) { - console.log(entry,": ",item.get(entry)); - } } } - + console.log(statMap); return statMap; } diff --git a/index.html b/index.html index a080562..2ac336d 100644 --- a/index.html +++ b/index.html @@ -133,6 +133,8 @@
Original Value: 0
+
+
@@ -142,6 +144,8 @@
Original Value: 0
+
+
@@ -151,6 +155,8 @@
Original Value: 0
+
+
@@ -160,6 +166,8 @@
Original Value: 0
+
+
@@ -169,6 +177,8 @@
Original Value: 0
+
+
diff --git a/test.js b/test.js index 8ae78bf..9356d4b 100644 --- a/test.js +++ b/test.js @@ -20,11 +20,12 @@ let player_build; let armorTypes = [ "helmet", "chestplate", "leggings", "boots" ]; let accessoryTypes = [ "ring", "bracelet", "necklace" ]; 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", "agiReq", "defReq", "hprPct", "mr", "sdPct", "mdPct", "ls", "ms", "xpb", "lb", "ref", "str", "dex", "int", "agi", "def", "thorns", "exploding", "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 nonRolledIDs = ["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", "agiReq", "defReq","str", "dex", "int", "agi", "def", "fixID", "category", "id"]; +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", "exploding", "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 nonRolledIDs = ["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","str", "dex", "int", "agi", "def", "fixID", "category", "id"]; let rolledIDs = ["hprPct", "mr", "sdPct", "mdPct", "ls", "ms", "xpb", "lb", "ref", "thorns", "exploding", "spd", "atkTier", "poison", "hpBonus", "spRegen", "eSteal", "hprRaw", "sdRaw", "mdRaw", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4", "rainbowRaw", "sprint", "sprintReg", "jh", "lq", "gXp", "gSpd"]; let stackingIDs = ["hprPct", "mr", "sdPct", "mdPct", "ls", "ms", "xpb", "lb", "ref", "thorns", "exploding", "spd", "atkTier", "poison", "hpBonus", "spRegen", "eSteal", "hprRaw", "sdRaw", "mdRaw", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4", "rainbowRaw", "sprint", "sprintReg", "jh", "lq", "gXp", "gSpd", "fDef", "wDef", "aDef", "tDef", "eDef", "str", "dex", "int", "agi", "def"]; -let standaloneIDs = ["name", "displayName", "tier", "set", "slots", "type", "material", "drop", "quest", "restrict", "nDam", "fDam", "wDam", "aDam", "tDam", "eDam", "atkSpd", "hp", "lvl", "classReq", "strReq", "dexReq", "intReq", "agiReq", "defReq", "fixID", "category", "id"]; +let standaloneIDs = ["name", "displayName", "tier", "set", "slots", "type", "material", "drop", "quest", "restrict", "nDam", "fDam", "wDam", "aDam", "tDam", "eDam", "atkSpd", "hp", "lvl", "classReq", "fixID", "category", "id"]; +let skpReqs = ["strReq", "dexReq", "intReq", "defReq", "agiReq"]; let itemTypes = armorTypes.concat(accessoryTypes).concat(weaponTypes); let itemLists = new Map(); for (const it of itemTypes) { @@ -281,6 +282,11 @@ function calculateBuild(){ setValue("agi-skp", skillpoints[4]); console.log(skillpoints); player_build.assigned_skillpoints; + setHTML("str-skp-pct", skillPointsToPercentage(skillpoints[0])*100 ); + setHTML("dex-skp-pct", skillPointsToPercentage(skillpoints[1])*100 ); + setHTML("int-skp-pct", skillPointsToPercentage(skillpoints[2])*100 ); + setHTML("def-skp-pct", skillPointsToPercentage(skillpoints[3])*100 ); + setHTML("agi-skp-pct", skillPointsToPercentage(skillpoints[4])*100 ); setHTML("summary-box", "Summary: Assigned "+player_build.assigned_skillpoints+" skillpoints."); @@ -293,7 +299,54 @@ function calculateBuild(){ setHTML("build-bracelet", expandedItemToString(expandItem(player_build.bracelet))); setHTML("build-necklace", expandedItemToString(expandItem(player_build.necklace))); setHTML("build-weapon", expandedItemToString(expandItem(player_build.weapon))); - setHTML("build-cumulative-stats", player_build.getMeleeDPS()); //Incomplete function + let meleeStats = player_build.getMeleeStats(); + //nDamAdj,eDamAdj,tDamAdj,wDamAdj,fDamAdj,aDamAdj,totalDamNorm,totalDamCrit,normDPS,critDPS,avgDPS + let meleeSummary = ""; + meleeSummary = meleeSummary.concat("

Melee Stats

"); + meleeSummary = meleeSummary.concat("

Average DPS: ",Math.round(meleeStats[10]),"



"); + meleeSummary = meleeSummary.concat("Non-Crit Stats:
"); + if(meleeStats[0][0] > 0){ + meleeSummary = meleeSummary.concat("Neutral Damage: ",meleeStats[0][0]," -> ",meleeStats[0][1],"
"); + } + if(meleeStats[1][0] > 0){ + meleeSummary = meleeSummary.concat("Earth Damage: ",meleeStats[1][0]," -> ",meleeStats[1][1],"
"); + } + if(meleeStats[2][0] > 0){ + meleeSummary = meleeSummary.concat("Thunder Damage: ",meleeStats[2][0]," -> ",meleeStats[2][1],"
"); + } + if(meleeStats[3][0] > 0){ + meleeSummary = meleeSummary.concat("Water Damage: ",meleeStats[3][0]," -> ",meleeStats[3][1],"
"); + } + if(meleeStats[4][0] > 0){ + meleeSummary = meleeSummary.concat("Fire Damage: ",meleeStats[4][0]," -> ",meleeStats[4][1],"
"); + } + if(meleeStats[5][0] > 0){ + meleeSummary = meleeSummary.concat("Air Damage: ",meleeStats[5][0]," -> ",meleeStats[5][1],"
"); + } + meleeSummary = meleeSummary.concat("
Total Damage: ",meleeStats[6][0]," -> ",meleeStats[6][1],"
"); + meleeSummary = meleeSummary.concat("Normal DPS: ",Math.round(meleeStats[8]),"

"); + meleeSummary = meleeSummary.concat("Crit Stats:
"); + if(meleeStats[0][2] > 0){ + meleeSummary = meleeSummary.concat("Neutral Damage: ",meleeStats[0][2]," -> ",meleeStats[0][3],"
"); + } + if(meleeStats[1][2] > 0){ + meleeSummary = meleeSummary.concat("Earth Damage: ",meleeStats[1][2]," -> ",meleeStats[1][3],"
"); + } + if(meleeStats[2][2] > 0){ + meleeSummary = meleeSummary.concat("Thunder Damage: ",meleeStats[2][2]," -> ",meleeStats[2][3],"
"); + } + if(meleeStats[3][2] > 0){ + meleeSummary = meleeSummary.concat("Water Damage: ",meleeStats[3][2]," -> ",meleeStats[3][3],"
"); + } + if(meleeStats[4][2] > 0){ + meleeSummary = meleeSummary.concat("Fire Damage: ",meleeStats[4][2]," -> ",meleeStats[4][3],"
"); + } + if(meleeStats[5][2] > 0){ + meleeSummary = meleeSummary.concat("Air Damage: ",meleeStats[5][2]," -> ",meleeStats[5][3],"
"); + } + meleeSummary = meleeSummary.concat("
Total Damage: ",meleeStats[7][0]," -> ",meleeStats[7][1],"
"); + meleeSummary = meleeSummary.concat("Crit DPS: ",Math.round(meleeStats[9]),"

"); + setHTML("build-cumulative-stats", "".concat(meleeSummary)); //Incomplete function location.hash = encodeBuild(); } /* Helper function that gets stats ranges for wearable items. @@ -357,7 +410,7 @@ function expandedItemToString(item){ itemString = itemString.concat(idPrefixes[ids[i]]); itemString = itemString.concat(item.get(ids[i]), idSuffixes[ids[i]],"
"); } - if(rolledIDs.includes(ids[i])&& item.get("minRolls").get(ids[i]) && item.get("maxRolls").get(ids[i]) ){//rolled ID & non-0/non-null/non-und ID + if(rolledIDs.includes(ids[i]) && item.get("minRolls").get(ids[i]) && item.get("maxRolls").get(ids[i]) ){//rolled ID & non-0/non-null/non-und ID itemString = itemString.concat(idPrefixes[ids[i]]); itemString = itemString.concat(item.get("minRolls").get(ids[i]), idSuffixes[ids[i]],"
"); }//Just don't do anything if else @@ -368,7 +421,7 @@ function expandedItemToString(item){ itemString = itemString.concat(idPrefixes[ids[i]]); itemString = itemString.concat(item.get(ids[i]), idSuffixes[ids[i]],"
"); } - if(rolledIDs.includes(ids[i])&& item.get("minRolls").get(ids[i]) && item.get("maxRolls").get(ids[i]) ){//rolled ID & non-0/non-null/non-und ID + if(rolledIDs.includes(ids[i]) && item.get("minRolls").get(ids[i]) && item.get("maxRolls").get(ids[i]) ){//rolled ID & non-0/non-null/non-und ID itemString = itemString.concat(idPrefixes[ids[i]]); itemString = itemString.concat(item.get("minRolls").get(ids[i]), idSuffixes[ids[i]], " -> ", idRound(item.get("maxRolls").get(ids[i])),idSuffixes[ids[i]],"
"); }//Just don't do anything if else