Merge branch 'dev' into master

This commit is contained in:
hppeng-wynn 2021-01-15 19:09:49 -06:00 committed by GitHub
commit a227d5625f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 775 additions and 233 deletions

View file

@ -1005,8 +1005,8 @@
"int": 50,
"def": 0,
"agi": 0,
"mr": -5,
"ms": -5,
"mr": -4,
"ms": -4,
"sdPct": 30,
"spPct1": -38,
"spPct2": -38,
@ -4997,7 +4997,7 @@
"category": "armor",
"lvl": 98,
"hp": 3200,
"tDef": 200,
"tDef": 100,
"aDef": -150,
"slots": 3,
"str": 0,
@ -5506,13 +5506,15 @@
"fDef": 40,
"aDef": 40,
"slots": 2,
"str": 4,
"dex": 4,
"int": 4,
"def": 4,
"agi": 4,
"sdRaw": 175,
"mdRaw": 230,
"str": 3,
"dex": 3,
"int": 3,
"def": 3,
"agi": 3,
"ls": 175,
"ms": 2,
"lb": 15,
"thorns": 20,
"id": 10259
},
{
@ -5597,11 +5599,6 @@
"int": 12,
"def": 12,
"agi": 12,
"eDamPct": 8,
"tDamPct": 8,
"wDamPct": 8,
"fDamPct": 8,
"aDamPct": 8,
"spPct2": -1,
"id": 10262
},
@ -7145,11 +7142,11 @@
"category": "weapon",
"lvl": 93,
"nDam": "0-0",
"eDam": "124-140",
"tDam": "54-210",
"wDam": "94-170",
"fDam": "109-115",
"aDam": "79-185",
"eDam": "120-142",
"tDam": "60-202",
"wDam": "90-172",
"fDam": "105-157",
"aDam": "75-187",
"slots": 4,
"str": 0,
"dex": 0,
@ -9510,7 +9507,7 @@
"agi": -550,
"ls": 973,
"ms": 6,
"atkTier": 3,
"atkTier": 1,
"sdRaw": 342,
"mdRaw": 727,
"wDamPct": -550,
@ -10202,73 +10199,5 @@
"tDamPct": 30,
"aDamPct": -50,
"id": 10394
},
{
"tier": "Rare",
"type": "helmet",
"name": "Dissociation (1.20)",
"displayName": "Dissociation (1.20)",
"set": null,
"quest": null,
"classReq": null,
"restrict": "1.20 item",
"fixID": false,
"strReq": 0,
"dexReq": 0,
"intReq": 0,
"defReq": 0,
"agiReq": 0,
"category": "armor",
"lvl": 101,
"slots": 0,
"str": -35,
"dex": 0,
"int": -20,
"def": -35,
"agi": 0,
"mr": 2,
"hpBonus": 3550,
"sdRaw": 300,
"mdPct": 60,
"tDefPct": 75,
"aDefPct": 75,
"spRaw3": -1,
"id": 10395
},
{
"tier": "Legendary",
"type": "leggings",
"name": "Anixolytic (1.20)",
"displayName": "Anixolytic (1.20)",
"set": null,
"quest": null,
"classReq": null,
"restrict": "1.20 item",
"fixID": false,
"strReq": 35,
"dexReq": 40,
"intReq": 50,
"defReq": 35,
"agiReq": 50,
"category": "armor",
"lvl": 101,
"hp": 3880,
"eDef": -175,
"tDef": 125,
"wDef": 150,
"fDef": -125,
"aDef": 150,
"slots": 0,
"str": 0,
"dex": 15,
"int": 10,
"def": 0,
"agi": 12,
"mr": 4,
"spRaw1": 1,
"spRaw3": 1,
"spRaw4": 1,
"sprintReg": 13,
"id": 10396
}
]
]

View file

@ -12,7 +12,7 @@ function skillPointsToPercentage(skp){
}else if(skp>=150){
return 0.808;
}else{
return(-0.0000000066695* Math.pow(Math.E, -0.00924033 * skp + 18.9) + 1.0771);
return (-0.0000000066695* Math.pow(Math.E, -0.00924033 * skp + 18.9) + 1.0771);
//return(-0.0000000066695* Math.pow(Math.E, -0.00924033 * skp + 18.9) + 1.0771).toFixed(3);
}
}
@ -56,7 +56,7 @@ class Build{
* @param powders : Powder application. List of lists of integers (powder IDs).
* In order: Helmet, Chestplate, Leggings, Boots, Weapon.
*/
constructor(level,equipment, powders){
constructor(level,equipment, powders, externalStats){
// NOTE: powders is just an array of arrays of powder IDs. Not powder objects.
this.powders = powders;
if(itemMap.get(equipment[0]) && itemMap.get(equipment[0]).type === "helmet") {
@ -135,9 +135,13 @@ class Build{
this.total_skillpoints = result[2];
this.assigned_skillpoints = result[3];
this.activeSetCounts = result[4];
// For strength boosts like warscream, vanish, etc.
this.damageMultiplier = 1.0;
this.defenseMultiplier = 1.0;
// For other external boosts ;-;
this.externalStats = externalStats;
this.initBuildStats();
}
@ -156,7 +160,7 @@ class Build{
getSpellCost(spellIdx, cost) {
cost = Math.ceil(cost * (1 - skillPointsToPercentage(this.total_skillpoints[2])));
cost += this.statMap.get("spRaw"+spellIdx);
return Math.max(1, Math.floor(cost * (1 + this.statMap.get("spPct"+spellIdx) / 100)))
return Math.max(1, Math.floor(cost * (1 + this.statMap.get("spPct"+spellIdx) / 100)));
}
@ -173,7 +177,7 @@ class Build{
}
// 0 for melee damage.
let results = calculateSpellDamage(stats, [100, 0, 0, 0, 0, 0], stats.get("mdRaw"), stats.get("mdPct"), 0, this.weapon, this.total_skillpoints, this.damageMultiplier);
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, this.damageMultiplier, this.externalStats);
let dex = this.total_skillpoints[1];
@ -209,19 +213,19 @@ class Build{
//EHP
let ehp = [totalHp, totalHp];
let defMult = classDefenseMultipliers.get(this.weapon.get("type"));
ehp[0] /= ((1-def_pct)*(1-agi_pct)*(2-defMult));
ehp[1] /= ((1-def_pct)*(2-defMult));
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
let totalHpr = rawToPct(stats.get("hprRaw"), stats.get("hprPct")/100.);
defenseStats.push(totalHpr);
//EHPR
let ehpr = [totalHpr, totalHpr];
ehpr[0] /= ((1-def_pct)*(1-agi_pct)*(2-defMult));
ehpr[1] /= ((1-def_pct)*(2-defMult));
ehpr[0] /= ((1-def_pct)*(1-agi_pct)*(2-defMult)*(2-this.defenseMultiplier));
ehpr[1] /= ((1-def_pct)*(2-defMult)*(2-this.defenseMultiplier));
defenseStats.push(ehpr);
//skp stats
defenseStats.push([def_pct*100, agi_pct*100]);
defenseStats.push([ (1 - ((1-def_pct) * (2 - this.defenseMultiplier)))*100, agi_pct*100]);
//eledefs - TODO POWDERS
let eledefs = [0, 0, 0, 0, 0];
for(const i in skp_elements){ //kinda jank but ok
@ -248,7 +252,7 @@ class Build{
statMap.set(staticID, 0);
}
statMap.set("hp", levelToHPBase(this.level)); //TODO: Add player base health
for (const item of this.items){
for (let [id, value] of item.get("maxRolls")) {
statMap.set(id,(statMap.get(id) || 0)+value);
@ -277,7 +281,16 @@ class Build{
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")]);
statMap.set("poisonPct", 100);
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;
}

View file

@ -11,10 +11,11 @@ console.log(url_tag);
* END testing section
*/
const BUILD_VERSION = "6.8.6";
const BUILD_VERSION = "6.9.2";
function setTitle() {
document.getElementById("header").textContent = "WynnBuilder version "+BUILD_VERSION+" (db version "+DB_VERSION+")";
document.getElementById("header").classList.add("funnynumber");
}
setTitle();
@ -110,8 +111,8 @@ function _ps(a,b,c,d,e) { return new PowderSpecial(a,b,c,d,e); } //bruh moment
let powderSpecialStats = [
_ps("Quake",new Map([["Radius",[5,5.5,6,6.5,7]], ["Damage",[155,220,285,350,415]] ]),"Rage",new Map([ ["Damage", [0.3,0.4,0.5,0.7,1.0]],["Description", "% " + "\u2764" + " Missing"] ]),400), //e
_ps("Chain Lightning",new Map([ ["Chains", [5,6,7,8,9]], ["Damage", [80,120,160,200,240]] ]),"Kill Streak",new Map([ ["Damage", [3,4.5,6,7.5,9]],["Duration", [5,5,5,5,5]],["Description", "Mob Killed"] ]),200), //t
_ps("Curse",new Map([ ["Duration", [7,7.5,8,8.5,9]],["Damage", [90,120,150,180,210]] ]),"Concentration",new Map([ ["Damage", [1,2,3,4,5]],["Duration",[1,1,1,1,1]],["Description", "Mana Used"] ]),150), //w
_ps("Chain Lightning",new Map([ ["Chains", [5,6,7,8,9]], ["Damage", [200,225,250,275,300]] ]),"Kill Streak",new Map([ ["Damage", [3,4.5,6,7.5,9]],["Duration", [5,5,5,5,5]],["Description", "Mob Killed"] ]),200), //t
_ps("Curse",new Map([ ["Duration", [7,7.5,8,8.5,9]],["Damage Boost", [90,120,150,180,210]] ]),"Concentration",new Map([ ["Damage", [1,2,3,4,5]],["Duration",[1,1,1,1,1]],["Description", "Mana Used"] ]),150), //w
_ps("Courage",new Map([ ["Duration", [6,6.5,7,7.5,8]],["Damage", [75,87.5,100,112.5,125]],["Damage Boost", [70,90,110,130,150]] ]),"Endurance",new Map([ ["Damage", [2,3,4,5,6]],["Duration", [8,8,8,8,8]],["Description", "Hit Taken"] ]),200), //f
_ps("Air Prison",new Map([ ["Duration", [3,3.5,4,4.5,5]],["Damage Boost", [400,450,500,550,600]],["Knockback", [8,12,16,20,24]] ]),"Dodge",new Map([ ["Damage",[2,3,4,5,6]],["Duration",[2,3,4,5,6]],["Description","Near Mobs"] ]),150) //a
];
@ -388,10 +389,34 @@ function encodeBuild() {
function calculateBuild(save_skp, skp){
try {
for (const boost of ["vanish", "warscream", "yourtotem", "allytotem"]) {
let elem = document.getElementById(boost+"-boost");
elem.classList.remove("toggleOn");
let specialNames = ["Quake", "Chain_Lightning", "Curse", "Courage", "Air_Prison"];
for (const sName of specialNames) {
for (let i = 1; i < 6; i++) {
let elem = document.getElementById(sName + "-" + i);
let name = sName.replace("_", " ");
if (elem.classList.contains("toggleOn")) { //toggle the pressed button off
elem.classList.remove("toggleOn");
let special = powderSpecialStats[specialNames.indexOf(sName)];
console.log(special);
if (special["weaponSpecialEffects"].has("Damage Boost")) {
if (name === "Courage" || name === "Curse") { //courage is universal damage boost
//player_build.damageMultiplier -= special.weaponSpecialEffects.get("Damage Boost")[i-1]/100;
player_build.externalStats.set("sdPct", player_build.externalStats.get("sdPct") - special.weaponSpecialEffects.get("Damage Boost")[i-1]);
player_build.externalStats.set("mdPct", player_build.externalStats.get("mdPct") - special.weaponSpecialEffects.get("Damage Boost")[i-1]);
player_build.externalStats.set("poisonPct", player_build.externalStats.get("poisonPct") - special.weaponSpecialEffects.get("Damage Boost")[i-1]);
} else if (name === "Air Prison") {
player_build.externalStats.set("aDamPct", player_build.externalStats.get("aDamPct") - special.weaponSpecialEffects.get("Damage Boost")[i-1]);
player_build.externalStats.get("damageBonus")[4] -= special.weaponSpecialEffects.get("Damage Boost")[i-1];
}
}
}
}
}
if(player_build){
updateBoosts("skip");
updatePowderSpecials("skip");
}
//updatePowderSpecials("skip"); //jank pt 1
save_skp = (typeof save_skp !== 'undefined') ? save_skp : false;
/* TODO: implement level changing
Make this entire function prettier
@ -434,9 +459,8 @@ function calculateBuild(save_skp, skp){
i.style.display = "grid";
}
console.log(equipment);
player_build = new Build(level, equipment, powderings);
console.log(player_build.toString());
player_build = new Build(level, equipment, powderings, new Map());
//console.log(player_build.toString());
displayEquipOrder(document.getElementById("build-order"),player_build.equip_order);
@ -484,11 +508,46 @@ function calculateBuild(save_skp, skp){
/* Updates all build statistics based on (for now) the skillpoint input fields and then calculates build stats.
*/
function updateStats() {
let specialNames = ["Quake", "Chain_Lightning", "Curse", "Courage", "Air_Prison"];
for (const sName of specialNames) {
for (let i = 1; i < 6; i++) {
let elem = document.getElementById(sName + "-" + i);
let name = sName.replace("_", " ");
if (elem.classList.contains("toggleOn")) { //toggle the pressed button off
elem.classList.remove("toggleOn");
let special = powderSpecialStats[specialNames.indexOf(sName)];
console.log(special);
if (special["weaponSpecialEffects"].has("Damage Boost")) {
if (name === "Courage" || name === "Curse") { //courage is universal damage boost
//player_build.damageMultiplier -= special.weaponSpecialEffects.get("Damage Boost")[i-1]/100;
player_build.externalStats.set("sdPct", player_build.externalStats.get("sdPct") - special.weaponSpecialEffects.get("Damage Boost")[i-1]);
player_build.externalStats.set("mdPct", player_build.externalStats.get("mdPct") - special.weaponSpecialEffects.get("Damage Boost")[i-1]);
player_build.externalStats.set("poisonPct", player_build.externalStats.get("poisonPct") - special.weaponSpecialEffects.get("Damage Boost")[i-1]);
} else if (name === "Air Prison") {
player_build.externalStats.set("aDamPct", player_build.externalStats.get("aDamPct") - special.weaponSpecialEffects.get("Damage Boost")[i-1]);
player_build.externalStats.get("damageBonus")[4] -= special.weaponSpecialEffects.get("Damage Boost")[i-1];
}
}
}
}
}
//WILL BREAK WEBSITE IF NO BUILD HAS BEEN INITIALIZED! @HPP
let skillpoints = player_build.total_skillpoints;
let delta_total = 0;
for (let i in skp_order) {
let manual_assigned = getValue(skp_order[i] + "-skp");
let value = document.getElementById(skp_order[i] + "-skp").value;
let manual_assigned = 0;
if (value.includes("+")) {
let skp = value.split("+");
for (const s of skp) {
manual_assigned += parseInt(s,10);
}
} else {
manual_assigned = parseInt(value,10);
}
let delta = manual_assigned - skillpoints[i];
skillpoints[i] = manual_assigned;
player_build.base_skillpoints[i] += delta;
@ -496,17 +555,40 @@ function updateStats() {
}
player_build.assigned_skillpoints += delta_total;
calculateBuildStats();
if(player_build){
updatePowderSpecials("skip");
updateBoosts("skip");
}
}
/* Updates all spell boosts
*/
function updateBoosts(buttonId) {
let elem = document.getElementById(buttonId);
if (elem.classList.contains("toggleOn")) {
player_build.damageMultiplier -= damageMultipliers.get(buttonId.split("-")[0]);
elem.classList.remove("toggleOn");
}else{
player_build.damageMultiplier += damageMultipliers.get(buttonId.split("-")[0]);
elem.classList.add("toggleOn");
let name = buttonId.split("-")[0];
if(buttonId !== "skip") {
if (elem.classList.contains("toggleOn")) {
player_build.damageMultiplier -= damageMultipliers.get(name);
if (name === "warscream") {
player_build.defenseMultiplier -= .10;
}
elem.classList.remove("toggleOn");
}else{
player_build.damageMultiplier += damageMultipliers.get(name);
if (name === "warscream") {
player_build.defenseMultiplier += .10;
}
elem.classList.add("toggleOn");
}
updatePowderSpecials("skip"); //jank pt 1
} else {
for (const [key, value] of damageMultipliers) {
let elem = document.getElementById(key + "-boost")
if (elem.classList.contains("toggleOn")) {
elem.classList.remove("toggleOn");
player_build.damageMultiplier -= value;
if (key === "warscream") { player_build.defenseMultiplier -= .10 }
}
}
}
calculateBuildStats();
}
@ -514,18 +596,56 @@ function updateBoosts(buttonId) {
/* Updates all powder special boosts
*/
function updatePowderSpecials(buttonId){
//console.log(player_build.statMap);
let name = (buttonId).split("-")[0];
let power = (buttonId).split("-")[1]; // [1, 5]
let specialNames = ["Quake", "Chain Lightning", "Curse", "Courage", "Air Prison"];
let powderSpecials = []; // [ [special, power], [special, power]]
let elem = document.getElementById(buttonId);
if (elem.classList.contains("toggleOn")) {
elem.classList.remove("toggleOn");
}else {
for (let i = 1;i < 6; i++) {
document.getElementById(name + "-" + i).classList.remove("toggleOn");
if(name !== "skip"){
let elem = document.getElementById(buttonId);
if (elem.classList.contains("toggleOn")) { //toggle the pressed button off
elem.classList.remove("toggleOn");
let special = powderSpecialStats[specialNames.indexOf(name.replace("_", " "))];
if (special.weaponSpecialEffects.has("Damage Boost")) {
name = name.replace("_", " ");
if (name === "Courage" || name === "Curse") { //courage and curse are universal damage boost
player_build.externalStats.set("sdPct", player_build.externalStats.get("sdPct") - special.weaponSpecialEffects.get("Damage Boost")[power-1]);
player_build.externalStats.set("mdPct", player_build.externalStats.get("mdPct") - special.weaponSpecialEffects.get("Damage Boost")[power-1]);
player_build.externalStats.set("poisonPct", player_build.externalStats.get("poisonPct") - special.weaponSpecialEffects.get("Damage Boost")[power-1]);
//poison?
} else if (name === "Air Prison") {
player_build.externalStats.set("aDamPct", player_build.externalStats.get("aDamPct") - special.weaponSpecialEffects.get("Damage Boost")[power-1]);
player_build.externalStats.get("damageBonus")[4] -= special.weaponSpecialEffects.get("Damage Boost")[power-1];
}
}
} else {
for (let i = 1;i < 6; i++) { //toggle all pressed buttons of the same powder special off
//name is same, power is i
if(document.getElementById(name.replace(" ", "_") + "-" + i).classList.contains("toggleOn")) {
document.getElementById(name.replace(" ", "_") + "-" + i).classList.remove("toggleOn");
let special = powderSpecialStats[specialNames.indexOf(name.replace("_", " "))];
if (special.weaponSpecialEffects.has("Damage Boost")) {
name = name.replace("_", " "); //might be redundant
if (name === "Courage" || name === "Curse") { //courage is universal damage boost
//player_build.damageMultiplier -= special.weaponSpecialEffects.get("Damage Boost")[i-1]/100;
player_build.externalStats.set("sdPct", player_build.externalStats.get("sdPct") - special.weaponSpecialEffects.get("Damage Boost")[i-1]);
player_build.externalStats.set("mdPct", player_build.externalStats.get("mdPct") - special.weaponSpecialEffects.get("Damage Boost")[i-1]);
player_build.externalStats.set("poisonPct", player_build.externalStats.get("poisonPct") - special.weaponSpecialEffects.get("Damage Boost")[i-1]);
} else if (name === "Air Prison") {
player_build.externalStats.set("aDamPct", player_build.externalStats.get("aDamPct") - special.weaponSpecialEffects.get("Damage Boost")[i-1]);
player_build.externalStats.get("damageBonus")[4] -= special.weaponSpecialEffects.get("Damage Boost")[i-1];
}
}
}
}
//toggle the pressed button on
elem.classList.add("toggleOn");
}
elem.classList.add("toggleOn");
}
for (const sName of specialNames) {
for (let i = 1;i < 6; i++) {
if (document.getElementById(sName.replace(" ","_") + "-" + i).classList.contains("toggleOn")) {
@ -535,9 +655,27 @@ function updatePowderSpecials(buttonId){
}
}
}
//console.log(powderSpecials);
displayPowderSpecials(document.getElementById("powder-special-stats"), powderSpecials);
if (name !== "skip") {
let elem = document.getElementById(buttonId);
if (elem.classList.contains("toggleOn")) {
let special = powderSpecialStats[specialNames.indexOf(name.replace("_", " "))];
if (special["weaponSpecialEffects"].has("Damage Boost")) {
let name = special["weaponSpecialName"];
if (name === "Courage" || name === "Curse") { //courage and curse are is universal damage boost
player_build.externalStats.set("sdPct", player_build.externalStats.get("sdPct") + special.weaponSpecialEffects.get("Damage Boost")[power-1]);
player_build.externalStats.set("mdPct", player_build.externalStats.get("mdPct") + special.weaponSpecialEffects.get("Damage Boost")[power-1]);
player_build.externalStats.set("poisonPct", player_build.externalStats.get("poisonPct") + special.weaponSpecialEffects.get("Damage Boost")[power-1]);
} else if (name === "Air Prison") {
player_build.externalStats.set("aDamPct", player_build.externalStats.get("aDamPct") + special.weaponSpecialEffects.get("Damage Boost")[power-1]);
player_build.externalStats.get("damageBonus")[4] += special.weaponSpecialEffects.get("Damage Boost")[power-1];
}
}
}
}
displayPowderSpecials(document.getElementById("powder-special-stats"), powderSpecials, player_build);
calculateBuildStats(); //also make damage boosts apply ;-;
}
/* Calculates all build statistics and updates the entire display.
@ -563,38 +701,33 @@ function calculateBuildStats() {
let summarybox = document.getElementById("summary-box");
summarybox.textContent = "";
let skpRow = document.createElement("tr");
let skpSummary = document.createElement("td");
skpSummary.textContent = "Summary: Assigned " + player_build.assigned_skillpoints + " skillpoints. Total: (";
skpSummary.classList.add("itemp");
skpRow.appendChild(skpSummary);
let skpRow = document.createElement("p");
//skpRow.classList.add("left");
let td = document.createElement("p");
//td.classList.add("left");
let skpSummary = document.createElement("b");
skpSummary.textContent = "Assigned " + player_build.assigned_skillpoints + " skillpoints. Total: (";
//skpSummary.classList.add("itemp");
td.appendChild(skpSummary);
for (let i = 0; i < skp_order.length; i++){
let skp = document.createElement("td");
let boost = document.createElement("td");
let separator = document.createElement("td");
skp.classList.add("itemp");
skp.classList.add("nopadding");
let skp = document.createElement("b");
let boost = document.createElement("b");
skp.classList.add(damageClasses[i+1]);
boost.classList.add("itemp");
boost.classList.add("nopadding");
boost.textContent = player_build.total_skillpoints[i];
skpRow.appendChild(skp);
skpRow.appendChild(document.createElement("br"));
skpRow.appendChild(boost);
if(i < 4){
skpRow.appendChild(separator);
if (i < 4) {
boost.classList.add("space");
}
td.appendChild(skp);
td.appendChild(boost);
}
let skpEnd = document.createElement("td");
let skpEnd = document.createElement("b");
skpEnd.textContent = ")";
skpEnd.classList.add("itemp");
skpRow.append(skpEnd);
td.appendChild(skpEnd);
skpRow.append(td);
let remainingRow = document.createElement("tr");
remainingRow.classList.add("itemp");
let remainingSkp = document.createElement("td");
remainingSkp.classList.add("left");
let remainingSkp = document.createElement("p");
remainingSkp.classList.add("center");
let remainingSkpTitle = document.createElement("b");
remainingSkpTitle.textContent = "Remaining skillpoints: ";
let remainingSkpContent = document.createElement("b");
@ -604,10 +737,9 @@ function calculateBuildStats() {
remainingSkp.appendChild(remainingSkpTitle);
remainingSkp.appendChild(remainingSkpContent);
remainingRow.appendChild(remainingSkp);
summarybox.append(skpRow);
summarybox.append(remainingRow);
summarybox.append(remainingSkp);
if(player_build.assigned_skillpoints > levelToSkillPoints(player_build.level)){
let skpWarning = document.createElement("p");
//skpWarning.classList.add("itemp");
@ -644,8 +776,9 @@ function calculateBuildStats() {
displayExpandedItem(player_build.items[i], buildFields[i]);
}
displayBuildStats(player_build, "build-overall-stats");
displaySetBonuses(player_build, "set-info");
displayBuildStats("build-overall-stats",player_build);
displaySetBonuses("set-info",player_build);
displayNextCosts("int-info",player_build);
let meleeStats = player_build.getMeleeStats();
displayMeleeDamage(document.getElementById("build-melee-stats"), document.getElementById("build-melee-statsAvg"), meleeStats);
@ -703,6 +836,7 @@ function resetFields(){
setValue("agi-skp", "0");
setValue("level-choice", "");
location.hash = "";
calculateBuild();
}
load_init(init);

View file

@ -276009,6 +276009,199 @@
"gXp": 0,
"gSpd": 0,
"id": 10397
},
{
"tier": "Unique",
"type": "boots",
"name": "Boots of Blue Stone (1.20)",
"displayName": "Boots of Blue Stone (1.20)",
"set": null,
"quest": null,
"classReq": null,
"restrict": "1.20 item",
"fixID": false,
"strReq": 20,
"dexReq": 20,
"intReq": 20,
"defReq": 20,
"agiReq": 20,
"category": "armor",
"lvl": 82,
"hp": 2000,
"eDef": 30,
"tDef": 30,
"wDef": 30,
"fDef": 30,
"aDef": 30,
"slots": 2,
"str": 5,
"dex": 5,
"int": 5,
"def": 5,
"agi": 5,
"sdRaw": 140,
"mdRaw": 180,
"eDamPct": 13,
"tDamPct": 13,
"wDamPct": 13,
"fDamPct": 13,
"aDamPct": 13,
"sprint": 13,
"sprintReg": 13,
"id": 10398
},
{
"tier": "Rare",
"type": "relik",
"name": "Estuarine (1.20)",
"displayName": "Estuarine (1.20)",
"set": null,
"quest": null,
"classReq": null,
"restrict": "1.20 item",
"fixID": false,
"strReq": 28,
"dexReq": 0,
"intReq": 32,
"defReq": 0,
"agiReq": 0,
"atkSpd": "NORMAL",
"category": "weapon",
"lvl": 71,
"nDam": "70-80",
"eDam": "100-110",
"tDam": "0-0",
"wDam": "71-85",
"fDam": "0-0",
"aDam": "0-0",
"slots": 3,
"str": 0,
"dex": 0,
"int": 8,
"def": 0,
"agi": 0,
"mr": 1,
"spd": -12,
"mdPct": -20,
"mdRaw": 130,
"wDamPct": 35,
"eDefPct": 30,
"id": 10399
},
{
"tier": "Rare",
"type": "helmet",
"name": "The Modulator (1.20)",
"displayName": "The Modulator (1.20)",
"set": null,
"quest": null,
"classReq": null,
"restrict": "1.20 item",
"fixID": true,
"strReq": 25,
"dexReq": 25,
"intReq": 25,
"defReq": 25,
"agiReq": 25,
"category": "armor",
"lvl": 88,
"hp": 2500,
"slots": 5,
"str": 8,
"dex": 8,
"int": 8,
"def": 8,
"agi": 8,
"spd": 15,
"eDefPct": 30,
"tDefPct": 30,
"wDefPct": 30,
"fDefPct": 30,
"aDefPct": 30,
"id": 10400
},
{
"tier": "Rare",
"type": "dagger",
"name": "Sreggad (1.20)",
"displayName": "Sreggad (1.20)",
"set": null,
"quest": null,
"classReq": null,
"restrict": "1.20 item",
"fixID": false,
"strReq": 0,
"dexReq": 0,
"intReq": 0,
"defReq": 0,
"agiReq": 0,
"atkSpd": "SUPER_SLOW",
"category": "weapon",
"lvl": 85,
"nDam": "0-0",
"eDam": "0-0",
"tDam": "0-0",
"wDam": "0-0",
"fDam": "0-0",
"aDam": "0-0",
"slots": 2,
"str": 0,
"dex": 0,
"int": 0,
"def": 20,
"agi": 20,
"hprRaw": 173,
"ls": 354,
"thorns": 333,
"hpBonus": 2500,
"ref": 333,
"eDefPct": 50,
"tDefPct": 50,
"wDefPct": 50,
"fDefPct": 50,
"aDefPct": 50,
"id": 10401
},
{
"tier": "Mythic",
"type": "dagger",
"name": "Nullification (1.20)",
"displayName": "Nullification (1.20)",
"set": null,
"quest": null,
"classReq": null,
"restrict": "1.20 item",
"fixID": false,
"strReq": 30,
"dexReq": 30,
"intReq": 30,
"defReq": 30,
"agiReq": 30,
"atkSpd": "FAST",
"category": "weapon",
"lvl": 95,
"nDam": "0-0",
"eDam": "80-88",
"tDam": "20-148",
"wDam": "65-103",
"fDam": "50-118",
"aDam": "35-133",
"slots": 3,
"str": 0,
"dex": 0,
"int": 0,
"def": 50,
"agi": 0,
"ls": 495,
"ms": 3,
"poison": -7000,
"ref": 80,
"eDefPct": 143,
"tDefPct": 143,
"wDefPct": 143,
"fDefPct": 143,
"aDefPct": 143,
"id": 10402
}
],
"sets": {

File diff suppressed because one or more lines are too long

View file

@ -1,10 +1,27 @@
const damageMultipliers = new Map([ ["allytotem", .15], ["yourtotem", .35], ["vanish", 0.80], ["warscream", 0.10] ]);
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.
function calculateSpellDamage(stats, spellConversions, rawModifier, pctModifier, spellMultiplier, weapon, total_skillpoints, damageMultiplier) {
// externalStats should be a map
function calculateSpellDamage(stats, spellConversions, rawModifier, pctModifier, spellMultiplier, weapon, total_skillpoints, damageMultiplier, externalStats) {
let buildStats = new Map(stats);
if(externalStats) { //if nothing is passed in, then this hopefully won't trigger
for (const [key,value] of externalStats) {
if (typeof value === "number") {
buildStats.set(key, buildStats.get(key) + value);
} else if (Array.isArray(value)) {
arr = [];
for (let i = 0; i < value.length; i++) {
arr[i] = buildStats.get(key)[i] + value[i];
}
buildStats.set(key, arr);
}
}
}
// Array of neutral + ewtfa damages. Each entry is a pair (min, max).
let damages = [];
for (const damage_string of stats.get("damageRaw")) {
for (const damage_string of buildStats.get("damageRaw")) {
const damage_vals = damage_string.split("-").map(Number);
damages.push(damage_vals);
}
@ -48,7 +65,7 @@ function calculateSpellDamage(stats, spellConversions, rawModifier, pctModifier,
melee = true;
}
else {
damageMult *= spellMultiplier * baseDamageMultiplier[attackSpeeds.indexOf(stats.get("atkSpd"))];
damageMult *= spellMultiplier * baseDamageMultiplier[attackSpeeds.indexOf(buildStats.get("atkSpd"))];
}
//console.log(damages);
//console.log(damageMult);
@ -66,16 +83,16 @@ function calculateSpellDamage(stats, spellConversions, rawModifier, pctModifier,
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.);
skillBoost.push(skillPointsToPercentage(total_skillpoints[i]) + buildStats.get("damageBonus")[i] / 100.);
}
for (let i in damages) {
let damageBoost = Math.max(1 + skillBoost[i] + staticBoost, 0);
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
Math.max(damages[i][0] * Math.max(damageBoost,0) * damageMult, 0), // Normal min
Math.max(damages[i][1] * Math.max(damageBoost,0) * damageMult, 0), // Normal max
Math.max(damages[i][0] * Math.max(1 + damageBoost, 0) * damageMult, 0), // Crit min
Math.max(damages[i][1] * Math.max(1 + damageBoost, 0) * damageMult, 0), // Crit max
]);
totalDamNorm[0] += damages_results[i][0];
totalDamNorm[1] += damages_results[i][1];
@ -191,13 +208,13 @@ const spell_table = {
],
"powder": [ //This is how instant-damage powder specials are implemented. To view time-boosted damage powder specials (curse, 2nd courage, air prison, view @TODO)
{ title: "Quake", cost: 0, parts:[
{type: "damage", multiplier: [155, 220, 285, 350, 415], conversion: [0,100,0,0,0,0], summary: true},
{ subtitle: "Total Damage", type: "damage", multiplier: [155, 220, 285, 350, 415], conversion: [0,100,0,0,0,0], summary: true},
] },
{ title: "Chain Lightning", cost: 0, parts: [
{type: "damage", multiplier: [80, 120, 160, 200, 240], conversion: [0,0,100,0,0,0], summary: true},
{ subtitle: "Total Damage", type: "damage", multiplier: [200, 225, 250, 275, 300], conversion: [0,0,100,0,0,0], summary: true},
]},
{ title: "Courage", cost: 0, parts: [
{type: "damage", multiplier: [75,87.5,100,112.5,125], conversion: [0,0,0,0,100,0], summary: true},
]},
{ subtitle: "Total Damage", type: "damage", multiplier: [75, 87.5, 100, 112.5, 125], conversion: [0,0,0,0,100,0], summary: true},
]}, //[75, 87.5, 100, 112.5, 125]
]
};

View file

@ -55,8 +55,8 @@ function expandItem(item, powders){
//console.log(powderStats[id]);
let powder = powderStats[id];
let name = powderNames.get(id);
expandedItem.set(name.charAt(0) + "Def", expandedItem.get(name.charAt(0)+"Def") + powder["defPlus"]);
expandedItem.set(skp_elements[(skp_elements.indexOf(name.charAt(0)) + 6 )% 5] + "Def", expandedItem.get(skp_elements[(skp_elements.indexOf(name.charAt(0)) + 6 )% 5]+"Def") - powder["defMinus"]);
expandedItem.set(name.charAt(0) + "Def", (expandedItem.get(name.charAt(0)+"Def") || 0) + powder["defPlus"]);
expandedItem.set(skp_elements[(skp_elements.indexOf(name.charAt(0)) + 4 )% 5] + "Def", (expandedItem.get(skp_elements[(skp_elements.indexOf(name.charAt(0)) + 4 )% 5]+"Def") || 0) - powder["defMinus"]);
}
}
@ -95,7 +95,7 @@ function apply_elemental_format(p_elem, id, suffix) {
p_elem.appendChild(i_elem2);
}
function displaySetBonuses(build, parent_id) {
function displaySetBonuses(parent_id,build) {
setHTML(parent_id, "");
let parent_div = document.getElementById(parent_id);
@ -134,7 +134,7 @@ function displaySetBonuses(build, parent_id) {
}
}
function displayBuildStats(build, parent_id){
function displayBuildStats(parent_id,build){
// Commands to "script" the creation of nice formatting.
// #commands create a new element.
// !elemental is some janky hack for elemental damage.
@ -246,6 +246,9 @@ function displayBuildStats(build, parent_id){
if (reversedIDs.filter(e => e !== "atkTier").includes(id)) {
style === "positive" ? style = "negative" : style = "positive";
}
if (id === "poison" && id_val > 0) {
id_val = Math.round(id_val*(build.statMap.get("poisonPct") + build.externalStats.get("poisonPct"))/100);
}
displayFixedID(active_elem, id, id_val, elemental_format, style);
if (id === "poison" && id_val > 0) {
let style = "positive";
@ -257,7 +260,7 @@ function displayBuildStats(build, parent_id){
prefix_elem.textContent = "-> With Strength: ";
let number_elem = document.createElement('b');
number_elem.classList.add(style);
number_elem.textContent = (id_val * (1+skillPointsToPercentage(build.total_skillpoints[0]))).toFixed(0) + idSuffixes[id];
number_elem.textContent = (id_val * (1+skillPointsToPercentage(build.total_skillpoints[0])) ).toFixed(0) + idSuffixes[id];
value_elem.append(prefix_elem);
value_elem.append(number_elem);
row.appendChild(value_elem);
@ -279,7 +282,7 @@ function displayExpandedItem(item, parent_id){
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, [0, 0, 0, 0, 0], 1);
let results = calculateSpellDamage(stats, [100, 0, 0, 0, 0, 0], 0, 0, 0, item, [0, 0, 0, 0, 0], 1, undefined);
let damages = results[2];
let damage_keys = [ "nDam_", "eDam_", "tDam_", "wDam_", "fDam_", "aDam_" ];
for (const i in damage_keys) {
@ -290,6 +293,7 @@ function displayExpandedItem(item, parent_id){
let display_commands = [
"#cdiv",
"displayName",
//"type", //REPLACE THIS WITH SKIN
"#ldiv",
"atkSpd",
"#ldiv",
@ -404,6 +408,18 @@ function displayExpandedItem(item, parent_id){
if (item.get("tier") !== " ") {
p_elem.classList.add(item.get("tier"));
}
/*let validTypes = ["helmet", "chestplate", "leggings", "boots", "relik", "wand", "bow", "spear", "dagger", "ring", "bracelet", "necklace"];
if (item.has("type") && validTypes.includes(item.get("type"))) {
p = document.createElement("p");
img = document.createElement("img");
img.src = "./media/items/generic-"+item.get("type")+".png";
img.alt = "image no display :(";
img.classList.add("center");
p.append(img);
p.classList.add("itemp");
p_elem.append(p);
}*/
} else if (skp_order.includes(id)) { //id = str, dex, int, def, or agi
p_elem.textContent = "";
p_elem.classList.add("itemtable");
@ -423,7 +439,7 @@ function displayExpandedItem(item, parent_id){
p_elem.appendChild(row);
} else if (id === "restrict") {
p_elem.classList.add("restrict");
}
}
}
}
else if (rolledIDs.includes(id) && item.get("minRolls").get(id)){ // && item.get("maxRolls").get(id) ){//rolled ID & non-0/non-null/non-und ID
@ -540,6 +556,80 @@ function displayExpandedItem(item, parent_id){
}
}
function displayNextCosts(parent_id, build) {
let p_elem = document.getElementById(parent_id);
let int = build.total_skillpoints[2];
let spells = spell_table[build.weapon.get("type")];
p_elem.textContent = "";
let title = document.createElement("p");
title.classList.add("title");
title.classList.add("Normal");
title.textContent = "Next Spell Costs";
let int_title = document.createElement("p");
int_title.classList.add("itemp");
int_title.textContent = int + " Intelligence points.";
p_elem.append(title);
p_elem.append(int_title);
for (const spell of spells) { //warp
let spellp = document.createElement("p");
let spelltitle = document.createElement("p");
spelltitle.classList.add("itemp");
spelltitle.textContent = spell.title;
spellp.appendChild(spelltitle);
let row = document.createElement("p");
row.classList.add("itemp");
let init_cost = document.createElement("b");
init_cost.textContent = build.getSpellCost(spells.indexOf(spell) + 1, 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.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 noUpdate = false;
//forgive me... I couldn't inverse ceil, floor, and max.
while (build.getSpellCost(spells.indexOf(spell) + 1, spell.cost) > target) {
if(needed > 150) {
noUpdate = true;
break;
}
needed++;
build.total_skillpoints[2] = needed;
}
let missing = needed - int;
//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);
}else {
next_cost.textContent = (init_cost.textContent === "1" ? 1 : build.getSpellCost(spells.indexOf(spell) + 1, spell.cost));
}
build.total_skillpoints[2] = int;//forgive me pt 2
int_needed.textContent = ": " + (needed > 150 ? ">150" : needed) + " int (+" + (needed > 150 ? "n/a" : missing) + ")";
}
row.appendChild(init_cost);
row.appendChild(arrow);
row.appendChild(next_cost);
row.appendChild(int_needed);
spellp.appendChild(row);
p_elem.append(spellp);
}
}
function displayFixedID(active, id, value, elemental_format, style) {
if (style) {
/*if(reversedIDs.filter(e => e !== "atkTier").includes(id)){
@ -612,8 +702,15 @@ function displayPoisonDamage(overallparent_elem, build) {
let overallpoisonDamage = document.createElement("p");
overallpoisonDamage.classList.add("itemp");
let poison_tick = Math.floor(build.statMap.get("poison") * (1+skillPointsToPercentage(build.total_skillpoints[0]))/3);
overallpoisonDamage.textContent = "Poison Tick: " + Math.max(poison_tick,0);
let overallpoisonDamageFirst = document.createElement("b");
let overallpoisonDamageSecond = document.createElement("b");
let poison_tick = Math.round(build.statMap.get("poison") * (1+skillPointsToPercentage(build.total_skillpoints[0])) * (build.statMap.get("poisonPct") + build.externalStats.get("poisonPct"))/100 /3);
overallpoisonDamageFirst.textContent = "Poison Tick: ";
overallpoisonDamageSecond.textContent = Math.max(poison_tick,0);
overallpoisonDamageSecond.classList.add("Damage");
overallpoisonDamage.appendChild(overallpoisonDamageFirst);
overallpoisonDamage.appendChild(overallpoisonDamageSecond);
overallparent_elem.append(overallpoisonDamage);
overallparent_elem.append(document.createElement("br"));
}
@ -665,7 +762,15 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){
//overall average DPS
let overallaverageDamage = document.createElement("p");
overallaverageDamage.classList.add("itemp");
overallaverageDamage.textContent = "Average DPS: " + stats[10];
let overallaverageDamageFirst = document.createElement("b");
overallaverageDamageFirst.textContent = "Average DPS: "
let overallaverageDamageSecond = document.createElement("b");
overallaverageDamageSecond.classList.add("Damage");
overallaverageDamageSecond.textContent = stats[10];
overallaverageDamage.appendChild(overallaverageDamageFirst);
overallaverageDamage.appendChild(overallaverageDamageSecond);
overallparent_elem.append(overallaverageDamage);
overallparent_elem.append(document.createElement("br"));
@ -681,7 +786,13 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){
let overallatkSpd = document.createElement("p");
overallatkSpd.classList.add("center");
overallatkSpd.classList.add("itemp");
overallatkSpd.textContent = "Attack Speed: " + attackSpeeds[stats[11]];
let overallatkSpdFirst = document.createElement("b");
overallatkSpdFirst.textContent = "Attack Speed: ";
let overallatkSpdSecond = document.createElement("b");
overallatkSpdSecond.classList.add("Damage");
overallatkSpdSecond.textContent = attackSpeeds[stats[11]];
overallatkSpd.appendChild(overallatkSpdFirst);
overallatkSpd.appendChild(overallatkSpdSecond);
overallparent_elem.append(overallatkSpd);
overallparent_elem.append(document.createElement("br"));
@ -714,7 +825,14 @@ function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats){
//overall average DPS
let singleHitDamage = document.createElement("p");
singleHitDamage.classList.add("itemp");
singleHitDamage.textContent = "Single Hit Average: " + stats[12].toFixed(2);
let singleHitDamageFirst = document.createElement("b");
singleHitDamageFirst.textContent = "Single Hit Average: ";
let singleHitDamageSecond = document.createElement("b");
singleHitDamageSecond.classList.add("Damage");
singleHitDamageSecond.textContent = stats[12].toFixed(2);
singleHitDamage.appendChild(singleHitDamageFirst);
singleHitDamage.appendChild(singleHitDamageSecond);
overallparent_elem.append(singleHitDamage);
overallparent_elem.append(document.createElement("br"));
@ -950,12 +1068,14 @@ function displayDefenseStats(parent_elem, build, insertSummary){
parent_elem.append(statsTable);
}
function displayPowderSpecials(parent_elem, powderSpecials) {
function displayPowderSpecials(parent_elem, powderSpecials, build) {
parent_elem.textContent = "Powder Specials";
let specials = powderSpecials.slice();
let stats = build.statMap;
let expandedStats = new Map();
//each entry of powderSpecials is [ps, power]
for (special of specials) {
//iterate through the special and display it warp
//iterate through the special and display its effects.
let powder_special = document.createElement("p");
powder_special.classList.add("left");
let specialSuffixes = new Map([ ["Duration", " sec"], ["Radius", " blocks"], ["Chains", ""], ["Damage", "%"], ["Damage Boost", "%"], ["Knockback", " blocks"] ]);
@ -969,7 +1089,7 @@ function displayPowderSpecials(parent_elem, powderSpecials) {
specialEffects.classList.add("nocolor");
let effects = special[0]["weaponSpecialEffects"];
let power = special[1];
specialTitle.textContent = special[0]["weaponSpecialName"] + " " + power;
specialTitle.textContent = special[0]["weaponSpecialName"] + " " + Math.floor((power-1)*0.5 + 4) + (power % 2 == 0 ? ".5" : "");
for (const [key,value] of effects) {
let effect = document.createElement("p");
effect.classList.add("itemp");
@ -977,35 +1097,99 @@ function displayPowderSpecials(parent_elem, powderSpecials) {
if(key === "Damage"){
effect.textContent += elementIcons[powderSpecialStats.indexOf(special[0])];
}
if (powderSpecials.indexOf(special[0]) == 2) {
effect.textContent += " / Mana Used";
if(special[0]["weaponSpecialName"] === "Air Prison" && key === "Damage Boost") {
effect.textContent += " (only 1st hit)";
}
specialEffects.appendChild(effect);
}
//specialTitle.textContent = special["weaponSpecialName"];
/*
if (element !== "") {//powder special is "[e,t,w,f,a]+[0,1,2,3,4]"
let powderSpecial = powderSpecialStats[ skp_elements.indexOf(element)];
let effects;
if (item.get("category") === "weapon") {//weapon
}else if (item.get("category") === "armor") {//armor
effects = powderSpecial["armorSpecialEffects"];
specialTitle.textContent += powderSpecial["armorSpecialName"] + ": ";
powder_special.appendChild(specialTitle);
powder_special.appendChild(specialEffects);
//if this special is an instant-damage special (Quake, Chain Lightning, Courage Burst), display the damage.
let specialDamage = document.createElement("p");
let spells = spell_table["powder"];
if (powderSpecialStats.indexOf(special[0]) == 0 || powderSpecialStats.indexOf(special[0]) == 1 || powderSpecialStats.indexOf(special[0]) == 3) { //Quake, Chain Lightning, or Courage
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
let critChance = skillPointsToPercentage(build.total_skillpoints[1]);
let save_damages = [];
let totalDamNormal = _results[0];
let totalDamCrit = _results[1];
let results = _results[2];
for (let i = 0; i < 6; ++i) {
for (let j in results[i]) {
results[i][j] = results[i][j].toFixed(2);
}
}
specialTitle.append(specialEffects);
powder_special.appendChild(specialTitle);
let nonCritAverage = (totalDamNormal[0]+totalDamNormal[1])/2 || 0;
let critAverage = (totalDamCrit[0]+totalDamCrit[1])/2 || 0;
let averageDamage = (1-critChance)*nonCritAverage+critChance*critAverage || 0;
parent_div.append(powder_special);
}
*/
powder_special.appendChild(specialTitle);
powder_special.appendChild(specialEffects);
parent_elem.appendChild(powder_special);
let averageLabel = document.createElement("p");
averageLabel.textContent = "Average: "+averageDamage.toFixed(2);
averageLabel.classList.add("damageSubtitle");
specialDamage.append(averageLabel);
let nonCritLabel = document.createElement("p");
nonCritLabel.textContent = "Non-Crit Average: "+nonCritAverage.toFixed(2);
nonCritLabel.classList.add("damageSubtitle");
specialDamage.append(nonCritLabel);
for (let i = 0; i < 6; i++){
if (results[i][1] > 0){
let p = document.createElement("p");
p.classList.add("damagep");
p.classList.add(damageClasses[i]);
p.textContent = results[i][0]+"-"+results[i][1];
specialDamage.append(p);
}
}
let normalDamage = document.createElement("p");
normalDamage.textContent = "Total: " + totalDamNormal[0].toFixed(2) + "-" + totalDamNormal[1].toFixed(2);
normalDamage.classList.add("itemp");
specialDamage.append(normalDamage);
let nonCritChanceLabel = document.createElement("p");
nonCritChanceLabel.textContent = "Non-Crit Chance: " + ((1-critChance)*100).toFixed(2) + "%";
specialDamage.append(nonCritChanceLabel);
let critLabel = document.createElement("p");
critLabel.textContent = "Crit Average: "+critAverage.toFixed(2);
critLabel.classList.add("damageSubtitle");
specialDamage.append(critLabel);
for (let i = 0; i < 6; i++){
if (results[i][1] > 0){
let p = document.createElement("p");
p.classList.add("damagep");
p.classList.add(damageClasses[i]);
p.textContent = results[i][2]+"-"+results[i][3];
specialDamage.append(p);
}
}
let critDamage = document.createElement("p");
critDamage.textContent = "Total: " + totalDamCrit[0].toFixed(2) + "-" + totalDamCrit[1].toFixed(2);
critDamage.classList.add("itemp");
specialDamage.append(critDamage);
let critChanceLabel = document.createElement("p");
critChanceLabel.textContent = "Crit Chance: " + (critChance*100).toFixed(2) + "%";
specialDamage.append(critChanceLabel);
save_damages.push(averageDamage);
powder_special.append(specialDamage);
}
parent_elem.appendChild(powder_special);
}
}
function displaySpellDamage(parent_elem, overallparent_elem, build, spell, spellIdx) {
parent_elem.textContent = "";
@ -1022,7 +1206,18 @@ function displaySpellDamage(parent_elem, overallparent_elem, build, spell, spell
if (spellIdx != 0) {
title_elem.textContent = spell.title + " (" + build.getSpellCost(spellIdx, spell.cost) + ")";
title_elemavg.textContent = spell.title + " (" + build.getSpellCost(spellIdx, spell.cost) + ")";
let first = document.createElement("b");
first.textContent = spell.title + " (";
title_elemavg.appendChild(first);
let second = document.createElement("b");
second.textContent = build.getSpellCost(spellIdx, spell.cost);
second.classList.add("Mana");
title_elemavg.appendChild(second);
let fourth = document.createElement("b");
fourth.textContent = ")";
title_elemavg.appendChild(fourth);
//title_elemavg.textContent = spell.title + " (" + build.getSpellCost(spellIdx, spell.cost) + ")";
}
else {
title_elem.textContent = spell.title;
@ -1042,6 +1237,7 @@ function displaySpellDamage(parent_elem, overallparent_elem, build, spell, spell
parent_elem.append(part_div);
let part_divavg = document.createElement("p");
//part_divavg.classList.add("Normal");
overallparent_elem.append(part_divavg);
let subtitle_elem = document.createElement("p");
@ -1054,10 +1250,10 @@ function displaySpellDamage(parent_elem, overallparent_elem, build, spell, spell
part_divavg.append(subtitle_elemavg);
}
if (part.type === "damage") {
//console.log(build.expandedStats);
let _results = calculateSpellDamage(stats, part.conversion,
stats.get("sdRaw"), stats.get("sdPct"),
part.multiplier / 100, build.weapon, build.total_skillpoints, build.damageMultiplier);
stats.get("sdRaw"), stats.get("sdPct") + build.externalStats.get("sdPct"),
part.multiplier / 100, build.weapon, build.total_skillpoints, build.damageMultiplier, build.externalStats);
let totalDamNormal = _results[0];
let totalDamCrit = _results[1];
let results = _results[2];
@ -1077,7 +1273,13 @@ function displaySpellDamage(parent_elem, overallparent_elem, build, spell, spell
if (part.summary == true) {
let overallaverageLabel = document.createElement("p");
overallaverageLabel.textContent = "Average: "+averageDamage.toFixed(2);
let first = document.createElement("b");
let second = document.createElement("b");
first.textContent = "Average: ";
second.textContent = averageDamage.toFixed(2);
overallaverageLabel.appendChild(first);
overallaverageLabel.appendChild(second);
second.classList.add("Damage");
overallaverageLabel.classList.add("damageSubtitle");
part_divavg.append(overallaverageLabel);
}
@ -1122,7 +1324,8 @@ function displaySpellDamage(parent_elem, overallparent_elem, build, spell, spell
if (part.summary == true) {
let overallhealLabel = document.createElement("p");
overallhealLabel.textContent = heal_amount;
overallhealLabel.classList.add("damagep")
overallhealLabel.classList.add("damagep");
overallhealLabel.classList.add("Set");
part_divavg.append(overallhealLabel);
}
}
@ -1137,8 +1340,16 @@ function displaySpellDamage(parent_elem, overallparent_elem, build, spell, spell
part_div.append(averageLabel);
let overallaverageLabel = document.createElement("p");
overallaverageLabel.textContent = "Average: "+total_damage.toFixed(2);
overallaverageLabel.classList.add("damageSubtitle");
let overallaverageLabelFirst = document.createElement("b");
let overallaverageLabelSecond = document.createElement("b");
overallaverageLabelFirst.textContent = "Average: ";
overallaverageLabelSecond.textContent = total_damage.toFixed(2);
overallaverageLabelSecond.classList.add("Damage");
overallaverageLabel.appendChild(overallaverageLabelFirst);
overallaverageLabel.appendChild(overallaverageLabelSecond);
part_divavg.append(overallaverageLabel);
}
}

View file

@ -172,8 +172,8 @@
</div>
<div class="center" style="grid-column:1/span 3;grid-row:3">
<br><br>
<div class="center" id="summary-box">
Summary:
<div class="nomargin" id="summary-box">
</div>
<br><br>
<div class="externalBuffs" id="buff-box">
@ -185,28 +185,33 @@
</tr>
<tr>
<td>
<button class = "button" id = "vanish-boost" onclick = "updateBoosts('vanish-boost')">
<button class = "button-narrow" id = "vanish-boost" onclick = "updateBoosts('vanish-boost')">
Vanish Boost (+80%)
</button>
</td>
<td>
<button class = "button" id = "warscream-boost" onclick = "updateBoosts('warscream-boost')">
<button class = "button-narrow" id = "warscream-boost" onclick = "updateBoosts('warscream-boost')">
War Scream (+10%)
</button>
</td>
<td>
<button class = "button" id = "yourtotem-boost" onclick = "updateBoosts('yourtotem-boost')">
<button class = "button-narrow" id = "yourtotem-boost" onclick = "updateBoosts('yourtotem-boost')">
Your Totem (+35%)
</button>
</td>
<td>
<button class = "button" id = "allytotem-boost" onclick = "updateBoosts('allytotem-boost')">
<button class = "button-narrow" id = "allytotem-boost" onclick = "updateBoosts('allytotem-boost')">
Ally Totem (+15%)
</button>
</td>
<td>
<button class = "button-narrow" id = "bash-boost" onclick = "updateBoosts('bash-boost')">
Bash (+50%)
</button>
</td>
</tr>
</table>
<!--div class = "powder-specials">
<div class = "powder-specials">
<div class = "powder-special-stats" style = "grid-column:1;grid-row:1">
<div class = "center" id = "powder-special-stats">
<p class = "itemp">Powder Specials</p>
@ -384,7 +389,7 @@
</div>
</div>
</div>
</div-->
</div>
</div>
</div>
</div>
@ -419,7 +424,7 @@
<div class="center" style="grid-column:1;grid-row:1">
<div>
<label for="str-skp" class="skpLabel" id="str-skp-label">Strength:</label><br>
<input class="skp-input" type="number" id="str-skp" name="str-skp" value="0" class="skpInput"/>
<input class="skp-input" type="string" id="str-skp" name="str-skp" value="0" class="skpInput"/>
</div>
<div id="str-skp-assign">
Manually Assigned: 0
@ -433,7 +438,7 @@
<div class="center" style="grid-column:2;grid-row:1">
<div>
<label for="dex-skp" class="skpLabel" id="dex-skp-label">Dexterity:</label><br>
<input class="skp-input" type="number" id="dex-skp" name="dex-skp" value="0" class="skpInput"/>
<input class="skp-input" type="string" id="dex-skp" name="dex-skp" value="0" class="skpInput"/>
</div>
<div id="dex-skp-assign">
Manually Assigned: 0
@ -447,7 +452,7 @@
<div class="center" style="grid-column:3;grid-row:1">
<div>
<label for="int-skp" class="skpLabel" id="int-skp-label">Intelligence:</label><br>
<input class="skp-input" type="number" id="int-skp" name="int-skp" value="0" class="skpInput"/>
<input class="skp-input" type="string" id="int-skp" name="int-skp" value="0" class="skpInput"/>
</div>
<div id="int-skp-assign">
Manually Assigned: 0
@ -461,7 +466,7 @@
<div class="center" style="grid-column:4;grid-row:1">
<div>
<label for="def-skp" class="skpLabel" id="def-skp-label">Defense:</label><br>
<input class="skp-input" type="number" id="def-skp" name="def-skp" value="0" class="skpInput"/>
<input class="skp-input" type="string" id="def-skp" name="def-skp" value="0" class="skpInput"/>
</div>
<div id="def-skp-assign">
Manually Assigned: 0
@ -475,7 +480,7 @@
<div class="center" style="grid-column:5;grid-row:1">
<div>
<label for="agi-skp" class="skpLabel" id="agi-skp-label">Agility:</label><br>
<input class="skp-input" type="number" id="agi-skp" name="agi-skp" value="0" class="skpInput"/>
<input class="skp-input" type="string" id="agi-skp" name="agi-skp" value="0" class="skpInput"/>
</div>
<div id="agi-skp-assign">
Manually Assigned: 0
@ -549,6 +554,9 @@
<div class = "center set-info" id = "set-info-div" style = "grid-column:1;grid-row:1; display: none;">
<div class = "center" id = "set-info">Set info</div>
</div>
<div class = "center int-info" id = "int-info-div" style = "grid-column:4;grid-row:1;visibility:visible;">
<div class = "center" id = "int-info">Next Spell Costs</div>
</div>
</div>
<div class="center" id="header2">
<p>Made by <b class = "hppeng">hppeng</b> and <b class = "ferricles">ferricles</b> with Atlas Inc (JavaScript required to function, nothing works without js)</p>

View file

@ -1,4 +1,4 @@
const DB_VERSION = 18;
const DB_VERSION = 19;
// @See https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/video-store/index.js
let db;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

BIN
media/items/generic-bow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

BIN
media/items/palette.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

View file

@ -5,7 +5,7 @@ function calculate_skillpoints(equipment, weapon) {
let fixed = [];
let consider = [];
let noboost = [];
console.log(equipment);
//console.log(equipment);
for (const item of equipment) {
if (item.get("reqs").every(x => x === 0)) {
fixed.push(item);

View file

@ -78,7 +78,7 @@ a.link{
text-align: left;
}
.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, .powder-special, .powder-special-stats {
.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, .powder-special, .powder-special-stats, .int-info {
color: #aaa;
background: #121516;
border: 3px solid #BCBCBC;
@ -110,6 +110,9 @@ a.link{
margin: 2px 2%;
padding: 0;
}
.space {
margin-right: 5px;
}
.damageSubtitle {
text-align: center;
@ -156,6 +159,10 @@ a.link{
.Neutral { color: #fa0; }
.Neutral:before { content: "\2724" ' '; }
.Damage { color: rgb(255, 198, 85)}
.Mana { color: #5ff;}
.Mana:after { content: "\2749"}
.Health {
color: #a00;
@ -193,6 +200,18 @@ a.link{
::-webkit-scrollbar-corner{
background: #110110;
}
.button-narrow {
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: 90%;
display: inline-block;
}
button {
background-color: #666;
border: 2px solid #444;
@ -205,6 +224,16 @@ button {
font-size: 120%;
display: inline-block;
}
button:hover {
background-color: #556;
}
button:active {
background-color: #558;
box-shadow: 0 3px #666;
transform: translateY(1px);
}
input {
background-color: #666;
border: 2px solid #444;
@ -248,4 +277,12 @@ input {
button.toggleOn{
background-color:#0a0;
border: 3 px solid rgb(0, 70, 0);
}
}
.funnynumber {
background-image: linear-gradient(to left, #f5f, #a0a, #5ff, #5f5, #ff5, #fa0, #a00); -webkit-background-clip: text;
color: transparent;
display: inline-block;
text-align: center;
transform: translateX(calc(50vw - 50%));
}

View file

@ -99,7 +99,7 @@ Base64 = (function () {
// 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.
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 negative.
Pct would be 0.80 for 80%, -1.20 for 120%, etc
Example Outputs:
raw: -100
@ -112,7 +112,7 @@ Base64 = (function () {
pct: +0.20, output = 120
pct: +1.20, output = 220
pct: -0.20, output = 80
pct: -1.20, output = 0
pct: -1.20, output = -20
*/
function rawToPct(raw, pct){
final = 0;