diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/Crate.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/Crate.kt index cea3d07..ef08f79 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/Crate.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/Crate.kt @@ -233,31 +233,47 @@ class Crate( if (!hasKeysAndNotify(player, physicalKey = true)) { return } - if (hasRanOutOfRewardsAndNotify(player)) { - return + + if (open(player, location, physicalKey)) { + if (physicalKey) { + usePhysicalKey(player) + } else { + adjustKeys(player, -1) + } } - - - if (physicalKey) { - usePhysicalKey(player) - } else { - adjustKeys(player, -1) - } - - open(player, location, physicalKey) } - fun open(player: Player, location: Location? = null, physicalKey: Boolean = false) { + fun open(player: Player, location: Location? = null, physicalKey: Boolean = false): Boolean { /* Prevent server crashes */ if (hasRanOutOfRewardsAndNotify(player)) { - return + return false + } + if (player.isOpeningCrate) { + return false } val event = CrateOpenEvent(player, this, physicalKey, getRandomReward(player)) Bukkit.getPluginManager().callEvent(event) val roll = makeRoll(player, location ?: player.location, event.reward) + var tick = 0 + + plugin.runnableFactory.create { + roll.tick(tick) + + tick++ + if (!roll.shouldContinueTicking(tick) || !player.isOpeningCrate) { + it.cancel() + roll.onFinish() + player.isOpeningCrate = false + this.handleFinish(player, roll, location ?: player.location) + } + }.runTaskTimer(1, 1) + + player.isOpeningCrate = true roll.roll() + + return true } fun previewForPlayer(player: Player) { @@ -316,3 +332,15 @@ class Crate( return Objects.hash(this.id) } } + +private val openingCrates = mutableSetOf() + +var Player.isOpeningCrate: Boolean + get() = openingCrates.contains(this.uniqueId) + set(value) { + if (value) { + openingCrates.add(this.uniqueId) + } else { + openingCrates.remove(this.uniqueId) + } + } diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/placed/particle/TwirlParticleAnimation.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/placed/particle/TwirlParticleAnimation.kt index f9daeef..94ad130 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/placed/particle/TwirlParticleAnimation.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/placed/particle/TwirlParticleAnimation.kt @@ -1,6 +1,7 @@ package com.willfp.ecocrates.crate.placed.particle import com.willfp.eco.util.NumberUtils +import com.willfp.ecocrates.util.lerp import org.bukkit.util.Vector import kotlin.math.PI @@ -26,6 +27,3 @@ class TwirlParticleAnimation : ParticleAnimation("twirl") { } } } - -private fun lerp(start: Double, end: Double, fraction: Double): Double = - (start * (1 - fraction)) + (end * fraction) diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/Roll.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/Roll.kt index cade54c..aecaf5d 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/Roll.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/Roll.kt @@ -3,6 +3,36 @@ package com.willfp.ecocrates.crate.roll import com.willfp.ecocrates.reward.Reward interface Roll { + /** + * The reward that will be given. + */ val reward: Reward + + /** + * Called on start - once the player begins opening the crate. + */ fun roll() + + /** + * Tick the roll. + * + * @param tick The current tick. + */ + fun tick(tick: Int) + + /** + * Get if the crate should continue ticking, + * if this returns false then the roll is finished, + * and onFinish will be called, rewards will be given, etc. + * + * @param tick The current tick. + * @return If ticking should continue. + */ + fun shouldContinueTicking(tick: Int): Boolean + + /** + * Called once the crate is finished, useful if the + * roll has an inventory as it can then be closed. + */ + fun onFinish() } diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/RollCSGO.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/RollCSGO.kt index def5f52..ade0e72 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/RollCSGO.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/RollCSGO.kt @@ -8,6 +8,7 @@ import com.willfp.eco.core.gui.slot.MaskItems import com.willfp.eco.core.items.Items import com.willfp.eco.util.NumberUtils import com.willfp.ecocrates.crate.Crate +import com.willfp.ecocrates.crate.isOpeningCrate import com.willfp.ecocrates.reward.Reward import org.bukkit.Location import org.bukkit.Material @@ -33,7 +34,7 @@ class RollCSGO private constructor( a maximum tick value of 25 (rather than 1); essentially doing f(x/) * . */ - private val delays = (1..scrollTimes) + private val delays = (1..scrollTimes + 1) .asSequence() .map { it / scrollTimes.toDouble() } .map { NumberUtils.bias(it, bias) } @@ -50,32 +51,7 @@ class RollCSGO private constructor( } private var scroll = 0 - private var tick = 0 - - private val runnable = plugin.runnableFactory.create { - val currentDelay = delays[scroll] - - if (tick % currentDelay == 0) { - tick = 0 - scroll++ - - gui.refresh(player) - - player.playSound( - player.location, - Sound.BLOCK_STONE_BUTTON_CLICK_ON, - 1.0f, - 1.0f - ) - - if (scroll >= scrollTimes) { - it.cancel() - plugin.scheduler.runLater(60) { player.closeInventory() } - } - } - - tick++ - } + private var ticksSinceLastScroll = 0 private val gui = menu(3) { setMask( @@ -106,21 +82,41 @@ class RollCSGO private constructor( ) } - onClose { event, _ -> - handleFinish(event.player as Player) + onClose { _, _ -> + player.isOpeningCrate = false } } override fun roll() { gui.open(player) - - // Run the scroll animation - runnable.runTaskTimer(1, 1) } - private fun handleFinish(player: Player) { - runnable.cancel() - crate.handleFinish(player, this, location) + override fun tick(tick: Int) { + val currentDelay = delays[scroll] + + if (ticksSinceLastScroll % currentDelay == 0) { + ticksSinceLastScroll = 0 + scroll++ + + gui.refresh(player) + + player.playSound( + player.location, + Sound.BLOCK_STONE_BUTTON_CLICK_ON, + 1.0f, + 1.0f + ) + } + + ticksSinceLastScroll++ + } + + override fun shouldContinueTicking(tick: Int): Boolean { + return scroll <= scrollTimes + } + + override fun onFinish() { + player.closeInventory() } object Factory : RollFactory("csgo") { diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/RollFlash.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/RollFlash.kt new file mode 100644 index 0000000..1293038 --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/RollFlash.kt @@ -0,0 +1,101 @@ +package com.willfp.ecocrates.crate.roll + +import com.willfp.eco.core.EcoPlugin +import com.willfp.ecocrates.crate.Crate +import com.willfp.ecocrates.reward.Reward +import org.bukkit.Location +import org.bukkit.Sound +import org.bukkit.entity.Item +import org.bukkit.entity.Player +import org.bukkit.potion.PotionEffect +import org.bukkit.potion.PotionEffectType +import org.bukkit.util.Vector + +class RollFlash private constructor( + override val reward: Reward, + private val crate: Crate, + private val plugin: EcoPlugin, + private val player: Player, + private val location: Location +) : Roll { + private val wait = plugin.configYml.getInt("rolls.flash.wait") + private val display = crate.getRandomRewards(player, 100, displayWeight = true) + + private lateinit var item: Item + + override fun roll() { + val world = location.world!! + + item = world.dropItem(location, display[0].display) + item.pickupDelay = Int.MAX_VALUE + item.setGravity(false) + item.isCustomNameVisible = true + + player.addPotionEffect( + PotionEffect( + PotionEffectType.BLINDNESS, + wait * 2, + 1, + false, + false, + false + ) + ) + } + + override fun tick(tick: Int) { + if (tick % 5 == 0) { + item.velocity = player.eyeLocation.toVector() + .add(player.eyeLocation.direction.normalize().multiply(1.5)) // Make it stop in front of the player + .subtract(item.location.toVector()) + .multiply(tick.toDouble() / wait) + .multiply(0.5) + + item.itemStack = display[tick.floorDiv(4)].display + item.customName = display[tick.floorDiv(4)].displayName + } + + if (tick % 4 == 0) { + player.playSound( + player.location, + Sound.BLOCK_NOTE_BLOCK_PLING, + 1f, + 0.5f + ) + } + } + + override fun shouldContinueTicking(tick: Int): Boolean { + return tick < wait + } + + override fun onFinish() { + player.removePotionEffect(PotionEffectType.BLINDNESS) + + player.playSound( + player.location, + Sound.ENTITY_FIREWORK_ROCKET_TWINKLE, + 1f, + 1f + ) + + item.itemStack = reward.display + item.customName = reward.displayName + item.velocity = Vector(0, 0, 0) + + plugin.scheduler.runLater(80) { + item.remove() + } + } + + object Factory : RollFactory("flash") { + override fun create(options: RollOptions): RollFlash = + RollFlash( + options.reward, + options.crate, + options.plugin, + options.player, + options.location + ) + } +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/Rolls.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/Rolls.kt index d03081a..e21b907 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/Rolls.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/crate/roll/Rolls.kt @@ -8,6 +8,7 @@ object Rolls { private val BY_ID = HashBiMap.create>() val CSGO: RollFactory<*> = RollCSGO.Factory + val FLASH: RollFactory<*> = RollFlash.Factory /** * Get roll factory matching id. diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/util/ExtraMath.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/util/ExtraMath.kt new file mode 100644 index 0000000..2b6ccbf --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecocrates/util/ExtraMath.kt @@ -0,0 +1,4 @@ +package com.willfp.ecocrates.util + +fun lerp(start: Double, end: Double, fraction: Double): Double = + (start * (1 - fraction)) + (end * fraction) diff --git a/eco-core/core-plugin/src/main/resources/config.yml b/eco-core/core-plugin/src/main/resources/config.yml index 32fba7a..f49124c 100644 --- a/eco-core/core-plugin/src/main/resources/config.yml +++ b/eco-core/core-plugin/src/main/resources/config.yml @@ -46,3 +46,5 @@ rolls: bias: 0.65 scrolls: 35 max-delay: 25 + flash: + wait: 80 \ No newline at end of file