Adding powdering and general spell calc framework

This commit is contained in:
b 2021-01-08 18:56:07 -06:00
parent d9941fac60
commit aa29998340
6 changed files with 196 additions and 114 deletions

View file

@ -55,50 +55,50 @@ class Build{
if(helmet.type.valueOf() != "helmet".valueOf()){
throw new TypeError("No such helmet named ", helmet.name);
}else{
this.helmet = helmet;
this.powders[0] = this.powders[0].slice(0,helmet.slots);
this.helmet = expandItem(helmet, this.powders[0]);
}
if(chestplate.type.valueOf() != "chestplate"){
throw new TypeError("No such chestplate named ", chestplate.name);
}else{
this.chestplate = chestplate;
this.powders[1] = this.powders[1].slice(0,chestplate.slots);
this.chestplate = expandItem(chestplate, this.powders[1]);
}
if(leggings.type.valueOf() != "leggings"){
throw new TypeError("No such leggings named ", leggings.name);
}else{
this.leggings = leggings;
this.powders[2] = this.powders[2].slice(0,leggings.slots);
this.leggings = expandItem(leggings, this.powders[2]);
}
if(boots.type.valueOf() != "boots"){
throw new TypeError("No such boots named ", boots.name);
}else{
this.boots = boots;
this.powders[3] = this.powders[3].slice(0,boots.slots);
this.boots = expandItem(boots, this.powders[3]);
}
if(ring1.type.valueOf() != "ring"){
throw new TypeError("No such ring named ", ring1.name);
}else{
this.ring1 = ring1;
this.ring1 = expandItem(ring1, []);
}
if(ring2.type.valueOf() != "ring"){
throw new TypeError("No such ring named ", ring2.name);
}else{
this.ring2 = ring2;
this.ring2 = expandItem(ring2, []);
}
if(bracelet.type.valueOf() != "bracelet"){
throw new TypeError("No such bracelet named ", bracelet.name);
}else{
this.bracelet = bracelet;
this.bracelet = expandItem(bracelet, []);
}
if(necklace.type.valueOf() != "necklace"){
throw new TypeError("No such necklace named ", necklace.name);
}else{
this.necklace = necklace;
this.necklace = expandItem(necklace, []);
}
if(weapon.type.valueOf() == "wand" || weapon.type.valueOf() == "bow" || weapon.type.valueOf() == "dagger" || weapon.type.valueOf() == "spear" || weapon.type.valueOf() == "relik"){
this.weapon = weapon;
this.powders[4] = this.powders[4].slice(0,weapon.slots);
this.weapon = expandItem(weapon, this.powders[4]);
}else{
throw new TypeError("No such weapon named ", weapon.name);
}
@ -110,17 +110,17 @@ class Build{
this.level = level;
}
this.availableSkillpoints = levelToSkillPoints(this.level);
this.equipment = [ helmet, chestplate, leggings, boots, ring1, ring2, bracelet, necklace ];
this.items = this.equipment.concat([weapon]);
this.equipment = [ this.helmet, this.chestplate, this.leggings, this.boots, this.ring1, this.ring2, this.bracelet, this.necklace ];
this.items = this.equipment.concat([this.weapon]);
// return [equip_order, best_skillpoints, final_skillpoints, best_total];
let result = calculate_skillpoints(this.equipment, weapon);
let result = calculate_skillpoints(this.equipment, this.weapon);
this.equip_order = result[0];
this.base_skillpoints = result[1];
this.total_skillpoints = result[2];
this.assigned_skillpoints = result[3];
// For strength boosts like warscream, vanish, etc.
this.damage_multiplier = 1.0;
this.damageMultiplier = 1.0;
this.initBuildStats();
}
@ -128,7 +128,7 @@ class Build{
/*Returns build in string format
*/
toString(){
return this.helmet.name + ", " + this.chestplate.name + ", " + this.leggings.name + ", " + this.boots.name + ", " + this.ring1.name + ", " + this.ring2.name + ", " + this.bracelet.name + ", " + this.necklace.name + ", " + this.weapon.name;
return this.helmet.get("name") + ", " + this.chestplate.get("name") + ", " + this.leggings.get("name") + ", " + this.boots.get("name") + ", " + this.ring1.get("name") + ", " + this.ring2.get("name") + ", " + this.bracelet.get("name") + ", " + this.necklace.get("name") + ", " + this.weapon.get("name");
}
/* Getters */
@ -147,67 +147,37 @@ class Build{
return health;
}
}
/* Get melee stats for build.
Returns an array in the order:
*/
getMeleeStats(){
const stats = this.statMap;
// Array of neutral + ewtfa damages. Each entry is a pair (min, max).
let damages = [];
for (const damage_string of stats.get("damageRaw")) {
const damage_vals = damage_string.split("-").map(Number);
damages.push(damage_vals);
}
let mdRaw = stats.get("mdRaw");
let mdPct = stats.get("mdPct");
let adjAtkSpd = attackSpeeds.indexOf(stats.get("atkSpd")) + stats.get("atkTier");
if(adjAtkSpd > 6){
adjAtkSpd = 6;
}else if(adjAtkSpd < 0){
adjAtkSpd = 0;
}
let poison = stats.get("poison");
let totalDamNorm = [mdRaw, mdRaw];
let totalDamCrit = [mdRaw, mdRaw];
let damages_results = [];
// 0th skillpoint is strength, 1st is dex.
let str = this.total_skillpoints[0];
// 0 for melee damage.
let results = calculateSpellDamage(stats, [100, 0, 0, 0, 0, 0], stats.get("mdRaw"), stats.get("mdPct"), 0, this.weapon, this.damageMultiplier, this.total_skillpoints);
let totalDamNorm = results[0];
let totalDamCrit = results[1];
let damages_results = results[2];
let dex = this.total_skillpoints[1];
let staticBoost = (mdPct / 100.) + skillPointsToPercentage(str);
let skillBoost = [0];
for (let i in this.total_skillpoints) {
skillBoost.push(skillPointsToPercentage(this.total_skillpoints[i]) + stats.get("damageBonus")[i] / 100.);
}
for (let i in damages) {
let damageBoost = 1 + skillBoost[i] + staticBoost;
damages_results.push([
Math.max(damages[i][0] * damageBoost * this.damage_multiplier, 0), // Normal min
Math.max(damages[i][1] * damageBoost * this.damage_multiplier, 0), // Normal max
Math.max(damages[i][0] * (1 + damageBoost) * this.damage_multiplier, 0), // Crit min
Math.max(damages[i][1] * (1 + damageBoost) * this.damage_multiplier, 0), // Crit max
]);
totalDamNorm[0] += damages_results[i][0];
totalDamNorm[1] += damages_results[i][1];
totalDamCrit[0] += damages_results[i][2];
totalDamCrit[1] += damages_results[i][3];
}
for (let i in damages_results[0]) {
damages_results[0][i] += mdRaw * this.damage_multiplier;
}
//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))) + (poison / 3.0 * (1 + skillPointsToPercentage(str)));
let avgDPS = (normDPS * (1 - skillPointsToPercentage(dex))) + (critDPS * (skillPointsToPercentage(dex)));
//console.log([nDamAdj,eDamAdj,tDamAdj,wDamAdj,fDamAdj,aDamAdj,totalDamNorm,totalDamCrit,normDPS,critDPS,avgDPS]);
return damages_results.concat([totalDamNorm,totalDamCrit,normDPS,critDPS,avgDPS,adjAtkSpd]);
}
/* Get all stats for this build. Stores in this.statMap.
@dep test.js.expandItem()
@pre The build itself should be valid. No checking of validity of pieces is done here.
*/
initBuildStats(){
@ -223,8 +193,7 @@ class Build{
}
statMap.set("hp", levelToHPBase(this.level)); //TODO: Add player base health
for (const _item of this.items){
let item = expandItem(_item);
for (const item of this.items){
for (let [id, value] of item.get("maxRolls")) {
statMap.set(id,(statMap.get(id) || 0)+value);
}
@ -234,8 +203,8 @@ class Build{
}
// The stuff relevant for damage calculation!!! @ferricles
statMap.set("atkSpd", this.weapon["atkSpd"]);
statMap.set("damageRaw", [this.weapon["nDam"], this.weapon["eDam"], this.weapon["tDam"], this.weapon["wDam"], this.weapon["fDam"], this.weapon["aDam"]]);
statMap.set("atkSpd", this.weapon.get("atkSpd"));
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")]);
statMap.set("damageBonus", [statMap.get("eDamPct"), statMap.get("tDamPct"), statMap.get("wDamPct"), statMap.get("fDamPct"), statMap.get("aDamPct")]);
statMap.set("defRaw", [statMap.get("eDam"), statMap.get("tDef"), statMap.get("wDef"), statMap.get("fDef"), statMap.get("aDef")]);
statMap.set("defBonus", [statMap.get("eDamPct"), statMap.get("tDefPct"), statMap.get("wDefPct"), statMap.get("fDefPct"), statMap.get("aDefPct")]);

85
damage_calc.js Normal file
View file

@ -0,0 +1,85 @@
// 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.
function calculateSpellDamage(stats, spellConversions, rawModifier, pctModifier, spellMultiplier, weapon, damageMultiplier, total_skillpoints) {
// Array of neutral + ewtfa damages. Each entry is a pair (min, max).
let damages = [];
for (const damage_string of stats.get("damageRaw")) {
const damage_vals = damage_string.split("-").map(Number);
damages.push(damage_vals);
}
// Applying powder.
let neutralRemaining = spellConversions[0];
let neutralBase = damages[0].slice();
let neutralRemainingRaw = damages[0];
for (let i = 0; i < 5; ++i) {
let conversionRatio = spellConversions[i+1]/100;
let min_diff = Math.min(neutralRemainingRaw[0], conversionRatio * neutralBase[0]);
let max_diff = Math.min(neutralRemainingRaw[1], conversionRatio * neutralBase[1]);
damages[i+1][0] = Math.floor(damages[i+1][0] + min_diff);
damages[i+1][1] = Math.floor(damages[i+1][1] + max_diff);
neutralRemainingRaw[0] = Math.floor(neutralRemainingRaw[0] - min_diff);
neutralRemainingRaw[1] = Math.floor(neutralRemainingRaw[1] - max_diff);
}
let rawBoosts = [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]];
for (const powderID of weapon.get("powders")) {
const powder = powderStats[powderID];
// Bitwise to force conversion to integer (integer division).
const element = (powderID/6) | 0;
let conversionRatio = powder.convert/100;
if (neutralRemainingRaw[0] > 0) {
let min_diff = Math.min(neutralRemainingRaw[0], conversionRatio * neutralBase[0]);
let max_diff = Math.min(neutralRemainingRaw[1], conversionRatio * neutralBase[1]);
damages[element+1][0] = Math.floor(damages[element+1][0] + min_diff);
damages[element+1][1] = Math.floor(damages[element+1][1] + max_diff);
neutralRemainingRaw[0] = Math.floor(neutralRemainingRaw[0] - min_diff);
neutralRemainingRaw[1] = Math.floor(neutralRemainingRaw[1] - max_diff);
}
damages[element+1][0] += powder.min;
damages[element+1][1] += powder.max;
}
damages[0][0] *= neutralRemaining / 100;
damages[0][1] *= neutralRemaining / 100;
console.log(damages);
let damageMult = damageMultiplier;
// If we are doing melee calculations:
if (spellMultiplier == 0) {
spellMultiplier = 1;
}
else {
damageMult *= spellMultiplier * baseDamageMultiplier[attackSpeeds.indexOf(stats.get("atkSpd"))];
}
rawModifier *= spellMultiplier;
let totalDamNorm = [rawModifier, rawModifier];
let totalDamCrit = [rawModifier, rawModifier];
let damages_results = [];
// 0th skillpoint is strength, 1st is dex.
let str = total_skillpoints[0];
let staticBoost = (pctModifier / 100.) + skillPointsToPercentage(str);
let skillBoost = [0];
for (let i in total_skillpoints) {
skillBoost.push(skillPointsToPercentage(total_skillpoints[i]) + stats.get("damageBonus")[i] / 100.);
}
for (let i in damages) {
let damageBoost = 1 + skillBoost[i] + staticBoost;
damages_results.push([
Math.max(damages[i][0] * damageBoost * damageMult, 0), // Normal min
Math.max(damages[i][1] * damageBoost * damageMult, 0), // Normal max
Math.max(damages[i][0] * (1 + damageBoost) * damageMult, 0), // Crit min
Math.max(damages[i][1] * (1 + damageBoost) * damageMult, 0), // Crit max
]);
totalDamNorm[0] += damages_results[i][0];
totalDamNorm[1] += damages_results[i][1];
totalDamCrit[0] += damages_results[i][2];
totalDamCrit[1] += damages_results[i][3];
}
for (let i in damages_results[0]) {
// Never account for attack speed.
damages_results[0][i] += rawModifier * damageMultiplier;
}
return [totalDamNorm, totalDamCrit, damages_results];
}

View file

@ -1,7 +1,7 @@
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 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", "skillpoints", "reqs", "nDam_", "fDam_", "wDam_", "aDam_", "tDam_", "eDam_"];
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"];
function expandItem(item){
function expandItem(item, powders){
let minRolls = new Map();
let maxRolls = new Map();
let expandedItem = new Map();
@ -36,6 +36,7 @@ function expandItem(item){
}
expandedItem.set("minRolls",minRolls);
expandedItem.set("maxRolls",maxRolls);
expandedItem.set("powders", powders);
return expandedItem;
}
/*An independent helper function that rounds a rolled ID to the nearest integer OR brings the roll away from 0.
@ -54,6 +55,19 @@ function displayExpandedItem(item, parent_id){
// #commands create a new element.
// !elemental is some janky hack for elemental damage.
// normals just display a thing.
if (item.get("category") === "weapon") {
let stats = new Map();
stats.set("atkSpd", item.get("atkSpd"));
stats.set("damageBonus", [0, 0, 0, 0, 0]);
stats.set("damageRaw", [item.get("nDam"), item.get("eDam"), item.get("tDam"), item.get("wDam"), item.get("fDam"), item.get("aDam")]);
let results = calculateSpellDamage(stats, [100, 0, 0, 0, 0, 0], 0, 0, 0, item, 1, [0, 0, 0, 0, 0]);
let damages = results[2];
let damage_keys = [ "nDam_", "eDam_", "tDam_", "wDam_", "fDam_", "aDam_" ];
for (const i in damage_keys) {
item.set(damage_keys[i], damages[i][0]+"-"+damages[i][1]);
}
}
let display_commands = [
"#cdiv",
"displayName",
@ -62,7 +76,7 @@ function displayExpandedItem(item, parent_id){
"#ldiv",
"!elemental",
"hp",
"nDam", "eDam", "tDam", "wDam", "fDam", "aDam",
"nDam_", "eDam_", "tDam_", "wDam_", "fDam_", "aDam_",
"eDef", "tDef", "wDef", "fDef", "aDef",
"!elemental",
"#ldiv",
@ -101,8 +115,8 @@ function displayExpandedItem(item, parent_id){
"quest",
"restrict"];
let idPrefixes = {"displayName": "", "lvl":"Combat Level Min: ", "classReq":"Class Req: ","strReq":"Strength Min: ","dexReq":"Dexterity Min: ","intReq":"Intelligence Min: ","defReq":"Defense Min: ","agiReq":"Agility Min: ", "nDam":"Neutral Damage: ", "eDam":"Earth Damage: ", "tDam":"Thunder Damage: ", "wDam":"Water Damage: ", "fDam":"Fire Damage: ", "aDam":"Air Damage: ", "atkSpd":"Attack Speed: ", "hp":"Health : ", "eDef":"Earth Defense: ", "tDef":"Thunder Defense: ", "wDef":"Water Defense: ", "fDef":"Fire Defense: ", "aDef":"Air Defense: ", "str":"Strength: ", "dex":"Dexterity: ", "int":"Intelligence: ", "def":"Defense: ","agi":"Agility: ", "hpBonus":"Health Bonus: ", "hprRaw":"Health Regen Raw: ", "hprPct":"Health Regen %: ", "sdRaw":"Raw Spell Damage: ", "sdPct":"Spell Damage %: ", "mdRaw":"Main Attack Neutral Damage: ", "mdPct":"Main Attack Damage %: ", "mr":"Mana Regen: ", "ms":"Mana Steal: ", "ref":"Reflection: ", "ls":"Life Steal: ", "poison":"Poison: ", "thorns":"Thorns: ", "exploding":"Expoding: ", "spd":"Walk Speed Bonus: ", "atkTier":"Attack Speed Bonus: ", "eDamPct":"Earth Damage %: ", "tDamPct":"Thunder Damage %: ", "wDamPct":"Water Damage %: ", "fDamPct":"Fire Damage %: ", "aDamPct":"Air Damage %: ", "eDefPct":"Earth Defense %: ", "tDefPct":"Thunder Defense %: ", "wDefPct":"Water Defense %: ", "fDefPct":"Fire Defense %: ", "aDefPct":"Air Defense %: ", "spPct1":"1st Spell Cost %: ", "spRaw1":"1st Spell Cost Raw: ", "spPct2":"2nd Spell Cost %: ", "spRaw2":"2nd Spell Cost Raw: ", "spPct3":"3rd Spell Cost %: ", "spRaw3":"3rd Spell Cost Raw: ", "spPct4":"4th Spell Cost %: ", "spRaw4":"4th Spell Cost Raw: ", "rainbowRaw":"Rainbow Spell Damage Raw: ", "sprint":"Sprint Bonus: ", "sprintReg":"Sprint Regen Bonus: ", "jh":"Jump Height: ", "xpb":"Combat XP Bonus: ", "lb":"Loot Bonus: ", "lq":"Loot Quality: ", "spRegen":"Soul Point Regen: ", "eSteal":"Stealing: ", "gXp":"Gathering XP Bonus: ", "gSpd":"Gathering Speed Bonus: ", "slots":"Powder Slots: ", "set":"Set: ", "quest":"Quest Req: ", "restrict":""};
let idSuffixes = {"displayName": "", "lvl":"", "classReq":"","strReq":"","dexReq":"","intReq":"","defReq":"","agiReq":"", "nDam":"", "eDam":"", "tDam":"", "wDam":"", "fDam":"", "aDam":"", "atkSpd":"", "hp":"", "eDef":"", "tDef":"", "wDef":"", "fDef":"", "aDef":"", "str":"", "dex":"", "int":"", "def":"","agi":"", "hpBonus":"", "hprRaw":"", "hprPct":"%", "sdRaw":"", "sdPct":"%", "mdRaw":"", "mdPct":"%", "mr":"/4s", "ms":"/4s", "ref":"%", "ls":"/4s", "poison":"/3s", "thorns":"%", "exploding":"%", "spd":"%", "atkTier":" tier", "eDamPct":"%", "tDamPct":"%", "wDamPct":"%", "fDamPct":"%", "aDamPct":"%", "eDefPct":"%", "tDefPct":"%", "wDefPct":"%", "fDefPct":"%", "aDefPct":"%", "spPct1":"%", "spRaw1":"", "spPct2":"%", "spRaw2":"", "spPct3":"%", "spRaw3":"", "spPct4":"%", "spRaw4":"", "rainbowRaw":"", "sprint":"%", "sprintReg":"%", "jh":"", "xpb":"%", "lb":"%", "lq":"%", "spRegen":"%", "eSteal":"%", "gXp":"%", "gSpd":"%", "slots":"", "set":" set.", "quest":"", "restrict":""};
let idPrefixes = {"displayName": "", "lvl":"Combat Level Min: ", "classReq":"Class Req: ","strReq":"Strength Min: ","dexReq":"Dexterity Min: ","intReq":"Intelligence Min: ","defReq":"Defense Min: ","agiReq":"Agility Min: ", "nDam_":"Neutral Damage: ", "eDam_":"Earth Damage: ", "tDam_":"Thunder Damage: ", "wDam_":"Water Damage: ", "fDam_":"Fire Damage: ", "aDam_":"Air Damage: ", "atkSpd":"Attack Speed: ", "hp":"Health : ", "eDef":"Earth Defense: ", "tDef":"Thunder Defense: ", "wDef":"Water Defense: ", "fDef":"Fire Defense: ", "aDef":"Air Defense: ", "str":"Strength: ", "dex":"Dexterity: ", "int":"Intelligence: ", "def":"Defense: ","agi":"Agility: ", "hpBonus":"Health Bonus: ", "hprRaw":"Health Regen Raw: ", "hprPct":"Health Regen %: ", "sdRaw":"Raw Spell Damage: ", "sdPct":"Spell Damage %: ", "mdRaw":"Main Attack Neutral Damage: ", "mdPct":"Main Attack Damage %: ", "mr":"Mana Regen: ", "ms":"Mana Steal: ", "ref":"Reflection: ", "ls":"Life Steal: ", "poison":"Poison: ", "thorns":"Thorns: ", "exploding":"Expoding: ", "spd":"Walk Speed Bonus: ", "atkTier":"Attack Speed Bonus: ", "eDamPct":"Earth Damage %: ", "tDamPct":"Thunder Damage %: ", "wDamPct":"Water Damage %: ", "fDamPct":"Fire Damage %: ", "aDamPct":"Air Damage %: ", "eDefPct":"Earth Defense %: ", "tDefPct":"Thunder Defense %: ", "wDefPct":"Water Defense %: ", "fDefPct":"Fire Defense %: ", "aDefPct":"Air Defense %: ", "spPct1":"1st Spell Cost %: ", "spRaw1":"1st Spell Cost Raw: ", "spPct2":"2nd Spell Cost %: ", "spRaw2":"2nd Spell Cost Raw: ", "spPct3":"3rd Spell Cost %: ", "spRaw3":"3rd Spell Cost Raw: ", "spPct4":"4th Spell Cost %: ", "spRaw4":"4th Spell Cost Raw: ", "rainbowRaw":"Rainbow Spell Damage Raw: ", "sprint":"Sprint Bonus: ", "sprintReg":"Sprint Regen Bonus: ", "jh":"Jump Height: ", "xpb":"Combat XP Bonus: ", "lb":"Loot Bonus: ", "lq":"Loot Quality: ", "spRegen":"Soul Point Regen: ", "eSteal":"Stealing: ", "gXp":"Gathering XP Bonus: ", "gSpd":"Gathering Speed Bonus: ", "slots":"Powder Slots: ", "set":"Set: ", "quest":"Quest Req: ", "restrict":""};
let idSuffixes = {"displayName": "", "lvl":"", "classReq":"","strReq":"","dexReq":"","intReq":"","defReq":"","agiReq":"", "nDam_":"", "eDam_":"", "tDam_":"", "wDam_":"", "fDam_":"", "aDam_":"", "atkSpd":"", "hp":"", "eDef":"", "tDef":"", "wDef":"", "fDef":"", "aDef":"", "str":"", "dex":"", "int":"", "def":"","agi":"", "hpBonus":"", "hprRaw":"", "hprPct":"%", "sdRaw":"", "sdPct":"%", "mdRaw":"", "mdPct":"%", "mr":"/4s", "ms":"/4s", "ref":"%", "ls":"/4s", "poison":"/3s", "thorns":"%", "exploding":"%", "spd":"%", "atkTier":" tier", "eDamPct":"%", "tDamPct":"%", "wDamPct":"%", "fDamPct":"%", "aDamPct":"%", "eDefPct":"%", "tDefPct":"%", "wDefPct":"%", "fDefPct":"%", "aDefPct":"%", "spPct1":"%", "spRaw1":"", "spPct2":"%", "spRaw2":"", "spPct3":"%", "spRaw3":"", "spPct4":"%", "spRaw4":"", "rainbowRaw":"", "sprint":"%", "sprintReg":"%", "jh":"", "xpb":"%", "lb":"%", "lq":"%", "spRegen":"%", "eSteal":"%", "gXp":"%", "gSpd":"%", "slots":"", "set":" set.", "quest":"", "restrict":""};
function apply_elemental_format(p_elem, id, suffix) {
suffix = (typeof suffix !== 'undefined') ? suffix : "";

View file

@ -14,8 +14,11 @@
<div class="header" id="header">
Wynn build calculator
</div>
<div class="center" id="header">
<a href="credits.txt">Credits</a>
<div class="center" id="header2">
Made by: hppeng and ferricles
</div>
<div class="center" id="credits">
<a href="credits.txt">Additional credits</a>
</div>
<div class="equipment">
<div class="center" style="grid-column:1;grid-row:1">
@ -133,13 +136,13 @@
</div>
<div class="skillpoints">
<div class="center" style="grid-column:1;grid-row:1">
<div id="str-skp-assign">
Before Boosts: 0
</div>
<div>
<label for="str-skp" class="skpLabel">Strength:</label>
<input type="number" id="str-skp" name="str-skp" value="0" class="skpInput"/>
</div>
<div id="str-skp-assign">
Before Boosts: 0
</div>
<div id="str-skp-base">
Original Value: 0
</div>
@ -147,13 +150,13 @@
</div>
</div>
<div class="center" style="grid-column:2;grid-row:1">
<div id="dex-skp-assign">
Before Boosts: 0
</div>
<div>
<label for="dex-skp" class="skpLabel">Dexterity:</label>
<input type="number" id="dex-skp" name="dex-skp" value="0" class="skpInput"/>
</div>
<div id="dex-skp-assign">
Before Boosts: 0
</div>
<div id="dex-skp-base">
Original Value: 0
</div>
@ -161,13 +164,13 @@
</div>
</div>
<div class="center" style="grid-column:3;grid-row:1">
<div id="int-skp-assign">
Before Boosts: 0
</div>
<div>
<label for="int-skp" class="skpLabel">Intelligence:</label>
<input type="number" id="int-skp" name="int-skp" value="0" class="skpInput"/>
</div>
<div id="int-skp-assign">
Before Boosts: 0
</div>
<div id="int-skp-base">
Original Value: 0
</div>
@ -175,13 +178,13 @@
</div>
</div>
<div class="center" style="grid-column:4;grid-row:1">
<div id="def-skp-assign">
Before Boosts: 0
</div>
<div>
<label for="def-skp" class="skpLabel">Defense:</label>
<input type="number" id="def-skp" name="def-skp" value="0" class="skpInput"/>
</div>
<div id="def-skp-assign">
Before Boosts: 0
</div>
<div id="def-skp-base">
Original Value: 0
</div>
@ -189,13 +192,13 @@
</div>
</div>
<div class="center" style="grid-column:5;grid-row:1">
<div id="agi-skp-assign">
Before Boosts: 0
</div>
<div>
<label for="agi-skp" class="skpLabel">Agility:</label>
<input type="number" id="agi-skp" name="agi-skp" value="0" class="skpInput"/>
</div>
<div id="agi-skp-assign">
Before Boosts: 0
</div>
<div id="agi-skp-base">
Original Value: 0
</div>
@ -241,6 +244,7 @@
<script type="text/javascript" src="utils.js"></script>
<script type="text/javascript" src="skillpoints.js"></script>
<script type="text/javascript" src="damage_calc.js"></script>
<script type="text/javascript" src="display.js"></script>
<script type="text/javascript" src="build.js"></script>
<script type="text/javascript" src="load.js"></script>

View file

@ -7,10 +7,10 @@ function calculate_skillpoints(equipment, weapon) {
let noboost = [];
console.log(equipment);
for (const item of equipment) {
if (item.reqs.every(x => x === 0)) {
if (item.get("reqs").every(x => x === 0)) {
fixed.push(item);
}
else if (item.skillpoints.every(x => x === 0)) {
else if (item.get("skillpoints").every(x => x === 0)) {
noboost.push(item);
}
else {
@ -19,13 +19,13 @@ function calculate_skillpoints(equipment, weapon) {
}
function apply_skillpoints(skillpoints, item) {
for (let i = 0; i < 5; i++) {
skillpoints[i] += item.skillpoints[i];
skillpoints[i] += item.get("skillpoints")[i];
}
}
function remove_skillpoints(skillpoints, item) {
for (let i = 0; i < 5; i++) {
skillpoints[i] -= item.skillpoints[i];
skillpoints[i] -= item.get("skillpoints")[i];
}
}
@ -35,13 +35,13 @@ function calculate_skillpoints(equipment, weapon) {
let applied = [0, 0, 0, 0, 0];
let total = 0;
for (let i = 0; i < 5; i++) {
if (item.skillpoints[i] < 0 && skillpoint_filter[i]) {
applied[i] -= item.skillpoints[i];
total -= item.skillpoints[i];
if (item.get("skillpoints")[i] < 0 && skillpoint_filter[i]) {
applied[i] -= item.get("skillpoints")[i];
total -= item.get("skillpoints")[i];
}
if (item.reqs[i] == 0) continue;
if (item.get("reqs")[i] == 0) continue;
if (skillpoint_filter) skillpoint_filter[i] = true;
const req = item.reqs[i];
const req = item.get("reqs")[i];
const cur = skillpoints[i];
if (req > cur) {
const diff = req - cur;

62
test.js
View file

@ -11,7 +11,7 @@ console.log(url_tag);
* END testing section
*/
const BUILD_VERSION = "1.3";
const BUILD_VERSION = "1.4";
document.getElementById("header").textContent = "Wynn build calculator "+BUILD_VERSION+" (db version "+DB_VERSION+")";
@ -43,12 +43,23 @@ let powderInputs = [
"weapon-powder",
];
// Ordering: [dmgMin, dmgMax, convert, defPlus, defMinus (+6 mod 5)]
class Powder {
constructor(min, max, convert, defPlus, defMinus) {
this.min = min;
this.max = max;
this.convert = convert;
this.defPlus = defPlus;
this.defMinus = defMinus;
}
}
function _p(a,b,c,d,e) { return new Powder(a,b,c,d,e); }
let powderStats = [
[3,6,17,2,1], [6,9,21,4,2], [8,14,25,8,3], [11,16,31,14,5], [15,18,38,22,9], [18,22,46,30,13],
[1,8,9,3,1], [1,13,11,5,1], [2,18,14,9,2], [3,24,17,14,4], [3,32,22,20,7], [5,40,28,28,10],
[3,4,13,3,1], [4,7,15,6,1], [6,10,17,11,2], [8,12,21,18,4], [11,14,26,28,7], [13,17,32,40,10],
[2,5,14,3,1], [4,8,16,5,2], [6,10,19,9,3], [9,13,24,16,5], [12,16,30,25,9], [15,19,37,36,13],
[2,6,11,3,1], [4,9,14,6,2], [7,10,17,10,3], [9,13,22,16,5], [13,18,28,24,9], [16,18,35,34,13]
_p(3,6,17,2,1), _p(6,9,21,4,2), _p(8,14,25,8,3), _p(11,16,31,14,5), _p(15,18,38,22,9), _p(18,22,46,30,13),
_p(1,8,9,3,1), _p(1,13,11,5,1), _p(2,18,14,9,2), _p(3,24,17,14,4), _p(3,32,22,20,7), _p(5,40,28,28,10),
_p(3,4,13,3,1), _p(4,7,15,6,1), _p(6,10,17,11,2), _p(8,12,21,18,4), _p(11,14,26,28,7), _p(13,17,32,40,10),
_p(2,5,14,3,1), _p(4,8,16,5,2), _p(6,10,19,9,3), _p(9,13,24,16,5), _p(12,16,30,25,9), _p(15,19,37,36,13),
_p(2,6,11,3,1), _p(4,9,14,6,2), _p(7,10,17,10,3), _p(9,13,22,16,5), _p(13,18,28,24,9), _p(16,18,35,34,13)
];
let itemTypes = armorTypes.concat(accessoryTypes).concat(weaponTypes);
@ -262,15 +273,15 @@ function encodeBuild() {
// Base64.fromIntN(player_build.bracelet.id, 3) +
// Base64.fromIntN(player_build.necklace.id, 3) +
// Base64.fromIntN(player_build.weapon.id, 3);
let build_string = "1_" + Base64.fromIntN(player_build.helmet.id, 3) +
Base64.fromIntN(player_build.chestplate.id, 3) +
Base64.fromIntN(player_build.leggings.id, 3) +
Base64.fromIntN(player_build.boots.id, 3) +
Base64.fromIntN(player_build.ring1.id, 3) +
Base64.fromIntN(player_build.ring2.id, 3) +
Base64.fromIntN(player_build.bracelet.id, 3) +
Base64.fromIntN(player_build.necklace.id, 3) +
Base64.fromIntN(player_build.weapon.id, 3);
let build_string = "1_" + 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);
for (const _powderset of player_build.powders) {
let n_bits = Math.ceil(_powderset.length / 6);
@ -363,7 +374,7 @@ function calculateBuild(){
let equip_order_text = "Equip order: <br>";
for (const item of player_build.equip_order) {
equip_order_text += item.displayName + "<br>";
equip_order_text += item.get("displayName") + "<br>";
}
setHTML("build-order", equip_order_text);
@ -382,22 +393,21 @@ function calculateBuild(){
}
setText(skp_order[i] + "-skp-pct", (skillPointsToPercentage(skillpoints[i])*100).toFixed(1).concat(skp_effects[i]));
}
console.log(skillpoints);
if(player_build.assigned_skillpoints > levelToSkillPoints(player_build.level)){
setHTML("summary-box", "Summary: Assigned "+player_build.assigned_skillpoints+" skillpoints.<br>" + "WARNING: Too many skillpoints need to be assigned!<br> For level " + player_build.level + ", there are only " + levelToSkillPoints(player_build.level) + " skill points available.");
}else{
setText("summary-box", "Summary: Assigned "+player_build.assigned_skillpoints+" skillpoints.");
}
displayExpandedItem(expandItem(player_build.helmet), "build-helmet");
displayExpandedItem(expandItem(player_build.chestplate), "build-chestplate");
displayExpandedItem(expandItem(player_build.leggings), "build-leggings");
displayExpandedItem(expandItem(player_build.boots), "build-boots");
displayExpandedItem(expandItem(player_build.ring1), "build-ring1");
displayExpandedItem(expandItem(player_build.ring2), "build-ring2");
displayExpandedItem(expandItem(player_build.bracelet), "build-bracelet");
displayExpandedItem(expandItem(player_build.necklace), "build-necklace");
displayExpandedItem(expandItem(player_build.weapon), "build-weapon");
displayExpandedItem(player_build.helmet, "build-helmet");
displayExpandedItem(player_build.chestplate, "build-chestplate");
displayExpandedItem(player_build.leggings, "build-leggings");
displayExpandedItem(player_build.boots, "build-boots");
displayExpandedItem(player_build.ring1, "build-ring1");
displayExpandedItem(player_build.ring2, "build-ring2");
displayExpandedItem(player_build.bracelet, "build-bracelet");
displayExpandedItem(player_build.necklace, "build-necklace");
displayExpandedItem(player_build.weapon, "build-weapon");
calculateBuildStats();
}