import { system, world, ItemStack, BlockPermutation, EnchantmentType } from "@minecraft/server";
import "./trident/handler";
import {
  divineBeamDamage, emeraldSwordSpecialOnhit,
  dragonLingeringDamage, rangeAttack, halberdRemoved, halberdAdded,
  spinningSwordStopMove, tornadoKnockback, netherPortalTeleport,
  useThrowingStar
} from "./weaponEffectHandler"

import {
  dragonSwordProjectile, dragonSwordProjectileHit,
  lapisSwordProjectile, lapisSwordProjectileHitBlock, lapisProjectileLoop,
  rubySwordProjectile, rubySwordProjectileHit,
  platinumSwordProjectile, platinumSwordProjectileHit,
  diamondSwordProjectile, diamondSwordProjectileHit, uraniumExplode,
  handleArrowProjectile, handleArrowProjectileHitBlock,
  electricBallProjectile, demonBowHitEntity,
  divineBeamDamageSmall, divineBowHitEntity,
  lapisProjectileBowHitEntity, ironBowRain,
  bedrockTornadoArrowHitEntity, dragonEnderHitEntity,
  sculkArrowHitBlock, sculkArrowHitEntity,
  swordRolloutHitBlock, swordRolloutHitEntity,
  woodenBallCageStop
} from "./projectile"

import {
  SPECIAL_BLASTER_SWORD, OTHER_DATA, TAGS, SPECIAL_SWORD_FUNCTION,
  OTHER_DAMAGE, WEAPON_EFFECT_STATS, DYNAMIC_PROPERTY, blacklistedEnemy,
  THROWING_STAR_DAMAGE
} from "./data"

import { specialBowHandler } from "./bow"

import { getRandomNumber, checkInventoryHaveItem } from "./utils/helpers.js";

import {
  ARMOR_SET,
  ARMOR_SET_REMOVED,
  LOOP_TAGS_CHECK
} from "./armor"

import { openGuidebook } from "./guidebook.js"

import { playerCrossbowUse } from "./crossbow"
import { handleCustomShovel, handleCustomHoe, handleCustomAxe } from "./handlers/itemHandler.js";
import { handlePlayerSpawn, checkPlayerItems, checkPlayerMovement } from "./handlers/playerHandler.js";
import { replaceBedrock, checkBlock } from "./handlers/blockHandler.js";
import { decreaseDurability, decreaseDurabilityAmount } from "./utils/durability.js";

function sleep(tick) {
  return new Promise(resolve => {
    system.runTimeout(() => {
      resolve(tick)
    }, tick)
  })
}



const SPECIAL_SWORD_HIT_FUNCTION = {
  "4ks_wp:emerald_sword_special": emeraldSwordSpecialOnhit
}

const SPECIAL_SWORD = [
  "4ks_wp:netherite_sword_special",
  "4ks_wp:cryo_sword_special",
  "4ks_wp:flame_sword_special",
  "4ks_wp:dragon_sword_special",
  "4ks_wp:emerald_sword_special",
  "4ks_wp:lapis_sword_special",
  "4ks_wp:divine_sword_special",
  "4ks_wp:demonic_sword_special", "4ks_wp:uranium_ball",
  "4ks_wp:wood_sword_special",
  "4ks_wp:stone_sword_special",
  "4ks_wp:iron_sword_special",
  "4ks_wp:gold_sword_special",
  "4ks_wp:bedrock_sword_special",
  "4ks_wp:sculk_sword_special",
]



const PROJECTILE = {
  "4ks_wp:dragon_sword_projectile": dragonSwordProjectile,
  "4ks_wp:lapis_wave": lapisSwordProjectile,
  "4ks_wp:ruby_projectile": rubySwordProjectile,
  "4ks_wp:platinum_projectile": platinumSwordProjectile,
  "4ks_wp:diamond_projectile": diamondSwordProjectile,
  "4ks_wp:electric_ball": electricBallProjectile
}

const PROJECTILE_HIT = {
  "4ks_wp:dragon_sword_projectile": dragonSwordProjectileHit,
  "4ks_wp:ruby_projectile": rubySwordProjectileHit,
  "4ks_wp:platinum_projectile": platinumSwordProjectileHit,
  "4ks_wp:diamond_projectile": diamondSwordProjectileHit
}

const EVENT_LIST = {
  "4ks_wp:dragon_lingering": dragonLingeringDamage,
  "4ks_wp:divine_beam": divineBeamDamage,
  "4ks_wp:divine_beam_small": divineBeamDamageSmall,
  "4ks_wp:lapis_wave": lapisProjectileLoop,
  "4ks_wp:invis_hit": rangeAttack,
  "4ks_wp:halberd_remove": halberdRemoved,
  "4ks_wp:halberd_add": halberdAdded,
  "4ks_wp:spinning_sword_stop_moving": spinningSwordStopMove,
  "4ks_wp:tornado_knockback": tornadoKnockback,
  "4ks_wp:nether_portal_teleport": netherPortalTeleport,
  "4ks_wp:obsidian_portal": netherPortalTeleport,
  "4ks_wp:iron_bow_rain": ironBowRain,
  "4ks_wp:uranium_explode": uraniumExplode,
  "4ks_wp:wooden_ball_cage_stop": woodenBallCageStop
}

world.afterEvents.entitySpawn.subscribe((e) => {
  const entity = e.entity
  if (PROJECTILE[entity.typeId] != undefined)
    PROJECTILE[entity.typeId](entity)
});

function setVariable(entity, name, value) {
  entity.playAnimation("animation.humanoid.base_pose", {
    controller: `controller.variable.${name}.${value}`,
    nextState: `0`,
    stopExpression: `v.${name} = ${value}f; return 1;`,
  });
}

function applyKnockback(player, victim, strength) {
  // Get the positions of the player and victim
  let playerPosition = player.location;  // assuming this is a Vector3
  let victimPosition = victim.location;  // assuming this is a Vector3
  // Calculate the direction from the victim to the player (this is the vector from victim to player)
  let dx = playerPosition.x - victimPosition.x;
  let dy = playerPosition.y - victimPosition.y;
  let dz = playerPosition.z - victimPosition.z;

  // Normalize this vector (so the direction is consistent regardless of distance)
  let magnitude = Math.sqrt(dx * dx + dy * dy + dz * dz);
  dx /= magnitude;
  dy /= magnitude;
  dz /= magnitude;

  // Now calculate the knockback direction by inverting the vector (moving away from the player)
  dx = -dx;
  dy = -dy;
  dz = -dz;

  if (dx == NaN || dy == NaN || dz == NaN)
    return;

  // Apply the knockback impulse (scaled by strength)
  victim.clearVelocity();
  victim.applyImpulse({
    x: dx * strength,
    y: 0.8,
    z: dz * strength
  });
}
world.afterEvents.itemStartUse.subscribe(async (e) => {
  const player = e.source
  const item = e.itemStack
  const itemID = item.typeId
  playerCrossbowUse(e)
  if (itemID.includes("4ks_wp:") && (itemID.includes("_long_bow") || itemID.includes("bow_special"))) {
    if (!checkInventoryHaveItem(player, "minecraft:arrow", 1)) {
      setVariable(player, "cancel_animation", 1)
      return
    }
    setVariable(player, "cancel_animation", 0)
  }


  if (itemID.includes("4ks_wp:") && itemID.includes("_crossbow") && (!itemID.includes("_loaded"))) {
    if (!checkInventoryHaveItem(player, "minecraft:arrow", 1)) {
      setVariable(player, "cancel_animation", 1)
      return
    }
    setVariable(player, "cancel_animation", 0)
    const enchantable = item.getComponent("minecraft:enchantable");
    let chargeTime = 25
    for (const enchant of enchantable.getEnchantments()) {
      if (enchant.type.id == "quick_charge") {
        chargeTime = chargeTime - (5 * enchant.level)
      }
    }
    player.setDynamicProperty("4ks_wp:charge_duration", chargeTime / 20)
    setVariable(player, "charge_time", chargeTime)
    player.runCommand("/playsound crossbow.loading.start @s")
    player.runCommand(`playanimation @s animation.player.first_person.crossbow_equipped null 0.0 \"!v.is_first_person || !q.is_using_item || q.state_time >= ${chargeTime / 20}\" ctrl.fpp.weapon`)
    player.runCommand("playanimation @s animation.player.crossbow_equipped null 0.0 \"v.is_first_person || !q.is_using_item\" ctrl.weapon2")
    await sleep(15)
    player.runCommand("/playsound crossbow.loading.middle @s")
  }
  if (item.typeId == "4ks_wp:sapphire_sword_special")
    player.runCommand("/playsound 4ks_wp.beam_start @a[r=8]")
  if (itemID.includes("4ks_wp:") && itemID.includes("bow")) {
    //player.runCommand(`/playanimation @s animation.player.bow_equipped null 0.0 "v.is_first_person || !q.is_using_item || !q.equipped_item_any_tag('slot.weapon.mainhand','oreville:is_bow') " ctrl.weapon`)
  }

  if (itemID.includes("4ks_wp:") && itemID.includes("_javelin")) {
    player.addTag("4kswpjavusing")
    await sleep(2)
    player.removeTag("4kswphalberd")
    player.runCommand("/event entity @e[type=4ks_wp:invisible_hitter, c=1,r=3] 4ks_wp:despawn")
  } else {
    player.removeTag("4kswpjavusing")
  }

  if (!SPECIAL_BLASTER_SWORD.includes(item.typeId)) return
  player.addTag(TAGS.USE_ITEM)
  player.setDynamicProperty("4ks_wp:use_tick", system.currentTick)
});

world.afterEvents.itemStopUse.subscribe((e) => {
  const { source: player, itemStack: item, useDuration } = e;
  if (!item || !player) return;
  player.setDynamicProperty("4ks_wp:netherite_bow_special_delay", false)
  player.setDynamicProperty("4ks_wp:still_using_item", false)
  player.removeTag("4kswpjavusing");
  // Handle non-4ks_wp items
  if (!item.typeId.includes("4ks_wp:")) return;
  const haveInfinity = item?.getComponent("minecraft:enchantable")?.hasEnchantment("infinity")
  const havePunch = item?.getComponent("minecraft:enchantable")?.getEnchantment("punch")
  const havePower = item?.getComponent("minecraft:enchantable")?.getEnchantment("power")
  player.setDynamicProperty("4ks_wp:punch", false)

  if (item.typeId == "4ks_wp:amethyst_bow_special" ||
    item.typeId == "4ks_wp:cryo_bow" ||
    item.typeId == "4ks_wp:cryo_diamond_bow" ||
    item.typeId == "4ks_wp:netherite_bow" ||
    item.typeId == "4ks_wp:diamond_bow" ||
    item.typeId == "4ks_wp:flame_bow" ||
    item.typeId == "4ks_wp:flame_diamond_bow" ||
    item.typeId == "4ks_wp:sapphire_bow_special" ||
    item.typeId == "4ks_wp:iron_bow_special" ||
    item.typeId == "4ks_wp:cryo_bow_special" ||
    item.typeId == "4ks_wp:flame_bow_special" ||
    item.typeId == "4ks_wp:gold_bow_special" ||
    item.typeId == "4ks_wp:flame_netherite_bow" ||
    item.typeId == "4ks_wp:cryo_netherite_bow"
  ) {
    if (e.useDuration <= 19999977 && haveInfinity) {
      const equippableOffhand = player.getComponent("minecraft:equippable")
      const offhand = equippableOffhand.getEquipment("Offhand")
      if (offhand.typeId == "minecraft:arrow") {
        offhand.amount++
        equippableOffhand.setEquipment("Offhand", offhand)
      }
    }
  }

  if (item.typeId == "4ks_wp:netherite_bow_special" || item.typeId == "4ks_wp:wood_bow_special") {
    const currentDurabilityDamage = player.getDynamicProperty("4ks_wp:durability_reduce") ?? 0
    if (currentDurabilityDamage > 0) {
      decreaseDurabilityAmount(player, currentDurabilityDamage)
      player.setDynamicProperty("4ks_wp:durability_reduce", 0)
    }
  }

  // Handle guidebook
  if (item.typeId === "4ks_wp:guidebook") {
    openGuidebook(player);
    return;
  }

  // Handle long bow
  if (item.typeId.includes("_long_bow")) {
    if (havePunch) {
      player.setDynamicProperty("4ks_wp:punch", havePunch.level)
    }
    if (!checkInventoryHaveItem(player, "minecraft:arrow", 1)) return;


    const useTick = Math.min(40, 19999980 - useDuration);
    if (useTick <= 5) return;

    const minTick = 1;
    const maxTick = 40;
    const scale = (Math.min(Math.max(useTick, minTick), maxTick) - minTick) / (maxTick - minTick);
    const power = 0.25 + (10 - 0.25) * scale;

    const viewDirection = player.getViewDirection();
    const velocity = {
      x: viewDirection.x * power,
      y: viewDirection.y * power,
      z: viewDirection.z * power
    };

    const headLocation = player.getHeadLocation();
    let projectileId = "4ks_wp:crossbow_arrow";
    if (item.typeId.includes("sculk")) {
      if (!havePower) projectileId = "4ks_wp:sculk_arrow"

      if (havePower) {
        projectileId = "4ks_wp:sculk_arrow_" + havePower.level
      }
    }
    const projectile = player.dimension.spawnEntity(projectileId, {
      x: headLocation.x + viewDirection.x,
      y: headLocation.y + viewDirection.y,
      z: headLocation.z + viewDirection.z
    });

    const enchantable = item.getComponent('minecraft:enchantable')
    if (enchantable != undefined) {
      for (const enchant of enchantable.getEnchantments()) {
        if (enchant.type.id == "flame") {
          projectile.setOnFire(10, true)
          break
        }
      }
    }

    const projectileComp = projectile.getComponent('minecraft:projectile');
    projectileComp.owner = player;
    projectileComp?.shoot(velocity);


    if (item.typeId == "4ks_wp:sculk_long_bow") {
      player.runCommand("/playsound mob.warden.sonic_boom @a[r=12] ~~~")
    } else {
      player.runCommand("/playsound random.bow @a[r=12]");
    }

    if (!haveInfinity) {
      player.runCommand("/clear @s minecraft:arrow 0 1");
    }
    decreaseDurability(player)
  }

  // Handle special bow
  if (item.typeId.includes("_bow_special") && checkInventoryHaveItem(player, "minecraft:arrow", 1)) {
    specialBowHandler(item.typeId, e, player, haveInfinity);
  }

  // Handle crossbow
  const isCrossbow = item.typeId.includes("_crossbow") &&
    !item.typeId.includes("_loaded") &&
    !item.typeId.includes("_piercing");

  if (isCrossbow && useDuration <= 20025 - (player.getDynamicProperty("4ks_wp:charge_duration") * 20)) {
    if (!checkInventoryHaveItem(player, "minecraft:arrow", 1)) return;

    const mainhand = player.getComponent("minecraft:equippable").getEquipment("Mainhand");
    if (mainhand.typeId !== item.typeId) return;

    const enchantable = item.getComponent("minecraft:enchantable");
    const havePiercing = enchantable?.getEnchantments().some(e => e.type.id === "piercing");

    const newType = item.typeId + (havePiercing ? "_piercing" : "_loaded");
    updateCrossbow(newType, item, player);

    if (!havePiercing) {
      player.runCommand("/clear @s minecraft:arrow 0 1");
    }
  }

  // Handle bow usage tracking
  if (item.typeId.includes("_bow")) {
    const mainhand = player.getComponent("minecraft:equippable").getEquipment("Mainhand");
    player.setDynamicProperty("4ks_wp:last_used_bow", mainhand?.typeId);
    player.setDynamicProperty("4ks_wp:last_used_duration", useDuration);


    if (havePunch) {
      player.setDynamicProperty("4ks_wp:punch", havePunch.level)
    }
  }

  // Handle sapphire sword special
  if (item.typeId === "4ks_wp:sapphire_sword_special") {
    player.runCommand("/stopsound @a[r=8]");
    player.runCommand("/playsound 4ks_wp.beam_end @a[r=8]");
    player.setDynamicProperty(DYNAMIC_PROPERTY.sapphire_beam_delay, false);
  }

  // Cleanup
  player.removeTag(TAGS.USE_ITEM);
  player.setDynamicProperty(DYNAMIC_PROPERTY.obsidian_sword_spawned, false);
  player.runCommand(`/stopsound @a[r=16] portal.travel`)
  player.runCommand(`/event entity @e[type=4ks_wp:nether_portal,tag=4ks_wp_${player.id}] 4ks_wp:despawn`);

  if (SPECIAL_SWORD.includes(item.typeId)) {
    SPECIAL_SWORD_FUNCTION[item.typeId](player);
  }
});

world.afterEvents.entityDie.subscribe(async (event) => {
  const entity = event.deadEntity
  if (entity.typeId == "minecraft:ender_dragon") {
    const location = entity.location
    let amount = Math.random() * Math.floor(Math.random() * (64 - 30 + 1)) + 30;
    while (amount-- > 0)
      entity.dimension.spawnItem(new ItemStack("4ks_wp:dragon_scrap"), location)
  }
  if (entity.typeId == "minecraft:warden") {
    const location = entity.location
    let amount = Math.random() * Math.floor(Math.random() * (40 - 20 + 1)) + 20;
    while (amount-- > 0)
      entity.dimension.spawnItem(new ItemStack("4ks_wp:sculk_essence"), location)
  }
});

world.afterEvents.entityHitEntity.subscribe(async (event) => {
  let victim = event.hitEntity;
  let player = event.damagingEntity;
  // if (victim.typeId == "minecraft:player") {
  //   for (const tag of victim.getTags()) {
  //     if (ON_HIT_TAGS[tag] != undefined) ON_HIT_TAGS[tag](player, victim)
  //   }
  // }

  let playerAttacked = false
  if (victim.typeId == "minecraft:player" && player.typeId != "minecraft:player") {
    playerAttacked = true
  }

  if (player.typeId !== 'minecraft:player')
    [victim, player] = [player, victim]
  if (player.typeId !== 'minecraft:player') return

  if (victim.typeId == "4ks_wp:invisible_hitter") {
    if (player.name == victim.getDynamicProperty("4kswpplayerid")) return
    const owner = victim.dimension.getEntities({ location: victim.location, name: victim.getDynamicProperty("4kswpplayerid"), maxDistance: 3, type: "minecraft:player" })[0]
    const equippable = player.getComponent("minecraft:equippable")
    const mainHand = equippable.getEquipment("Mainhand")
    if (mainHand != undefined) {
      const identifier = mainHand.typeId.replace("minecraft", "").replace("4ks_wp:", "")
      const oreType = identifier.split("_")[0]
      let weaponType = identifier.split("_")[1]
      if (OTHER_DAMAGE[oreType] != undefined && OTHER_DAMAGE[oreType]["items"][weaponType] != undefined) {
        if (identifier.includes("special"))
          weaponType += "_special"
        if (oreType == "flame") {
          owner.setOnFire(3, true)
        } else if (oreType == "cryo") {
          owner.runCommand("/effect @s slowness 5 2")
        }
        const damage = OTHER_DAMAGE[oreType]["items"][weaponType]
        const health = owner.getComponent('minecraft:health')
        owner.applyDamage(health.currentValue - damage, { cause: "entityAttack", damagingEntity: player })
      }
    }
  }

  if (playerAttacked) return

  const equip = player.getComponent("minecraft:equippable")
  const hand = equip.getEquipment("Mainhand")
  if (hand != undefined && hand.typeId.includes("_special")) {
    decreaseDurability(player)
  }
  const equippable = player.getComponent("minecraft:equippable")
  const mainHand = equippable.getEquipment("Mainhand")
  if (mainHand == undefined) return;
  const identifier = mainHand.typeId.replace("minecraft", "").replace("4ks_wp:", "")
  const oreType = identifier.split("_")[0]
  let weaponType = identifier.split("_")[1]

  if (oreType == "flame") {
    victim.setOnFire(5, true)
  } else if (oreType == "cryo") {
    victim.runCommand("/effect @s slowness 5 2")
  }

  if (weaponType == "club") {
    const knockbackStrength = WEAPON_EFFECT_STATS.club_knockback_strength.horizontal
    const knockbackVerticalStrength = WEAPON_EFFECT_STATS.club_knockback_strength.vertical
    const { x, z } = player.getViewDirection();
    victim.applyKnockback(x, z, knockbackStrength, knockbackVerticalStrength);
  } else if (weaponType == "gladius") {
    for (const entity of player.dimension.getEntities({ location: victim.location, maxDistance: 3, excludeTypes: blacklistedEnemy })) {
      if (entity.id == player.id || entity.typeId == "minecraft:item") continue
      if (entity.id == victim.id) entity.runCommand(`/damage @s 1 entity_attack entity @p`)
      else entity.runCommand(`/damage @s 1 entity_attack entity @p`)
    }
  } else if (weaponType == "greatsword") {
    victim.runCommand("/effect @s fatal_poison 3 1 true ")
  } else if (weaponType == "mace") {
    victim.runCommand("/effect @s slowness 1 255 true ")
    victim.runCommand("/execute if entity @s[type=ghast] run tag @s add 4kswpmace")
    victim.runCommand("/execute if entity @s[type=blaze] run tag @s add 4kswpmace")
    victim.runCommand("/execute if entity @s[type=hoglin] run tag @s add 4kswpmace")
    victim.runCommand("/execute if entity @s[type=magma_cube] run tag @s add 4kswpmace")
    victim.runCommand("/execute if entity @s[type=piglin] run tag @s add 4kswpmace")
    victim.runCommand("/execute if entity @s[type=piglin_brute] run tag @s add 4kswpmace")
    victim.runCommand("/execute if entity @s[type=strider] run tag @s add 4kswpmace")
    victim.runCommand("/execute if entity @s[type=wither_skeleton] run tag @s add 4kswpmace")
    victim.runCommand("/execute if entity @s[type=zoglin] run tag @s add 4kswpmace")
    victim.runCommand("/execute if entity @s[type=zombie_pigman] run tag @s add 4kswpmace")

    if (victim.hasTag("4kswpmace")) {
      victim.applyDamage(OTHER_DAMAGE[oreType]["items"]["mace"], { cause: "entityAttack", damagingEntity: player })
    }
  } else if (weaponType == 'dagger') {
    if (
      victim.typeId.includes("pig") || victim.typeId.includes("sheep") ||
      victim.typeId.includes("rabbit") || victim.typeId.includes("cow") ||
      victim.typeId.includes("chicken")
    ) {
      victim.kill()
    }
  }

})



world.afterEvents.itemCompleteUse.subscribe(async (e) => {
  const item = e.itemStack
  const source = e.source
  if (!item.typeId.startsWith("4ks_wp:")) {
    source.setDynamicProperty("4ks_wp:punch", false)
    source.setDynamicProperty(`4ks_wp:last_used_bow`, undefined)
    source.setDynamicProperty(`4ks_wp:last_used_duration`, 0)
  }

  if (item.typeId.includes("4ks_wp:") && item.typeId.includes("_piercing")) {
    updateCrossbow(`${item.typeId.replace("_piercing", "")}`, item, source)

  }
});

world.beforeEvents.itemUseOn.subscribe(async (e) => {
  const itemid = e.itemStack.typeId
  const location = e.block.location
  const block = e.block

  if (!itemid.includes("4ks_wp") || e.source == undefined) return

  if (itemid.includes("hoe")) {
    if (!block.permutation.matches("dirt") && !block.permutation.matches("grass_block")) return

    system.run(() => {
      handleCustomHoe(block, e.source, location)
    })
  }
  else if (itemid.includes("shovel")) {
    if (!block.permutation.matches("dirt") && !block.permutation.matches("grass_block") &&
      block.typeId != "minecraft:campfire" && block.typeId != "minecraft:soul_campfire" &&
      !block.permutation.matches("podzol") && !block.permutation.matches("mycelium")) return

    system.run(() => {
      handleCustomShovel(block, e.source, location)
    })
  }
  else if (itemid.includes("_axe")) {
    handleCustomAxe(block, e.source, location)
  }
})

world.afterEvents.entityHurt.subscribe(async (e) => {
  const player = e.damageSource.damagingEntity
  const victim = e.hurtEntity
  if (player == undefined || victim == undefined || player.typeId != 'minecraft:player') return
  if (victim.hasTag("4kswpjsht")) return
  const equippable = player.getComponent("minecraft:equippable")
  const mainHand = equippable.getEquipment("Mainhand")
  if (mainHand != undefined) {    
    const identifier = mainHand.typeId.replace("minecraft", "").replace("4ks_wp:", "")
    const oreType = identifier.split("_")[0]
    let weaponType = identifier.split("_")[1]
    if (OTHER_DAMAGE[oreType] != undefined && OTHER_DAMAGE[oreType]["items"][weaponType] != undefined) {
      let damage = OTHER_DAMAGE[oreType]["items"][weaponType]
      if (identifier.includes("special") && !identifier.includes("demon") && !identifier.includes("divine") && !identifier.includes("netherite"))
        damage = 10
      else if (identifier.includes("special") && identifier.includes("demon")) {
        damage += 4
      } else if (identifier.includes("special") && identifier.includes("divine")) {
        damage += 4
      } else if (identifier.includes("special") && identifier.includes("netherite")) {
        damage += 5
      } else {
        damage += 1
      }

      if (identifier.includes("halberd") || identifier.includes("spear")) {
        damage -= 2
      }
      if (identifier == "dragon_sword_special") {
        damage += 2
      }

      if (identifier == "sculk_sword_special" || identifier == "bedrock_sword_special") {
        damage = 13
      }

      if (player.getEffect("strength")?.amplifier > 0) {
        damage = damage + (3 * player.getEffect("strength").amplifier)
      }

      const enchantable = mainHand.getComponent('minecraft:enchantable')
      if (enchantable != undefined) {
        for (const enchant of enchantable.getEnchantments()) {
          if (enchant.type.id == "sharpness") {
            if (enchant.level == 5) damage += 6
            else if (enchant.level == 4) damage += 5
            else if (enchant.level == 3) damage += 3
            else if (enchant.level == 2) damage += 2
            else if (enchant.level == 1) damage += 1
          }
          if (enchant.type.id == "bane_of_arthropods" || enchant.type.id == "smite") {
            damage = damage + Math.floor(enchant.level * 2.5)
          }
        }
      }

      if (identifier.includes("khopesh")) {
        victim.runCommand("/execute as @s run function 4ks/wp/checkArmor")
        if (!victim.hasTag("4kswpkhopesh")) {
          damage = Math.ceil(damage * 1.25)
        }

        victim.removeTag("4kswpkhopesh")
      }

      let finalDamage = damage - 1

      if (player.getDynamicProperty("4ks_we:critical_damage")) {
        finalDamage = Math.round(finalDamage * 1.5)
      }

      const health = victim.getComponent('minecraft:health')
      //console.warn("health before: " + health.currentValue)
      //console.warn("final damage: " + finalDamage)

      //victim.runCommand(`/damage @s ${finalDamage} entity_attack entity \"${player.name}\"`)
      //victim.clearVelocity()
      victim.applyDamage(finalDamage)
      victim.addTag("4kswpjsht")
      await sleep(1)
      victim.removeTag("4kswpjsht")
      //health.setCurrentValue(health.currentValue - finalDamage + additionalDamage)
      //console.warn("health after: " + health.currentValue)
    }
  }
  if (SPECIAL_SWORD_HIT_FUNCTION[mainHand?.typeId] == undefined) return
  SPECIAL_SWORD_HIT_FUNCTION[mainHand?.typeId](player, victim)

});



world.afterEvents.playerSpawn.subscribe(handlePlayerSpawn);

world.afterEvents.projectileHitBlock.subscribe((e) => {
  const projectileID = e.projectile.typeId;

  if (projectileID == "4ks_wp:lapis_wave") {
    lapisSwordProjectileHitBlock(e);
  }
  if (projectileID == "minecraft:arrow" || projectileID == "4ks_wp:crossbow_arrow") {
    handleArrowProjectileHitBlock(e);
  }
  if (projectileID == "4ks_wp:sculk_arrow") {
    sculkArrowHitBlock(e);
  }

  if (projectileID == "4ks_wp:divine_arrow") {
    e.projectile.triggerEvent("4ks_wp:despawn")
    e.dimension.runCommand(`/summon 4ks_wp:divine_beam_small ${e.location.x} ${e.location.y + 1} ${e.location.z}`)
  }
  if (projectileID == "4ks_wp:platinum_projectile_bow") {
    if (!e.projectile.isValid()) return
    e.projectile.runCommand("/summon 4ks_wp:platinum_sword_explosion ~~~")
    e.projectile.triggerEvent("4ks_wp:despawn")
  }
  if (projectileID == "4ks_wp:sword_rollout") {
    swordRolloutHitBlock(e);
  }
  if (PROJECTILE_HIT[projectileID]) {
    PROJECTILE_HIT[projectileID](e);
  }
});

function applyKnockbackFromEntity(centerEntity, victim, strength, vstrength) {
  // Get the positions of the player and victim
  let playerPosition = centerEntity;  // assuming this is a Vector3
  let victimPosition = victim?.location;  // assuming this is a Vector3

  // Calculate the direction from the victim to the player (this is the vector from victim to player)
  let dx = playerPosition.x - victimPosition.x;
  let dy = playerPosition.y - victimPosition.y;
  let dz = playerPosition.z - victimPosition.z;

  // Normalize this vector (so the direction is consistent regardless of distance)
  let magnitude = Math.sqrt(dx * dx + dy * dy + dz * dz);
  dx /= magnitude;
  dy /= magnitude;
  dz /= magnitude;

  // Now calculate the knockback direction by inverting the vector (moving away from the player)
  dx = -dx;
  dy = -dy;
  dz = -dz;

  // Apply the knockback impulse (scaled by strength)
  victim?.clearVelocity();
  victim?.applyImpulse({
    x: dx * strength,
    y: vstrength,
    z: dz * strength
  });
}

world.afterEvents.projectileHitEntity.subscribe((e) => {
  const victim = e.getEntityHit().entity;
  const entityType = victim.typeId;
  const source = e.source;
  const projectile = e.projectile;
  const projectileID = projectile.typeId;

  if (entityType == projectileID) return;
  
  if(THROWING_STAR_DAMAGE[projectileID] != undefined) {
    victim.applyDamage(THROWING_STAR_DAMAGE[projectileID] - 1, {cause: "selfDestruct", damagingEntity: source})
    if (projectileID.includes("cryo")) {
      victim.runCommand(`/effect @s slowness ${WEAPON_EFFECT_STATS.cryo_bows_slowness_duration} ${WEAPON_EFFECT_STATS.cryo_bows_slowness_level}`)
    } else if (projectileID.includes("flame")) {
      victim.setOnFire(WEAPON_EFFECT_STATS.flame_bows_fire_duration, true)
    }
    return
  }

  if (source?.getDynamicProperty("4ks_wp:punch") !== false) {
    const punchLevel = source?.getDynamicProperty("4ks_wp:punch")
    if (punchLevel) {
      const punch = punchLevel / 2
      victim.applyImpulse({ x: e.hitVector.x * punch, y: e.hitVector.y * punch, z: e.hitVector.z * punch })
    }
  }

  if (projectileID.includes("4ks_wp:") && projectileID.includes("throwing_star")) {
    if (projectileID.includes("cryo")) {
      victim.runCommand(`/effect @s slowness ${WEAPON_EFFECT_STATS.cryo_bows_slowness_duration} ${WEAPON_EFFECT_STATS.cryo_bows_slowness_level}`)
    } else if (projectileID.includes("flame")) {
      victim.setOnFire(WEAPON_EFFECT_STATS.flame_bows_fire_duration, true)
    }
  }

  if (projectileID == "minecraft:arrow" || projectileID == "4ks_wp:crossbow_arrow") {
    handleArrowProjectile(victim, source);
  }
  if (projectileID == "4ks_wp:demon_arrow") {
    demonBowHitEntity(victim);
  }
  if (projectileID == "4ks_wp:divine_arrow") {
    divineBowHitEntity(victim);
  }
  if (projectileID == "4ks_wp:emerald_arrow") {
    emeraldSwordSpecialOnhit(source, victim);
  }
  if (projectileID == "4ks_wp:lapis_projectile_bow") {
    lapisProjectileBowHitEntity(victim);
  }
  if (projectileID == "4ks_wp:bedrock_tornado_arrow") {
    bedrockTornadoArrowHitEntity(victim, e.projectile);
  }
  if (projectileID == "4ks_wp:dragon_ender") {
    dragonEnderHitEntity(victim, e.projectile);
  }
  if (projectileID == "4ks_wp:sculk_arrow") {
    sculkArrowHitEntity(victim);
  }
  if (projectileID == "4ks_wp:sword_rollout") {
    swordRolloutHitEntity(victim, e.projectile);
  }
  if (projectileID == "4ks_wp:steel_arrow") {
    const nearEntities = victim.dimension.getEntities({ location: victim.location, maxDistance: 5, families: ["mob"] });
    for (const entity of nearEntities) {
      applyKnockback(e.projectile, entity, 3)
    }
  }
  if (projectileID == "4ks_wp:platinum_projectile_bow") {
    if (!e.projectile.isValid()) return
    if (e.projectile?.getDynamicProperty("4ks_wp:hit_time") == undefined) {
      e.projectile?.setDynamicProperty("4ks_wp:hit_time", 0)
    }
    e.projectile?.setDynamicProperty("4ks_wp:hit_time", e.projectile?.getDynamicProperty("4ks_wp:hit_time") + 1)
    if (e.projectile?.getDynamicProperty("4ks_wp:hit_time") >= 5) {
      e.projectile?.triggerEvent("4ks_wp:despawn")
      return
    }
    victim?.runCommand("/summon 4ks_wp:platinum_sword_explosion ~~~")
  }
  if (PROJECTILE_HIT[projectileID]) {
    PROJECTILE_HIT[projectileID](e);
  }
});

// Interval Tasks
system.runInterval(() => {
  for (const player of world.getPlayers()) {
    checkPlayerItems(player);
    if (player.hasTag("4kscheckmovement")) {
      checkPlayerMovement(player);
    }
  }
}, 0);

system.runInterval(() => {
  for (const player of world.getPlayers()) {
    if (player.hasTag(TAGS.HAS_CUSTOM_ARMOR)) {
      playerCheckArmor(player);
    }
    for (const tag of player.getTags()) {
      if (LOOP_TAGS_CHECK[tag]) {
        LOOP_TAGS_CHECK[tag](player);
      }
    }
  }
}, 1);

async function playerCheckArmor(player) {
  const equippable = player.getComponent("minecraft:equippable");
  const armorPieces = {
    "Head": equippable?.getEquipment("Head")?.typeId.replace("_helmet", "").replace("4kswp_", ""),
    "Chest": equippable?.getEquipment("Chest")?.typeId.replace("_chestplate", "").replace("4kswp_", ""),
    "Legs": equippable?.getEquipment("Legs")?.typeId.replace("_leggings", "").replace("4kswp_", ""),
    "Feet": equippable?.getEquipment("Feet")?.typeId.replace("_boots", "").replace("4kswp_", "")
  };

  const armorIDs = Object.values(armorPieces);
  const uniqueArmorIDs = new Set(armorIDs);
  const hasCustomArmor = player.hasTag(TAGS.HAS_CUSTOM_ARMOR);

  if (uniqueArmorIDs.size !== 1) {
    for (const armorID of armorIDs) {
      const armorRemoved = ARMOR_SET_REMOVED[armorID];
      if (armorRemoved) {
        await armorRemoved(player);
      }
    }
    if (hasCustomArmor) {
      player.removeTag(TAGS.HAS_CUSTOM_ARMOR);
    }
    return;
  }


  const helmetID = armorPieces["Head"];
  const helmetAction = ARMOR_SET[helmetID];

  if (helmetAction) {
    if (!hasCustomArmor) {

      helmetAction(player);
      player.addTag(TAGS.HAS_CUSTOM_ARMOR);
    }
  } else {

    if (hasCustomArmor) {
      for (const armorRemoved of Object.values(ARMOR_SET_REMOVED)) {
        await armorRemoved(player);
      }
      player.removeTag(TAGS.HAS_CUSTOM_ARMOR);
    }
  }
}


world.afterEvents.itemUse.subscribe(async event => {
  if (!event.itemStack.typeId.startsWith("4ks_wp:")) {
    event.source.setDynamicProperty("4ks_wp:punch", false)
    event.source.setDynamicProperty(`4ks_wp:last_used_bow`, undefined)
    event.source.setDynamicProperty(`4ks_wp:last_used_duration`, 0)
  }

  if (event.itemStack.typeId.includes("4ks_wp:") && event.itemStack.typeId.includes("_throwing_star")) {
    useThrowingStar(event.source, event.itemStack)
  }
  playerCheckArmor(event.source)
})

const updateCrossbow = (newTypeId, item, source) => {
  const newCrossbow = new ItemStack(newTypeId, 1);

  // Transfer enchantments
  const previousEnchantments = item.getComponent("minecraft:enchantable").getEnchantments();
  const newEnchantments = newCrossbow.getComponent("minecraft:enchantable");
  newEnchantments.addEnchantments(previousEnchantments);

  // Transfer name tag
  newCrossbow.nameTag = item.nameTag;

  // Transfer and adjust durability
  const previousDurability = item.getComponent("minecraft:durability").damage;
  const newDurability = newCrossbow.getComponent("minecraft:durability");
  newDurability.damage = previousDurability;
  if (!newTypeId.includes("_loaded")) {
    newDurability.damage++;
  }

  // Equip the new crossbow
  const playerEquippable = source.getComponent("minecraft:equippable");
  playerEquippable.setEquipment("Mainhand", newCrossbow);
};


const blockDropID = new Set([
  "minecraft:ice",
  "minecraft:blue_ice",
  "minecraft:netherrack",
  "minecraft:obsidian",
].map((id) => BlockPermutation.resolve(id)));

const ingotDrop = [
  "4ks_wp:cryo_raw",
  "4ks_wp:cryo_raw",
  "4ks_wp:flame_raw",
  "4ks_wp:dragon_scrap",
]

const blockChance = [
  OTHER_DATA.cryo_ice_drop,
  OTHER_DATA.cryo_blue_ice_drop,
  OTHER_DATA.flame_drop,
  OTHER_DATA.dragon_drop
]

world.beforeEvents.playerBreakBlock.subscribe(async event => {
  const location = event.block.location
  const blockPermutation = event.block.permutation
  if (!blockDropID.has(blockPermutation)) return

  let blockDropIDArray = Array.from(blockDropID);
  const itemIndex = blockDropIDArray.indexOf(blockPermutation);
  const chance = blockChance[itemIndex]
  let randomNumber = Math.random() * 1.00;
  system.run(() => {
    if (randomNumber <= chance) {
      let itemToDrop = ingotDrop[itemIndex]
      const equippable = event.player.getComponent("minecraft:equippable")
      const mainHand = equippable.getEquipment("Mainhand")

      const enchantable = mainHand?.getComponent('minecraft:enchantable')
      if (enchantable != undefined) {
        for (const enchant of enchantable.getEnchantments()) {
          if (enchant.type.id == "silk_touch") return
          if (enchant.type.id != "fortune") continue
          let dropCount = 0
          let chance = getRandomNumber(1, 100)
          if (enchant.level == 1) {
            if (chance <= 33) dropCount = 1
          } else if (enchant.level == 2) {
            if (chance > 75) dropCount += 1
            if (chance > 50) dropCount += 1
          } else if (enchant.level == 3) {
            if (chance > 80) dropCount += 1
            if (chance > 60) dropCount += 1
            if (chance > 40) dropCount += 1
          }
          while (dropCount-- > 0) {
            event.player.dimension.spawnItem(new ItemStack(itemToDrop), location)
          }
        }
      }
      event.player.dimension.spawnItem(new ItemStack(itemToDrop), location)

    }
  })
}, {
  blockTypes: [
    "minecraft:ice",
    "minecraft:blue_ice",
    "minecraft:netherrack",
    "minecraft:obsidian",
  ]
})

world.beforeEvents.playerBreakBlock.subscribe(async event => {
  const location = event.block.location
  const itemToDrop = event.block.typeId.replace("_stone", "").replace("_deepslate", "").replace("_granite", "").replace("_ore", "_ingot")
  system.run(() => {
    const equippable = event.player.getComponent("minecraft:equippable")
    const mainHand = equippable.getEquipment("Mainhand")
    const enchantable = mainHand?.getComponent('minecraft:enchantable')
    if (enchantable != undefined) {
      for (const enchant of enchantable.getEnchantments()) {
        if (enchant.type.id != "fortune") continue
        let dropCount = 0
        let chance = getRandomNumber(1, 100)
        if (enchant.level == 1) {
          if (chance <= 33) dropCount = 1
        } else if (enchant.level == 2) {
          if (chance > 75) dropCount += 1
          if (chance > 50) dropCount += 1
        } else if (enchant.level == 3) {
          if (chance > 80) dropCount += 1
          if (chance > 60) dropCount += 1
          if (chance > 40) dropCount += 1
        }
        while (dropCount-- > 0) {
          event.player.dimension.spawnItem(new ItemStack(itemToDrop), location)
        }
      }
    }
  })
}, {
  blockTypes: [
    "4ks_wp:ruby_ore_granite",
    "4ks_wp:ruby_ore_stone",
    "4ks_wp:sapphire_ore_stone",
    "4ks_wp:sapphire_ore_deepslate"
  ]
})

world.beforeEvents.playerBreakBlock.subscribe(async event => {
  const location = event.block.location
  const equippable = event.player.getComponent("minecraft:equippable")
  const mainHand = equippable?.getEquipment("Mainhand")
  if (mainHand?.typeId != "4ks_wp:flame_shovel") return
  event.cancel = true
  system.run(() => {
    decreaseDurability(event.player)
    event.player.dimension.runCommand(`/setblock ${location.x} ${location.y} ${location.z} air`)
    event.player.runCommand("/playsound dig.sand @s")
    const enchantable = mainHand.getComponent('minecraft:enchantable')
    // if (enchantable != undefined) {
    //   for (const enchant of enchantable.getEnchantments()) {
    //     if (enchant.type.id != "fortune") continue
    //     let dropCount = 0
    //     let chance = getRandomNumber(1, 100)
    //     if (enchant.level == 1) {
    //       if (chance <= 33) dropCount = 1
    //     } else if (enchant.level == 2) {
    //       if (chance > 75) dropCount += 1
    //       if (chance > 50) dropCount += 1
    //     } else if (enchant.level == 3) {
    //       if (chance > 80) dropCount += 1
    //       if (chance > 60) dropCount += 1
    //       if (chance > 40) dropCount += 1
    //     }
    //     while (dropCount-- > 0) {
    //       event.player.dimension.spawnItem(new ItemStack("minecraft:glass"), location)
    //     }
    //   }
    // }
    event.player.dimension.spawnItem(new ItemStack("minecraft:glass"), location)
  })
}, {
  blockTypes: [
    "minecraft:sand"
  ]
})

world.beforeEvents.playerBreakBlock.subscribe(async event => {
  const location = event.block.location
  const equippable = event.player.getComponent("minecraft:equippable")
  const mainHand = equippable.getEquipment("Mainhand")
  if (mainHand?.typeId != "4ks_wp:flame_axe") return
  event.cancel = true
  system.run(() => {
    decreaseDurability(event.player)
    event.player.dimension.runCommand(`/setblock ${location.x} ${location.y} ${location.z} air`)
    event.player.runCommand("/playsound dig.wood @s")
    // const enchantable = mainHand.getComponent('minecraft:enchantable')
    // if (enchantable != undefined) {
    //   for (const enchant of enchantable.getEnchantments()) {
    //     if (enchant.type.id != "fortune") continue
    //     let dropCount = 0
    //     let chance = getRandomNumber(1, 100)
    //     if (enchant.level == 1) {
    //       if (chance <= 33) dropCount = 1
    //     } else if (enchant.level == 2) {
    //       if (chance > 75) dropCount += 1
    //       if (chance > 50) dropCount += 1
    //     } else if (enchant.level == 3) {
    //       if (chance > 80) dropCount += 1
    //       if (chance > 60) dropCount += 1
    //       if (chance > 40) dropCount += 1
    //     }
    //     while (dropCount-- > 0) {
    //       event.player.dimension.spawnItem(new ItemStack("minecraft:charcoal"), location)
    //     }
    //   }
    // }
    event.player.dimension.spawnItem(new ItemStack("minecraft:charcoal"), location)
  })
}, {
  blockTypes: [
    "minecraft:acacia_wood",
    "minecraft:birch_wood",
    "minecraft:cherry_wood",
    "minecraft:dark_oak_wood",
    "minecraft:jungle_wood",
    "minecraft:mangrove_wood",
    "minecraft:oak_wood",
    "minecraft:spruce_wood",

    "minecraft:stripped_acacia_wood",
    "minecraft:stripped_birch_wood",
    "minecraft:stripped_cherry_wood",
    "minecraft:stripped_dark_oak_wood",
    "minecraft:stripped_jungle_wood",
    "minecraft:stripped_mangrove_wood",
    "minecraft:stripped_oak_wood",
    "minecraft:stripped_spruce_wood",

    "minecraft:acacia_log",
    "minecraft:birch_log",
    "minecraft:cherry_log",
    "minecraft:dark_oak_log",
    "minecraft:jungle_log",
    "minecraft:mangrove_log",
    "minecraft:oak_log",
    "minecraft:spruce_log",

    "minecraft:stripped_acacia_log",
    "minecraft:stripped_birch_log",
    "minecraft:stripped_cherry_log",
    "minecraft:stripped_dark_oak_log",
    "minecraft:stripped_jungle_log",
    "minecraft:stripped_mangrove_log",
    "minecraft:stripped_oak_log",
    "minecraft:stripped_spruce_log",

    "minecraft:stripped_crimson_hyphae",
    "minecraft:stripped_crimson_stem",

    "minecraft:crimson_hyphae",
    "minecraft:crimson_stem",

    "minecraft:stripped_warped_hyphae",
    "minecraft:stripped_warped_stem",

    "minecraft:warped_hyphae",
    "minecraft:warped_stem",

    "minecraft:pale_oak_wood",
    "minecraft:pale_oak_log",
    "minecraft:stripped_pale_oak_wood",
    "minecraft:stripped_pale_oak_log",
  ]
})

const flameBlockDropID = new Set([
  "minecraft:iron_ore",
  "minecraft:deepslate_iron_ore",
  "minecraft:gold_ore",
  "minecraft:deepslate_gold_ore",
  "minecraft:copper_ore",
  "minecraft:deepslate_copper_ore",
  "minecraft:stone",
  "4ks_wp:uranium_ore_deepslate",
  "4ks_wp:uranium_ore_sandstone",
  "4ks_wp:uranium_ore_stone"
].map((id) => BlockPermutation.resolve(id)));


const flameIngotDrop = [
  "minecraft:iron_ingot",
  "minecraft:iron_ingot",
  "minecraft:gold_ingot",
  "minecraft:gold_ingot",
  "minecraft:copper_ingot",
  "minecraft:copper_ingot",
  "minecraft:stone",
  "4ks_wp:uranium_ingot",
  "4ks_wp:uranium_ingot",
  "4ks_wp:uranium_ingot"
]
world.beforeEvents.playerBreakBlock.subscribe(async event => {

  const equippable = event.player.getComponent("minecraft:equippable")
  const mainHand = equippable.getEquipment("Mainhand")
  if (mainHand?.typeId != "4ks_wp:flame_pickaxe") return

  const location = event.block.location
  const blockPermutation = event.block.permutation
  if (!flameBlockDropID.has(blockPermutation)) return

  let blockDropIDArray = Array.from(flameBlockDropID);
  const itemIndex = blockDropIDArray.indexOf(blockPermutation);
  event.cancel = true
  system.run(() => {
    decreaseDurability(event.player)
    event.player.dimension.runCommand(`/setblock ${location.x} ${location.y} ${location.z} air`)
    event.player.runCommand("/playsound dig.stone @s")
    const enchantable = mainHand.getComponent('minecraft:enchantable')
    if (enchantable != undefined && flameIngotDrop[itemIndex] != "minecraft:stone") {
      for (const enchant of enchantable.getEnchantments()) {
        if (enchant.type.id != "fortune") continue
        let dropCount = 0
        let chance = getRandomNumber(1, 100)
        if (enchant.level == 1) {
          if (chance <= 33) dropCount = 1
        } else if (enchant.level == 2) {
          if (chance > 75) dropCount += 1
          if (chance > 50) dropCount += 1
        } else if (enchant.level == 3) {
          if (chance > 83) dropCount += 1
          if (chance > 66) dropCount += 1
          if (chance > 49) dropCount += 1
        }
        while (dropCount-- > 0) {
          event.player.dimension.spawnItem(new ItemStack(flameIngotDrop[itemIndex]), location)
        }
      }
    }
    event.player.dimension.spawnItem(new ItemStack(flameIngotDrop[itemIndex]), location)

  })
}, {
  blockTypes: [
    "minecraft:iron_ore",
    "minecraft:deepslate_iron_ore",
    "minecraft:gold_ore",
    "minecraft:deepslate_gold_ore",
    "minecraft:copper_ore",
    "minecraft:deepslate_copper_ore",
    "minecraft:stone",
    "4ks_wp:uranium_ore_deepslate",
    "4ks_wp:uranium_ore_sandstone",
    "4ks_wp:uranium_ore_stone"
  ]
})

world.beforeEvents.explosion.subscribe(async (event) => {
  let found = false
  let location = undefined
  for (const block of event.getImpactedBlocks()) {
    if (block?.permutation.matches("4ks_wp:divine_block")) {
      event.cancel = true
      found = true
      location = block.location
      const rnd = Math.random();

      if (rnd <= (1 - OTHER_DATA.divine_to_demonic_chance)) {
        system.run(() => {
          event.dimension.runCommand(`/setblock ${block.location.x} ${block.location.y} ${block.location.z} minecraft:air destroy`)
        });
        continue
      }
      system.run(() => {
        event.dimension.setBlockType(block.location, "4ks_wp:demonic_block")
      });
    } else if (block?.permutation.matches("minecraft:diamond_block")) {
      event.cancel = true
      found = true
      location = block.location
      const rnd = Math.random();

      if (rnd <= (1 - OTHER_DATA.diamond_block_to_divine_chance)) {
        system.run(() => {
          event.dimension.runCommand(`/setblock ${block.location.x} ${block.location.y} ${block.location.z} minecraft:air destroy`)
        });
        continue
      }
      system.run(() => {
        event.dimension.setBlockType(block.location, "4ks_wp:divine_block")
      });
    }
  }
  if (found) {
    system.run(() => {
      event.dimension.runCommand(`/playsound random.explode @a ${location.x} ${location.y} ${location.z}`)
    });

  }
});




world.afterEvents.playerBreakBlock.subscribe(async e => {
  if (e.brokenBlockPermutation.matches("4ks_wp:xp_ore")) {
    let bottleCount = Math.floor(Math.random() * (2 - 1 + 1)) + 1
    const equippable = e.player.getComponent("minecraft:equippable")
    const mainHand = equippable.getEquipment("Mainhand")
    const enchantable = mainHand?.getComponent('minecraft:enchantable')
    
    const location = { x: e.block.location.x, y: e.block.location.y, z: e.block.location.z }
    
    if (enchantable != undefined) {
      for (const enchant of enchantable.getEnchantments()) {
        if(enchant.type.id == "silk_touch") {
          return
        }
        if (enchant.type.id != "fortune") continue

        let chance = getRandomNumber(1, 100)
        if (enchant.level == 1) {
          if (chance <= 33) bottleCount = 1
        } else if (enchant.level == 2) {
          if (chance > 75) bottleCount += 2
          if (chance > 50) bottleCount += 1
        } else if (enchant.level == 3) {
          if (chance > 80) bottleCount += 3
          if (chance > 60) bottleCount += 2
          if (chance > 40) bottleCount += 1
        }

      }
    }

    
    while (bottleCount-- > 0) {
      const xpAmount = Math.floor(Math.random() * (11 - 3 + 1)) + 3
      for (let i = 0; i < xpAmount; i++) {
        e.player.runCommand(`/summon xp_orb ${location.x} ${location.y} ${location.z}`)
      }
    }
  }

  const item = e.itemStackAfterBreak
  if (item == undefined) return

  const durabilityComponent = item.getComponent('minecraft:durability');
  if (!durabilityComponent) return
  //console.warn("current durability before break: " + durabilityComponent.damage + "/" + durabilityComponent.maxDurability)
  if (durabilityComponent.damage >= durabilityComponent.maxDurability) {
    e.player.runCommand("/playsound random.break @s")
    e.player.runCommand("/replaceitem entity @s slot.weapon.mainhand 0 minecraft:air")
    return
  }
  if (!item.typeId.includes("4ks_wp:")) return
  if (item.typeId.includes("boots") || item.typeId.includes("leggings") || item.typeId.includes("chestplate") || item.typeId.includes("helmet")) return

  const enchantable = item.getComponent('minecraft:enchantable')
  if (enchantable != undefined) {
    if (enchantable != undefined) {
      for (const enchant of enchantable.getEnchantments()) {
        if (enchant.type.id != "unbreaking") continue
        let chance = getRandomNumber(1, 100)
        if (enchant.level == 1) {
          if (chance <= 50) return
        } else if (enchant.level == 2) {
          if (chance <= 66) return
        } else if (enchant.level == 3) {
          if (chance <= 75) return
        }
      }
    }
  }
  durabilityComponent.damage += 1
  durabilityComponent.damage = Math.min(durabilityComponent.damage, durabilityComponent.maxDurability)

  const equippable = e.player.getComponent("minecraft:equippable")
  if (durabilityComponent.damage >= durabilityComponent.maxDurability) {
    e.player.runCommand("/playsound random.break @s")
    e.player.runCommand("/replaceitem entity @s slot.weapon.mainhand 0 minecraft:air")
    return
  }

  equippable.setEquipment("Mainhand", item)
})


system.afterEvents.scriptEventReceive.subscribe(e => {
  const id = e.id
  if (id == "4ks_wp:print") {
    console.warn("stone axe :" + (OTHER_DAMAGE.stone.items["axe"] - 1))
    console.warn("stone shovel :" + (OTHER_DAMAGE.stone.items["shovel"] - 1))
    console.warn("stone pickaxe :" + (OTHER_DAMAGE.stone.items["pickaxe"] - 1))
    console.warn("stone hoe :" + (OTHER_DAMAGE.stone.items["hoe"] - 1))
    console.warn("stone sword :" + (OTHER_DAMAGE.stone.items["sword"] - 1))
    console.warn("stone sword_special :" + (OTHER_DAMAGE.stone.items["sword_special"] - 2))
    console.warn("stone battleaxe :" + (OTHER_DAMAGE.stone.items["battleaxe"] - 2))
    console.warn("stone club :" + (OTHER_DAMAGE.stone.items["club"] - 2))
    console.warn("stone cutlass :" + (OTHER_DAMAGE.stone.items["cutlass"] - 2))
    console.warn("stone dagger :" + (OTHER_DAMAGE.stone.items["dagger"] - 2))
    console.warn("stone gladius :" + (OTHER_DAMAGE.stone.items["gladius"] - 2))
    console.warn("stone greatsword :" + (OTHER_DAMAGE.stone.items["greatsword"] - 2))
    console.warn("stone halberd :" + (OTHER_DAMAGE.stone.items["halberd"] - 2))
    console.warn("stone khopesh :" + (OTHER_DAMAGE.stone.items["khopesh"] - 2))
    console.warn("stone club :" + (OTHER_DAMAGE.stone.items["club"] - 2))
    console.warn("stone spear :" + (OTHER_DAMAGE.stone.items["spear"] - 2))
    console.warn("stone mace :" + (OTHER_DAMAGE.stone.items["mace"] - 2))
  }
  if (EVENT_LIST[id] == undefined) {
    //e.sourceEntity.clearDynamicProperties(); return
    return
  }
  EVENT_LIST[id](e)
});


async function armorTagsCheck() {
  for (const player of world.getPlayers()) {
    if (player.hasTag(TAGS.HAS_CUSTOM_ARMOR)) playerCheckArmor(player)
    for (const tag of player.getTags()) {
      if (LOOP_TAGS_CHECK[tag] != undefined) {
        LOOP_TAGS_CHECK[tag](player);
      }
    }

    const helmet = player.getComponent("minecraft:equippable").getEquipment("Head")
    if (helmet?.typeId == "4ks_wp:4kswp_sculk_helmet" && !player.hasTag("4ks_wp.sculkhelmet")) {
      player.runCommand("/effect @s night_vision infinite 1 true")
      player.addTag("4ks_wp.sculkhelmet")
    }
    if (helmet?.typeId != "4ks_wp:4kswp_sculk_helmet" && player.hasTag("4ks_wp.sculkhelmet")) {
      player.runCommand("/effect @s night_vision 0 1 true")
      player.removeTag("4ks_wp.sculkhelmet")
    }
  }
}

async function playerCheckArmorLoop() {
  for (const player of world.getPlayers()) {
    if (!player.hasTag(TAGS.HAS_CUSTOM_ARMOR)) playerCheckArmor(player)
  }
}

world.afterEvents.weatherChange.subscribe(e => {
  world.setDynamicProperty("4ks_wp:thunderstorm", !(e.newWeather == "Rain" || e.newWeather == "Clear"));
  if (e.newWeather == "Rain") {
    world.setDynamicProperty("4ks_wp:raining", true)
  }
  else {
    world.setDynamicProperty("4ks_wp:raining", false)
  }
});

// world.afterEvents.entityHealthChanged.subscribe(e => {
//   if(e.entity.typeId.includes("iron_golem")) {
//     console.warn(e.oldValue, e.newValue, e.oldValue - e.newValue)
//   }
// });

system.runInterval(replaceBedrock, 5)
system.runInterval(armorTagsCheck, 1)
system.runInterval(playerCheckArmorLoop, 20)
system.runInterval(checkBlock, 1)