Last active
February 10, 2024 22:34
-
-
Save wiiaboo/8d41c241b6fa58439007db11a5302b62 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const MAX_LEVEL = 90; | |
const craftables = [ | |
{ | |
level: 21, | |
name: 'lv20 grade 4 ishgard', | |
xp: 67771, | |
maximumLevel: 41, | |
}, | |
{ | |
level: 41, | |
name: 'lv40 grade 4 ishgard 2nd tier', | |
xp: 177985, | |
maximumLevel: 53, | |
}, | |
{ | |
level: 53, | |
name: 'lv40 grade 4 ishgard max tier', | |
xp: 359521, | |
maximumLevel: 63, | |
}, | |
{ | |
level: 63, | |
name: 'lv63 ishgard', | |
xp: 464875, | |
maximumLevel: 71, | |
}, | |
{ | |
level: 71, | |
name: 'lv71 ishgard', | |
xp: 755426, | |
maximumLevel: 80, | |
}, | |
{ | |
level: 80, | |
name: 'lv80 levequests', | |
xp: 1449240, | |
maximumLevel: 81, | |
}, | |
{ | |
level: 81, | |
name: 'lv81 collectables', | |
xp: 1055241, | |
}, | |
{ | |
level: 85, | |
name: 'lv85 collectables', | |
xp: 1417077, | |
}, | |
// { | |
// level: 87, | |
// name: 'lv87 collectables', | |
// xp: 1629469, | |
// }, | |
// { | |
// level: 89, | |
// name: 'lv89 collectables', | |
// xp: 1853298, | |
// } | |
]; | |
const getXpTable = async () => { | |
const XIVAPI = require('@xivapi/js') | |
const xiv = new XIVAPI() | |
let res = await xiv.data.list('ParamGrow', { | |
limit: MAX_LEVEL, | |
columns: 'ID,ExpToNext' | |
}); | |
return res.Results.reduce((t, level) => { | |
t[level.ID+1] = { | |
fromLevel: level.ID, | |
toLevel: level.ID+1, | |
perLevel: level.ExpToNext, | |
total: level.ID == 1 ? level.ExpToNext : t[level.ID].total + level.ExpToNext | |
} | |
return t; | |
}, {}); | |
} | |
const craftsNeeded = async (startingLevel='21', finalLevel=MAX_LEVEL, {extraXP='0', xpPerCraft}) => { | |
const xpTable = await getXpTable(); | |
extraXP = Number(extraXP); | |
const crafts = []; | |
let level = Number(startingLevel), currentXP = xpTable[Number(startingLevel)].total + extraXP; | |
while (level < Number(finalLevel)) { | |
let craft = { level, currentXP, extraXP }; | |
craft.recipe = craftables.findLast(recipe => recipe.level <= level); | |
craft.nextRecipeMinimumLevel = craftables[craftables.indexOf(craft.recipe) + 1]?.level ?? MAX_LEVEL; | |
craft.resultLevel = Math.min(finalLevel, craft.nextRecipeMinimumLevel); | |
craft.resultLevelXP = xpTable[craft.resultLevel].total; | |
craft.craft = xpPerCraft ? {name: 'user-provided craft', xp: Number(xpPerCraft)} : craft.recipe; | |
craft.resultCrafts = Math.ceil((craft.resultLevelXP - craft.currentXP) / craft.craft.xp); | |
craft.resultXP = craft.currentXP + craft.resultCrafts * craft.craft.xp; | |
craft.resultExtraXP = craft.resultXP % craft.resultLevelXP; | |
crafts.push(craft); | |
level = craft.resultLevel; | |
currentXP = craft.resultXP; | |
extraXP = craft.resultExtraXP; | |
if (craft.nextRecipeMinimumLevel != MAX_LEVEL) continue; | |
let optimizedRecipe = craftables | |
.find(recipe => (!recipe.maximumLevel || recipe.maximumLevel >= craft.resultLevel) && craft.resultExtraXP - recipe.xp > 0); | |
if (optimizedRecipe) { | |
craft.resultCrafts--; | |
craft.resultXP -= craft.craft.xp; | |
craft.resultLevel--; | |
craft.resultExtraXP = craft.resultXP % xpTable[craft.resultLevel].total | |
let extraCraft = { | |
level: craft.resultLevel, | |
resultLevel: craft.resultLevel + 1, | |
currentXP: craft.resultXP, | |
extraXP: craft.resultExtraXP, | |
recipe: optimizedRecipe, | |
craft: optimizedRecipe, | |
resultCrafts: 1, | |
resultXP: craft.resultXP + optimizedRecipe.xp, | |
resultExtraXP: (craft.resultXP + optimizedRecipe.xp) % craft.resultLevelXP | |
} | |
crafts.push(extraCraft); | |
level = extraCraft.resultLevel; | |
currentXP = extraCraft.resultXP; | |
extraXP = extraCraft.resultExtraXP; | |
} | |
// crafts.push(`${craft.level} (+${craft.extraXP} XP) to ${craft.craftUpToLevel} (+${craft.resultExtraXP} XP)\n\t= ${Math.ceil(craft.resultCrafts)} × ${craftables[craft.recipeMinimumLevel] ? craftables[craft.recipeMinimumLevel].name : ''} (${craft.xp} XP craft)`); | |
// console.log(`xp per craft: ${craft.xp}, ${craft.resultCrafts} crafts, starting lvl/xp: ${level}/${craft.currentXP}, ending lvl/xp: ${craft.craftUpToLevel}/${craft.resultXP} + ${craft.resultExtraXP}`) | |
} | |
// crafts.forEach(craft => console.log(craft)); | |
crafts.forEach(craft => console.log(`${craft.level} (+${craft.extraXP} XP) to ${craft.resultLevel}${craft.resultLevel < MAX_LEVEL ? ` (+${craft.resultExtraXP} XP)` : ''} | |
= ${Math.ceil(craft.resultCrafts)} × ${craft.craft.name} (${craft.craft.xp} XP craft)`)); | |
// console.log(`lv${startingLevel} (+${currentXP} XP) --> lv${finalLevel} | |
// = ${result} × ${xpPerCraft} XP`.trim()); | |
return craftsNeeded; | |
}; | |
(() => { | |
const [ fromLevel, toLevel, extraXP, xpPerCraft ] = process.argv.slice(2); | |
craftsNeeded(fromLevel, toLevel, {extraXP, xpPerCraft}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment