crossbow!

This commit is contained in:
rattatwinko
2025-05-01 22:38:34 +02:00
parent ed944e0d76
commit 61ed03b7d9
2 changed files with 90 additions and 65 deletions

View File

@@ -4,6 +4,7 @@ import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.NamespacedKey
import org.bukkit.Particle
import org.bukkit.Registry
import org.bukkit.Sound
import org.bukkit.command.Command
@@ -18,31 +19,31 @@ import org.bukkit.event.entity.EntityShootBowEvent
import org.bukkit.event.entity.ProjectileHitEvent
import org.bukkit.inventory.ItemFlag
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta
import org.bukkit.inventory.meta.CrossbowMeta
import org.bukkit.plugin.java.JavaPlugin
import org.bukkit.scheduler.BukkitRunnable
import org.bukkit.util.Vector
import java.util.*
class AutoBow : JavaPlugin(), Listener {
class AutoCrossbow : JavaPlugin(), Listener {
companion object {
private const val POWER_LEVEL = 10
private const val AUTO_AIM_DISTANCE = 100.0 // Maximum distance for auto-aim
private const val KNOCKBACK_MULTIPLIER = 5.0
private const val MULTISHOT_LEVEL = 5 // Super OP Multishot
}
override fun onEnable() {
logger.info("AutoBow plugin has been enabled!")
logger.info("AutoCrossbow plugin has been enabled!")
server.pluginManager.registerEvents(this, this)
getCommand("autobow")?.setExecutor(AutoBowCommand())
getCommand("autocrossbow")?.setExecutor(AutoCrossbowCommand())
// Register for arrow hit events to handle knockback
server.pluginManager.registerEvents(object : Listener {
@EventHandler
fun onProjectileHit(event: ProjectileHitEvent) {
val arrow = event.entity
if (arrow is Arrow && arrow.scoreboardTags.contains("autobow-knockback")) {
if (arrow is Arrow && arrow.scoreboardTags.contains("autocrossbow-knockback")) {
// Apply knockback if our arrow hit an entity
val hitEntity = event.hitEntity
if (hitEntity is Player) {
@@ -62,10 +63,10 @@ class AutoBow : JavaPlugin(), Listener {
}
override fun onDisable() {
logger.info("AutoBow plugin has been disabled!")
logger.info("AutoCrossbow plugin has been disabled!")
}
private inner class AutoBowCommand : CommandExecutor {
private inner class AutoCrossbowCommand : CommandExecutor {
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<String>): Boolean {
if (sender !is Player) {
sender.sendMessage("${ChatColor.RED}This command can only be used by players!")
@@ -80,12 +81,12 @@ class AutoBow : JavaPlugin(), Listener {
return true
}
// Create the auto bow
val autoBow = createAutoBow()
// Create the auto crossbow
val autoCrossbow = createAutoCrossbow()
// Give the player the bow
player.inventory.addItem(autoBow)
player.sendMessage("${ChatColor.GREEN}You have received the ${ChatColor.GOLD}Auto Bow${ChatColor.GREEN}! It will auto-aim at the nearest player.")
// Give the player the crossbow
player.inventory.addItem(autoCrossbow)
player.sendMessage("${ChatColor.GREEN}You have received the ${ChatColor.GOLD}Auto Crossbow${ChatColor.GREEN}! It will auto-aim at the nearest player.")
// Also give arrows if player doesn't have any
if (!player.inventory.contains(Material.ARROW)) {
@@ -97,15 +98,15 @@ class AutoBow : JavaPlugin(), Listener {
}
}
private fun createAutoBow(): ItemStack {
val bow = ItemStack(Material.BOW)
val meta = bow.itemMeta ?: return bow
private fun createAutoCrossbow(): ItemStack {
val crossbow = ItemStack(Material.CROSSBOW)
val meta = crossbow.itemMeta as CrossbowMeta? ?: return crossbow
// Set display name and lore
meta.setDisplayName("${ChatColor.GOLD}${ChatColor.BOLD}Auto-Aim Bow")
meta.setDisplayName("${ChatColor.GOLD}${ChatColor.BOLD}Auto-Aim Crossbow")
val lore = ArrayList<String>()
lore.add("${ChatColor.GRAY}This bow automatically aims at the nearest player.")
lore.add("${ChatColor.GRAY}This crossbow automatically aims at the nearest player.")
lore.add("${ChatColor.RED}Extreme Knockback")
lore.add("${ChatColor.RED}Power")
lore.add("${ChatColor.DARK_PURPLE}OP Only Weapon")
@@ -118,42 +119,48 @@ class AutoBow : JavaPlugin(), Listener {
// Set the item to be unbreakable
meta.isUnbreakable = true
bow.itemMeta = meta
// Enchant the bow - FIXED LINES (122-124)
// Add enchantments (Power, Multishot, etc.)
val powerEnchant = Registry.ENCHANTMENT.get(NamespacedKey.minecraft("power"))
val infinityEnchant = Registry.ENCHANTMENT.get(NamespacedKey.minecraft("infinity"))
val unbreakingEnchant = Registry.ENCHANTMENT.get(NamespacedKey.minecraft("unbreaking"))
val knockbackEnchant = Registry.ENCHANTMENT.get(NamespacedKey.minecraft("knockback"))
val multishotEnchant = Registry.ENCHANTMENT.get(NamespacedKey.minecraft("multishot"))
if (powerEnchant != null) bow.addUnsafeEnchantment(powerEnchant, POWER_LEVEL)
if (infinityEnchant != null) bow.addUnsafeEnchantment(infinityEnchant, 1)
if (unbreakingEnchant != null) bow.addUnsafeEnchantment(unbreakingEnchant, 10)
if (knockbackEnchant != null) bow.addUnsafeEnchantment(knockbackEnchant, 10)
if (powerEnchant != null) crossbow.addUnsafeEnchantment(powerEnchant, POWER_LEVEL)
if (infinityEnchant != null) crossbow.addUnsafeEnchantment(infinityEnchant, 1)
if (unbreakingEnchant != null) crossbow.addUnsafeEnchantment(unbreakingEnchant, 10)
if (knockbackEnchant != null) crossbow.addUnsafeEnchantment(knockbackEnchant, 10)
if (multishotEnchant != null) crossbow.addUnsafeEnchantment(multishotEnchant, MULTISHOT_LEVEL)
return bow
// Set the custom meta to the item
crossbow.itemMeta = meta
return crossbow
}
@EventHandler
fun onBowShoot(event: EntityShootBowEvent) {
fun onCrossbowShoot(event: EntityShootBowEvent) {
if (event.entity !is Player) {
return
}
val shooter = event.entity as Player
val bow = event.bow ?: return
val crossbow = event.bow ?: return
// Check if it's our special bow
if (bow.hasItemMeta() && bow.itemMeta?.hasDisplayName() == true &&
bow.itemMeta?.displayName == "${ChatColor.GOLD}${ChatColor.BOLD}Auto-Aim Bow") {
// Check if it's our special crossbow
if (crossbow.hasItemMeta() && crossbow.itemMeta?.hasDisplayName() == true &&
crossbow.itemMeta?.displayName == "${ChatColor.GOLD}${ChatColor.BOLD}Auto-Aim Crossbow") {
// Cancel the original arrow
// Cancel the original crossbow shot
event.isCancelled = true
// Show particle effects when the crossbow is fired
shooter.world.spawnParticle(Particle.FIREWORK, shooter.location, 50, 0.5, 1.0, 0.5, 0.1)
// Find the nearest player
val nearestPlayer = Bukkit.getOnlinePlayers()
.filter { it != shooter }
.minByOrNull { it.location.distanceSquared(shooter.location) }
.filter { it != shooter }
.minByOrNull { it.location.distanceSquared(shooter.location) }
if (nearestPlayer != null) {
val distance = shooter.location.distance(nearestPlayer.location)
@@ -163,39 +170,57 @@ class AutoBow : JavaPlugin(), Listener {
// Calculate the vector from the shooter to the target, accounting for movement and gravity
val direction = calculateInterceptVector(shooter, nearestPlayer)
// Spawn a new arrow with the calculated direction
val arrow = shooter.launchProjectile(Arrow::class.java, direction)
arrow.velocity = direction.multiply(2.0) // Increase arrow speed
arrow.isCritical = true
arrow.fireTicks = 100 // Set arrow on fire for visual effect
// Spawn multiple arrows with the calculated direction (multishot effect)
for (i in 0 until 3) {
val arrow = shooter.launchProjectile(Arrow::class.java, direction.add(Vector(Math.random() * 0.2 - 0.1, 0.0, Math.random() * 0.2 - 0.1)))
arrow.velocity = direction.multiply(2.0)
arrow.isCritical = true
arrow.fireTicks = 100 // Set arrow on fire for visual effect
// Tag our arrow for custom knockback
arrow.addScoreboardTag("autobow-knockback")
// Tag our arrow for custom knockback
arrow.addScoreboardTag("autocrossbow-knockback")
// Set shooter as the arrow's shooter for proper damage attribution
arrow.shooter = shooter
// Set shooter as the arrow's shooter for proper damage attribution
arrow.shooter = shooter
// Play sound for feedback
shooter.playSound(shooter.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f, 1.0f)
// Play sound for feedback
shooter.playSound(shooter.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f, 1.0f)
}
// Give the player an arrow after shooting
val arrowStack = ItemStack(Material.ARROW, 1)
shooter.inventory.addItem(arrowStack)
shooter.sendMessage("${ChatColor.GREEN}Auto-aiming at ${ChatColor.RED}${nearestPlayer.name}${ChatColor.GREEN} (${Math.round(distance)} blocks away)")
} else {
shooter.sendMessage("${ChatColor.RED}No players within range for auto-aim!")
// Fire a normal arrow if no valid targets
val arrow = shooter.launchProjectile(Arrow::class.java)
arrow.velocity = shooter.location.direction.multiply(2.0)
arrow.isCritical = true
arrow.addScoreboardTag("autobow-knockback")
// Fire a normal shot with multiple arrows if no valid targets
for (i in 0 until 3) {
val arrow = shooter.launchProjectile(Arrow::class.java)
arrow.velocity = shooter.location.direction.multiply(2.0)
arrow.isCritical = true
arrow.addScoreboardTag("autocrossbow-knockback")
}
// Give the player an arrow after shooting
val arrowStack = ItemStack(Material.ARROW, 1)
shooter.inventory.addItem(arrowStack)
}
} else {
shooter.sendMessage("${ChatColor.RED}No players to auto-aim at!")
// Fire a normal arrow if no valid targets
val arrow = shooter.launchProjectile(Arrow::class.java)
arrow.velocity = shooter.location.direction.multiply(2.0)
arrow.isCritical = true
arrow.addScoreboardTag("autobow-knockback")
// Fire a normal shot with multiple arrows
for (i in 0 until 3) {
val arrow = shooter.launchProjectile(Arrow::class.java)
arrow.velocity = shooter.location.direction.multiply(2.0)
arrow.isCritical = true
arrow.addScoreboardTag("autocrossbow-knockback")
}
// Give the player an arrow after shooting
val arrowStack = ItemStack(Material.ARROW, 1)
shooter.inventory.addItem(arrowStack)
}
}
}

View File

@@ -1,15 +1,15 @@
name: AutoBow
name: AutoCrossbow
version: 1.0-SNAPSHOT
main: org.AutoBow.autoBow.AutoBow
main: org.AutoBow.autoBow.AutoCrossbow
api-version: 1.18
description: Gives OP players an auto-aiming bow with knockback
description: Gives OP players an auto-aiming crossbow with extreme knockback and multishot
commands:
autobow:
description: Gives you an auto-aiming bow with extreme knockback
usage: /autobow
permission: autobow.use
autocrossbow:
description: Gives you an auto-aiming crossbow with extreme knockback and multishot
usage: /autocrossbow
permission: autocrossbow.use
permission-message: You must be an operator to use this command!
permissions:
autobow.use:
description: Allows use of the AutoBow command
default: op
autocrossbow.use:
description: Allows use of the AutoCrossbow command
default: op