import { EntityDamageCause, EquipmentSlot, GameMode, ItemStack, Player, system, world } from '@minecraft/server';
import * as itemOnMineBlock from './item/registry/on_mine_block';
import * as itemOnHitEntity from './item/registry/on_hit_entity';
import * as itemOnUse from './item/registry/on_use';
import * as blockOnRandomTick from './block/registry/on_random_tick';
import * as blockOnBeforeOnPlayerPlace from './block/registry/on_before_on_player_place';
import { checkArmor } from 'utils/checkArmor';
import { getItemInPlayerSlot } from 'utils/playerUtils';
import { fromHorizontalIndex, fromVerticalIndex, toVector3 } from 'utils/direction';
world.beforeEvents.worldInitialize.subscribe((eventData) => {
    // On Mine Block
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_mine_block_digger', new itemOnMineBlock.digger());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_mine_block_diamond_five_by_five', new itemOnMineBlock.diamondFiveByFive());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_mine_block_diamond_three_by_three', new itemOnMineBlock.diamondThreeByThree());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_mine_block_iron_three_by_three', new itemOnMineBlock.ironThreeByThree());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_mine_block_stone_three_by_three', new itemOnMineBlock.stoneThreeByThree());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_mine_block_diamond_vein_miner', new itemOnMineBlock.diamondVeinMiner());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_mine_block_stone_vein_miner', new itemOnMineBlock.stoneVeinMiner());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_mine_block_iron_vein_miner', new itemOnMineBlock.ironVeinMiner());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_mine_block_infernium_tree_miner', new itemOnMineBlock.inferniumTreeMiner());
    // On Hit Entity
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_infernium_set_on_fire', new itemOnHitEntity.inferniumSetOnFire());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_ice_freeze', new itemOnHitEntity.iceFreeze());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_amethyst_particle', new itemOnHitEntity.amethystParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_dragonite_particle', new itemOnHitEntity.dragoniteParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_echo_particle', new itemOnHitEntity.echoParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_emerald_particle', new itemOnHitEntity.emeraldParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_enderite_particle', new itemOnHitEntity.enderiteParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_ice_particle', new itemOnHitEntity.iceParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_infernium_particle', new itemOnHitEntity.inferniumParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_iris_particle', new itemOnHitEntity.irisParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_jade_particle', new itemOnHitEntity.jadeParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_plutonite_particle', new itemOnHitEntity.plutoniteParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_rose_particle', new itemOnHitEntity.roseParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_ruby_particle', new itemOnHitEntity.rubyParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_sapphire_particle', new itemOnHitEntity.sapphireParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_shadowite_particle', new itemOnHitEntity.shadowiteParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_spectra_particle', new itemOnHitEntity.spectraParticle());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_hit_entity_titanite_particle', new itemOnHitEntity.titaniteParticle());
    // On Use
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_use_enderite_teleport', new itemOnUse.enderiteTeleport());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_use_shadowite_blackhole', new itemOnUse.shadowiteBlackhole());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_use_amethyst_crystal', new itemOnUse.amethystCrystal());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_use_dragonite_breath', new itemOnUse.dragoniteBreath());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_use_iris_ray', new itemOnUse.irisRay());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_use_titanite_lightning', new itemOnUse.titaniteLightning());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_use_plutonite_shockwave', new itemOnUse.plutoniteShockwave());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_use_spectra_dash', new itemOnUse.spectraDash());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_use_echo_sonic', new itemOnUse.echoSonic());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_use_infernium_boom', new itemOnUse.inferniumBoom());
    eventData.itemComponentRegistry.registerCustomComponent('endorah_mo:on_use_redstone_dynamic_light', new itemOnUse.redstoneDynamicLight());
    eventData.blockComponentRegistry.registerCustomComponent('endorah_mo:on_random_tick_grow', new blockOnRandomTick.grow());
    eventData.blockComponentRegistry.registerCustomComponent('endorah_mo:on_random_tick_progress_crystal_growth', new blockOnRandomTick.progressCrystalGrowth());
    eventData.blockComponentRegistry.registerCustomComponent('endorah_mo:on_before_on_player_place_stone_statue', new blockOnBeforeOnPlayerPlace.stoneStatue());
});
const armor_effects = {
    'endorah_mo:amethyst': [{ effect: 'minecraft:haste', duration: 11 }],
    'endorah_mo:dragonite': [],
    'endorah_mo:titanite': [{ effect: 'minecraft:absorption', duration: 11 }],
    'endorah_mo:iris': [
        { effect: 'minecraft:village_hero', duration: 11 },
        { effect: 'minecraft:strength', duration: 11 },
        { effect: 'minecraft:speed', duration: 11 },
        { effect: 'minecraft:jump_boost', duration: 11 }
    ],
    'endorah_mo:plutonite': [{ effect: 'minecraft:strength', duration: 11 }],
    'endorah_mo:spectra': [
        { effect: 'minecraft:invisibility', duration: 11 },
        { effect: 'minecraft:night_vision', duration: 11 }
    ],
    'endorah_mo:infernium': [
        { effect: 'minecraft:fire_resistance', duration: 11 },
        { effect: 'special', duration: 200 }
    ],
    'endorah_mo:emerald': [{ effect: 'minecraft:village_hero', duration: 11 }],
    'endorah_mo:lapis_lazuli': []
};
function applyEffects(player, armor_type) {
    armor_effects[armor_type].forEach(({ effect, duration }) => {
        if (effect == 'special') {
            const dimension = player.dimension;
            const job = system.runInterval(() => {
                const block = dimension.getBlock(player.location);
                if (block.typeId == 'minecraft:air') {
                    block.setType('minecraft:light_block_10');
                    system.runTimeout(() => {
                        block.setType('minecraft:air');
                    }, 20);
                }
            });
            system.runTimeout(() => {
                system.clearRun(job);
            }, duration);
        }
        else
            player.addEffect(effect, duration, { showParticles: false });
    });
}
system.runInterval(() => {
    const players = world.getPlayers();
    players.forEach((player) => {
        for (const armor_type of Object.keys(armor_effects)) {
            if (checkArmor(player, `${armor_type}_helmet`, `${armor_type}_chestplate`, `${armor_type}_leggings`, `${armor_type}_boots`)) {
                if (armor_type == 'endorah_mo:dragonite') {
                    //@ts-ignore
                    if (player.isOnGround)
                        player.jumpCount = 0;
                    if (player.isJumping &&
                        //@ts-ignore
                        !player.lastJumping &&
                        !player.isOnGround)
                        //@ts-ignore
                        ++player.jumpCount;
                    //@ts-ignore
                    if (player.jumpCount == 2) {
                        // double jump action
                        player.addEffect('minecraft:levitation', 11, {
                            showParticles: false
                        });
                        system.runTimeout(() => {
                            player.addEffect('minecraft:slow_falling', 20 * 11, {
                                showParticles: false
                            });
                        }, 10);
                    }
                    //@ts-ignore
                    player.lastJumping = player.isJumping;
                }
                else if (armor_type == 'endorah_mo:lapis_lazuli') {
                    if (player.getDynamicProperty('endorah_mo:old_xp') ==
                        undefined) {
                        player.setDynamicProperty('endorah_mo:old_xp', player.getTotalXp());
                    }
                    const oldXp = player.getDynamicProperty('endorah_mo:old_xp');
                    let currentXp = player.getTotalXp();
                    if (oldXp < currentXp) {
                        const doubleXp = currentXp - oldXp;
                        player.addExperience(doubleXp);
                        currentXp += doubleXp;
                        player.setDynamicProperty('endorah_mo:old_xp', currentXp);
                    }
                    else {
                        player.setDynamicProperty('endorah_mo:old_xp', currentXp);
                    }
                }
                else {
                    applyEffects(player, armor_type);
                }
            }
        }
    });
});
const ring_effects = {
    'endorah_mo:sapphire_ring': 'minecraft:speed',
    'endorah_mo:jade_ring': 'minecraft:slow_falling',
    'endorah_mo:ruby_ring': 'minecraft:strength'
};
const pickaxe_effects = [
    'endorah_mo:dragonite_pickaxe',
    'endorah_mo:enderite_pickaxe',
    'endorah_mo:shadowite_pickaxe',
    'endorah_mo:titanite_pickaxe',
    'endorah_mo:iris_pickaxe'
];
const cooldown_colour = {
    amethyst: '§u',
    dragonite: '§5',
    echo: '§3',
    enderite: '§e',
    infernium: '§v',
    iris: '§d',
    plutonite: '§i',
    redstone: '§m',
    shadowite: '§j',
    spectra: '§h',
    titanite: '§g'
};
system.runInterval(() => {
    const players = world.getPlayers();
    players.forEach((player) => {
        const item_offhand = getItemInPlayerSlot(player, EquipmentSlot.Offhand);
        const item_mainhand = getItemInPlayerSlot(player, EquipmentSlot.Mainhand);
        try {
            if (ring_effects[item_offhand.typeId])
                player.addEffect(ring_effects[item_offhand.typeId], 11, {
                    showParticles: false
                });
        }
        catch (error) { }
        try {
            if (pickaxe_effects.includes(item_mainhand.typeId))
                player.addEffect('minecraft:haste', 11, {
                    showParticles: false
                });
        }
        catch (error) { }
        try {
            if (item_mainhand.typeId == 'endorah_mo:book_item')
                return;
            if (!item_mainhand.typeId.includes('endorah_mo'))
                return;
            const cooldown = item_mainhand.getComponent('cooldown');
            if (cooldown == undefined)
                return;
            const remainingCooldown = cooldown.getCooldownTicksRemaining(player);
            if (remainingCooldown == 0)
                return;
            const totalCooldown = cooldown.cooldownTicks;
            const percentageLeft = (remainingCooldown / totalCooldown) * 100;
            // Determine the number of colons (:) and dashes (-) to print
            const colons = Math.round(percentageLeft / 5);
            const dashes = 20 - colons;
            // Build the string to print
            let colour_code = '';
            // Check if typeId includes any key from cooldown_colour
            for (const key in cooldown_colour) {
                if (item_mainhand.typeId.includes(key)) {
                    colour_code = cooldown_colour[key];
                    break;
                }
            }
            const output = colour_code + '::'.repeat(colons) + '§0' + '::'.repeat(dashes);
            player.onScreenDisplay.setActionBar(output);
        }
        catch (error) { }
    });
});
world.afterEvents.entityHurt.subscribe((eventData) => {
    const hurt_entity = eventData.hurtEntity;
    const damaging_entity = eventData.damageSource.damagingEntity;
    if (hurt_entity.typeId !== 'minecraft:player' ||
        damaging_entity == undefined)
        return;
    const player = hurt_entity;
    if (!checkArmor(player, 'endorah_mo:infernium_helmet', 'endorah_mo:infernium_chestplate', 'endorah_mo:infernium_leggings', 'endorah_mo:infernium_boots'))
        return;
    damaging_entity.setOnFire(5);
});
world.afterEvents.entityHurt.subscribe((eventData) => {
    const hurt_entity = eventData.hurtEntity;
    const damaging_entity = eventData.damageSource.damagingEntity;
    if (hurt_entity.typeId !== 'minecraft:player' ||
        damaging_entity == undefined)
        return;
    const player = hurt_entity;
    if (!checkArmor(player, 'endorah_mo:ice_helmet', 'endorah_mo:ice_chestplate', 'endorah_mo:ice_leggings', 'endorah_mo:ice_boots'))
        return;
    player.playSound('endorah.mo.ice_crystal.freeze_sound');
    const particles = [
        'endorah_mo:ice_ore_special_1',
        'endorah_mo:ice_ore_special_2',
        'endorah_mo:ice_ore_special_3'
    ];
    particles.forEach((particle) => {
        damaging_entity.dimension.spawnParticle(particle, damaging_entity.location);
    });
    damaging_entity.addEffect('minecraft:slowness', 20);
    damaging_entity.addEffect('minecraft:weakness', 20);
});
function blackholeImpulse(entity, center) {
    const direction = {
        x: center.x - entity.location.x,
        y: center.y - entity.location.y,
        z: center.z - entity.location.z
    };
    entity.applyImpulse(direction);
}
function blackholeKnockback(entity, center) {
    const directionX = center.x - entity.location.x;
    const directionZ = center.z - entity.location.z;
    entity.applyKnockback(directionX, directionZ, 1, 0);
}
world.afterEvents.entitySpawn.subscribe((eventData) => {
    const entity = eventData.entity;
    if (entity.typeId != 'endorah_mo:blackhole')
        return;
    const applyBlackHoleEffect = () => {
        const entities = entity.dimension.getEntities({
            location: entity.location,
            maxDistance: 10,
            excludeTypes: ['minecraft:player', 'endorah_mo:blackhole']
        });
        entities.forEach((entity2) => {
            blackholeImpulse(entity2, entity.location);
        });
        const players = entity.dimension.getPlayers({
            location: entity.location,
            maxDistance: 10,
            excludeTags: [entity.id]
        });
        players.forEach((player) => {
            blackholeKnockback(player, entity.location);
        });
    };
    system.runTimeout(() => {
        const job = system.runInterval(applyBlackHoleEffect);
        const players_camera_shake = entity.dimension.getPlayers({
            location: entity.location,
            maxDistance: 32,
            gameMode: GameMode.survival
        });
        players_camera_shake.forEach((player) => {
            player.runCommand('/camerashake add @s 0.25 11.5 positional');
        });
        system.runTimeout(() => {
            system.clearRun(job);
        }, 190);
    }, 20);
});
world.afterEvents.entitySpawn.subscribe((eventData) => {
    const entity = eventData.entity;
    if (entity.typeId != 'endorah_mo:crystal' ||
        !entity.hasTag('endorah_mo:amethyst_crystal'))
        return;
    const particles = [
        'endorah_mo:amethyst_special_1',
        'endorah_mo:amethyst_special_2'
    ];
    const spawnParticles = () => {
        if (!entity.isValid())
            return;
        particles.forEach((particle) => {
            entity.dimension.spawnParticle(particle, entity.location);
        });
    };
    const job = system.runInterval(spawnParticles);
    system.runTimeout(() => {
        system.clearRun(job);
    }, 19 * 10);
});
world.beforeEvents.entityRemove.subscribe((eventData) => {
    if (eventData.removedEntity.typeId != 'endorah_mo:crystal' ||
        !eventData.removedEntity.hasTag('endorah_mo:amethyst_crystal'))
        return;
    const location = eventData.removedEntity.location;
    const dimension = eventData.removedEntity.dimension;
    system.runTimeout(() => {
        const entities = dimension.getEntities({
            location,
            maxDistance: 5,
            excludeTypes: ['minecraft:item']
        });
        entities.forEach((entity) => {
            entity.applyDamage(5);
        });
    });
});
world.afterEvents.itemReleaseUse.subscribe((eventData) => {
    const item_type = eventData.itemStack.typeId;
    if (!item_type.includes('endorah_mo') || !item_type.includes('spear'))
        return;
    const source = eventData.source;
    const head_location = source.getHeadLocation();
    const view_direction = source.getViewDirection();
    const projectile = eventData.source.dimension.spawnEntity(`${item_type}_projectile`, head_location);
    projectile.setRotation(source.getRotation());
    const projectile_component = projectile.getComponent('projectile');
    projectile_component.owner = source;
    projectile_component.shoot({
        x: view_direction.x * 4,
        y: view_direction.y * 4,
        z: view_direction.z * 4
    });
});
world.afterEvents.itemUse.subscribe((eventData) => {
    const item_type = eventData.itemStack.typeId;
    if (!item_type.includes('endorah_mo') || !item_type.includes('kunai'))
        return;
    const source = eventData.source;
    const head_location = source.getHeadLocation();
    const view_direction = source.getViewDirection();
    const projectile = eventData.source.dimension.spawnEntity(item_type, head_location);
    projectile.setRotation(source.getRotation());
    const projectile_component = projectile.getComponent('projectile');
    projectile_component.owner = source;
    projectile_component.shoot({
        x: view_direction.x * 4,
        y: view_direction.y * 4,
        z: view_direction.z * 4
    });
});
system.runInterval(() => {
    const players = world.getPlayers();
    players.forEach((player) => {
        const entities = player.dimension.getEntities({
            location: player.location,
            maxDistance: 1
        });
        const processEntity = (entity, type) => {
            if (!entity.typeId.includes('endorah_mo') ||
                !entity.typeId.includes(type))
                return;
            if (!entity.isOnGround)
                return;
            const inventory = player.getComponent('inventory');
            if (inventory.container.emptySlotsCount <= 0)
                return;
            const item = new ItemStack(entity.typeId.replace('_projectile', ''));
            inventory.container.addItem(item);
            entity.remove();
            player.playSound('random.pop');
        };
        entities.forEach((entity) => processEntity(entity, 'spear_projectile'));
        entities.forEach((entity) => processEntity(entity, 'kunai'));
    });
});
world.afterEvents.playerSpawn.subscribe((eventData) => {
    eventData.player.setDynamicProperty('endorah_mo:rose_arrow', JSON.stringify([]));
});
world.afterEvents.entitySpawn.subscribe((eventData) => {
    const entity = eventData.entity;
    if (entity.typeId != 'minecraft:arrow')
        return;
    const projectile = entity.getComponent('projectile');
    if (projectile == undefined)
        return;
    const owner = projectile.owner;
    if (!(owner instanceof Player))
        return;
    const item = getItemInPlayerSlot(owner, EquipmentSlot.Mainhand);
    if (item.typeId != 'endorah_mo:rose_bow')
        return;
    entity.addTag('endorah_mo:rose_arrow');
    const property = owner.getDynamicProperty('endorah_mo:rose_arrow');
    const arrow_ids = property ? JSON.parse(property) : [];
    arrow_ids.push(entity.id);
    owner.setDynamicProperty('endorah_mo:rose_arrow', JSON.stringify(arrow_ids));
    const particles = [
        'endorah_mo:pink_rose_ore_special_1',
        'endorah_mo:pink_rose_ore_special_2'
    ];
    const job = system.runInterval(() => {
        if (!entity.isValid() || entity.isOnGround)
            return;
        try {
            particles.forEach((particle) => {
                entity.dimension.spawnParticle(particle, entity.location);
            });
        }
        catch (error) { }
    }, 1);
    system.runTimeout(() => {
        system.clearRun(job);
    }, 190);
});
world.afterEvents.projectileHitEntity.subscribe((eventData) => {
    const hit_entity = eventData.getEntityHit().entity;
    const owner = eventData.source;
    if (!(owner instanceof Player))
        return;
    const property = owner.getDynamicProperty('endorah_mo:rose_arrow');
    if (property == undefined)
        return;
    const array = JSON.parse(property);
    const projectile_id = eventData.projectile.id;
    const index = array.indexOf(projectile_id);
    if (index !== -1) {
        hit_entity.addEffect('minecraft:levitation', 20 * 10);
        array.splice(index, 1);
        owner.setDynamicProperty('endorah_mo:rose_arrow', JSON.stringify(array));
    }
});
world.afterEvents.itemStartUse.subscribe((eventData) => {
    if (eventData.itemStack.typeId != 'endorah_mo:rose_bow')
        return;
    eventData.source.playAnimation('animation.humanoid.bow_and_arrow', {
        blendOutTime: 99999
    });
});
world.afterEvents.itemStopUse.subscribe((eventData) => {
    if (eventData.source.getGameMode() == GameMode.spectator)
        return;
    if (!eventData.itemStack)
        return;
    if (eventData.itemStack.typeId != 'endorah_mo:rose_bow')
        return;
    eventData.source.playAnimation('animation.humanoid.bow_and_arrow');
});
world.afterEvents.projectileHitEntity.subscribe((eventData) => {
    const entity = eventData.projectile;
    if (!entity.typeId.includes('endorah_mo') ||
        !entity.typeId.includes('spear_projectile') ||
        entity.hasTag('endorah_mo:dummy_projectile'))
        return;
    const source = eventData.source;
    const dimension = entity.dimension;
    const rotation = entity.getRotation();
    const hitEntity = eventData.getEntityHit().entity;
    entity.remove();
    hitEntity.applyDamage(5, {
        damagingEntity: source,
        cause: EntityDamageCause.contact
    });
    void system.waitTicks(1).then(() => {
        const new_entity = dimension.spawnEntity(entity.typeId, {
            x: hitEntity.location.x + getRandomTwo(),
            y: hitEntity.location.y,
            z: hitEntity.location.z + getRandomTwo()
        });
        new_entity.addTag('endorah_mo:dummy_projectile');
        new_entity.setRotation(rotation);
        void system.waitTicks(20).then(() => {
            if (new_entity.isValid())
                new_entity.triggerEvent('endorah_mo:remove_projectile');
        });
    });
});
world.afterEvents.projectileHitEntity.subscribe((eventData) => {
    const entity = eventData.projectile;
    if (!entity.typeId.includes('endorah_mo') ||
        !entity.typeId.includes('kunai') ||
        entity.hasTag('endorah_mo:dummy_projectile'))
        return;
    const source = eventData.source;
    const dimension = entity.dimension;
    const rotation = entity.getRotation();
    const hitEntity = eventData.getEntityHit().entity;
    entity.remove();
    hitEntity.applyDamage(5, {
        damagingEntity: source,
        cause: EntityDamageCause.contact
    });
    void system.waitTicks(1).then(() => {
        const new_entity = dimension.spawnEntity(entity.typeId, {
            x: hitEntity.location.x + getRandomTwo(),
            y: hitEntity.location.y,
            z: hitEntity.location.z + getRandomTwo()
        });
        new_entity.addTag('endorah_mo:dummy_projectile');
        new_entity.setRotation(rotation);
        void system.waitTicks(20).then(() => {
            if (new_entity.isValid())
                new_entity.triggerEvent('endorah_mo:remove_projectile');
        });
    });
});
world.afterEvents.projectileHitBlock.subscribe((eventData) => {
    const entity = eventData.projectile;
    if (!entity.typeId.includes('endorah_mo') ||
        !entity.typeId.includes('spear_projectile'))
        return;
    void system.waitTicks(20).then(() => {
        if (entity.isValid())
            entity.triggerEvent('endorah_mo:remove_projectile');
    });
});
world.afterEvents.projectileHitBlock.subscribe((eventData) => {
    const entity = eventData.projectile;
    if (!entity.typeId.includes('endorah_mo') ||
        !entity.typeId.includes('kunai'))
        return;
    void system.waitTicks(20).then(() => {
        if (entity.isValid())
            entity.triggerEvent('endorah_mo:remove_projectile');
    });
});
function getRandomTwo() {
    return Math.random() < 0.5 ? -2 : 2;
}
function getRandomOffset() {
    return {
        x: (Math.random() - 0.5) * 2,
        y: (Math.random() - 0.5) * 2,
        z: (Math.random() - 0.5) * 2
    };
}
world.afterEvents.entityHitEntity.subscribe((eventData) => {
    if (eventData.hitEntity.typeId != 'endorah_mo:stone_statue')
        return;
    if (eventData.damagingEntity.typeId != 'minecraft:player')
        return;
    eventData.hitEntity.kill();
});
world.afterEvents.playerBreakBlock.subscribe((eventData) => {
    const block = eventData.brokenBlockPermutation;
    if (!block.type.id.includes('endorah_mo') || !block.type.id.includes('ore'))
        return;
    const items = eventData.dimension.getEntities({
        location: eventData.block.location,
        type: 'minecraft:item'
    });
    if (items.length == 0)
        return;
    const quantity = Math.floor(Math.random() * 5) + 3;
    const location = eventData.block.location;
    for (let i = 0; i < quantity; i++) {
        const offset = getRandomOffset();
        eventData.dimension.spawnEntity('minecraft:xp_orb', {
            x: location.x + offset.x,
            y: location.y + offset.y,
            z: location.z + offset.z
        });
    }
});
world.afterEvents.playerBreakBlock.subscribe((eventData) => {
    const block = eventData.block;
    const dimension = block.dimension;
    for (let i = 0; i < 4; i++) {
        const direction = fromHorizontalIndex(i);
        const vector = toVector3(direction);
        const block_to_check = block.offset(vector);
        if (block_to_check.typeId.includes('endorah_mo') &&
            block_to_check.typeId.includes('crystal_bud')) {
            dimension.runCommand(`setblock ${block_to_check.location.x} ${block_to_check.location.y} ${block_to_check.location.z} air destroy`);
        }
    }
    for (let i = 0; i < 2; i++) {
        const direction = fromVerticalIndex(i);
        const vector = toVector3(direction);
        const block_to_check = block.offset(vector);
        if (block_to_check.typeId.includes('endorah_mo') &&
            block_to_check.typeId.includes('crystal_bud')) {
            dimension.runCommand(`setblock ${block_to_check.location.x} ${block_to_check.location.y} ${block_to_check.location.z} air destroy`);
        }
    }
});
world.afterEvents.dataDrivenEntityTrigger.subscribe((eventData) => {
    if (eventData.eventId != 'endorah_mo:have_collision')
        return;
    if (eventData.entity.isValid())
        clearVelocity(eventData.entity);
});
function clearVelocity(entity) {
    const { x, z } = entity.getVelocity();
    // Calculate the norm (magnitude) of the horizontal components (x and z)
    const horizontalNorm = Math.sqrt(x * x + z * z);
    // Calculate directionX and directionZ as normalized values
    let directionX = 0;
    let directionZ = 0;
    if (horizontalNorm !== 0) {
        directionX = -x / horizontalNorm;
        directionZ = -z / horizontalNorm;
    }
    // Apply the knockback
    entity.applyKnockback(directionX, directionZ, horizontalNorm, 0);
}
world.afterEvents.entitySpawn.subscribe((eventData) => {
    const entity = eventData.entity;
    if (entity.typeId != 'minecraft:ender_dragon')
        return;
    const crystals = world
        .getDimension('the_end')
        .getEntities({ type: 'minecraft:ender_crystal' });
    const locations = crystals.map((crystal) => crystal.location);
    world.setDynamicProperty('endorah_mo:crystal_locations', JSON.stringify(locations));
});
world.afterEvents.entityDie.subscribe((eventData) => {
    const entity = eventData.deadEntity;
    if (entity.typeId != 'minecraft:ender_dragon')
        return;
    const locations = JSON.parse(world.getDynamicProperty('endorah_mo:crystal_locations'));
    locations.forEach((location) => {
        system.runJob(spawnDragonite(location));
    });
    world.setDynamicProperty('endorah_mo:crystal_locations', JSON.stringify([]));
});
function* spawnDragonite(location) {
    for (let x = -5; x <= 5; x++) {
        for (let y = -32; y < 0; y++) {
            for (let z = -5; z <= 5; z++) {
                const new_location = {
                    x: location.x + x,
                    y: location.y + y,
                    z: location.z + z
                };
                const block = world
                    .getDimension('the_end')
                    .getBlock(new_location);
                let probability = 0.1 * Math.exp(-((x * x + y * y + z * z) / 20));
                if (block.typeId == 'minecraft:obsidian' &&
                    Math.random() < probability)
                    block.setType('endorah_mo:dragonite_obsidian_ore');
                yield;
            }
        }
    }
}
world.afterEvents.playerSpawn.subscribe((eventData) => {
    if (!eventData.initialSpawn)
        return;
    const player = eventData.player;
    const has_spawned_before = player.getDynamicProperty('endorah_mo:has_spawned_before');
    if (!has_spawned_before) {
        player.setDynamicProperty('endorah_mo:has_spawned_before', true);
        // TODO: Handle how to give the player the Bestiary and Capture Device if they're in Creative mode.
        const inventory = player.getComponent('inventory');
        const empty_slots = inventory.container?.emptySlotsCount;
        if (empty_slots === 0) {
            spawnItem(player, 'endorah_mo:book_item');
        }
        else {
            addItemToInventory(inventory, 'endorah_mo:book_item');
        }
    }
});
function spawnItem(player, item_name, quantity = 1) {
    player.dimension.spawnItem(new ItemStack(item_name, quantity), player.getHeadLocation());
}
function addItemToInventory(inventory, item_name, quantity = 1) {
    inventory.container?.addItem(new ItemStack(item_name, quantity));
}
