new system ; now you can cast in the air! and also pull towards it!
This commit is contained in:
@@ -26,6 +26,7 @@ class GrapplingHook : JavaPlugin(), Listener {
|
||||
private val grapplingHookKey = NamespacedKey(this, "grappling_hook")
|
||||
private val cooldowns = HashMap<UUID, Long>()
|
||||
private val recentlyGrappled = HashSet<UUID>()
|
||||
private val activeHooks = HashMap<UUID, FishHook>()
|
||||
|
||||
private var cooldownSeconds = 2
|
||||
private var pullStrength = 1.5
|
||||
@@ -33,6 +34,8 @@ class GrapplingHook : JavaPlugin(), Listener {
|
||||
private var maxDistance = 30.0
|
||||
private var showParticles = true
|
||||
private var hookSpeed = 2.5
|
||||
private var airGrappleStrength = 1.2
|
||||
private var airGrappleEnabled = true
|
||||
|
||||
override fun onEnable() {
|
||||
server.pluginManager.registerEvents(this, this)
|
||||
@@ -58,6 +61,8 @@ class GrapplingHook : JavaPlugin(), Listener {
|
||||
writer.println("max-distance: 30.0")
|
||||
writer.println("show-particles: true")
|
||||
writer.println("hook-speed: 2.5")
|
||||
writer.println("air-grapple-enabled: true")
|
||||
writer.println("air-grapple-strength: 1.2")
|
||||
writer.close()
|
||||
} catch (e: Exception) {
|
||||
logger.severe("Could not create config.yml: ${e.message}")
|
||||
@@ -77,6 +82,8 @@ class GrapplingHook : JavaPlugin(), Listener {
|
||||
maxDistance = config.getDouble("max-distance", 30.0)
|
||||
showParticles = config.getBoolean("show-particles", true)
|
||||
hookSpeed = config.getDouble("hook-speed", 2.5)
|
||||
airGrappleEnabled = config.getBoolean("air-grapple-enabled", true)
|
||||
airGrappleStrength = config.getDouble("air-grapple-strength", 1.2)
|
||||
}
|
||||
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
@@ -139,6 +146,7 @@ class GrapplingHook : JavaPlugin(), Listener {
|
||||
val lore = ArrayList<String>()
|
||||
lore.add("${ChatColor.GRAY}Right-click to launch the hook")
|
||||
lore.add("${ChatColor.GRAY}Pull yourself to the hook location")
|
||||
lore.add("${ChatColor.YELLOW}Right-click while hook is in air for a quick boost!")
|
||||
meta?.lore = lore
|
||||
|
||||
meta?.isUnbreakable = true
|
||||
@@ -167,7 +175,7 @@ class GrapplingHook : JavaPlugin(), Listener {
|
||||
val player = event.player
|
||||
val item = player.inventory.itemInMainHand
|
||||
|
||||
if (!isGrapplingHook(item)) return
|
||||
if (!isGrapplingHook(item) && !isGrapplingHook(player.inventory.itemInOffHand)) return
|
||||
|
||||
when (event.state) {
|
||||
PlayerFishEvent.State.FISHING -> {
|
||||
@@ -185,6 +193,9 @@ class GrapplingHook : JavaPlugin(), Listener {
|
||||
cooldowns[uuid] = System.currentTimeMillis()
|
||||
event.hook.velocity = event.hook.velocity.multiply(hookSpeed)
|
||||
player.world.playSound(player.location, Sound.ENTITY_ARROW_SHOOT, 1.0f, 1.0f)
|
||||
|
||||
// Store the active hook for air grapples
|
||||
activeHooks[uuid] = event.hook
|
||||
}
|
||||
|
||||
PlayerFishEvent.State.IN_GROUND, PlayerFishEvent.State.CAUGHT_ENTITY -> {
|
||||
@@ -196,29 +207,47 @@ class GrapplingHook : JavaPlugin(), Listener {
|
||||
return
|
||||
}
|
||||
|
||||
val direction = hook.location.toVector().subtract(player.location.toVector())
|
||||
var adjustedPullStrength = pullStrength
|
||||
if (distance > 15.0) {
|
||||
adjustedPullStrength *= 1.0 + ((distance - 15.0) / 15.0)
|
||||
}
|
||||
// Standard grapple when the hook hits something
|
||||
pullPlayerTowards(player, hook.location.toVector(), pullStrength, distance)
|
||||
|
||||
direction.normalize().multiply(adjustedPullStrength)
|
||||
direction.y = Math.max(0.4, direction.y)
|
||||
player.velocity = direction
|
||||
// Clean up
|
||||
activeHooks.remove(player.uniqueId)
|
||||
}
|
||||
|
||||
if (preventFallDamage) {
|
||||
recentlyGrappled.add(player.uniqueId)
|
||||
object : BukkitRunnable() {
|
||||
override fun run() {
|
||||
recentlyGrappled.remove(player.uniqueId)
|
||||
PlayerFishEvent.State.REEL_IN -> {
|
||||
// This is triggered when player right-clicks while the hook is in the air
|
||||
if (airGrappleEnabled && activeHooks.containsKey(player.uniqueId)) {
|
||||
val hook = activeHooks[player.uniqueId]
|
||||
if (hook != null && !hook.isDead) {
|
||||
// Air grapple logic - boost in the direction the player is looking
|
||||
val lookDirection = player.location.direction
|
||||
val boost = lookDirection.normalize().multiply(airGrappleStrength)
|
||||
|
||||
// Add a slight upward boost to prevent players from smashing into the ground
|
||||
if (boost.y < 0.2) {
|
||||
boost.y = 0.2
|
||||
}
|
||||
}.runTaskLater(this, 100L)
|
||||
}
|
||||
|
||||
player.world.playSound(player.location, Sound.ENTITY_ZOMBIE_INFECT, 1.0f, 2.0f)
|
||||
player.velocity = boost
|
||||
|
||||
if (showParticles) {
|
||||
showGrapplingParticles(player, hook)
|
||||
if (preventFallDamage) {
|
||||
recentlyGrappled.add(player.uniqueId)
|
||||
object : BukkitRunnable() {
|
||||
override fun run() {
|
||||
recentlyGrappled.remove(player.uniqueId)
|
||||
}
|
||||
}.runTaskLater(this, 100L)
|
||||
}
|
||||
|
||||
player.world.playSound(player.location, Sound.ENTITY_BAT_TAKEOFF, 1.0f, 1.5f)
|
||||
|
||||
if (showParticles) {
|
||||
showAirGrappleParticles(player)
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
activeHooks.remove(player.uniqueId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,6 +255,34 @@ class GrapplingHook : JavaPlugin(), Listener {
|
||||
}
|
||||
}
|
||||
|
||||
private fun pullPlayerTowards(player: Player, targetLocation: Vector, strength: Double, distance: Double) {
|
||||
val direction = targetLocation.subtract(player.location.toVector())
|
||||
var adjustedPullStrength = strength
|
||||
|
||||
if (distance > 15.0) {
|
||||
adjustedPullStrength *= 1.0 + ((distance - 15.0) / 15.0)
|
||||
}
|
||||
|
||||
direction.normalize().multiply(adjustedPullStrength)
|
||||
direction.y = Math.max(0.4, direction.y)
|
||||
player.velocity = direction
|
||||
|
||||
if (preventFallDamage) {
|
||||
recentlyGrappled.add(player.uniqueId)
|
||||
object : BukkitRunnable() {
|
||||
override fun run() {
|
||||
recentlyGrappled.remove(player.uniqueId)
|
||||
}
|
||||
}.runTaskLater(this, 100L)
|
||||
}
|
||||
|
||||
player.world.playSound(player.location, Sound.ENTITY_ZOMBIE_INFECT, 1.0f, 2.0f)
|
||||
|
||||
if (showParticles) {
|
||||
showGrapplingParticles(player, targetLocation.toLocation(player.world))
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onEntityDamage(event: EntityDamageEvent) {
|
||||
if (event.entity !is Player) return
|
||||
@@ -241,25 +298,25 @@ class GrapplingHook : JavaPlugin(), Listener {
|
||||
}
|
||||
}
|
||||
|
||||
private fun isGrapplingHook(item: ItemStack): Boolean {
|
||||
if (item.type != Material.FISHING_ROD) return false
|
||||
private fun isGrapplingHook(item: ItemStack?): Boolean {
|
||||
if (item == null || item.type != Material.FISHING_ROD) return false
|
||||
val meta = item.itemMeta ?: return false
|
||||
return meta.persistentDataContainer.has(grapplingHookKey, PersistentDataType.BYTE)
|
||||
}
|
||||
|
||||
private fun showGrapplingParticles(player: Player, hook: FishHook) {
|
||||
private fun showGrapplingParticles(player: Player, targetLocation: org.bukkit.Location) {
|
||||
object : BukkitRunnable() {
|
||||
var distance = player.location.distance(hook.location)
|
||||
var distance = player.location.distance(targetLocation)
|
||||
var traveled = 0.0
|
||||
val particleSpacing = 0.3
|
||||
|
||||
override fun run() {
|
||||
if (traveled >= distance || !player.isOnline || hook.isDead) {
|
||||
if (traveled >= distance || !player.isOnline) {
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
|
||||
val direction = hook.location.toVector().subtract(player.location.toVector()).normalize()
|
||||
val direction = targetLocation.toVector().subtract(player.location.toVector()).normalize()
|
||||
val particleLocation = player.location.clone().add(direction.multiply(traveled))
|
||||
|
||||
player.world.spawnParticle(Particle.CRIT, particleLocation, 2, 0.05, 0.05, 0.05, 0.01)
|
||||
@@ -271,4 +328,33 @@ class GrapplingHook : JavaPlugin(), Listener {
|
||||
}
|
||||
}.runTaskTimer(this, 0L, 1L)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showAirGrappleParticles(player: Player) {
|
||||
// Create a swirl of particles around the player
|
||||
object : BukkitRunnable() {
|
||||
var counter = 0
|
||||
|
||||
override fun run() {
|
||||
if (counter >= 10 || !player.isOnline) {
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
|
||||
// Create a circular pattern
|
||||
for (i in 0 until 8) {
|
||||
val angle = i * Math.PI / 4
|
||||
val x = Math.cos(angle) * 0.7
|
||||
val z = Math.sin(angle) * 0.7
|
||||
val particleLocation = player.location.clone().add(x, counter * 0.1, z)
|
||||
|
||||
player.world.spawnParticle(Particle.CLOUD, particleLocation, 1, 0.05, 0.05, 0.05, 0.01)
|
||||
if (i % 2 == 0) {
|
||||
player.world.spawnParticle(Particle.CRIT, particleLocation, 1, 0.05, 0.05, 0.05, 0.01)
|
||||
}
|
||||
}
|
||||
|
||||
counter++
|
||||
}
|
||||
}.runTaskTimer(this, 0L, 2L)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user