Skip to content

Commit 6684c55

Browse files
committed
sheep kit
Fixes #25
1 parent 2f56908 commit 6684c55

File tree

8 files changed

+783
-2
lines changed

8 files changed

+783
-2
lines changed
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
package dev.betrix.superSmashMobsBrawl.abilities
2+
3+
import dev.betrix.superSmashMobsBrawl.disguises.SheepDisguise
4+
import dev.betrix.superSmashMobsBrawl.events.BrawlDamageEvent
5+
import dev.betrix.superSmashMobsBrawl.events.BrawlDamageType
6+
import dev.betrix.superSmashMobsBrawl.events.Damager
7+
import dev.betrix.superSmashMobsBrawl.extensions.disguise
8+
import gg.flyte.twilight.extension.getNearbyEntities
9+
import gg.flyte.twilight.scheduler.TwilightRunnable
10+
import gg.flyte.twilight.scheduler.repeatingTask
11+
import org.bukkit.*
12+
import org.bukkit.entity.LivingEntity
13+
import org.bukkit.entity.Player
14+
import org.bukkit.event.player.PlayerInteractEvent
15+
import org.bukkit.inventory.EquipmentSlot
16+
import org.bukkit.util.Vector
17+
import kotlin.math.min
18+
19+
class StaticLaserAbility(player: Player) :
20+
BrawlAbility("static_laser", player) {
21+
22+
private var chargingTask: TwilightRunnable? = null
23+
private var isCharging = false
24+
25+
private val damage = metadata.double("damage") ?: 7.0
26+
private val hitboxRadius = metadata.double("hitboxRadius") ?: 1.5
27+
private val damageRadius = metadata.double("damageRadius") ?: 2.5
28+
private val knockbackMultiplier = metadata.double("knockbackMultiplier") ?: 3.0
29+
private val range = metadata.double("range") ?: 40.0
30+
private val maxCharge = metadata.float("maxCharge") ?: 0.99f
31+
private val chargePerTick = metadata.float("chargePerTick") ?: 0.035f
32+
33+
override fun onPlayerInteract(event: PlayerInteractEvent) {
34+
if (event.hand != null && event.hand != EquipmentSlot.HAND) return
35+
36+
if (!isCorrectActionForUsage(event.action)) {
37+
return
38+
}
39+
40+
val item = event.item ?: return
41+
42+
if (!isCorrectItemForAbility(item)) {
43+
return
44+
}
45+
46+
event.isCancelled = true
47+
48+
if (isCharging) {
49+
return
50+
}
51+
52+
if (!canActivate()) {
53+
return
54+
}
55+
56+
startCharging()
57+
}
58+
59+
private fun startCharging() {
60+
isCharging = true
61+
activate()
62+
63+
chargingTask?.cancel()
64+
chargingTask =
65+
repeatingTask(0, 0) {
66+
if (!player.isValid || !player.isOnline) {
67+
stopCharging()
68+
cancel()
69+
return@repeatingTask
70+
}
71+
72+
if (!player.isBlocking) {
73+
stopCharging()
74+
fireLaser()
75+
cancel()
76+
return@repeatingTask
77+
}
78+
79+
player.exp = min(maxCharge, player.exp + chargePerTick)
80+
81+
player.world.playSound(
82+
player.location,
83+
Sound.BLOCK_FIRE_EXTINGUISH,
84+
0.25f + player.exp,
85+
0.75f + player.exp,
86+
)
87+
88+
setSheepColor(
89+
if (Math.random() > 0.5) DyeColor.YELLOW else DyeColor.BLACK
90+
)
91+
92+
if (player.exp >= maxCharge) {
93+
stopCharging()
94+
fireLaser()
95+
cancel()
96+
return@repeatingTask
97+
}
98+
}
99+
100+
chargingTask?.let { runnables.add(it) }
101+
}
102+
103+
private fun stopCharging() {
104+
isCharging = false
105+
chargingTask?.cancel()
106+
chargingTask = null
107+
}
108+
109+
private fun fireLaser() {
110+
if (player.exp <= 0.2) {
111+
setSheepColor(DyeColor.WHITE)
112+
player.exp = 0f
113+
return
114+
}
115+
116+
val chargeLevel = player.exp
117+
val effectiveRange = range * chargeLevel
118+
119+
val start = player.eyeLocation
120+
val direction = start.direction
121+
122+
val result =
123+
player.world.rayTraceBlocks(
124+
start,
125+
direction,
126+
effectiveRange,
127+
FluidCollisionMode.NEVER,
128+
true,
129+
)
130+
131+
val endLocation =
132+
result?.hitPosition?.toLocation(player.world)
133+
?: start.clone().add(direction.clone().multiply(effectiveRange))
134+
135+
drawLaserBeam(start, endLocation)
136+
137+
val targetPlayer = findTargetInBeam(start, direction, effectiveRange)
138+
139+
if (targetPlayer != null) {
140+
BrawlDamageEvent(
141+
targetPlayer,
142+
Damager.DamagerLivingEntity(player),
143+
damage * chargeLevel,
144+
knockbackMultiplier,
145+
BrawlDamageType.Projectile,
146+
)
147+
.callEvent()
148+
}
149+
150+
val groundHitLocation = endLocation.clone().subtract(0.0, 1.0, 0.0)
151+
groundHitLocation
152+
.getNearbyEntities(damageRadius, damageRadius, damageRadius)
153+
.filterIsInstance<LivingEntity>()
154+
.filter { it != player }
155+
.filter { canDamageEntity(it) }
156+
.forEach { entity ->
157+
if (entity != targetPlayer) {
158+
BrawlDamageEvent(
159+
entity,
160+
Damager.DamagerLivingEntity(player),
161+
damage * chargeLevel,
162+
knockbackMultiplier,
163+
BrawlDamageType.Projectile,
164+
)
165+
.callEvent()
166+
}
167+
}
168+
169+
Particle.EXPLOSION.builder()
170+
.location(endLocation)
171+
.count(1)
172+
.receivers(96, true)
173+
.spawn()
174+
175+
player.world.playSound(
176+
player.eyeLocation,
177+
Sound.ENTITY_ZOMBIE_VILLAGER_CURE,
178+
0.5f + chargeLevel,
179+
1.75f - chargeLevel,
180+
)
181+
player.world.playSound(
182+
player.location,
183+
Sound.ENTITY_SHEEP_AMBIENT,
184+
2f,
185+
1.5f,
186+
)
187+
188+
setSheepColor(DyeColor.WHITE)
189+
player.exp = 0f
190+
}
191+
192+
private fun drawLaserBeam(start: Location, end: Location) {
193+
val distance = start.distance(end)
194+
val step = 0.2
195+
val steps = (distance / step).toInt()
196+
197+
val direction = end.toVector().subtract(start.toVector()).normalize()
198+
199+
for (i in 0..steps) {
200+
val point =
201+
start.clone().add(direction.clone().multiply(i * step))
202+
Particle.FIREWORK.builder()
203+
.location(point)
204+
.count(1)
205+
.offset(0.0, 0.0, 0.0)
206+
.extra(0.0)
207+
.receivers(96, true)
208+
.spawn()
209+
}
210+
}
211+
212+
private fun findTargetInBeam(
213+
start: Location,
214+
direction: Vector,
215+
range: Double
216+
): Player? {
217+
val step = 0.2
218+
val steps = (range / step).toInt()
219+
220+
for (i in 0..steps) {
221+
val checkLocation = start.clone().add(direction.clone().multiply(i * step))
222+
val nearby =
223+
checkLocation
224+
.getNearbyEntities(hitboxRadius, hitboxRadius, hitboxRadius)
225+
.filterIsInstance<Player>()
226+
.filter { it != player }
227+
.filter { canDamageEntity(it) }
228+
229+
if (nearby.isNotEmpty()) {
230+
return nearby.minByOrNull { it.location.distance(checkLocation) }
231+
}
232+
}
233+
234+
return null
235+
}
236+
237+
private fun canDamageEntity(entity: LivingEntity): Boolean {
238+
if (entity !is Player) {
239+
return true
240+
}
241+
242+
val minigame = minigameService.getMinigameForPlayer(player) ?: return true
243+
244+
return !minigame.arePlayersOnSameTeam(player, entity)
245+
}
246+
247+
private fun setSheepColor(color: DyeColor) {
248+
(player.disguise as? SheepDisguise)?.setColor(color)
249+
}
250+
251+
override fun teardown() {
252+
stopCharging()
253+
setSheepColor(DyeColor.WHITE)
254+
super.teardown()
255+
}
256+
}
257+

0 commit comments

Comments
 (0)