From fef0072007ce793110455209ea96e8702d9dc1b1 Mon Sep 17 00:00:00 2001 From: TDSTOS Date: Mon, 8 Dec 2025 21:59:40 +0100 Subject: [PATCH] Add new game states and update --- .../kotlin/club/mcscrims/speedhg/SpeedHG.kt | 5 + .../club/mcscrims/speedhg/game/GameManager.kt | 22 ++- .../club/mcscrims/speedhg/game/GameState.kt | 25 +-- .../mcscrims/speedhg/game/impl/BattleState.kt | 3 +- .../speedhg/game/impl/DeathmatchState.kt | 113 +++++++++++ .../mcscrims/speedhg/game/impl/EndState.kt | 43 +++++ .../mcscrims/speedhg/game/impl/FeastState.kt | 182 +++++++++++++++++- .../speedhg/game/impl/ImmunityState.kt | 11 +- .../speedhg/game/impl/PreStartState.kt | 15 +- .../mcscrims/speedhg/util/RandomCollection.kt | 73 +++++++ 10 files changed, 440 insertions(+), 52 deletions(-) create mode 100644 src/main/kotlin/club/mcscrims/speedhg/game/impl/DeathmatchState.kt create mode 100644 src/main/kotlin/club/mcscrims/speedhg/game/impl/EndState.kt create mode 100644 src/main/kotlin/club/mcscrims/speedhg/util/RandomCollection.kt diff --git a/src/main/kotlin/club/mcscrims/speedhg/SpeedHG.kt b/src/main/kotlin/club/mcscrims/speedhg/SpeedHG.kt index 4c64425..bd3bd7d 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/SpeedHG.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/SpeedHG.kt @@ -16,6 +16,7 @@ import club.mcscrims.spigot.chat.ChatFormatter import club.mcscrims.spigot.chat.ChatManager import club.mcscrims.spigot.network.SpigotNetworkManager import club.mcscrims.spigot.scheduler.SchedulerManager +import club.mcscrims.spigot.util.WorldEditUtils import com.mongodb.client.model.Indexes import kotlinx.coroutines.runBlocking import net.luckperms.api.LuckPerms @@ -44,6 +45,8 @@ class SpeedHG : JavaPlugin() { internal lateinit var gameManager: GameManager internal lateinit var worldManager: WorldManager + internal lateinit var worldEditUtils: WorldEditUtils + internal lateinit var luckPerms: LuckPerms internal var isReady: Boolean = false @@ -74,6 +77,8 @@ class SpeedHG : JavaPlugin() { schedulerManager = SchedulerManager( this ) + worldEditUtils = WorldEditUtils( this ) + gameManager = GameManager( this ) gameManager.initialize() diff --git a/src/main/kotlin/club/mcscrims/speedhg/game/GameManager.kt b/src/main/kotlin/club/mcscrims/speedhg/game/GameManager.kt index 72b0d17..6d3833b 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/game/GameManager.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/game/GameManager.kt @@ -2,6 +2,8 @@ package club.mcscrims.speedhg.game import club.mcscrims.speedhg.SpeedHG import club.mcscrims.speedhg.game.impl.BattleState +import club.mcscrims.speedhg.game.impl.DeathmatchState +import club.mcscrims.speedhg.game.impl.EndState import club.mcscrims.speedhg.game.impl.FeastState import club.mcscrims.speedhg.game.impl.ImmunityState import club.mcscrims.speedhg.game.impl.PreStartState @@ -16,7 +18,7 @@ class GameManager( ) { private var currentState: GameState? = null - private val gameStateTypes = ConcurrentHashMap() + internal val gameStateTypes = ConcurrentHashMap() private val winners = ArrayList() @@ -33,20 +35,20 @@ class GameManager( plugin.pluginConfig.data.getDuration( "waiting" ).seconds ) + gameStateTypes[ GameStateTypes.WAITING ] = currentState!! + gameStateTypes[ GameStateTypes.PRE_START ] = PreStartState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "pre_start" ).seconds ) + gameStateTypes[ GameStateTypes.IMMUNITY ] = ImmunityState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "immunity" ).seconds ) + gameStateTypes[ GameStateTypes.BATTLE ] = BattleState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "battle" ).seconds ) + gameStateTypes[ GameStateTypes.FEAST ] = FeastState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "feast" ).seconds ) + gameStateTypes[ GameStateTypes.DEATHMATCH ] = DeathmatchState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "deathmatch" ).seconds ) + gameStateTypes[ GameStateTypes.END ] = EndState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "end" ).seconds ) + try { currentState?.onEnter( null ) } catch ( e: Exception ) { plugin.logger.severe("Error during onEnter for state ${currentState?.name}: ${e.message}") e.printStackTrace() } - - gameStateTypes[ GameStateTypes.WAITING ] = currentState!! - gameStateTypes[ GameStateTypes.PRE_START ] = PreStartState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "pre_start" ).seconds ) - gameStateTypes[ GameStateTypes.IMMUNITY ] = ImmunityState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "immunity" ).seconds ) - gameStateTypes[ GameStateTypes.BATTLE ] = BattleState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "battle" ).seconds ) - gameStateTypes[ GameStateTypes.FEAST ] = FeastState( this, plugin, plugin.schedulerManager, plugin.pluginConfig.data.getDuration( "feast" ).seconds ) - gameStateTypes[ GameStateTypes.DEATHMATCH ] = TODO() - gameStateTypes[ GameStateTypes.END ] = TODO() } fun transitionTo( @@ -85,6 +87,8 @@ class GameManager( winners.forEach { this.winners.add( it ) } } + fun getWinners(): List = winners.toList() + fun getCurrentState(): GameState? = currentState fun getCurrentStateType(): GameStateTypes? = gameStateTypes.filter { it.value.name == currentState?.name }.keys.firstOrNull() diff --git a/src/main/kotlin/club/mcscrims/speedhg/game/GameState.kt b/src/main/kotlin/club/mcscrims/speedhg/game/GameState.kt index 9a40089..04c2ea4 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/game/GameState.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/game/GameState.kt @@ -6,8 +6,6 @@ import club.mcscrims.spigot.scheduler.SchedulerManager import club.mcscrims.spigot.scheduler.TaskRegistration import org.bukkit.Bukkit import org.bukkit.entity.Player -import org.bukkit.event.HandlerList -import org.bukkit.event.Listener abstract class GameState( val name: String, @@ -17,7 +15,6 @@ abstract class GameState( protected val durationSeconds: Int? = null ) { - private val listeners = mutableListOf() private var tickTask: TaskRegistration? = null var remainingSeconds: Int = durationSeconds ?: 0 private var isActive: Boolean = false @@ -41,7 +38,6 @@ abstract class GameState( ) { isActive = false stopTicking() - unregisterAllListeners() } private fun startTicking() @@ -63,7 +59,7 @@ abstract class GameState( if ( durationSeconds != null && remainingSeconds > 0 ) { - if (plugin.pluginConfig.data.getDuration( name ).type == DurationType.INCREASING) + if (plugin.pluginConfig.data.getDuration( name ).type == DurationType.INCREASING ) { remainingSeconds++ return@runRepeating @@ -87,25 +83,6 @@ abstract class GameState( tickTask = null } - protected fun registerListener( - listener: Listener - ) { - listeners.add( listener ) - Bukkit.getPluginManager().registerEvents( listener, plugin ) - } - - private fun unregisterAllListeners() - { - listeners.forEach { listener -> HandlerList.unregisterAll( listener ) } - listeners.clear() - } - - protected fun transitionTo( - next: GameState - ) { - gameManager.transitionTo( next ) - } - protected fun broadcast( messageKey: String, vararg placeholders: Pair diff --git a/src/main/kotlin/club/mcscrims/speedhg/game/impl/BattleState.kt b/src/main/kotlin/club/mcscrims/speedhg/game/impl/BattleState.kt index cc8adfe..6a4b21b 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/game/impl/BattleState.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/game/impl/BattleState.kt @@ -32,6 +32,7 @@ class BattleState( { 300 -> { + gameManager.gameStateTypes[ GameStateTypes.BATTLE ] = this gameManager.transitionTo( GameStateTypes.FEAST ) afterFeast = true } @@ -51,7 +52,7 @@ class BattleState( private fun checkForWinners(): Boolean { - val players = Bukkit.getOnlinePlayers() + val players = Bukkit.getOnlinePlayers().filter { !it.isDead } if ( players.size > 1 ) return false diff --git a/src/main/kotlin/club/mcscrims/speedhg/game/impl/DeathmatchState.kt b/src/main/kotlin/club/mcscrims/speedhg/game/impl/DeathmatchState.kt new file mode 100644 index 0000000..d856202 --- /dev/null +++ b/src/main/kotlin/club/mcscrims/speedhg/game/impl/DeathmatchState.kt @@ -0,0 +1,113 @@ +package club.mcscrims.speedhg.game.impl + +import club.mcscrims.speedhg.SpeedHG +import club.mcscrims.speedhg.game.GameManager +import club.mcscrims.speedhg.game.GameState +import club.mcscrims.speedhg.game.GameStateTypes +import club.mcscrims.speedhg.game.impl.PreStartState.AnnouncementType +import club.mcscrims.spigot.scheduler.SchedulerManager +import org.bukkit.Bukkit +import org.bukkit.Location +import org.bukkit.Material +import org.bukkit.Statistic +import org.bukkit.potion.PotionEffect +import org.bukkit.potion.PotionEffectType + +class DeathmatchState( + gameManager: GameManager, + plugin: SpeedHG, + schedulerManager: SchedulerManager, + durationSeconds: Int? = null +) : GameState( "deathmatch", gameManager, plugin, schedulerManager, durationSeconds ) { + + private val world = plugin.worldManager.getWorld() + private val pitLocation = Location( world, 0.0, 1.0, 0.0 ) + + override fun onTick() + { + checkForWinners() + + when( remainingSeconds ) + { + 0 -> + { + plugin.chatManager.broadcast( "gameStates.deathmatch.started" ) + circle() + schedulerManager.runLater( 10L ) { randomTeleport() } + } + + 600 -> announce( AnnouncementType.MINUTES, 5 ) + 660 -> announce( AnnouncementType.MINUTES, 4 ) + 720 -> announce( AnnouncementType.MINUTES, 3 ) + 780 -> announce( AnnouncementType.MINUTES, 2 ) + 840 -> announce( AnnouncementType.MINUTES, 1 ) + 870 -> announce( AnnouncementType.SECONDS, 30 ) + 885 -> announce( AnnouncementType.SECONDS, 15 ) + 890 -> announce( AnnouncementType.SECONDS, 10 ) + 895 -> announce( AnnouncementType.SECONDS, 5 ) + 896 -> announce( AnnouncementType.SECONDS, 4 ) + 897 -> announce( AnnouncementType.SECONDS, 3 ) + 898 -> announce( AnnouncementType.SECONDS, 2 ) + 899 -> announce( AnnouncementType.SECONDS, 1 ) + + 900 -> try { + onEndOfDuration() + } catch ( e: Exception ) { + plugin.logger.severe("Error during onEndOfDuration for state $name: ${e.message}") + e.printStackTrace() + } + } + } + + override fun onEndOfDuration() + { + val winner = Bukkit.getOnlinePlayers().stream() + .filter { !it.isDead } + .map { it.getStatistic( Statistic.PLAYER_KILLS ) to it } + .max(compareBy { it.first }) + .get().second + + gameManager.addWinners( winner ) + gameManager.transitionTo( GameStateTypes.END ) + } + + private fun checkForWinners(): Boolean + { + val players = Bukkit.getOnlinePlayers().filter { !it.isDead } + + if ( players.size > 1 ) + return false + + gameManager.addWinners( players.first() ) + gameManager.transitionTo( GameStateTypes.END ) + return true + } + + private fun announce( + type: AnnouncementType, + time: Int + ) { + val arg = if ( type == AnnouncementType.MINUTES ) "M" else "S" + broadcast( "gameStates.deathmatch.ending$arg", "{time}" to time.toString() ) + } + + private fun randomTeleport() + { + forAlivePlayers { player -> + player.addPotionEffect(PotionEffect( PotionEffectType.RESISTANCE, 40, 20 )) + + val loc = pitLocation.clone() + loc.x = (( pitLocation.blockX - 15 )..( pitLocation.blockX + 15 )).random().toDouble() + loc.z = (( pitLocation.blockZ - 15 )..( pitLocation.blockZ + 15 )).random().toDouble() + loc.y = world!!.getHighestBlockYAt( loc.blockX, loc.blockZ ).toDouble() + player.teleport( loc ) + } + } + + private fun circle() + { + val highestLocation = plugin.worldManager.highestLocationWithRadius( pitLocation, 30 ) + plugin.worldEditUtils.createCylinder( world!!, pitLocation, 30.0, highestLocation.blockY, Material.AIR, true ) + } + +} diff --git a/src/main/kotlin/club/mcscrims/speedhg/game/impl/EndState.kt b/src/main/kotlin/club/mcscrims/speedhg/game/impl/EndState.kt new file mode 100644 index 0000000..7b33945 --- /dev/null +++ b/src/main/kotlin/club/mcscrims/speedhg/game/impl/EndState.kt @@ -0,0 +1,43 @@ +package club.mcscrims.speedhg.game.impl + +import club.mcscrims.speedhg.SpeedHG +import club.mcscrims.speedhg.game.GameManager +import club.mcscrims.speedhg.game.GameState +import club.mcscrims.spigot.chat.getDisplayName +import club.mcscrims.spigot.scheduler.SchedulerManager +import kotlinx.coroutines.runBlocking +import org.bukkit.Bukkit + +class EndState( + gameManager: GameManager, + plugin: SpeedHG, + schedulerManager: SchedulerManager, + durationSeconds: Int? = null +) : GameState( "end", gameManager, plugin, schedulerManager, durationSeconds ) { + + override fun onEnter( + previous: GameState? + ) { + super.onEnter( previous ) + val winners = gameManager.getWinners() + + if ( winners.size > 1 ) + plugin.chatManager.broadcast( "gameStates.end.multipleWinners", "{winners}" to winners.joinToString { it.getDisplayName } ) + else if ( winners.size == 1 ) + plugin.chatManager.broadcast( "gameStates.end.oneWinner", "{winner}" to winners.first().getDisplayName ) + else + plugin.chatManager.broadcast( "gameStates.end.noWinners" ) + + runBlocking { winners.forEach { + plugin.statsRepository.addWins( it.uniqueId, 1 ) + } } + } + + override fun onTick() {} + + override fun onEndOfDuration() + { + Bukkit.shutdown() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/club/mcscrims/speedhg/game/impl/FeastState.kt b/src/main/kotlin/club/mcscrims/speedhg/game/impl/FeastState.kt index 5376fa0..1f53273 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/game/impl/FeastState.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/game/impl/FeastState.kt @@ -3,10 +3,21 @@ package club.mcscrims.speedhg.game.impl import club.mcscrims.speedhg.SpeedHG import club.mcscrims.speedhg.game.GameManager import club.mcscrims.speedhg.game.GameState +import club.mcscrims.speedhg.game.GameStateTypes +import club.mcscrims.speedhg.game.impl.PreStartState.AnnouncementType +import club.mcscrims.speedhg.util.RandomCollection +import club.mcscrims.spigot.item.ItemBuilder import club.mcscrims.spigot.scheduler.SchedulerManager +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer import org.bukkit.Location +import org.bukkit.Material +import org.bukkit.block.Chest +import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.meta.PotionMeta +import org.bukkit.potion.PotionEffect +import org.bukkit.potion.PotionEffectType import org.bukkit.util.BoundingBox -import java.util.Random +import java.util.* class FeastState( gameManager: GameManager, @@ -18,18 +29,181 @@ class FeastState( private val world = plugin.worldManager.getWorld() private val random = Random() - internal lateinit var feastLocation: Location + internal var feastLocation: Location internal lateinit var feastBox: BoundingBox internal var feastHeight: Int = 1 + init + { + this.feastLocation = getLocation() + this.feastHeight = plugin.worldManager.highestLocationWithRadius( feastLocation, 11 ).blockY + 3 + this.feastBox = BoundingBox.of( feastLocation, 11.0, feastHeight.toDouble(), 11.0 ) + } + + override fun onEnter( + previous: GameState? + ) { + super.onEnter( previous ) + circle() + } + override fun onTick() { - TODO("Not yet implemented") + when( remainingSeconds ) + { + 300 -> announce( AnnouncementType.MINUTES, 5 ) + 240 -> announce( AnnouncementType.MINUTES, 4 ) + 180 -> announce( AnnouncementType.MINUTES, 3 ) + 120 -> announce( AnnouncementType.MINUTES, 2 ) + 60 -> announce( AnnouncementType.MINUTES, 1 ) + 30 -> announce( AnnouncementType.SECONDS, 30 ) + 15 -> announce( AnnouncementType.SECONDS, 15 ) + 10 -> announce( AnnouncementType.SECONDS, 10 ) + 5 -> announce( AnnouncementType.SECONDS, 5 ) + 4 -> announce( AnnouncementType.SECONDS, 4 ) + 3 -> announce( AnnouncementType.SECONDS, 3 ) + 2 -> announce( AnnouncementType.SECONDS, 2 ) + 1 -> announce( AnnouncementType.SECONDS, 1 ) + } } override fun onEndOfDuration() { - TODO("Not yet implemented") + plugin.chatManager.broadcast( "feast.started", + "{x}" to feastLocation.blockX.toString(), + "{y}" to feastLocation.blockY.toString(), + "{z}" to feastLocation.blockZ.toString() + ) + + chests() + gameManager.transitionTo( GameStateTypes.BATTLE ) + } + + private fun chests() + { + feastLocation.clone().block.type = Material.ENCHANTING_TABLE + + val chestLocations = arrayOfNulls( 12 ) + + chestLocations[0] = feastLocation.clone().add( 1.0, 0.0, 1.0 ) + chestLocations[1] = feastLocation.clone().add( -1.0, 0.0, 1.0 ) + chestLocations[2] = feastLocation.clone().add( -1.0, 0.0, -1.0 ) + chestLocations[3] = feastLocation.clone().add( 1.0, 0.0, -1.0 ) + chestLocations[4] = feastLocation.clone().add( 2.0, 0.0, 2.0 ) + chestLocations[5] = feastLocation.clone().add( 0.0, 0.0, 2.0 ) + chestLocations[6] = feastLocation.clone().add( -2.0, 0.0, 2.0 ) + chestLocations[7] = feastLocation.clone().add( 2.0, 0.0, 0.0 ) + chestLocations[8] = feastLocation.clone().add( -2.0, 0.0, 0.0 ) + chestLocations[9] = feastLocation.clone().add( 2.0, 0.0, -2.0 ) + chestLocations[10] = feastLocation.clone().add( 0.0, 0.0, -2.0 ) + chestLocations[11] = feastLocation.clone().add( -2.0, 0.0, -2.0 ) + + Arrays.stream( chestLocations ).forEach { it!!.block.type = Material.CHEST } + + val diamondItems = RandomCollection() + diamondItems.add( 1.0, ItemStack( Material.DIAMOND_BOOTS )) + diamondItems.add( 1.0, ItemStack( Material.DIAMOND_CHESTPLATE )) + diamondItems.add( 1.0, ItemStack( Material.DIAMOND_SWORD )) + + val ironItems = RandomCollection() + ironItems.add( 1.0, ItemStack( Material.IRON_BOOTS )) + ironItems.add( 1.0, ItemStack( Material.IRON_LEGGINGS )) + ironItems.add( 1.0, ItemStack( Material.IRON_CHESTPLATE )) + ironItems.add( 1.0, ItemStack( Material.IRON_HELMET )) + ironItems.add( 1.0, ItemStack( Material.IRON_SWORD )) + + val netheriteItems = RandomCollection() + netheriteItems.add( 1.0, ItemStack( Material.NETHERITE_INGOT )) + netheriteItems.add( 1.0, ItemStack( Material.SMITHING_TABLE )) + + val sizeableItems = RandomCollection() + sizeableItems.add( 1.0, ItemStack( Material.RED_MUSHROOM )) + sizeableItems.add( 1.0, ItemStack( Material.BROWN_MUSHROOM )) + sizeableItems.add( 1.0, ItemStack( Material.BOWL )) + sizeableItems.add( 1.0, ItemStack( Material.CACTUS )) + sizeableItems.add( 1.0, ItemStack( Material.COCOA_BEANS )) + sizeableItems.add( 1.0, ItemStack( Material.MUSHROOM_STEW )) + sizeableItems.add( 1.0, ItemStack( Material.LAPIS_LAZULI )) + sizeableItems.add( 1.0, ItemStack( Material.ARROW )) + sizeableItems.add( 1.0, ItemStack( Material.COOKED_BEEF )) + sizeableItems.add( 1.0, ItemStack( Material.COOKED_PORKCHOP )) + sizeableItems.add( 1.0, ItemStack( Material.COOKED_CHICKEN )) + + val singleItems = RandomCollection() + singleItems.add( 1.0, ItemStack( Material.BOW )) + singleItems.add( 1.0, ItemStack( Material.COBWEB )) + singleItems.add( 1.0, ItemStack( Material.FLINT_AND_STEEL )) + singleItems.add( 1.0, ItemStack( Material.TNT )) + singleItems.add( 1.0, ItemStack( Material.ENDER_PEARL )) + singleItems.add( 1.0, ItemStack( Material.LAVA_BUCKET )) + singleItems.add( 1.0, ItemStack( Material.WATER_BUCKET )) + + val strengthPotion = ItemStack( Material.SPLASH_POTION ) + val effect = PotionEffect( PotionEffectType.STRENGTH, (60..240).random(), 0 ) + strengthPotion.editMeta { ( it as PotionMeta ).addCustomEffect( effect, true ) } + + singleItems.add( 1.0, strengthPotion ) + + val cleanser = ItemBuilder( plugin, Material.SUGAR ) + .name(LegacyComponentSerializer.legacySection().serialize(plugin.chatFormatter.format( "feast.cleanser.name" ))) + .unbreakable( true ) + .hideAttributes() + .build() + + singleItems.add( 1.0, cleanser ) + + val lootPool = RandomCollection>() + lootPool.add( 17.5, ironItems ) + lootPool.add( 6.8, diamondItems ) + lootPool.add( 33.0, sizeableItems ) + lootPool.add( 33.0, singleItems ) + lootPool.add( 1.5, netheriteItems ) + + for ( location in chestLocations ) + { + val chest = location!!.block.state as Chest + + for ( i in 0..( 6..12 ).random() ) + { + val randomItemCollection = lootPool.getRandom() + val itemList = randomItemCollection.random().getRandom() + + for ( item in itemList ) + { + if ( randomItemCollection == sizeableItems ) + item.amount = ( 1..16 ).random() + + chest.inventory.setItem(random.nextInt( 26 - 1 ) + 1, item) + } + } + } + } + + private fun announce( + type: AnnouncementType, + time: Int + ) { + val arg = if ( type == AnnouncementType.MINUTES ) "M" else "S" + broadcast( "gameStates.feast.starting$arg", "{time}" to time.toString() ) + } + + private fun circle() + { + plugin.worldEditUtils.createCylinder( world!!, feastLocation, 11.0, feastHeight, Material.GRASS_BLOCK, false ) + plugin.worldEditUtils.createCylinder( world, feastLocation.add( 0.0, 1.0, 0.0 ), 11.0, feastHeight, Material.AIR, false) + } + + private fun getLocation(): Location + { + val x = ( -100..100 ).random() + val z = ( -100..100 ).random() + + val highestY = world!!.getHighestBlockYAt( x, z ) + + if ( highestY >= 70 ) + return getLocation() + + return Location( world, x.toDouble(), highestY.toDouble() + 5.0, z.toDouble() ) } } \ No newline at end of file diff --git a/src/main/kotlin/club/mcscrims/speedhg/game/impl/ImmunityState.kt b/src/main/kotlin/club/mcscrims/speedhg/game/impl/ImmunityState.kt index 925a69f..4fd80c5 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/game/impl/ImmunityState.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/game/impl/ImmunityState.kt @@ -62,15 +62,14 @@ class ImmunityState( 3 -> announce( AnnouncementType.SECONDS, 3 ) 2 -> announce( AnnouncementType.SECONDS, 2 ) 1 -> announce( AnnouncementType.SECONDS, 1 ) - 0 -> - { - broadcast( "gameStates.immunity.ended" ) - gameManager.transitionTo( GameStateTypes.BATTLE ) - } } } - override fun onEndOfDuration() {} + override fun onEndOfDuration() + { + broadcast( "gameStates.immunity.ended" ) + gameManager.transitionTo( GameStateTypes.BATTLE ) + } private fun announce( type: AnnouncementType, diff --git a/src/main/kotlin/club/mcscrims/speedhg/game/impl/PreStartState.kt b/src/main/kotlin/club/mcscrims/speedhg/game/impl/PreStartState.kt index dc79a73..7aeb5fb 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/game/impl/PreStartState.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/game/impl/PreStartState.kt @@ -60,15 +60,16 @@ class PreStartState( 3 -> announce( AnnouncementType.SECONDS, 3 ) 2 -> announce( AnnouncementType.SECONDS, 2 ) 1 -> announce( AnnouncementType.SECONDS, 1 ) - 0 -> - { - broadcast( "gameStates.preStart.started" ) - isStarting = false - gameManager.transitionTo( GameStateTypes.IMMUNITY ) - } } } + override fun onEndOfDuration() + { + broadcast( "gameStates.preStart.started" ) + isStarting = false + gameManager.transitionTo( GameStateTypes.IMMUNITY ) + } + override fun onExit( next: GameState? ) { @@ -76,8 +77,6 @@ class PreStartState( Bukkit.getOnlinePlayers().forEach { it.inventory.clear() } } - override fun onEndOfDuration() {} - private fun announce( type: AnnouncementType, time: Int diff --git a/src/main/kotlin/club/mcscrims/speedhg/util/RandomCollection.kt b/src/main/kotlin/club/mcscrims/speedhg/util/RandomCollection.kt new file mode 100644 index 0000000..37ecea2 --- /dev/null +++ b/src/main/kotlin/club/mcscrims/speedhg/util/RandomCollection.kt @@ -0,0 +1,73 @@ +package club.mcscrims.speedhg.util + +import java.util.* + +class RandomCollection { + + private val map = TreeMap>() + private val names = hashMapOf, String>() + + private val random = Random() + private var total = 0.0 + + fun add( + weight: Double, + result: E + ) { + if ( weight <= 0 ) return + total += weight + map[ total ] = listOf( result ) + } + + fun add( + name: String, + weight: Double, + result: E + ) { + if ( weight <= 0 ) return + total += weight + map[ total ] = listOf( result ) + names[listOf( result )] = name + } + + fun add( + weight: Double, + result: List + ) { + if ( weight <= 0 ) return + total += weight + map[ total ] = result + } + + fun add( + name: String, + weight: Double, + result: List + ) { + if ( weight <= 0 ) return + total += weight + map[ total ] = result + names[ result ] = name + } + + fun getName( + key: E + ): String + { + return names.getOrDefault(listOf( key ), "" ) + } + + fun getName( + key: List + ): String + { + return names.getOrDefault( key, "" ) + } + + fun getRandom(): List + { + val value = random.nextDouble() * total + return map.higherEntry( value ).value + } + +} \ No newline at end of file