9ebac6b59e
patch: - ing changes (manual) - two endgame items (the ones that I got customs for) bugfix: - Fix bug in reverse mapping that mapped item "type" to "accessoryType"
336 lines
16 KiB
JavaScript
336 lines
16 KiB
JavaScript
/**
|
|
* File containing utility functions that are useful for the builder page.
|
|
*/
|
|
|
|
/*Turns the input amount of skill points into a float precision percentage.
|
|
* @param skp - the integer skillpoint count to be converted
|
|
*/
|
|
function skillPointsToPercentage(skp){
|
|
if (skp<=0) {
|
|
return 0.0;
|
|
} else if (skp>=150) {
|
|
skp = 150;
|
|
}
|
|
const r = 0.9908;
|
|
return (r/(1-r)*(1 - Math.pow(r, skp))) / 100.0;
|
|
//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);
|
|
//return Math.min(Math.max(0.00,(-0.0000000066695* Math.pow(Math.E, -0.00924033 * skp + 18.9) + 1.0771)),.808);
|
|
//return clamp((-0.0000000066695* Math.pow(Math.E, -0.00924033 * skp + 18.9) + 1.0771), 0.00, 0.808);
|
|
}
|
|
|
|
// WYNN2: Skillpoint max scaling. Intel is cost reduction
|
|
const skillpoint_final_mult = [1, 1, 0.5/skillPointsToPercentage(150), 0.867, 0.951];
|
|
// intel water%
|
|
const skillpoint_damage_mult = [1, 1, 1, 0.867, 0.951];
|
|
|
|
/*Turns the input amount of levels into skillpoints available.
|
|
*
|
|
* @param level - the integer level count to be converted
|
|
*/
|
|
function levelToSkillPoints(level){
|
|
if(level < 1){
|
|
return 0;
|
|
}else if(level >= 101){
|
|
return 200;
|
|
}else{
|
|
return (level - 1) * 2;
|
|
}
|
|
}
|
|
|
|
/*Turns the input amount of levels in to base HP.
|
|
* @param level - the integer level count to be converted
|
|
*/
|
|
function levelToHPBase(level){
|
|
if(level < 1){ //bad level
|
|
return this.levelToHPBase(1);
|
|
}else if (level > 106){ //also bad level
|
|
return this.levelToHPBase(106);
|
|
}else{ //good level
|
|
return 5*level + 5;
|
|
}
|
|
}
|
|
|
|
const skp_order = ["str","dex","int","def","agi"];
|
|
const skill = ["Strength", "Dexterity", "Intelligence", "Defense", "Agility"];
|
|
const skp_elements = ["e","t","w","f","a"];
|
|
const damageClasses = ["Neutral","Earth","Thunder","Water","Fire","Air"];
|
|
// Set up item lists for quick access later.
|
|
const armorTypes = [ "helmet", "chestplate", "leggings", "boots" ];
|
|
const accessoryTypes = [ "ring", "bracelet", "necklace" ];
|
|
const weaponTypes = [ "wand", "spear", "bow", "dagger", "relik" ];
|
|
const consumableTypes = [ "potion", "scroll", "food"];
|
|
const tome_types = ['weaponTome', 'armorTome', 'guildTome'];
|
|
const attackSpeeds = ["SUPER_SLOW", "VERY_SLOW", "SLOW", "NORMAL", "FAST", "VERY_FAST", "SUPER_FAST"];
|
|
const baseDamageMultiplier = [ 0.51, 0.83, 1.5, 2.05, 2.5, 3.1, 4.3 ];
|
|
//0.51, 0.82, 1.50, 2.05, 2.50, 3.11, 4.27
|
|
const classes = ["Warrior", "Assassin", "Mage", "Archer", "Shaman"];
|
|
const wep_to_class = new Map([["dagger", "Assassin"], ["spear", "Warrior"], ["wand", "Mage"], ["bow", "Archer"], ["relik", "Shaman"]])
|
|
const tiers = ["Normal", "Unique", "Rare", "Legendary", "Fabled", "Mythic", "Set", "Crafted"] //I'm not sure why you would make a custom crafted but if you do you should be able to use it w/ the correct powder formula
|
|
const all_types = armorTypes.concat(accessoryTypes).concat(weaponTypes).concat(consumableTypes).concat(tome_types).map(x => x.substring(0,1).toUpperCase() + x.substring(1));
|
|
//weaponTypes.push("sword");
|
|
//console.log(types)
|
|
let item_types = armorTypes.concat(accessoryTypes).concat(weaponTypes).concat(tome_types);
|
|
|
|
let elementIcons = ["\u2724","\u2726", "\u2749", "\u2739", "\u274b" ];
|
|
let skpReqs = skp_order.map(x => x + "Req");
|
|
|
|
let item_fields = [ "name", "displayName", "lore", "color", "tier", "set", "slots", "type", "material", "drop", "quest", "restrict", "nDam", "fDam", "wDam", "aDam", "tDam", "eDam", "atkSpd", "hp", "fDef", "wDef", "aDef", "tDef", "eDef", "lvl", "classReq", "strReq", "dexReq", "intReq", "defReq", "agiReq", "hprPct", "mr", "sdPct", "mdPct", "ls", "ms", "xpb", "lb", "ref", "str", "dex", "int", "agi", "def", "thorns", "expd", "spd", "atkTier", "poison", "hpBonus", "spRegen", "eSteal", "hprRaw", "sdRaw", "mdRaw", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "fixID", "category", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4", "rSdRaw", "sprint", "sprintReg", "jh", "lq", "gXp", "gSpd", "id", "majorIds", "damMobs", "defMobs",
|
|
|
|
// wynn2 damages.
|
|
"eMdPct","eMdRaw","eSdPct","eSdRaw",/*"eDamPct,"*/"eDamRaw","eDamAddMin","eDamAddMax",
|
|
"tMdPct","tMdRaw","tSdPct","tSdRaw",/*"tDamPct,"*/"tDamRaw","tDamAddMin","tDamAddMax",
|
|
"wMdPct","wMdRaw","wSdPct","wSdRaw",/*"wDamPct,"*/"wDamRaw","wDamAddMin","wDamAddMax",
|
|
"fMdPct","fMdRaw","fSdPct","fSdRaw",/*"fDamPct,"*/"fDamRaw","fDamAddMin","fDamAddMax",
|
|
"aMdPct","aMdRaw","aSdPct","aSdRaw",/*"aDamPct,"*/"aDamRaw","aDamAddMin","aDamAddMax",
|
|
"nMdPct","nMdRaw","nSdPct","nSdRaw","nDamPct","nDamRaw","nDamAddMin","nDamAddMax", // neutral which is now an element
|
|
/*"mdPct","mdRaw","sdPct","sdRaw",*/"damPct","damRaw","damAddMin","damAddMax", // These are the old ids. Become proportional.
|
|
"rMdPct","rMdRaw","rSdPct",/*"rSdRaw",*/"rDamPct","rDamRaw","rDamAddMin","rDamAddMax", // rainbow (the "element" of all minus neutral). rSdRaw is rainraw
|
|
"critDamPct",
|
|
"spPct1Final", "spPct2Final", "spPct3Final", "spPct4Final"
|
|
];
|
|
// Extra fake IDs (reserved for use in spell damage calculation) : damMult, defMult, poisonPct, activeMajorIDs
|
|
let str_item_fields = [ "name", "displayName", "lore", "color", "tier", "set", "type", "material", "drop", "quest", "restrict", "category", "atkSpd" ]
|
|
|
|
//File reading for ID translations for JSON purposes
|
|
let reversetranslations = new Map();
|
|
let _translations_list = [["name", "name"],["displayName", "displayName"],["tier", "tier"],["set", "set"],["sockets", "slots"],["type", "type"],["armorColor", "color"],["addedLore", "lore"],["dropType", "drop"],["quest", "quest"],["restrictions", "restrict"],["damage", "nDam"],["fireDamage", "fDam"],["waterDamage", "wDam"],["airDamage", "aDam"],["thunderDamage", "tDam"],["earthDamage", "eDam"],["attackSpeed", "atkSpd"],["health", "hp"],["fireDefense", "fDef"],["waterDefense", "wDef"],["airDefense", "aDef"],["thunderDefense", "tDef"],["earthDefense", "eDef"],["level", "lvl"],["classRequirement", "classReq"],["strength", "strReq"],["dexterity", "dexReq"],["intelligence", "intReq"],["agility", "agiReq"],["defense", "defReq"],["healthRegen", "hprPct"],["manaRegen", "mr"],["spellDamageBonus", "sdPct"],["spellElementalDamageBonus", "rSdPct"],["spellNeutralDamageBonus", "nSdPct"],["spellFireDamageBonus", "fSdPct"],["spellWaterDamageBonus", "wSdPct"],["spellAirDamageBonus", "aSdPct"],["spellThunderDamageBonus", "tSdPct"],["spellEarthDamageBonus", "eSdPct"],["mainAttackDamageBonus", "mdPct"],["mainAttackElementalDamageBonus", "rMdPct"],["mainAttackNeutralDamageBonus", "nMdPct"],["mainAttackFireDamageBonus", "fMdPct"],["mainAttackWaterDamageBonus", "wMdPct"],["mainAttackAirDamageBonus", "aMdPct"],["mainAttackThunderDamageBonus", "tMdPct"],["mainAttackEarthDamageBonus", "eMdPct"],["lifeSteal", "ls"],["manaSteal", "ms"],["xpBonus", "xpb"],["lootBonus", "lb"],["reflection", "ref"],["strengthPoints", "str"],["dexterityPoints", "dex"],["intelligencePoints", "int"],["agilityPoints", "agi"],["defensePoints", "def"],["thorns", "thorns"],["exploding", "expd"],["speed", "spd"],["attackSpeedBonus", "atkTier"],["poison", "poison"],["healthBonus", "hpBonus"],["soulPoints", "spRegen"],["emeraldStealing", "eSteal"],["healthRegenRaw", "hprRaw"],["spellDamageBonusRaw", "sdRaw"],["spellElementalDamageBonusRaw", "rSdRaw"],["spellNeutralDamageBonusRaw", "nSdRaw"],["spellFireDamageBonusRaw", "fSdRaw"],["spellWaterDamageBonusRaw", "wSdRaw"],["spellAirDamageBonusRaw", "aSdRaw"],["spellThunderDamageBonusRaw", "tSdRaw"],["spellEarthDamageBonusRaw", "eSdRaw"],["mainAttackDamageBonusRaw", "mdRaw"],["mainAttackElementalDamageBonusRaw", "rMdRaw"],["mainAttackNeutralDamageBonusRaw", "nMdRaw"],["mainAttackFireDamageBonusRaw", "fMdRaw"],["mainAttackWaterDamageBonusRaw", "wMdRaw"],["mainAttackAirDamageBonusRaw", "aMdRaw"],["mainAttackThunderDamageBonusRaw", "tMdRaw"],["mainAttackEarthDamageBonusRaw", "eMdRaw"],["fireDamageBonus", "fDamPct"],["waterDamageBonus", "wDamPct"],["airDamageBonus", "aDamPct"],["thunderDamageBonus", "tDamPct"],["earthDamageBonus", "eDamPct"],["bonusFireDefense", "fDefPct"],["bonusWaterDefense", "wDefPct"],["bonusAirDefense", "aDefPct"],["bonusThunderDefense", "tDefPct"],["bonusEarthDefense", "eDefPct"],["accessoryType", "type"],["identified", "fixID"],["skin", "skin"],["category", "category"],["spellCostPct1", "spPct1"],["spellCostRaw1", "spRaw1"],["spellCostPct2", "spPct2"],["spellCostRaw2", "spRaw2"],["spellCostPct3", "spPct3"],["spellCostRaw3", "spRaw3"],["spellCostPct4", "spPct4"],["spellCostRaw4", "spRaw4"],["sprint", "sprint"],["sprintRegen", "sprintReg"],["jumpHeight", "jh"],["lootQuality", "lq"],["gatherXpBonus", "gXp"],["gatherSpeed", "gSpd"]];
|
|
let translations = new Map(_translations_list);
|
|
|
|
//does not include damMobs (wep tomes) and defMobs (armor tomes)
|
|
for (const [k, v] of _translations_list) {
|
|
if (reversetranslations.has(v)) { continue; }
|
|
reversetranslations.set(v, k);
|
|
}
|
|
|
|
let nonRolledIDs = [
|
|
"name",
|
|
"lore",
|
|
"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_",
|
|
"majorIds",
|
|
"damMobs",
|
|
"defMobs"
|
|
];
|
|
let rolledIDs = [
|
|
"hprPct",
|
|
"mr",
|
|
"sdPct",
|
|
"mdPct",
|
|
"ls",
|
|
"ms",
|
|
"xpb",
|
|
"lb",
|
|
"ref",
|
|
"thorns",
|
|
"expd",
|
|
"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",
|
|
"rSdRaw",
|
|
"sprint",
|
|
"sprintReg",
|
|
"jh",
|
|
"lq",
|
|
"gXp",
|
|
"gSpd",
|
|
// wynn2 damages.
|
|
"eMdPct","eMdRaw","eSdPct","eSdRaw",/*"eDamPct,"*/"eDamRaw","eDamAddMin","eDamAddMax",
|
|
"tMdPct","tMdRaw","tSdPct","tSdRaw",/*"tDamPct,"*/"tDamRaw","tDamAddMin","tDamAddMax",
|
|
"wMdPct","wMdRaw","wSdPct","wSdRaw",/*"wDamPct,"*/"wDamRaw","wDamAddMin","wDamAddMax",
|
|
"fMdPct","fMdRaw","fSdPct","fSdRaw",/*"fDamPct,"*/"fDamRaw","fDamAddMin","fDamAddMax",
|
|
"aMdPct","aMdRaw","aSdPct","aSdRaw",/*"aDamPct,"*/"aDamRaw","aDamAddMin","aDamAddMax",
|
|
"nMdPct","nMdRaw","nSdPct","nSdRaw","nDamPct","nDamRaw","nDamAddMin","nDamAddMax", // neutral which is now an element
|
|
/*"mdPct","mdRaw","sdPct","sdRaw",*/"damPct","damRaw","damAddMin","damAddMax", // These are the old ids. Become proportional.
|
|
"rMdPct","rMdRaw","rSdPct",/*"rSdRaw",*/"rDamPct","rDamRaw","rDamAddMin","rDamAddMax", // rainbow (the "element" of all minus neutral). rSdRaw is rainraw
|
|
"spPct1Final", "spPct2Final", "spPct3Final", "spPct4Final"
|
|
];
|
|
let reversedIDs = [ "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4" ];
|
|
|
|
let ingFields = ["fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "hprPct", "mr", "sdPct", "mdPct", "ls", "ms", "xpb", "lb", "lq", "ref", "str", "dex", "int", "agi", "def", "thorns", "expd", "spd", "atkTier", "poison", "hpBonus", "spRegen", "eSteal", "hprRaw", "sdRaw", "mdRaw", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4", "jh", "sprint", "sprintReg", "gXp", "gSpd"];
|
|
|
|
/**
|
|
* Take an item with id list and turn it into a set of minrolls and maxrolls.
|
|
*/
|
|
function expandItem(item) {
|
|
let minRolls = new Map();
|
|
let maxRolls = new Map();
|
|
let expandedItem = new Map();
|
|
if (item.fixID) { //The item has fixed IDs.
|
|
expandedItem.set("fixID",true);
|
|
for (const id of rolledIDs) { //all rolled IDs are numerical
|
|
let val = (item[id] || 0);
|
|
minRolls.set(id,val);
|
|
maxRolls.set(id,val);
|
|
}
|
|
} else { //The item does not have fixed IDs.
|
|
for (const id of rolledIDs) {
|
|
let val = (item[id] || 0);
|
|
if (val > 0) { // positive rolled IDs
|
|
if (reversedIDs.includes(id)) {
|
|
maxRolls.set(id,idRound(val*0.7));
|
|
minRolls.set(id,idRound(val*1.3));
|
|
} else {
|
|
maxRolls.set(id,idRound(val*1.3));
|
|
minRolls.set(id,idRound(val*0.3));
|
|
}
|
|
} else if (val < 0) { //negative rolled IDs
|
|
if (reversedIDs.includes(id)) {
|
|
maxRolls.set(id,idRound(val*1.3));
|
|
minRolls.set(id,idRound(val*0.3));
|
|
}
|
|
else {
|
|
maxRolls.set(id,idRound(val*0.7));
|
|
minRolls.set(id,idRound(val*1.3));
|
|
}
|
|
}
|
|
else { // if val == 0
|
|
// NOTE: DO NOT remove this case! idRound behavior does not round to 0!
|
|
maxRolls.set(id,0);
|
|
minRolls.set(id,0);
|
|
}
|
|
}
|
|
}
|
|
for (const id of nonRolledIDs) {
|
|
expandedItem.set(id,item[id]);
|
|
}
|
|
expandedItem.set("minRolls",minRolls);
|
|
expandedItem.set("maxRolls",maxRolls);
|
|
return expandedItem;
|
|
}
|
|
|
|
class Item {
|
|
constructor(item_obj = null) {
|
|
if (item_obj) { this.statMap = expandItem(item_obj); }
|
|
else { this.statMap = new Map(); }
|
|
}
|
|
|
|
copy() {
|
|
const ret = new Item();
|
|
ret.statMap = new Map(this.statMap);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/* Takes in an ingredient object and returns an equivalent Map().
|
|
*/
|
|
function expandIngredient(ing) {
|
|
let expandedIng = new Map();
|
|
let mapIds = ['consumableIDs', 'itemIDs', 'posMods'];
|
|
for (const id of mapIds) {
|
|
let idMap = new Map();
|
|
for (const key of Object.keys(ing[id])) {
|
|
idMap.set(key, ing[id][key]);
|
|
}
|
|
expandedIng.set(id, idMap);
|
|
}
|
|
let normIds = ['lvl','name', 'displayName','tier','skills','id'];
|
|
for (const id of normIds) {
|
|
expandedIng.set(id, ing[id]);
|
|
}
|
|
if (ing['isPowder']) {
|
|
expandedIng.set("isPowder",ing['isPowder']);
|
|
expandedIng.set("pid",ing['pid']);
|
|
}
|
|
//now the actually hard one
|
|
let idMap = new Map();
|
|
idMap.set("minRolls", new Map());
|
|
idMap.set("maxRolls", new Map());
|
|
for (const field of ingFields) {
|
|
let val = (ing['ids'][field] || 0);
|
|
idMap.get("minRolls").set(field, val['minimum']);
|
|
idMap.get("maxRolls").set(field, val['maximum']);
|
|
}
|
|
expandedIng.set("ids",idMap);
|
|
return expandedIng;
|
|
}
|
|
|
|
/* Takes in a recipe object and returns an equivalent Map().
|
|
*/
|
|
function expandRecipe(recipe) {
|
|
let expandedRecipe = new Map();
|
|
let normIDs = ["name", "skill", "type","id"];
|
|
for (const id of normIDs) {
|
|
expandedRecipe.set(id,recipe[id]);
|
|
}
|
|
let rangeIDs = ["durability","lvl", "healthOrDamage", "duration", "basicDuration"];
|
|
for (const id of rangeIDs) {
|
|
if(recipe[id]){
|
|
expandedRecipe.set(id, [recipe[id]['minimum'], recipe[id]['maximum']]);
|
|
} else {
|
|
expandedRecipe.set(id, [0,0]);
|
|
}
|
|
}
|
|
expandedRecipe.set("materials", [ new Map([ ["item", recipe['materials'][0]['item']], ["amount", recipe['materials'][0]['amount']] ]) , new Map([ ["item", recipe['materials'][1]['item']], ["amount",recipe['materials'][1]['amount'] ] ]) ]);
|
|
return expandedRecipe;
|
|
}
|
|
|
|
/*An independent helper function that rounds a rolled ID to the nearest integer OR brings the roll away from 0.
|
|
* @param id
|
|
*/
|
|
function idRound(id){
|
|
rounded = Math.round(id);
|
|
if(rounded == 0){
|
|
return Math.sign(id); //this is a hack, will need changing along w/ rest of ID system if anything changes
|
|
}else{
|
|
return rounded;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* stupid stupid multiplicative stats
|
|
*/
|
|
function merge_stat(stats, name, value) {
|
|
const start = name.slice(0, 7);
|
|
if (start === 'damMult' || start === 'defMult') {
|
|
if (!stats.has(start)) {
|
|
stats.set(start, new Map());
|
|
}
|
|
const map = stats.get(start);
|
|
if (value instanceof Map) {
|
|
for (const [k, v] of value.entries()) {
|
|
merge_stat(map, k, v);
|
|
}
|
|
return;
|
|
}
|
|
merge_stat(map, name.slice(8), value);
|
|
return;
|
|
}
|
|
if (stats.has(name)) {
|
|
stats.set(name, stats.get(name) + value);
|
|
}
|
|
else { stats.set(name, value); }
|
|
}
|