@@ -19,6 +19,24 @@ import org.bukkit.event.player.PlayerItemHeldEvent
1919import org.bukkit.persistence.PersistentDataType
2020
2121class CorruptedArrowPassive (player : Player ) : BrawlPassive(" corrupted_arrow" , player) {
22+ companion object {
23+ private val playerEnergy = mutableMapOf< java.util.UUID , Double > ()
24+ private val lastDamageTime = mutableMapOf< java.util.UUID , Long > ()
25+
26+ fun getEnergy (player : Player ): Double = playerEnergy[player.uniqueId] ? : 0.0
27+
28+ fun addEnergy (player : Player , amount : Double , multiplier : Double = 1.0) {
29+ val current = playerEnergy[player.uniqueId] ? : 0.0
30+ val maxEnergy = 100.0
31+ playerEnergy[player.uniqueId] = (current + (amount * multiplier)).coerceIn(0.0 , maxEnergy)
32+ lastDamageTime[player.uniqueId] = System .currentTimeMillis()
33+ }
34+
35+ fun clearEnergy (player : Player ) {
36+ playerEnergy.remove(player.uniqueId)
37+ lastDamageTime.remove(player.uniqueId)
38+ }
39+ }
2240
2341 private val maxCharge: Int
2442 get() = metadata.int(" maxCharge" ) ? : 7
@@ -32,6 +50,24 @@ class CorruptedArrowPassive(player: Player) : BrawlPassive("corrupted_arrow", pl
3250 private val chargeRateTicks: Long
3351 get() = metadata.long(" chargeRateTicks" ) ? : 6L
3452
53+ private val minDamage: Double
54+ get() = metadata.double(" minDamage" ) ? : 5.0
55+
56+ private val maxDamage: Double
57+ get() = metadata.double(" maxDamage" ) ? : 12.0
58+
59+ private val energyPerDamage: Double
60+ get() = metadata.double(" energyPerDamage" ) ? : 1.5
61+
62+ private val energyDecayDelayMs: Long
63+ get() = metadata.long(" energyDecayDelayMs" ) ? : 3000L
64+
65+ private val energyDecayRate: Double
66+ get() = metadata.double(" energyDecayRate" ) ? : 10.0
67+
68+ private val baseBowDamageCap: Double
69+ get() = metadata.double(" baseBowDamageCap" ) ? : 5.0
70+
3571 private var charge = 0
3672 private var chargeRunnable: TwilightRunnable ? = null
3773 private val firedArrows = mutableListOf<Arrow >()
@@ -42,6 +78,8 @@ class CorruptedArrowPassive(player: Player) : BrawlPassive("corrupted_arrow", pl
4278 setupItemHeldListener()
4379 setupBowFireListener()
4480 setupDamageListener()
81+ setupDamageGainListener()
82+ setupEnergyDecayTask()
4583 setupParticleTask()
4684 super .setup()
4785 }
@@ -115,26 +153,31 @@ class CorruptedArrowPassive(player: Player) : BrawlPassive("corrupted_arrow", pl
115153 val arrow = damager as ? Arrow ? : return @event
116154 val victim = entity as ? org.bukkit.entity.LivingEntity ? : return @event
117155
118- // Check if this arrow has corrupted charge
119- val arrowCharge =
120- arrow.persistentDataContainer.get(damageBoostKey, PersistentDataType .INTEGER )
121- ? : return @event
122-
123- if (arrowCharge <= 0 ) return @event
124-
125156 // Check if arrow was shot by this player
126157 if (arrow.shooter != player) return @event
127158
128159 // Cancel vanilla damage and apply our custom damage
129160 isCancelled = true
130161
131- val baseDamage = damage
132- val totalDamage = baseDamage + (arrowCharge * damagePerCharge)
162+ // Check if this arrow has corrupted charge
163+ val arrowCharge =
164+ arrow.persistentDataContainer.get(damageBoostKey, PersistentDataType .INTEGER )
165+ ? : 0
166+
167+ val calculatedDamage = if (arrowCharge > 0 ) {
168+ // Corrupted arrow: scale damage based on energy (5-12)
169+ val energy = getEnergy(player)
170+ val energyRatio = energy / 100.0
171+ minDamage + (maxDamage - minDamage) * energyRatio
172+ } else {
173+ // Non-corrupted arrow: cap at base damage
174+ damage.coerceAtMost(baseBowDamageCap)
175+ }
133176
134177 BrawlDamageEvent (
135178 victim,
136179 dev.betrix.superSmashMobsBrawl.events.Damager .DamagerLivingEntity (player),
137- totalDamage ,
180+ calculatedDamage ,
138181 damageType = BrawlDamageType .Projectile ,
139182 )
140183 .callEvent()
@@ -145,6 +188,45 @@ class CorruptedArrowPassive(player: Player) : BrawlPassive("corrupted_arrow", pl
145188 )
146189 }
147190
191+ private fun setupDamageGainListener () {
192+ listeners.add(
193+ event<BrawlDamageEvent > {
194+ // Only track damage dealt by this player
195+ if (damager !is dev.betrix.superSmashMobsBrawl.events.Damager .DamagerLivingEntity ) return @event
196+ val source = (damager as dev.betrix.superSmashMobsBrawl.events.Damager .DamagerLivingEntity ).livingEntity
197+ if (source != player) return @event
198+
199+ // Gain energy based on damage dealt
200+ addEnergy(player, damage * energyPerDamage)
201+
202+ // Update exp bar to show energy
203+ player.exp = kotlin.math.min(0.9999F , (getEnergy(player) / 100.0 ).toFloat())
204+ }
205+ )
206+ }
207+
208+ private fun setupEnergyDecayTask () {
209+ runnables.add(
210+ repeatingTask(20 ) {
211+ if (! player.isOnline || player.isDead) {
212+ return @repeatingTask
213+ }
214+
215+ val timeSinceLastDamage = System .currentTimeMillis() - (lastDamageTime[player.uniqueId] ? : 0L )
216+
217+ // Start decaying after delay
218+ if (timeSinceLastDamage >= energyDecayDelayMs) {
219+ val currentEnergy = getEnergy(player)
220+ if (currentEnergy > 0 ) {
221+ val newEnergy = (currentEnergy - energyDecayRate).coerceAtLeast(0.0 )
222+ playerEnergy[player.uniqueId] = newEnergy
223+ player.exp = kotlin.math.min(0.9999F , (newEnergy / 100.0 ).toFloat())
224+ }
225+ }
226+ }
227+ )
228+ }
229+
148230 private fun setupParticleTask () {
149231 runnables.add(
150232 repeatingTask(1 ) {
@@ -186,6 +268,17 @@ class CorruptedArrowPassive(player: Player) : BrawlPassive("corrupted_arrow", pl
186268 charge++
187269 player.exp = min(0.9999F , charge.toFloat() / maxCharge.toFloat())
188270 player.playSound(player.eyeLocation, Sound .BLOCK_DISPENSER_FAIL , 0.5f , 1 + 0.1f * charge)
271+
272+ // Show particle indicator when charging
273+ Particle .DUST
274+ .builder()
275+ .location(player.eyeLocation.add(player.location.direction.normalize().multiply(0.5 )))
276+ .count(3 )
277+ .offset(0.1 , 0.1 , 0.1 )
278+ .extra(0.0 )
279+ .data(Particle .DustOptions (org.bukkit.Color .fromRGB(139 , 0 , 0 ), 0.8f ))
280+ .receivers(96 , true )
281+ .spawn()
189282 }
190283
191284 private fun finishCharging () {
@@ -201,6 +294,7 @@ class CorruptedArrowPassive(player: Player) : BrawlPassive("corrupted_arrow", pl
201294 override fun teardown () {
202295 finishCharging()
203296 firedArrows.clear()
297+ clearEnergy(player)
204298 super .teardown()
205299 }
206300}
0 commit comments