package dev.zxq5.items.sets import dev.zxq5.items.template.ArmorSet import dev.zxq5.items.template.GenericGearSet import dev.zxq5.items.ModItems.register import dev.zxq5.items.template.registerItem import dev.zxq5.items.template.provideDelegate import net.minecraft.core.component.DataComponents import net.minecraft.core.particles.ParticleTypes import net.minecraft.core.particles.PowerParticleOption import net.minecraft.server.level.ServerLevel import net.minecraft.sounds.SoundEvents import net.minecraft.sounds.SoundSource import net.minecraft.util.Unit import net.minecraft.world.InteractionHand import net.minecraft.world.InteractionResult import net.minecraft.world.damagesource.DamageSource import net.minecraft.world.entity.Entity import net.minecraft.world.entity.player.Player import net.minecraft.world.item.Item import net.minecraft.world.item.Items import net.minecraft.world.item.ToolMaterial import net.minecraft.world.item.component.UseCooldown import net.minecraft.world.item.equipment.* import net.minecraft.world.level.Level import kotlin.getValue object Dragonite: GenericGearSet() { override val materialName = "dragonite" override val materialDefinition get() = super.materialDefinition.copy(assetId = materialKey) val SCALE by registerItem("dragon_scale", ::Item) val INGOT by registerItem("dragonite_ingot", ::Item) { shapedRecipe("SBS", "CXC", "SBS", key=mapOf( 'S' to Items.SHULKER_SHELL, 'X' to SCALE, 'B' to Items.DRAGON_BREATH, 'C' to Items.CHORUS_FRUIT )) } val SWORD by registerItem("dragonite_sword", ::DragoniteSword) { properties { enchantable(armorMaterial.enchantmentValue) .component(DataComponents.USE_COOLDOWN, UseCooldown(2f)) .sword(ToolMaterial.NETHERITE, 3F, -2.4F) } smithingUpgrade(Items.END_CRYSTAL, Items.NETHERITE_SWORD, INGOT) } val HELMET by registerItem("dragonite_helmet", ::Item) { properties { humanoidArmor(armorMaterial, ArmorType.HELMET) } smithingUpgrade(Items.DRAGON_HEAD, Items.NETHERITE_HELMET, INGOT) } val CHESTPLATE by registerItem("dragonite_chestplate", ::Item) { properties { humanoidArmor(armorMaterial, ArmorType.CHESTPLATE) .component(DataComponents.GLIDER, Unit.INSTANCE) .component(DataComponents.UNBREAKABLE, Unit.INSTANCE) } smithingUpgrade(Items.ELYTRA, Items.NETHERITE_CHESTPLATE, INGOT) } val LEGGINGS by registerItem("dragonite_leggings", ::Item) { properties { humanoidArmor(armorMaterial, ArmorType.LEGGINGS) } smithingUpgrade(Items.CRYING_OBSIDIAN, Items.NETHERITE_LEGGINGS, INGOT) } val BOOTS by registerItem("dragonite_boots", ::Item) { properties { humanoidArmor(armorMaterial, ArmorType.BOOTS) } smithingUpgrade(Items.CRYING_OBSIDIAN, Items.NETHERITE_BOOTS, INGOT) } override val armorSet: ArmorSet = ArmorSet(HELMET, CHESTPLATE, LEGGINGS, BOOTS) override val items = listOf(SWORD, HELMET, CHESTPLATE, LEGGINGS, BOOTS, SCALE, INGOT) override fun onLoad() {} } class DragoniteSword(properties: Properties) : Item(properties) { override fun use(level: Level, user: Player, hand: InteractionHand): InteractionResult { if (level.isClientSide || !Dragonite.fullSetEquippedBy(user)) return InteractionResult.PASS val direction = user.lookAngle val scale = if (user.isFallFlying) { 4.0 } else { 1.5 } user.deltaMovement = direction.scale(scale) user.hurtMarked = true level.playSound(null, user.x, user.y, user.z, SoundEvents.ENDER_DRAGON_FLAP, SoundSource.PLAYERS, 1.0f, 1.0f) (level as? ServerLevel)?.sendParticles( PowerParticleOption.create(ParticleTypes.DRAGON_BREATH, 1.0f), user.x, user.y, user.z, 100, 0.5, 0.5, 0.5, 0.5 ) return InteractionResult.SUCCESS } override fun getAttackDamageBonus(victim: Entity, damage: Float, damageSource: DamageSource): Float { val superBonus = super.getAttackDamageBonus(victim, damage, damageSource) // 0f from vanilla, but respect it anyway val attacker = damageSource.entity as? Player ?: return superBonus if (Dragonite.fullSetEquippedBy(attacker)) return superBonus if (attacker.level().isClientSide) return superBonus if (!attacker.isFallFlying) return superBonus val speed = attacker.deltaMovement.length() if (speed < MIN_DIVE_SPEED) return superBonus val clampedSpeed = speed.coerceAtMost(MAX_DIVE_SPEED) val t = (clampedSpeed - MIN_DIVE_SPEED) / (MAX_DIVE_SPEED - MIN_DIVE_SPEED) val multiplier = 1.0f + (t * MAX_BONUS_MULTIPLIER).toFloat() // damage is the current total (base + crit + whatever ran before this hook). // We want final = damage * multiplier, and this method adds its return value on top of damage, // so the bonus we need to return is exactly (damage * multiplier) - damage. val extraBonus = damage * (multiplier - 1f) println("base: $damage bonus: ${superBonus + extraBonus}") return superBonus + extraBonus } companion object { const val MIN_DIVE_SPEED = 0.3 const val MAX_DIVE_SPEED = 1.1 const val MAX_BONUS_MULTIPLIER = 2.0f } }