mirror of
https://github.com/misode/misode.github.io.git
synced 2026-05-03 14:12:54 +00:00
3f52a908a6
Convert negative integers to unsigned integers. Truncate the alpha from colors before passing them to the HTML color picker, since it doesn't allow alpha values (and they'd be in the wrong place if it did).
138 lines
6.1 KiB
TypeScript
138 lines
6.1 KiB
TypeScript
import type { ItemStack } from 'deepslate-1.20.4/core'
|
|
import { AttributeModifierOperation, Enchantment, Identifier, MobEffectInstance, Potion } from 'deepslate-1.20.4/core'
|
|
import { NbtList, NbtType } from 'deepslate-1.20.4/nbt'
|
|
import { useLocale } from '../contexts/Locale.jsx'
|
|
import { useVersion } from '../contexts/Version.jsx'
|
|
import { useAsync } from '../hooks/useAsync.js'
|
|
import { getLanguage, getTranslation } from '../services/Resources.js'
|
|
import { intToDisplayHexRgb, message } from '../Utils.js'
|
|
import { TextComponent } from './TextComponent.jsx'
|
|
|
|
interface Props {
|
|
item: ItemStack,
|
|
advanced?: boolean,
|
|
}
|
|
export function ItemTooltip1204({ item, advanced }: Props) {
|
|
const { version } = useVersion()
|
|
const { lang } = useLocale()
|
|
|
|
const { value: language } = useAsync(() => getLanguage(version, lang), [version, lang])
|
|
|
|
const isPotion = item.is('potion') || item.is('splash_potion') || item.is('lingering_potion')
|
|
let displayName = item.tag.getCompound('display').getString('Name')
|
|
let name: string | undefined
|
|
if (displayName) {
|
|
try {
|
|
name = JSON.parse(displayName)
|
|
} catch (e) {
|
|
console.warn(`Error parsing display name '${displayName}': ${message(e)}`)
|
|
displayName = ''
|
|
}
|
|
}
|
|
if (name === undefined) {
|
|
if (language) {
|
|
let descriptionId = `${item.id.namespace}.${item.id.path}`
|
|
if (isPotion) {
|
|
descriptionId = `${descriptionId}.effect.${Potion.fromNbt(item).name}`
|
|
}
|
|
name = getTranslation(language, `item.${descriptionId}`)
|
|
name ??= getTranslation(language, `block.${descriptionId}`)
|
|
}
|
|
name ??= item.id.path
|
|
.replace(/[_\/]/g, ' ')
|
|
.split(' ')
|
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
.join(' ')
|
|
}
|
|
const lore: any[] = []
|
|
item.tag.getCompound('display').getList('Lore', NbtType.String).forEach((line) => {
|
|
try {
|
|
lore.push(JSON.parse(line['value']))
|
|
} catch (e) {
|
|
console.warn(`Error parsing lore line '${line}': ${message(e)}`)
|
|
}
|
|
})
|
|
|
|
const durability = item.getItem().durability
|
|
const enchantments = (item.is('enchanted_book') ? item.tag.getList('StoredEnchantments', NbtType.Compound) : item.tag.getList('Enchantments', NbtType.Compound)) ?? NbtList.create()
|
|
|
|
const effects = isPotion ? Potion.getAllEffects(item) : []
|
|
const attributeModifiers = isPotion ? Potion.getAllAttributeModifiers(item) : []
|
|
|
|
return <>
|
|
<TextComponent component={name} base={{ color: 'white', italic: displayName.length > 0 }} />
|
|
{shouldShow(item, 'additional') && <>
|
|
{(!advanced && displayName.length === 0 && item.is('filled_map') && item.tag.hasNumber('map')) && <>
|
|
<TextComponent component={{ text: `#${item.tag.getNumber('map')}`, color: 'gray' }} />
|
|
</>}
|
|
{(item.is('filled_map') && advanced) && <>
|
|
<TextComponent component={{ translate: 'filled_map.unknown', color: 'gray' }} />
|
|
</>}
|
|
{isPotion && effects.length === 0
|
|
? <TextComponent component={{ translate: 'effect.none', color: 'gray' }} />
|
|
: effects.map(e => {
|
|
const color = e.effect.category === 'harmful' ? 'red' : 'blue'
|
|
let component: any = { translate: `effect.${e.effect.id.namespace}.${e.effect.id.path}` }
|
|
if (e.amplifier > 0) {
|
|
component = { translate: 'potion.withAmplifier', with: [component, { translate: `potion.potency.${e.amplifier}` }] }
|
|
}
|
|
if (e.duration > 20) {
|
|
component = { translate: 'potion.withDuration', with: [component, MobEffectInstance.formatDuration(e)] }
|
|
}
|
|
return <TextComponent component={{ ...component, color }} />
|
|
})}
|
|
{attributeModifiers.length > 0 && <>
|
|
<TextComponent component='' />
|
|
<TextComponent component={{ translate: 'potion.whenDrank', color: 'dark_purple' }} />
|
|
{attributeModifiers.map(([attr, { amount, operation }]) => {
|
|
const a = operation === AttributeModifierOperation.addition ? amount * 100 : amount
|
|
if (amount > 0) {
|
|
return <TextComponent component={{ translate: `attribute.modifier.plus.${operation}`, with: [Math.floor(a * 100) / 100, { translate: `attribute.name.${attr.id.path}` }], color: 'blue' }} />
|
|
} else if (amount < 0) {
|
|
return <TextComponent component={{ translate: `attribute.modifier.take.${operation}`, with: [Math.floor(a * -100) / 100, { translate: `attribute.name.${attr.id.path}` }], color: 'red' }} />
|
|
}
|
|
return null
|
|
})}
|
|
</>}
|
|
</>}
|
|
{shouldShow(item, 'enchantments') && enchantments.map(enchantment => {
|
|
const id = enchantment.getString('id')
|
|
const lvl = enchantment.getNumber('lvl')
|
|
const ench = Enchantment.REGISTRY.get(Identifier.parse(id))
|
|
const component: any[] = [{ translate: `enchantment.${id.replace(':', '.')}`, color: ench?.isCurse ? 'red' : 'gray' }]
|
|
if (lvl !== 1 || ench?.maxLevel !== 1) {
|
|
component.push(' ', { translate: `enchantment.level.${lvl}`})
|
|
}
|
|
return <TextComponent component={component} />
|
|
})}
|
|
{item.tag.hasCompound('display') && <>
|
|
{shouldShow(item, 'dye') && item.tag.getCompound('display').hasNumber('color') && (advanced
|
|
? <TextComponent component={{ translate: 'item.color', with: [intToDisplayHexRgb(item.tag.getCompound('display').getNumber('color'))], color: 'gray' }} />
|
|
: <TextComponent component={{ translate: 'item.dyed', color: 'gray' }} />)}
|
|
{lore.map((component) => <TextComponent component={component} base={{ color: 'dark_purple', italic: true }} />)}
|
|
</>}
|
|
{shouldShow(item, 'unbreakable') && item.tag.getBoolean('Unbreakable') && <TextComponent component={{ translate: 'item.unbreakable', color: 'blue' }} />}
|
|
{(advanced && item.tag.getNumber('Damage') > 0 && durability) && <TextComponent component={{ translate: 'item.durability', with: [`${durability - item.tag.getNumber('Damage')}`, `${durability}`] }} />}
|
|
{advanced && <>
|
|
<TextComponent component={{ text: item.id.toString(), color: 'dark_gray'}} />
|
|
{item.tag.size > 0 && <TextComponent component={{ translate: 'item.nbt_tags', with: [item.tag.size], color: 'dark_gray' }} />}
|
|
</>}
|
|
</>
|
|
}
|
|
|
|
const TooltipMasks = {
|
|
enchantments: 1,
|
|
modifiers: 2,
|
|
unbreakable: 4,
|
|
can_destroy: 8,
|
|
can_place: 16,
|
|
additional: 32,
|
|
dye: 64,
|
|
upgrades: 128,
|
|
}
|
|
|
|
function shouldShow(item: ItemStack, mask: keyof typeof TooltipMasks) {
|
|
const flags = item.tag.getNumber('HideFlags')
|
|
return (flags & TooltipMasks[mask]) === 0
|
|
}
|