import * as mc from "@minecraft/server"
import V3 from "./utilities/V3";
import * as ui from "@minecraft/server-ui";
import './cyd_dino_pack';
import { menuMain, setupStaticMenus, showFogMenuSettings } from "./cyd_dino_menu";
import { handleRiderInteract } from "./cyd_dino_rider_interact";

import './bosses/cyd_dino_bosses_attack'

import './cyd_dino_wind';
import './cyd_dino_trust';
import { updateTrust } from "./cyd_dino_trust";

import "./items/spike_trap";
import "./items/net_crossbow"
import "./items/bolas";
import "./items/slingshot";
import "./items/drak_horn"

import './hunters/hunters_main'

import "./misc/attacks"
import './misc/biome_toggler'

import './cyd_dino_structures'
import './cyd_dino_log'

export const VERSION = "1.0.0";
const PLAYER_TICK_INTERVAL = 1;

const SOUND_PROJECTILE_THROW = "cyd_lbb.bath_bomb_throw";
const SOUND_OPTIONS = { pitch: 1.0, volume: 1.0, };
const IMPULSE = 1.8;

const ancientFruitDropChances = new Map([
    ["cyd_dino:dicksonia_leaves", 0.20], // 20%
    ["cyd_dino:fan_palm_leaves", 0.20], // 20%
    ["cyd_dino:gunnera", 0.05], // 5%

    // TODO: check if these are gunnera plants
    ["cyd_dino:dicroidium", 0.05], // 5%
    ["cyd_dino:fiddlehead_fern", 0.05], // 5%
    ["cyd_dino:giant_horsetail", 0.05], // 5%
    ["cyd_dino:lycopod", 0.05], // 5%
    ["cyd_dino:neuropteris", 0.05], // 5%
])
const ANCIENT_FRUIT_ITEM_ID = "cyd_dino:ancient_fruit"

const trees = {
    araucaria: [
        `structure load "cyd_dino/trees/araucaria/big_araucaria_01" ~-5~~-5`,
        `structure load "cyd_dino/trees/araucaria/big_araucaria_02" ~-4~~-5`,
        `structure load "cyd_dino/trees/araucaria/big_araucaria_03" ~-5~~-5`,
        `structure load "cyd_dino/trees/araucaria/little_araucaria_01" ~-3~~-3`,
        `structure load "cyd_dino/trees/araucaria/little_araucaria_02" ~-2~~-2`,
        `structure load "cyd_dino/trees/araucaria/little_araucaria_03" ~-4~~-4`
    ],
    bennettitales: [
        `structure load "cyd_dino/trees/benne/big_benne_01" ~-1~~-1`,
        `structure load "cyd_dino/trees/benne/big_benne_02" ~-1~~-3`,
        `structure load "cyd_dino/trees/benne/big_benne_03" ~-1~~-3`,
        `structure load "cyd_dino/trees/benne/little_benne_01" ~-1~~-1`,
        `structure load "cyd_dino/trees/benne/little_benne_02" ~-1~~-1`,
        `structure load "cyd_dino/trees/benne/little_benne_03" ~-1~~-1`,
    ],
    cheirolepidiceae: [
        `structure load "cyd_dino/trees/cheiro/cheiro_01" ~-1~~-1`,
        `structure load "cyd_dino/trees/cheiro/cheiro_02" ~-1~~-1`,
        `structure load "cyd_dino/trees/cheiro/cheiro_03" ~-1~~-1`,
        `structure load "cyd_dino/trees/cheiro/cheiro_04" ~-1~~-1`,
        `structure load "cyd_dino/trees/cheiro/cheiro_05" ~-1~~-1`
    ],
    conifer: [
        `structure load "cyd_dino/trees/conifer/big_conifer_01" ~-3~~-3`,
        `structure load "cyd_dino/trees/conifer/big_conifer_02" ~-4~~-4`,
        `structure load "cyd_dino/trees/conifer/big_conifer_03" ~-3~~-3`,
        `structure load "cyd_dino/trees/conifer/little_conifer_01" ~-1~~-1`,
        `structure load "cyd_dino/trees/conifer/little_conifer_02" ~-1~~-1`,
        `structure load "cyd_dino/trees/conifer/little_conifer_03" ~-1~~-1`
    ],
    cordaites: [
        `structure load "cyd_dino/trees/cordaites/big_cordaites_01" ~-2~~-2`,
        `structure load "cyd_dino/trees/cordaites/big_cordaites_02" ~-2~~-2`,
        `structure load "cyd_dino/trees/cordaites/big_cordaites_03" ~-2~~-2`,
        `structure load "cyd_dino/trees/cordaites/little_cordaites_01" ~-1~~-1`,
        `structure load "cyd_dino/trees/cordaites/little_cordaites_02" ~-1~~-1`,
        `structure load "cyd_dino/trees/cordaites/little_cordaites_03" ~-1~~-1`
    ],
    cycads: [
        `structure load "cyd_dino/trees/cycads/cycads_01" ~-1~~-1`,
        `structure load "cyd_dino/trees/cycads/cycads_02" ~-1~~-1`,
        `structure load "cyd_dino/trees/cycads/cycads_03" ~-1~~-1`,
        `structure load "cyd_dino/trees/cycads/cycads_04" ~-2~~-2`,
        `structure load "cyd_dino/trees/cycads/cycads_05" ~-1~~-2`
    ],
    dicksonia: [
        `structure load "cyd_dino/trees/dicksonia/big_dicksonia_01" ~-2~~-2`,
        `structure load "cyd_dino/trees/dicksonia/big_dicksonia_02" ~-2~~-2`,
        `structure load "cyd_dino/trees/dicksonia/big_dicksonia_03" ~-2~~-2`,
        `structure load "cyd_dino/trees/dicksonia/little_dicksonia_01" ~-2~~-2`,
        `structure load "cyd_dino/trees/dicksonia/little_dicksonia_02" ~-2~~-2`
    ],
    fan_palm: [
        `structure load "cyd_dino/trees/fanpalm/fanpalm_01" ~-2~~-3`,
        `structure load "cyd_dino/trees/fanpalm/fanpalm_02" ~-2~~-2`,
        `structure load "cyd_dino/trees/fanpalm/fanpalm_03" ~-2~~-2`,
        `structure load "cyd_dino/trees/fanpalm/fanpalm_04" ~-2~~-2`,
        `structure load "cyd_dino/trees/fanpalm/fanpalm_05" ~-2~~-2`
    ],
    ginkgo: [
        `structure load "cyd_dino/trees/ginkgo/big_ginkgo_01" ~-7~~-6`,
        `structure load "cyd_dino/trees/ginkgo/big_ginkgo_02" ~-4~~-5`,
        `structure load "cyd_dino/trees/ginkgo/big_ginkgo_03" ~-6~~-6`,
        `structure load "cyd_dino/trees/ginkgo/little_ginkgo_01" ~-3~~-3`,
        `structure load "cyd_dino/trees/ginkgo/little_ginkgo_02" ~-2~~-2`,
        `structure load "cyd_dino/trees/ginkgo/little_ginkgo_03" ~-2~~-1`
    ],
    metasequoia: [
        `structure load "cyd_dino/trees/meta/big_meta_01" ~-3~~-2`,
        `structure load "cyd_dino/trees/meta/big_meta_02" ~-3~~-3`,
        `structure load "cyd_dino/trees/meta/big_meta_03" ~-2~~-2`,
        `structure load "cyd_dino/trees/meta/little_meta_01" ~-1~~-1`,
        `structure load "cyd_dino/trees/meta/little_meta_02" ~-1~~-1`,
        `structure load "cyd_dino/trees/meta/little_meta_03" ~-2~~-2`
    ],
    podocarps: [
        `structure load "cyd_dino/trees/podo/big_podo_01" ~-4~~-5`,
        `structure load "cyd_dino/trees/podo/big_podo_02" ~-4~~-4`,
        `structure load "cyd_dino/trees/podo/big_podo_03" ~-4~~-5`,
        `structure load "cyd_dino/trees/podo/little_podo_01" ~-3~~-4`,
        `structure load "cyd_dino/trees/podo/little_podo_02" ~-4~~-4`,
        `structure load "cyd_dino/trees/podo/little_podo_03" ~-2~~-2`
    ],
    sigillaria: [
        `structure load "cyd_dino/trees/sigillaria/big_sigillaria_01" ~-3~~-3`,
        `structure load "cyd_dino/trees/sigillaria/big_sigillaria_02" ~-5~~-4`,
        `structure load "cyd_dino/trees/sigillaria/big_sigillaria_03" ~-5~~-3`,
        `structure load "cyd_dino/trees/sigillaria/little_sigillaria_01" ~-3~~-4`,
        `structure load "cyd_dino/trees/sigillaria/little_sigillaria_02" ~-2~~-1`,
        `structure load "cyd_dino/trees/sigillaria/little_sigillaria_03" ~-2~~-2`
    ]
}

const dinos = ['nest_allosaurus', 'nest_anky', 'nest_archeo', 'nest_bary', 'nest_brachio', 'nest_carno', 'nest_ceratosaurus', 'nest_conchoraptor', 'nest_dime', 'nest_gigantspinosaurus', 'nest_iguan', 'nest_majungosaurus', 'nest_micro', 'nest_ohmdenosaurus', 'nest_pachy', 'nest_para', 'nest_psitacosaurus', 'nest_ptera', 'nest_ptera', 'nest_sinotyrannus', 'nest_spino', 'nest_stego', 'nest_stegouros', 'nest_styrac', 'nest_suchomimus', 'nest_trex', 'nest_trice', 'nest_tupandactylus', 'nest_utah', 'nest_velo', 'nest_zhanghenlong']
const aquatics = ['nest_cameroceras', 'nest_dunkleosteus', 'nest_icty', 'nest_onchopristis', 'nest_prognathodon', 'nest_simolestes', 'nest_xiphactinus']
const flyers = ['cyd_dino:quetz', 'cyd_dino:ptera', 'cyd_dino:tupandactylus']
const herbivores = ["cyd_dino:anky", "cyd_dino:brachio", "cyd_dino:gigantspinosaurus", "cyd_dino:micro", "cyd_dino:ohmdenosaurus", "cyd_dino:pachy", "cyd_dino:para", "cyd_dino:psitacosaurus", "cyd_dino:stego", "cyd_dino:stegouros", "cyd_dino:styrac", "cyd_dino:trice", "cyd_dino:zhanghenlong"]

const bosses = ['cyd_dino:carnankylos', 'cyd_dino:stegospheryx', 'cyd_dino:mega', 'cyd_dino:empy']
const npcs = ['cyd_dino:gaiakin', 'cyd_dino:draxer', 'cyd_dino:green_merchant', 'cyd_dino:red_merchant']

export const dinoData = new Map([
    ["cyd_dino:allosaurus", { name: "Allosaurus", tier: "large" }],
    ["cyd_dino:anky", { name: "Ankylosaurus", tier: "medium" }],
    ["cyd_dino:archeo", { name: "Archeopteryx", tier: "small" }],
    ["cyd_dino:bary", { name: "Baryonyx", tier: "large" }],
    ["cyd_dino:brachio", { name: "Brachiosaurus", tier: "large" }],
    ["cyd_dino:cameroceras", { name: "Cameroceras", tier: "large" }],
    ["cyd_dino:carno", { name: "Carnotaurus", tier: "large" }],
    ["cyd_dino:ceratosaurus", { name: "Ceratosaurus", tier: "large" }],
    ["cyd_dino:conchoraptor", { name: "Conchoraptor", tier: "small" }],
    ["cyd_dino:dime", { name: "Dimetrodon", tier: "small" }],
    ["cyd_dino:dunkleosteus", { name: "Dunkleosteus", tier: "large" }],
    ["cyd_dino:gigantspinosaurus", { name: "Gigantspinosaurus", tier: "large" }],
    ["cyd_dino:icty", { name: "Ichtyosaurus", tier: "large" }],
    ["cyd_dino:iguan", { name: "Iguanodon", tier: "medium" }],
    ["cyd_dino:majungosaurus", { name: "Majungosaurus", tier: "medium" }],
    ["cyd_dino:micro", { name: "Microceratus", tier: "small" }],
    ["cyd_dino:ohmdenosaurus", { name: "Ohmdenosaurus", tier: "large" }],
    ["cyd_dino:onchopristis", { name: "Onchopristis", tier: "medium" }],
    ["cyd_dino:pachy", { name: "Pachycephalosaurus", tier: "medium" }],
    ["cyd_dino:para", { name: "Parasaurolophus", tier: "medium" }],
    ["cyd_dino:prognathodon", { name: "Prognathodon", tier: "large" }],
    ["cyd_dino:psitacosaurus", { name: "Psitacosaurus", tier: "small" }],
    ["cyd_dino:ptera", { name: "Pteranodon", tier: "large" }],
    ["cyd_dino:quetz", { name: "Quetzalcoatlus", tier: "large" }],
    ["cyd_dino:simolestes", { name: "Simolestes", tier: "large" }],
    ["cyd_dino:sinotyrannus", { name: "Sinotyrannus", tier: "medium" }],
    ["cyd_dino:spino", { name: "Spinosaurus", tier: "large" }],
    ["cyd_dino:stego", { name: "Stegosaurus", tier: "large" }],
    ["cyd_dino:stegouros", { name: "Stegouros", tier: "medium" }],
    ["cyd_dino:styrac", { name: "Styracosaurus", tier: "medium" }],
    ["cyd_dino:suchomimus", { name: "Suchomimus", tier: "medium" }],
    ["cyd_dino:trex", { name: "Tyranosaurus", tier: "large" }],
    ["cyd_dino:trice", { name: "Triceratops", tier: "medium" }],
    ["cyd_dino:tupandactylus", { name: "Tupandactylus", tier: "large" }],
    ["cyd_dino:utah", { name: "Utahraptor", tier: "small" }],
    ["cyd_dino:velo", { name: "Velociraptor", tier: "small" }],
    ["cyd_dino:xiphactinus", { name: "Xiphactinus", tier: "large" }],
    ["cyd_dino:zhanghenlong", { name: "Zhanghenlong", tier: "medium" }]
])

export const actionNames = new Map([
    ["storage", "Storage"],
    ["stone_breaker", "Stone Breaker"],
    ["fisher", "Fisher"],
    ["flying", "Flying"],
    ["stomp", "Stomp"],
    ["none", "None"]
])

export const personalityNames = new Map([
    ["loyal", "Loyal"],
    ["hot_headed", "Hot Headed"],
    ["playful", "Playful"],
    ["brave", "Brave"],
    ["shy", "Shy"],
    ["rebellious", "Rebellious"],
    ["nurturing", "Nurturing"],
    ["peaceful", "Peaceful"]
])

mc.world.afterEvents.itemUse.subscribe((eventData) => {
    let player = eventData.source;
    let itemUse = eventData.itemStack;
    if (itemUse === undefined) return;

    if (itemUse.typeId == "cyd_dino:dino_taming_manual") menuMain(player);
})

mc.world.afterEvents.entitySpawn.subscribe(event => {
    if (!event.entity.typeId.startsWith('cyd_dino:')) return

    const entity = event.entity
    if (!entity) return
    if (!entity.getComponent('minecraft:type_family')?.hasTypeFamily('dino')) return

    for (const player of entity.dimension.getPlayers({
        location: entity.location,
        maxDistance: 6
    })) {
        if (player.getGameMode() === mc.GameMode.creative) return
    }

    const { x, y, z } = entity.location

    mc.system.run(() => entity.runCommand(`spreadplayers ${Math.floor(x)} ${Math.floor(z)} 3 4 @e[type=${entity.typeId},r=4] ${Math.floor(y)}`))
})

mc.world.beforeEvents.playerInteractWithEntity.subscribe(async eventData => {
    const { player, target, itemStack } = eventData;
    if (itemStack) {
        if (itemStack.typeId == 'cyd_dino:giant_bone') { showTameCommandMenu(player, target); eventData.cancel = true; return }
        if (itemStack.typeId == 'cyd_dino:totem') {
            if (!target.typeId.startsWith('cyd_dino:')) return
            eventData.cancel = true

            await mc.system.waitTicks(1)

            const lore = []
            const tier = target.getProperty('cyd_dino:tier')

            if (aquatics.map(x => x.replace('nest_', 'cyd_dino:')).includes(target.typeId)) lore.push('Water Breathing')
            if (flyers.includes(target.typeId)) lore.push('Levitation')
            if (tier == 5) lore.push('Strength & Resistance')
            if (tier == 4) lore.push('Strength')
            if (herbivores.includes(target.typeId)) lore.push('Regeneration')

            itemStack.setLore(lore)
            if (lore.length) player.getComponent('equippable').setEquipment(mc.EquipmentSlot.Mainhand, itemStack)

            return
        }
        if (!target.getComponent('is_tamed') && isCorrectDietaryItem(diets.get(target.typeId), itemStack)) {
            const health = target.getComponent('health')
            const prev = health.currentValue
            mc.system.run(() => {
                if (health.currentValue > prev) updateTrust(target, player, 50)

                switch (dinoData.get(target.typeId)?.tier ?? 'small') {
                    case 'small':
                        updateTrust(target, player, 40)
                        break
                    case 'medium':
                        updateTrust(target, player, 17)
                        break
                    case 'large':
                        updateTrust(target, player, 10)
                        break
                }
            })
        }
    }
    if (target.getComponent('rideable')?.getRiders()?.includes(player)) { handleRiderInteract(target, player, itemStack) }
})

const armored = ["cyd_dino:anky", "cyd_dino:cameroceras", "cyd_dino:dunkleosteus", "cyd_dino:stegouros"]

mc.world.afterEvents.entityHurt.subscribe(event => {
    const { damageSource, hurtEntity, damage } = event;

    const entity = damageSource.damagingEntity;
    if (!entity || !hurtEntity) return;
    const hurtEntityId = hurtEntity.typeId

    if (hurtEntityId == 'minecraft:player') { playerHurtHandler(entity); return }
    if (bosses.includes(hurtEntityId)) return
    if (npcs.includes(hurtEntityId)) return
    if (hurtEntityId.startsWith('cyd_dino:hunter_')) return
    if (hurtEntity.typeId === 'cyd_dino:primeval_merchant') return
    if (hurtEntity.getComponent('type_family')?.hasTypeFamily('critter')) return

    try {
        if (hurtEntityId.startsWith('cyd_dino:')) {
            if (entity.typeId == 'minecraft:player') {
                if (hurtEntity.getComponent('is_tamed')) return
                if (!hurtEntity.getProperty('cyd_dino:tier')) return
                if (hurtEntity.getProperty('cyd_dino:tier') == 5) updateTrust(hurtEntity, entity, 1)

                updateTrust(hurtEntity, entity, -60)

                if (hurtEntity.getComponent('health').currentValue <= 0 && hurtEntity.getProperty('cyd_dino:is_alpha'))
                    hurtEntity.dimension.getEntities({
                        type: hurtEntityId,
                        tags: entity.getTags().map(x => parseInt(x)).filter(x => !Number.isNaN(x))
                    }).forEach(member => updateTrust(member, entity, 50))

                if (armored.includes(hurtEntityId) && entity.getComponent('equippable')
                    .getEquipment(mc.EquipmentSlot.Mainhand)?.typeId == 'cyd_dino:dinosaur_tooth_dagger')
                    hurtEntity.applyDamage(damage * 1.5)

                return
            }

            try {
                speedBoostPersonalityBonus(entity, entity.getProperty('cyd_dino:personality'))
            } catch ($) { }
        }
    } catch ($) { }
})

mc.world.afterEvents.playerSpawn.subscribe((eventData) => {
    const player = eventData.player
    if (player.hasTag('cyd_dino_book')) return

    player.dimension.spawnItem(new mc.ItemStack("cyd_dino:guidebook_g", 1), player.location)

    // fog settings on by default
    mc.world.setDynamicProperty('cyd_dino:enabled_fog', true)
    player.dimension.spawnItem(new mc.ItemStack('cyd_dino:fog_settings', 1), player.location)

    player.addTag('cyd_dino_book')
});

setupStaticMenus();

mc.world.afterEvents.projectileHitEntity.subscribe(eventData => {
    const { projectile } = eventData;
    if (projectile.typeId == 'cyd_dino:tranq_dart') dartHit(eventData.getEntityHit().entity)
})

mc.world.beforeEvents.worldInitialize.subscribe(async (eventData) => {
    const { blockComponentRegistry, itemComponentRegistry } = eventData;
    itemComponentRegistry.registerCustomComponent('cyd_dino:dart_gun', {
        onUse(e) {
            spawnProjectile(e.source)
        }
    })
    itemComponentRegistry.registerCustomComponent('cyd_dino:aoe', {
        onHitEntity(e) {
            const { attackingEntity, hitEntity } = e;
            hitEntity.dimension.getEntities({ location: hitEntity.location, maxDistance: 8 }).forEach(entity => {
                if (attackingEntity == entity) return;
                if (hitEntity == entity) return;
                try {
                    entity.applyDamage(8, { cause: mc.EntityDamageCause.entityAttack, damagingEntity: attackingEntity })
                } catch (error) { }
            })
        }
    })
    itemComponentRegistry.registerCustomComponent('cyd_dino:bonus_knockback', {
        onHitEntity(e) {
            const { hadEffect, attackingEntity, hitEntity } = e;
            const l = attackingEntity.location
            const l2 = hitEntity.location
            if (hadEffect) hitEntity.applyKnockback(-l.x + l2.x, -l.z + l2.z, 1, 0.2)
        }
    })
    itemComponentRegistry.registerCustomComponent('cyd_dino:fog_settings', {
        onUse(event) {
            const player = event.source
            showFogMenuSettings(player)
        }
    })
    itemComponentRegistry.registerCustomComponent('cyd_dino:totem', {
        onUse(e) {
            const { source, itemStack } = e;
            const lore = itemStack.getLore()
            if (!lore) return

            if (lore.length === 0) return

            lore.forEach(entry => {
                switch (entry) {
                    case 'Water Breathing': source.addEffect('water_breathing', 600)
                        break;
                    case 'Levitation': source.addEffect('levitation', 100)
                        break;
                    case 'Regeneration': source.addEffect('regeneration', 600)
                        break;
                    case 'Strength & Resistance': source.addEffect('resistance', 600)
                    case 'Strength': source.addEffect('strength', 600)
                        break;
                }
            })
            source.getComponent('equippable').setEquipment(mc.EquipmentSlot.Mainhand)
        }
    })
    blockComponentRegistry.registerCustomComponent('cyd_dino:volcano_block', {
        onRandomTick(e) {
            const { block, dimension } = e
            const location = block.center()

            dimension.spawnParticle('cyd_dino:lava_burst_1', location)
            dimension.spawnParticle('cyd_dino:lava_burst_2', location)
            dimension.spawnParticle('cyd_dino:lava_burst_3', location)
        },
        onTick(e) {
            const { block, dimension } = e

            dimension.getEntities({
                location: block.above().center(),
                maxDistance: 1
            }).forEach(entity => entity.applyDamage(3, { cause: mc.EntityDamageCause.fireTick }))
        }
    })
    blockComponentRegistry.registerCustomComponent('cyd_dino:biome_nest', {
        onTick(e) {
            const { block } = e;
            block.setType('cyd_dino:' + dinos[Math.floor(Math.random() * dinos.length)])
        }
    })
    blockComponentRegistry.registerCustomComponent('cyd_dino:aquatic_nest', {
        onTick(e) {
            const { block } = e;
            block.setType('cyd_dino:' + aquatics[Math.floor(Math.random() * aquatics.length)])
        }
    })

    blockComponentRegistry.registerCustomComponent('cyd_dino:green_hunter', {
        onTick(e) {
            const { block, dimension } = e;
            const spawnLocation = block.bottomCenter()
            const hunter = dimension.spawnEntity('cyd_dino:gaiakin', spawnLocation)
            block.setType('air')
        }
    })

    blockComponentRegistry.registerCustomComponent('cyd_dino:red_hunter', {
        onTick(e) {
            const { block, dimension } = e;
            const spawnLocation = block.bottomCenter()
            const hunter = dimension.spawnEntity('cyd_dino:draxer', spawnLocation)
            block.setType('air')
        }
    })

    blockComponentRegistry.registerCustomComponent('cyd_dino:nest_spawner', {
        onTick(e) {
            const { block, dimension } = e;
            const { typeId } = block;
            const nestLocation = block.bottomCenter()
            const spawnCenter = block.above().center()

            const type = typeId.slice(14)
            const chance = Math.random()

            if (chance < 75) {
                const parentLocation1 = findSafeSpawnLocation(dimension, spawnCenter, 10)
                const parent = dimension.spawnEntity('cyd_dino:' + type + '<cyd_dino:as_nesting_parent>', parentLocation1)
                const parentLocation2 = findSafeSpawnLocation(dimension, spawnCenter, 14)
                const parent2 = dimension.spawnEntity('cyd_dino:' + type + '<cyd_dino:as_nesting_parent>', parentLocation2)

                mc.system.runTimeout(() => {
                    parent.triggerEvent('cyd_dino:is_asleep')
                    parent2.triggerEvent('cyd_dino:is_asleep')
                });

                const nest = dimension.spawnEntity('cyd_dino:nest', nestLocation)

                const rideableComponent = nest.getComponent('rideable')
                for (let i = 0; i < Math.floor(Math.random() * 3) + 1; i++) {
                    const egg = dimension.spawnEntity('cyd_dino:baby_' + type + '<cyd_dino:as_egg>', nestLocation)
                    egg.setDynamicProperty('parent', parent.id)
                    egg.setDynamicProperty('parent2', parent2.id)

                    rideableComponent.addRider(egg)
                }
            } else {
                const babyCount = Math.floor(Math.random() * 3) + 1

                for (let i = 0; i < babyCount; i++) {
                    const babyLocation = findSafeSpawnLocation(dimension, spawnCenter, 5)
                    dimension.spawnEntity(`cyd_dino:baby_${type}`, babyLocation)
                }
            }

            block.setType('air')
        }
    })
    blockComponentRegistry.registerCustomComponent('cyd_dino:leaves', {
        beforeOnPlayerPlace: playerPlacedLeaf,
        onRandomTick(e) {
            handleDecay(e, [{ x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 }, { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }, { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 }])
        }
    })
    blockComponentRegistry.registerCustomComponent('cyd_dino:vertical_leaves', {
        beforeOnPlayerPlace: playerPlacedLeaf,
        onRandomTick(e) {
            handleDecay(e, [{ x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 }])
        }
    })
    blockComponentRegistry.registerCustomComponent('cyd_dino:cardinal_leaves', {
        beforeOnPlayerPlace: playerPlacedLeaf,
        onRandomTick(e) {
            handleDecay(e, [{ x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }, { x: 0, y: 0, z: -1 }, { x: -1, y: 0, z: 1 }])
        }
    })
    blockComponentRegistry.registerCustomComponent('cyd_dino:cardinally_down_leaves', {
        beforeOnPlayerPlace: playerPlacedLeaf,
        onRandomTick(e) {
            handleDecay(e, [{ x: 1, y: -1, z: 0 }, { x: -1, y: -1, z: 0 }, { x: 0, y: -1, z: -1 }, { x: 0, y: -1, z: 1 }])
        }
    })

    blockComponentRegistry.registerCustomComponent('cyd_dino:drop_ancient_fruit', {
        onPlayerDestroy(event) {
            const { block, dimension } = event
            const blockTypeId = block.typeId

            if (ancientFruitDropChances.has(blockTypeId)) {
                const dropChance = ancientFruitDropChances.get(blockTypeId)
                if (Math.random() < dropChance) dimension.spawnItem(
                    new mc.ItemStack(ANCIENT_FRUIT_ITEM_ID, 1), block.center()
                )
            }
        }
    })

    blockComponentRegistry.registerCustomComponent('cyd_dino:diagonal_leaves', {
        beforeOnPlayerPlace: playerPlacedLeaf,
        onRandomTick(e) {
            handleDecay(e, [{ x: 1, y: 0, z: 1 }, { x: -1, y: 0, z: -1 }, { x: 1, y: 0, z: -1 }, { x: -1, y: 0, z: 1 }])
        }
    })

    blockComponentRegistry.registerCustomComponent('cyd_dino:sapling', {
        onPlayerInteract(e) {
            const { player, block } = e
            const itemStack = player.getComponent('equippable').getEquipment(mc.EquipmentSlot.Mainhand)
            if (itemStack?.typeId != 'minecraft:bone_meal') return;
            const age = block.permutation.getState('cyd_dino:age_bit')
            const treeType = block.typeId.split(':').pop().replace('_sapling', '')
            block.dimension.spawnParticle('minecraft:crop_growth_emitter', block.center());
            if (player.getGameMode() != 'creative') {
                try {
                    itemStack.amount -= 1
                    player?.getComponent('equippable').setEquipment('Mainhand', itemStack)
                } catch (error) {
                    player?.getComponent('equippable').setEquipment('Mainhand')
                }
            }
            player.playSound('item.bone_meal.use', { location: block.location })
            if (Math.random() > 0.45) return;
            if (age) block.dimension.runCommand(`execute positioned ${block.x} ${block.y} ${block.z} run ` + trees[treeType][Math.floor(Math.random() * trees[treeType].length)])
            else block.setPermutation(block.permutation.withState('cyd_dino:age_bit', !age))
        },
        onRandomTick(e) {
            const { block } = e
            if (Math.floor(Math.random() * 7) > 0) return;
            const treeType = block.typeId.split(':').pop().replace('_sapling', '')
            const age = block.permutation.getState('cyd_dino:age_bit')
            if (age) block.dimension.runCommand(`execute positioned ${block.x} ${block.y} ${block.z} run ` + trees[treeType][Math.floor(Math.random() * trees[treeType].length)])
            else block.setPermutation(block.permutation.withState('cyd_dino:age_bit', !age))
        }
    })

})

function playerPlacedLeaf(e) {
    e.permutationToPlace = e.permutationToPlace.withState('cyd_dino:can_decay', false);
}

function findSafeSpawnLocation(dimension, center, radius) {
    for (let i = 0; i < 10; i++) {
        const randomOffset = {
            x: center.x + (Math.random() * radius * 2 - radius),
            y: center.y,
            z: center.z + (Math.random() * radius * 2 - radius)
        }

        const block = dimension.getBlock(randomOffset)
        if (block && block.isAir) return randomOffset
    }

    return center
}

function handleDecay(e, offsets) {
    // const { block } = e;

    // const permutation = block.permutation;
    // if (!permutation.getState('cyd_dino:can_decay')) return;

    // let maxTier = 0;
    // for (const offset of offsets) {
    //     const b = block.offset(offset)
    //     if (!b) continue;
    //     if (b.hasTag('log')) { maxTier = 4; break }
    //     const tier = (b.permutation.getState('cyd_dino:decay_tier') ?? 1) - 1
    //     if (tier > maxTier) maxTier = tier;
    // }

    // try {
    //     if (maxTier === 0) block.setType('air');
    //     else if (permutation.getState('cyd_dino:decay_tier') !== maxTier) block.setPermutation(permutation.withState('cyd_dino:decay_tier', maxTier));
    // } catch (error) { }
}

/**
 * @param {mc.Entity} hitEntity 
 */
function dartHit(hitEntity) {
    if (!hitEntity.typeId.startsWith('cyd_dino:')) return;
    if (!hitEntity.getComponent('type_family').hasTypeFamily('wild')) return;
    hitEntity.addEffect('slowness', 200, { amplifier: 255, showParticles: false })
    hitEntity.triggerEvent('cyd_dino:is_asleep')
}

const GLIDE_FORCE = 0.4
const GLIDE_INTERVAL = 5
const BOOST_VERTICAL_FORCE = 0.8
const BOOST_HORIZONTAL_FORCE = 2.0

const fltyingEntities = new Map()

function startGliding(player = mc.Player.prototype, vehicle = mc.Entity.prototype) {
    if (fltyingEntities.has(vehicle.id)) mc.system.clearRun(fltyingEntities.get(vehicle.id))

    vehicle.setDynamicProperty('cyd_dino:is_flying', true)
    player.playSound('entity.phantom.flap')

    const glideInterval = mc.system.runInterval(() => {
        const currVehicle = player.getComponent('riding')?.entityRidingOn
        if (!currVehicle || currVehicle.id !== vehicle.id) {
            stopGliding(vehicle)
            return
        }

        if (vehicle.isOnGround) {
            stopGliding(vehicle)
            return
        }

        const viewDirection = player.getViewDirection();
        const pitch = Math.asin(viewDirection.y) * (180 / Math.PI)

        const yaw = (player.getRotation().y * Math.PI) / 180
        const forward = {
            x: -Math.sin(yaw), y: 0,
            z: Math.cos(yaw)
        }

        if (pitch > -20) {
            //            vehicle.applyImpulse({
            //                x: forward.x * 0.1, y: 0.03, z: forward.z * 0.1
            //            })

            vehicle.addEffect('levitation', GLIDE_INTERVAL + 5, {
                showParticles: false,
                amplifier: 0
            });
            vehicle.addEffect('speed', GLIDE_INTERVAL + 5, {
                showParticles: false,
                amplifier: 28
            })

        }
        else if (pitch <= -20) {
            //           vehicle.applyImpulse({
            //               x: forward.x * 0.2, y: -0.01, z: forward.z * 0.2
            //           })

            vehicle.addEffect('slow_falling', GLIDE_INTERVAL + 5, {
                showParticles: false,
                amplifier: 1
            })
        }

        // vehicle.applyImpulse(viewDirection)
        // vehicle.addEffect('levitation', GLIDE_INTERVAL + 5, {
        //     showParticles: false,
        //     amplifier: 1
        // })

        fltyingEntities.set(vehicle.id, glideInterval)
    }, GLIDE_INTERVAL)
}

function stopGliding(vehicle = mc.Entity.prototype) {
    if (!vehicle) return

    if (fltyingEntities.has(vehicle.id)) {
        mc.system.clearRun(fltyingEntities.get(vehicle.id))
        fltyingEntities.delete(vehicle.id)
    }

    vehicle.setDynamicProperty('cyd_dino:is_flying', false)
    vehicle.removeEffect('levitation')
    vehicle.removeEffect('slow_falling')
    vehicle.removeEffect('speed')
}

mc.world.afterEvents.playerButtonInput.subscribe(event => {
    const { newButtonState, player } = event

    const vehicle = player.getComponent('riding')?.entityRidingOn
    if (!vehicle) return

    if (newButtonState == mc.ButtonState.Pressed) {
        const isGliding = vehicle.getDynamicProperty('cyd_dino:is_flying') ?? false

        if (vehicle.hasTag('swimming')) {
            // if (!isGliding) startGliding(player, vehicle)
            // else {
            //     const viewDirection = player.getViewDirection()
            //     vehicle.applyKnockback(viewDirection.x, viewDirection.y, BOOST_HORIZONTAL_FORCE, BOOST_VERTICAL_FORCE)
            // }

            vehicle.applyImpulse(player.getViewDirection())
            vehicle.addEffect('levitation', 20 * 3, { showParticles: false, amplifier: 1 })
            return
        }

        if (!vehicle.getComponent('type_family').hasTypeFamily('flying')) return
        if (!isGliding) startGliding(player, vehicle)
        else {
            const viewDirection = player.getViewDirection()
            vehicle.applyKnockback(viewDirection.x, viewDirection.y, BOOST_HORIZONTAL_FORCE, BOOST_VERTICAL_FORCE)
        }
    }
}, { buttons: [mc.InputButton.Jump] })

/**
 * @typedef Diet
 * @property {string[] | undefined} items 
 * @property {string[] | undefined} tags 
 * @property {string[] | undefined} regex 
 */

/**
 * @type {Map<string,Diet>}
 */
const diets = new Map([
    ["cyd_dino:allosaurus", { items: ['cyd_dino:large_meat', 'cyd_dino:small_meat'] }],
    ["cyd_dino:anky", { items: ['minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:sweet_berries', 'cyd_dino:club_moss', 'cyd_dino:dicroidium', 'cyd_dino:giant_horsetail', 'cyd_dino:gunnera', 'cyd_dino:fiddlehead_fern', 'cyd_dino:lycopod'], regex: ['_leaves', '_sapling'] }],
    ["cyd_dino:archeo", { tags: ["minecraft:is_meat"], items: ['cyd_dino:bug'] }],
    ["cyd_dino:bary", { tags: ["minecraft:is_fish", "minecraft:is_meat"] }],
    ["cyd_dino:brachio", { items: ['minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:sweet_berries', 'cyd_dino:club_moss', 'cyd_dino:dicroidium', 'cyd_dino:giant_horsetail', 'cyd_dino:gunnera', 'cyd_dino:fiddlehead_fern', 'cyd_dino:lycopod'], regex: ['_leaves'] }],
    ["cyd_dino:cameroceras", { tags: ["minecraft:is_fish"] }],
    ["cyd_dino:carno", { tags: ["minecraft:is_meat"] }],
    ["cyd_dino:ceratosaurus", { items: ['cyd_dino:large_meat', 'cyd_dino:small_meat'] }],
    ["cyd_dino:conchoraptor", { items: ['cyd_dino:small_meat'] }],
    ["cyd_dino:dime", { tags: ["minecraft:is_fish", "minecraft:is_meat"] }],
    ["cyd_dino:dunkleosteus", { tags: ["minecraft:is_fish"] }],
    ["cyd_dino:gigantspinosaurus", { items: ['minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:sweet_berries', 'cyd_dino:club_moss', 'cyd_dino:dicroidium', 'cyd_dino:giant_horsetail', 'cyd_dino:gunnera', 'cyd_dino:fiddlehead_fern', 'cyd_dino:lycopod'], regex: ['_leaves', '_sapling'] }],
    ["cyd_dino:icty", { tags: ["minecraft:is_fish"] }],
    ["cyd_dino:iguan", { items: ['minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:sweet_berries', 'cyd_dino:club_moss', 'cyd_dino:dicroidium', 'cyd_dino:giant_horsetail', 'cyd_dino:gunnera', 'cyd_dino:fiddlehead_fern', 'cyd_dino:lycopod'], regex: ['_leaves', '_sapling'] }],
    ["cyd_dino:majungosaurus", { items: ['cyd_dino:large_meat', 'cyd_dino:small_meat'] }],
    ["cyd_dino:micro", { items: ['minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:sweet_berries', 'cyd_dino:club_moss', 'cyd_dino:dicroidium', 'cyd_dino:giant_horsetail', 'cyd_dino:gunnera', 'cyd_dino:fiddlehead_fern', 'cyd_dino:lycopod'], regex: ['_leaves', '_sapling'] }],
    ["cyd_dino:ohmdenosaurus", { items: ['minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:sweet_berries', 'cyd_dino:club_moss', 'cyd_dino:dicroidium', 'cyd_dino:giant_horsetail', 'cyd_dino:gunnera', 'cyd_dino:fiddlehead_fern', 'cyd_dino:lycopod'], regex: ['_leaves', '_sapling'] }],
    ["cyd_dino:onchopristis", { tags: ["minecraft:is_fish"] }],
    ["cyd_dino:pachy", { items: ['minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:sweet_berries', 'cyd_dino:club_moss', 'cyd_dino:dicroidium', 'cyd_dino:giant_horsetail', 'cyd_dino:gunnera', 'cyd_dino:fiddlehead_fern', 'cyd_dino:lycopod'], regex: ['_leaves', '_sapling'] }],
    ["cyd_dino:para", { items: ['minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:sweet_berries', 'cyd_dino:club_moss', 'cyd_dino:dicroidium', 'cyd_dino:giant_horsetail', 'cyd_dino:gunnera', 'cyd_dino:fiddlehead_fern', 'cyd_dino:lycopod'], regex: ['_leaves', '_sapling'] }],
    ["cyd_dino:prognathodon", { tags: ["minecraft:is_fish"], items: ['cyd_dino:large_meat'] }],
    ["cyd_dino:psitacosaurus", { items: ['minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:sweet_berries', 'cyd_dino:club_moss', 'cyd_dino:dicroidium', 'cyd_dino:giant_horsetail', 'cyd_dino:gunnera', 'cyd_dino:fiddlehead_fern', 'cyd_dino:lycopod'], regex: ['_leaves', '_sapling'] }],
    ["cyd_dino:ptera", { tags: ["minecraft:is_fish", "minecraft:is_meat"] }],
    ["cyd_dino:quetz", { tags: ["minecraft:is_fish", "minecraft:is_meat"] }],
    ["cyd_dino:simolestes", { tags: ["minecraft:is_fish"] }],
    ["cyd_dino:sinotyrannus", { items: ['cyd_dino:large_meat', 'cyd_dino:small_meat'] }],
    ["cyd_dino:spino", { tags: ["minecraft:is_fish", "minecraft:is_meat"] }],
    ["cyd_dino:stego", { items: ['minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:sweet_berries', 'cyd_dino:club_moss', 'cyd_dino:dicroidium', 'cyd_dino:giant_horsetail', 'cyd_dino:gunnera', 'cyd_dino:fiddlehead_fern', 'cyd_dino:lycopod'], regex: ['_leaves', '_sapling'] }],
    ["cyd_dino:stegouros", { items: ['minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:sweet_berries', 'cyd_dino:club_moss', 'cyd_dino:dicroidium', 'cyd_dino:giant_horsetail', 'cyd_dino:gunnera', 'cyd_dino:fiddlehead_fern', 'cyd_dino:lycopod'], regex: ['_leaves', '_sapling'] }],
    ["cyd_dino:styrac", { items: ['minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:sweet_berries', 'cyd_dino:club_moss', 'cyd_dino:dicroidium', 'cyd_dino:giant_horsetail', 'cyd_dino:gunnera', 'cyd_dino:fiddlehead_fern', 'cyd_dino:lycopod'], regex: ['_leaves', '_sapling'] }],
    ["cyd_dino:suchomimus", { tags: ["minecraft:is_fish"], items: ['cyd_dino:large_meat'] }],
    ["cyd_dino:trex", { tags: ["minecraft:is_meat"] }],
    ["cyd_dino:trice", { items: ['minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:sweet_berries', 'cyd_dino:club_moss', 'cyd_dino:dicroidium', 'cyd_dino:giant_horsetail', 'cyd_dino:gunnera', 'cyd_dino:fiddlehead_fern', 'cyd_dino:lycopod'], regex: ['_leaves', '_sapling'] }],
    ["cyd_dino:tupandactylus", { tags: ["minecraft:is_fish"], items: ['cyd_dino:small_meat'] }],
    ["cyd_dino:utah", { tags: ["minecraft:is_meat"] }],
    ["cyd_dino:velo", { tags: ["minecraft:is_meat"] }],
    ["cyd_dino:xiphactinus", { tags: ["minecraft:is_fish"] }],
    ["cyd_dino:zhanghenlong", { items: ['minecraft:apple', 'minecraft:golden_apple', 'minecraft:enchanted_golden_apple', 'minecraft:sweet_berries', 'cyd_dino:club_moss', 'cyd_dino:dicroidium', 'cyd_dino:giant_horsetail', 'cyd_dino:gunnera', 'cyd_dino:fiddlehead_fern', 'cyd_dino:lycopod'], regex: ['_leaves', '_sapling'] }]
])

const mobsIds = Array.from(diets.keys())

mc.world.afterEvents.dataDrivenEntityTrigger.subscribe(event => {
    const { entity } = event;
    entity.dimension.spawnItem(new mc.ItemStack(entity.typeId.replace('baby_', '') + '_egg'), entity.location)
    const player = entity.dimension.getEntities({ closest: 1, location: entity.location, type: 'minecraft:player' })[0];
    try {
        updateTrust(mc.world.getEntity(entity.getDynamicProperty('parent') || ''), player, -100)
    } catch (error) { } //Incase entity is not loaded; entity is dead, egg is placed by player
    try {
        updateTrust(mc.world.getEntity(entity.getDynamicProperty('parent2') || ''), player, -100)
    } catch (error) { } //Incase entity is not loaded; entity is dead, egg is placed by player
    entity.remove()
}, { eventTypes: ['cyd_dino:picked_up'] })

/**
 * @param {Diet} diet 
 * @param {mc.ItemStack} itemStack 
 */
function isCorrectDietaryItem(diet, itemStack) {
    if (diet === undefined) return false;
    if (diet.tags && itemStack.getTags().some(tag => diet.tags.includes(tag))) return true;
    if (diet.items?.includes(itemStack.typeId)) return true;
    if (diet.regex && diet.regex.some(rgx => itemStack.typeId.match(new RegExp(rgx))?.length > 0)) return true;
    return false;
}

const tameCommandEvents = new Map([
    ['cyd_dino:tame_command_menu.stay', 'cyd_dino:stay'],
    ['cyd_dino:tame_command_menu.follow', 'cyd_dino:follow'],
    ['cyd_dino:tame_command_menu.attack', 'cyd_dino:attack'],
    ['cyd_dino:tame_command_menu.guard', 'cyd_dino:guard'],
    ['cyd_dino:tame_command_menu.hurt_nearby_entities', 'cyd_dino:enable_nearby_mob_hurt'],
    ['cyd_dino:tame_command_menu.stop_hurting_nearby_entities', 'cyd_dino:disable_nearby_mob_hurt'],
    ['cyd_dino:tame_command_menu.destroy_trees', 'cyd_dino:toggle_tree_destruction'],
    ['cyd_dino:tame_command_menu.stop_destroying_trees', 'cyd_dino:toggle_tree_destruction'],
    ['cyd_dino:tame_command_menu.fish', 'cyd_dino:try_fish'],
    ['cyd_dino:tame_command_menu.stop_fishing', 'cyd_dino:stop_trying_to_fish'],
])

/**
 * @param {mc.Player} player 
 * @param {mc.Entity} creature 
 */
async function showTameCommandMenu(player, creature) {
    const creatureName = creature.nameTag ? creature.nameTag : { translate: 'entity.' + creature.typeId + '.name' };
    const actions = [
        'cyd_dino:tame_command_menu.stay',
        'cyd_dino:tame_command_menu.follow',
        'cyd_dino:tame_command_menu.attack',
        'cyd_dino:tame_command_menu.guard'
    ]

    await mc.system.waitTicks(1);

    if (!creature.isValid()) return;
    if (!creature.typeId.startsWith('cyd_dino:')) return;

    const tameableComponent = creature.getComponent('tameable')

    if (!tameableComponent || !tameableComponent.isTamed || tameableComponent.tamedToPlayerId != player.id) return;

    if (creature.getComponent('rideable')?.getRiders()?.includes(player)) {
        if (creature.getProperty('cyd_dino:is_tree_cutter')) {
            if (!creature.getProperty('cyd_dino:is_cutting_trees')) actions.push('cyd_dino:tame_command_menu.destroy_trees')
            else actions.push('cyd_dino:tame_command_menu.stop_destroying_trees')
        }

        if (!creature.getProperty('cyd_dino:is_hurting_nearby_mobs')) actions.push('cyd_dino:tame_command_menu.hurt_nearby_entities')
        else actions.push('cyd_dino:tame_command_menu.stop_hurting_nearby_entities')
    }

    if (creature.getProperty('cyd_dino:utility') == 'fisher') {
        if (creature.getProperty('cyd_dino:is_trying_fishing') || creature.getProperty('cyd_dino:is_fishing')) actions.push('cyd_dino:tame_command_menu.stop_fishing')
        else actions.push('cyd_dino:tame_command_menu.fish')
    }

    const form = new ui.ActionFormData()
    form.title(creatureName)
    actions.forEach(action => form.button({ translate: action }))

    const result = await form.show(player);
    if (result.canceled) return;

    const personality = creature.getProperty('cyd_dino:personality')

    if (personality == 'rebellious' && Math.random() < 0.3) { player.onScreenDisplay.setActionBar(['§6', creatureName, '§r', { translate: 'cyd_dino:tame_command_menu.disobeyed' }]); return }

    if (result.selection === 0) creature.getComponent('rideable')?.ejectRiders()

    creature.triggerEvent(tameCommandEvents.get(actions[result.selection]))
    player.onScreenDisplay.setActionBar(['§6', creatureName, '§r', { translate: 'cyd_dino:tame_command_menu.will_now' }, '§6', { translate: actions[result.selection] }])
}

/**
 * @param {mc.Player} player
 */
function spawnProjectile(player) {
    player.runCommandAsync("ride @s stop_riding");
    player.playSound(SOUND_PROJECTILE_THROW, SOUND_OPTIONS);
    const spawnLocation = player.getHeadLocation()
    mc.system.run(() => {
        const proj = player.dimension.spawnEntity("cyd_dino:tranq_dart", spawnLocation);
        const playerViewDirection = new V3(player.getViewDirection());
        proj.addEffect('slow_falling', 1000, { amplifier: 1, showParticles: false });
        // proj.clearVelocity();
        const projComp = (proj.getComponent(mc.EntityComponentTypes.Projectile));
        projComp.owner = player;
        projComp.shoot(playerViewDirection.scale(IMPULSE));
    });
}


/** @param {mc.Player} player  */
function playerHurtHandler(player) {
    player.dimension.getEntities({ families: ['tamed'], location: player.location, maxDistance: 16 }).filter(x => x.getComponent('tameable')?.tamedToPlayerId == player.id).forEach(entity => {
        if (entity.getProperty('cyd_dino:personality') == 'shy') entity.addEffect('strength')
    })
}

function speedBoostPersonalityBonus(entity, personality) {
    if (personality != 'loyal' && personality != 'hot_headed' && personality != 'brave') return;
    entity.addEffect('speed', 40)
}

mc.world.afterEvents.entityHealthChanged.subscribe(event => {
    try {
        const { newValue, entity } = event;
        const percentage = newValue / entity.getComponent('health')?.effectiveMin;
        if (percentage <= 0.5 && percentage > 0.25) {
            entity.addEffect("speed", 1000, { amplifier: 3, showParticles: false });
            entity.addEffect("strength", 1000, { amplifier: 3, showParticles: false })
        } else if (percentage <= 0.25) {
            entity.addEffect("slowness", 1000, { amplifier: 3, showParticles: false });
        }
    } catch ($) { }
}, { entityTypes: mobsIds })

// const MENU_PET_INFO = new ui.ActionFormData();
// function setupDynamicMenus(entityInteract) {
//     //PET INFO
//     let identifier = entityInteract.typeId;
//     MENU_PET_INFO.title({ translate: `entity.${ identifier }.name` });
//     MENU_PET_INFO.body({ translate: `cyd_dino.dynamic.information`, "with": { "rawtext": [{ "text": `${ entityInteract.getProperty("cyd_dino:utility") }` }, { "text": `${ entityInteract.getProperty("cyd_dino:personality") }` }, { "text": "\n" }, { "text": `${ entityInteract.getProperty("cyd_dino:taming_percentage") }` },] } });
// }



// async function petMenu(player) {
//     await mc.system.waitTicks(1);
//     MENU_PET_INFO.show(player).then(result => {
//         if (result.canceled) return;
//     });

// }

mc.world.afterEvents.dataDrivenEntityTrigger.subscribe(event => {
    if (event.eventId != 'cyd_dino:tamed') return

    const entity = event.entity
    if (!entity || !entity.typeId.startsWith('cyd_dino:')) return

    const ownerNametag = entity.getComponent('minecraft:tameable')?.tamedToPlayer?.nameTag
    if (!ownerNametag) return

    const name = `${ownerNametag}'s ${dinoData.get(entity.typeId)?.name ?? 'Dino'}`
    entity.nameTag = name
})

mc.world.beforeEvents.worldInitialize.subscribe(eventData => {
    const { blockComponentRegistry, itemComponentRegistry } = eventData;
    blockComponentRegistry.registerCustomComponent('cyd_dino:remove_snow', {
        onTick(e) {
            const { block, dimension } = e;
            const spawnLocation = block.above()
            const SNOW_MAP = {
                thin: 'cyd_dino:cheirolepidiceae_thin_snow',
                thick: 'cyd_dino:cheirolepidiceae_thick_snow'
            };

            if (spawnLocation.typeId.includes('minecraft:snow_layer')) {
                spawnLocation.setType('air');

                let curr = block;
                let depth = 0;
                while (depth < 5) {
                    const { typeId, x, y, z } = curr;
                    const density = typeId.includes('thin') ? 'thin'
                        : typeId.includes('thick') ? 'thick'
                            : null;
                    if (!density) break;

                    curr.setType(SNOW_MAP[density]);
                    curr = dimension.getBlock({ x, y: y - 1, z });
                    depth++;
                }
            }
        }
    })
})

mc.world.afterEvents.playerPlaceBlock.subscribe(event => {
    const { block, dimension } = event

    if (block.typeId != 'cyd_dino:water_lily') return
    const above = {
        x: block.location.x,
        y: block.location.y + 1,
        z: block.location.z
    }

    dimension.getBlock(above).setPermutation(mc.BlockPermutation.resolve('cyd_dino:water_lily'))
    block.setPermutation(mc.BlockPermutation.resolve('minecraft:air'))

    dimension.playSound('dig.grass', above, { volume: 0.8 })
})