LookAtMySuitBot/js/node_modules/prismarine-item/lib/anvil.js

179 lines
7.3 KiB
JavaScript
Raw Normal View History

2023-12-24 20:08:39 -05:00
function loader (registry, Item) {
// TODO: anvil support for bedrock
if (registry.type === 'bedrock') return undefined
function combine (itemOne, itemTwo, creative, renamedName) {
const rename = typeof renamedName === 'string'
const data = {
finalEnchs: [],
fixedDurability: 0
}
let onlyRename = false // to tell if it's just a rename
if (!combinePossible(itemOne, itemTwo) && itemTwo !== null) return { xpCost: 0, item: null }
let cost = 0
if (rename) {
onlyRename = true
const renameCost = getRenameCost(itemOne)
if (renameCost === -1) return { xpCost: 0, item: null }
cost += renameCost
}
if (itemOne.durabilityUsed !== 0) {
onlyRename = false
const { xpLevelCost: repairCost, fixedDurability, usedMats } = getRepairCost(itemOne, itemTwo)
data.fixedDurability = fixedDurability
data.usedMats = usedMats
cost += repairCost
}
if (itemTwo && (itemTwo.name === itemOne.name || itemTwo.name === 'enchanted_book')) {
onlyRename = false
const { xpLevelCost: enchantCost, finalEnchs } = combineEnchants(itemOne, itemTwo, creative)
data.finalEnchs = finalEnchs
if (enchantCost === 0 && !rename && itemOne.metadata === 0) return { xpCost: 0, item: null } // no change
cost += enchantCost
}
if (itemTwo === null && itemOne.customName === renamedName) return { xpCost: 0, item: null } // no change
cost += itemOne.repairCost + (itemTwo?.repairCost ?? 0)
if (cost > 39 && onlyRename) cost = 39
else if (cost >= 40) return { xpCost: 0, item: null } // show too expensive message
let finalItem = null
if (itemOne) {
finalItem = new Item(itemOne.type, itemOne.count, 0, JSON.parse(JSON.stringify(itemOne.nbt)), null, true)
const resultDurability = itemOne.durabilityUsed - data.fixedDurability
const repairCost = Math.max(itemOne.repairCost, (itemTwo?.repairCost ?? 0)) * 2 + 1
if (data?.finalEnchs.length > 0) finalItem.enchants = data.finalEnchs
if (rename) finalItem.customName = renamedName
finalItem.repairCost = repairCost
if (resultDurability && itemOne.name !== 'enchanted_book') finalItem.durabilityUsed = resultDurability
}
return { xpCost: cost, item: finalItem, usedMats: data.usedMats }
}
/**
*
* @param {Item} itemOne left hand item
* @param {Item} itemTwo right hand item
* @param {boolean} creative whether the bot is in creative mode
* @returns {{finalEnchs: (*|[]|{lvl: *, name: *|null}[]|NormalizedEnchant[]), xpLevelCost: number}}
* xpLevelCost is enchant data that is strictly from combining enchants
* finalEnchs is the array of enchants on the final object
*/
function combineEnchants (itemOne, itemTwo, creative) {
const rightIsBook = itemTwo.name === 'enchanted_book'
const finalEnchs = itemOne.enchants
const finalEnchsByName = finalEnchs.map(x => x.name)
const itemTwoEnch = itemTwo.enchants
let xpLevelCost = 0
for (const ench of itemTwoEnch) {
const enchOnItemOne = finalEnchs.find(x => x.name === ench.name)
let { exclude, maxLevel, category, weight } = registry.enchantmentsByName[ench.name]
const multiplier = getMultipliers(weight, rightIsBook)
if (!(itemOne.name === 'enchanted_book' && rightIsBook) && !registry.itemsByName[itemOne.name].enchantCategories.includes(category) && !creative) continue
else if (enchOnItemOne === undefined) { // first item doesn't have this ench
exclude = exclude.map(name => registry.enchantmentsByName[name].name)
if (exclude.some(excludedEnch => finalEnchsByName.includes(excludedEnch))) { // has an excluded enchant
xpLevelCost++
} else {
const finalLevel = ench.lvl
xpLevelCost += finalLevel * multiplier
finalEnchs.push({ name: ench.name, lvl: ench.lvl })
}
} else {
let finalLevel = 0
const itemOneLevel = enchOnItemOne.lvl
const itemTwoLevel = ench.lvl
if (itemOneLevel === itemTwoLevel) {
finalLevel = Math.min(itemOneLevel + 1, maxLevel)
enchOnItemOne.lvl = finalLevel
} else if (itemTwoLevel > itemOneLevel) {
finalLevel = itemTwoLevel
enchOnItemOne.lvl = finalLevel
} else if (itemOneLevel > itemTwoLevel) {
finalLevel = itemOneLevel
}
xpLevelCost += finalLevel * multiplier
}
}
return { xpLevelCost, finalEnchs }
}
// converts enchant weight to enchant cost multiplier
function getMultipliers (weight, isBook) {
const itemMultiplier = {
10: 1,
5: 2,
2: 4,
1: 8
}[weight]
return isBook ? Math.max(1, itemMultiplier / 2) : itemMultiplier
}
/**
*
* @param {Item} itemOne left hand item
* @param {Item} itemTwo right hand item
* @returns {{usedMats: number, fixedDurability: number, xpLevelCost: number}|number}
* xpLevelCost is the number of xp levels used for repair (if any)
* fixedDurability is duribility after using the anvil
* usedMats is the number of materials used to fix the broken item (if many mats is used)
*/
function getRepairCost (itemOne, itemTwo) {
if (itemTwo === null) return { xpLevelCost: 0, fixedDurability: 0, usedMats: 0 } // air
else if (itemTwo.name === 'enchanted_book') return { xpLevelCost: 0, fixedDurability: 0, usedMats: 0 }
const maxDurability = registry.itemsByName[itemOne.name].maxDurability
const durabilityLost = itemOne.durabilityUsed
const fixMaterials = registry.itemsByName[itemOne.name].repairWith.concat([itemOne.name])
if (!fixMaterials.includes(itemTwo.name) && itemOne.name !== itemTwo.name) {
return 0 // Enchanted book can't fix
}
let results = {
fixedDurability: 0,
xpLevelCost: 0,
usedMats: 0
}
if (itemTwo.name === itemOne.name) {
const possibleFixedDura = Math.floor(0.12 * maxDurability) + itemTwo.metadata
results = {
fixedDurability: itemOne.metadata < possibleFixedDura ? itemOne.durabilityUsed : possibleFixedDura,
xpLevelCost: 2,
usedMats: 1
}
} else if (durabilityLost !== 0) {
const durabilityFixedPerMat = Math.floor(maxDurability * 0.25)
const matsToFullyRepair = Math.ceil(durabilityLost / durabilityFixedPerMat)
if (itemTwo.count > matsToFullyRepair) { // takeall of itemTwo
results = {
fixedDurability: maxDurability - itemOne.durabilityUsed,
xpLevelCost: matsToFullyRepair, // 1 exp lvl per mat used
usedMats: matsToFullyRepair
}
} else if (itemOne && itemTwo) {
results = {
fixedDurability: Math.min(itemOne.durabilityUsed, durabilityFixedPerMat * itemTwo.count),
xpLevelCost: itemTwo.count, // 1 exp lvl per mat used
usedMats: itemTwo.count
}
}
}
return results
}
function getRenameCost (item) {
if (item?.nbt?.value?.RepairCost?.value === 0x7fffffff) return -1
return 1
}
function combinePossible (itemOne, itemTwo) {
if (!itemOne?.name || !itemTwo?.name || (!itemOne?.name && !itemTwo?.name)) return false
let fixMaterials = (registry.itemsByName[itemOne.name].repairWith ?? []).concat([itemOne.name])
if (itemOne.name !== 'enchanted_book') fixMaterials = fixMaterials.concat(['enchanted_book'])
return fixMaterials.includes(itemTwo.name)
}
return combine
}
module.exports = loader