Skip to content

Commit fd31341

Browse files
committed
horse kit
Fixes #20
1 parent f296f34 commit fd31341

File tree

7 files changed

+624
-1
lines changed

7 files changed

+624
-1
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package dev.betrix.superSmashMobsBrawl.abilities
2+
3+
import dev.betrix.superSmashMobsBrawl.events.BrawlDamageEvent
4+
import dev.betrix.superSmashMobsBrawl.events.BrawlDamageType
5+
import dev.betrix.superSmashMobsBrawl.events.Damager
6+
import dev.betrix.superSmashMobsBrawl.extensions.isOnBlock
7+
import dev.betrix.superSmashMobsBrawl.extensions.setVelocity
8+
import gg.flyte.twilight.extension.getNearbyEntities
9+
import gg.flyte.twilight.scheduler.TwilightRunnable
10+
import gg.flyte.twilight.scheduler.repeatingTask
11+
import kotlin.math.abs
12+
import org.bukkit.Effect
13+
import org.bukkit.Sound
14+
import org.bukkit.block.BlockFace
15+
import org.bukkit.entity.LivingEntity
16+
import org.bukkit.entity.Player
17+
import org.bukkit.util.Vector
18+
19+
class GlidingGallopAbility(player: Player) : BrawlAbility("gliding_gallop", player) {
20+
21+
private val launchStrength: Double = metadata.double("launchStrength") ?: 1.0
22+
private val launchYAdd: Double = metadata.double("launchYAdd") ?: 1.5
23+
private val launchYMax: Double = metadata.double("launchYMax") ?: 2.0
24+
private val landingCheckDelayTicks: Long =
25+
metadata.long("landingCheckDelayTicks") ?: 10L
26+
private val landingCheckIntervalTicks: Long =
27+
(metadata.long("landingCheckIntervalTicks") ?: 1L).coerceAtLeast(1L)
28+
private val impactDamage: Double = metadata.double("impactDamage") ?: 5.0
29+
private val impactRadius: Double = metadata.double("impactRadius") ?: 4.0
30+
private val impactKnockbackMultiplier: Double =
31+
metadata.double("impactKnockbackMultiplier") ?: 2.0
32+
private val impactEnemyLaunchStrength: Double =
33+
metadata.double("impactEnemyLaunchStrength") ?: 1.8
34+
private val impactEnemyLaunchYAdd: Double =
35+
metadata.double("impactEnemyLaunchYAdd") ?: 1.5
36+
37+
private var landingCheckTask: TwilightRunnable? = null
38+
39+
override fun activate() {
40+
super.activate()
41+
42+
// Launch player upward
43+
val launchDirection: Vector =
44+
player.location.direction.clone().apply { y = abs(y) }
45+
46+
player.setVelocity(
47+
velocity = launchDirection,
48+
strength = launchStrength,
49+
ySet = false,
50+
yBase = 0.0,
51+
yAdd = launchYAdd,
52+
yMax = launchYMax,
53+
groundBoost = true,
54+
)
55+
56+
player.world.playSound(player.location, Sound.ENTITY_HORSE_JUMP, 1.5f, 1.0f)
57+
58+
// Start checking for landing
59+
landingCheckTask?.cancel()
60+
landingCheckTask =
61+
repeatingTask(landingCheckDelayTicks, landingCheckIntervalTicks) {
62+
if (!player.isValid || player.isDead) {
63+
cancel()
64+
landingCheckTask = null
65+
return@repeatingTask
66+
}
67+
68+
if (player.isOnBlock()) {
69+
cancel()
70+
landingCheckTask = null
71+
performImpact()
72+
}
73+
}
74+
75+
landingCheckTask?.let { runnables.add(it) }
76+
}
77+
78+
override fun teardown() {
79+
landingCheckTask?.cancel()
80+
landingCheckTask = null
81+
super.teardown()
82+
}
83+
84+
private fun performImpact() {
85+
val ownerLocation = player.location
86+
87+
// Launch nearby enemies into the air
88+
ownerLocation
89+
.getNearbyEntities(impactRadius, impactRadius, impactRadius)
90+
.mapNotNull { it as? LivingEntity }
91+
.filter { it != player }
92+
.filter { canDamageEntity(it) }
93+
.forEach { target ->
94+
val distance = target.location.distance(ownerLocation)
95+
val normalizedDistance =
96+
((impactRadius - distance) / impactRadius).coerceAtLeast(0.0)
97+
val scaledDamage = (impactDamage * normalizedDistance) + 0.5
98+
99+
BrawlDamageEvent(
100+
target,
101+
Damager.DamagerLivingEntity(player),
102+
scaledDamage,
103+
impactKnockbackMultiplier,
104+
BrawlDamageType.Explosion,
105+
)
106+
.callEvent()
107+
108+
// Launch enemy upward
109+
val launchDirection =
110+
target.location
111+
.toVector()
112+
.subtract(ownerLocation.toVector())
113+
.normalize()
114+
target.setVelocity(
115+
velocity = launchDirection,
116+
strength = impactEnemyLaunchStrength * normalizedDistance,
117+
ySet = false,
118+
yBase = 0.0,
119+
yAdd = impactEnemyLaunchYAdd,
120+
yMax = 10.0,
121+
groundBoost = false,
122+
)
123+
124+
if (target is Player) {
125+
target.sendMessage(
126+
lang.t("messages.abilities.glidingGallop.hitBy") {
127+
"abilityId" to id
128+
"attacker" to player.name
129+
}
130+
)
131+
}
132+
}
133+
134+
// Play impact sound and effects
135+
ownerLocation.world.playSound(
136+
ownerLocation,
137+
Sound.ENTITY_IRON_GOLEM_HURT,
138+
2f,
139+
0.6f,
140+
)
141+
ownerLocation.world.playSound(
142+
ownerLocation,
143+
Sound.ENTITY_HORSE_LAND,
144+
2f,
145+
1.0f,
146+
)
147+
148+
// Spawn particle effects
149+
ownerLocation.world.spawnParticle(
150+
org.bukkit.Particle.EXPLOSION,
151+
ownerLocation,
152+
3,
153+
1.0,
154+
0.5,
155+
1.0,
156+
0.0,
157+
)
158+
159+
// Trigger block effects
160+
val originBlock = ownerLocation.block
161+
for (x in -2..2) {
162+
for (z in -2..2) {
163+
val checkBlock = originBlock.getRelative(x, 0, z)
164+
165+
if (!checkBlock.type.isSolid) {
166+
continue
167+
}
168+
169+
val aboveBlock = checkBlock.getRelative(BlockFace.UP)
170+
171+
if (aboveBlock.type.isSolid) {
172+
continue
173+
}
174+
175+
if (Math.random() < 0.3) {
176+
ownerLocation.world.playEffect(
177+
checkBlock.location,
178+
Effect.STEP_SOUND,
179+
checkBlock.type,
180+
)
181+
}
182+
}
183+
}
184+
}
185+
186+
private fun canDamageEntity(entity: LivingEntity): Boolean {
187+
if (entity !is Player) {
188+
return true
189+
}
190+
191+
val minigame = minigameService.getMinigameForPlayer(player) ?: return true
192+
193+
return !minigame.arePlayersOnSameTeam(player, entity)
194+
}
195+
}
196+

0 commit comments

Comments
 (0)