function init(hero) {
    hero.setName("Kai/Ninjago").setVersion("SOG").setTier(6);

    hero.setHelmet("Mask").setChestplate("Chestplate").setLeggings("Leggings").setBoots("Shoes");

    hero.addPowers("nin:kai", "nin:throw")
        .addAttribute("FALL_RESISTANCE", 6.0, 0)
        .addAttribute("JUMP_HEIGHT", 2.5, 0)
        .addAttribute("PUNCH_DAMAGE", 8.0, 0)
        .addAttribute("SPRINT_SPEED", 0.40, 1)
        .addAttribute("STEP_HEIGHT", 0.5, 0)
        .addAttribute("BASE_SPEED_LEVELS", 1.0, 0)
        .addAttribute("IMPACT_DAMAGE", 0.1, 1);

    hero.addKeyBindFunc("Func_POWERSET_NEXT", nextpowersetKey, "Next Powerset", 5)
        .addKeyBindFunc("Func_POWERSET_PREV", prevpowersetKey, "Prev Powerset", 5);

    hero.addKeyBind("AIM", "FireBlast", 1)
        .addKeyBind("BLADE", "Sword Of Fire", 2)
        .addKeyBindFunc("TENTACLES", StartClimb, "Wall Run", 3)
        .addKeyBind("SUPER_SPEED", "Super speed", 1)
        .addKeyBind("STEEL_TRANSFORM", "Airjitzu", 2)
        .addKeyBind("ENERGY_PROJECTION", "Spinjitzu", 3)
        .addKeyBind("SLOW_MOTION", "Ninja Senses", 4);

    hero.addPrimaryEquipment("fisktag:weapon{WeaponType:nin:katana}", true, item => item.nbt().getString("WeaponType") == 'nin:katana');

    hero.setAttributeProfile(getProfile)
        .setDamageProfile(getProfile)
        .supplyFunction("canDischargeEnergy", false)
        .setHasProperty(hasProperty)
        .supplyFunction("canAim", canAim)
        .setModifierEnabled(isModifierEnabled)
        .setKeyBindEnabled(isKeyBindEnabled)
        .addAttributeProfile("SNEAK", sneakProfile)
        .addAttributeProfile("SCYTHE", scytheProfile)
        .addAttributeProfile("FALL", fallProfile)
        .setAttributeProfile(entity => {
            if (entity.getData("nin:dyn/sneaking_timer")) return "SNEAK";
            if (entity.getHeldItem().nbt().getString("WeaponType") == "nin:katana") return "SCYTHE";
            if (entity.getData("nin:dyn/fall_damage_immunity_cooldown") > 0 && entity.getData("nin:dyn/fall_damage_immunity_cooldown") < 0.5) return "FALL";
            if (entity.getData("fiskheroes:dyn/steel_cooldown") > 0 && entity.isOnGround()) return "FALL";
            return null;
        })
        .addDamageProfile("FIRE", { "types": { "FIRE": 1.0 } });

    hero.setTickHandler((entity, manager) => {
        manager.incrementData(entity, "nin:dyn/blade", 8, entity.getData("fiskheroes:blade_timer"));
        spinjitzuAttack(hero, entity, manager);

        if (entity.isInWater()) manager.setData(entity, "fiskheroes:flying", true);
        manager.setData(entity, "nin:dyn/spinning", !!entity.getData("fiskheroes:energy_projection"));

        let climbValue = entity.getData("nin:dyn/climb");
        if (entity.getData('fiskheroes:tentacle_lift')) {
            if (entity.motionY() > 0.05 || (entity.isSneaking() && entity.world().getBlock(entity.pos().add(0, -1, 0)) == 'minecraft:air')) {
                manager.setData(entity, "nin:dyn/climb", climbValue + 0.1);
            }
        } else if (climbValue != 0) {
            manager.setData(entity, "nin:dyn/climb", 0).setData(entity, "nin:dyn/climb_bool", false);
        }

        let tentacles = entity.getData("fiskheroes:tentacles");
        let tentacleLift = entity.getData('fiskheroes:tentacle_lift');
        manager.setData(entity, "fiskheroes:tentacle_lift", tentacles != null && !tentacleLift);

        if (climbValue > 0) manager.setData(entity, "nin:dyn/fall_damage_immunity_cooldown", 1);
    });
}

function fallProfile(profile) {
    profile.inheritDefaults()
        .addAttribute("FALL_RESISTANCE", 55.0, 1)
        .addAttribute("IMPACT_DAMAGE", 0.1, 2);
}

function scytheProfile(profile) {
    profile.inheritDefaults().addAttribute("PUNCH_DAMAGE", 40.0, 0);
}

function canAim(entity) {
    return entity.exists();
}

function spinjitzuAttack(hero, entity, manager) {
    if (entity.getData("fiskheroes:energy_projection")) {
        let list = entity.world().getEntitiesInRangeOf(entity.pos(), 2.5);
        let weaponType = entity.getHeldItem().nbt().getString("WeaponType");
        let damage = weaponType == "nin:katana" ? 50 : 35;
        let message = weaponType == "nin:katana" ? "%s was burned to a crisp by %s's spinjitzu" : "%s was ripped to shreds by %s's spinjitzu";

        list.forEach(other => {
            if (other.isLivingEntity() && !entity.equals(other) && entity.world().isUnobstructed(entity.pos().add(0, 1, 0), other.pos().add(0, 1, 0))) {
                other.hurtByAttacker(hero, "FIRE", message, damage, entity);
            }
        });
    }
}

function getProfile(entity) {
    return entity.getData("nin:dyn/sneaking_timer") ? "SNEAK" : null;
}

function sneakProfile(profile) {
    profile.inheritDefaults().addAttribute("BASE_SPEED", 0.5, 1);
}

function isModifierEnabled(entity, modifier) {
    var trans = entity.getData("fiskheroes:dyn/steel_timer") == 1;
    var leap = entity.getData("fiskheroes:energy_projection");
    var YDif = Math.round(entity.posY()) - entity.posY(); 
    var pitch = entity.rotPitch();
    var syaw = entity.getData("nin:dyn/startedyaw");
    var yaw = entity.rotYaw();
    let transformation = entity.getData("fiskheroes:dyn/steeled");
    switch (modifier.name()) {
        case "fiskheroes:metal_skin": return transformation;
        default: return true;
    }
}

function isKeyBindEnabled(entity, keyBind) {
    let powerset = entity.getData("nin:dyn/powerset");
    switch (keyBind) {
        case "AIM": case "BLADE": return powerset == 1;
        case "SLOW_MOTION": case "ENERGY_PROJECTION": case "STEEL_TRANSFORM": case "SUPER_SPEED": return powerset == 2;
        case "Func_POWERSET_NEXT": return !entity.isSneaking();
        case "Func_POWERSET_PREV": return entity.isSneaking();
        case "TENTACLES": return !entity.isInWater() && entity.rotPitch() <= 30 && powerset != 2;
        default: return true;
    }
}

function hasProperty(entity, property) {
    return property == "MASK_TOGGLE";
}

function prevpowersetKey(player, manager) {
    let flag = player.getData("nin:dyn/powerset");
    manager.setDataWithNotify(player, "nin:dyn/powerset", flag == 1 ? 2 : flag - 1);
    return true;
}

function nextpowersetKey(player, manager) {
    let flag = player.getData("nin:dyn/powerset");
    manager.setDataWithNotify(player, "nin:dyn/powerset", flag == 2 ? 1 : flag + 1);
    return true;
}

function StartClimb(entity, manager) {
    manager.setData(entity, "nin:dyn/startedclimb", true)
        .setData(entity, "nin:dyn/startedyaw", entity.rotYaw());
    return true;
}
