Remove legacy modules, add language & scoreboard
Large refactor removing many legacy subsystems (abilities, kit system, database repos, recraft, world manager, extensive config classes, lunar/luckperms integrations and various listeners/commands). Introduces a lightweight LanguageManager, AntiRunningManager, ScoreboardManager, ConnectListener and a SoupListener; simplifies the main SpeedHG plugin to initialize these components and register the connection listener. Build changes: update Gradle wrapper to 8.10, remove paperweight and several external dependencies, add fr.mrmicky:fastboard and simplify shadowJar/build task configuration. Adds default language resource (languages/en_US.yml) and updates plugin/config resources. Purpose: simplify and decouple the plugin, reduce dependency surface and prepare for a leaner, modular rewrite.
This commit is contained in:
@@ -2,7 +2,6 @@ plugins {
|
||||
id("java")
|
||||
id("maven-publish")
|
||||
id("com.github.johnrengelman.shadow") version "8.1.1"
|
||||
id("io.papermc.paperweight.userdev") version "1.7.1"
|
||||
kotlin("jvm") version libs.versions.kotlin
|
||||
kotlin("kapt") version libs.versions.kotlin
|
||||
}
|
||||
@@ -18,36 +17,11 @@ repositories {
|
||||
maven("https://libraries.minecraft.net/")
|
||||
maven("https://repo.codemc.io/repository/maven-public/")
|
||||
maven("https://repo.lunarclient.dev")
|
||||
|
||||
maven {
|
||||
url = uri("https://maven.pkg.github.com/McScrims-Network/Main-CoreSystem")
|
||||
credentials {
|
||||
username = System.getenv("GITHUB_ACTOR")
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.mongodb:mongodb-driver-kotlin-coroutine:4.11.1")
|
||||
implementation("org.mongodb:bson-kotlinx:4.11.1")
|
||||
|
||||
implementation("net.kyori:adventure-api:4.14.0")
|
||||
implementation("net.kyori:adventure-text-minimessage:4.14.0")
|
||||
implementation("net.kyori:adventure-platform-bukkit:4.3.2")
|
||||
|
||||
compileOnly("net.luckperms:api:5.4")
|
||||
|
||||
compileOnly("com.lunarclient:apollo-api:1.2.0")
|
||||
compileOnly("com.lunarclient:apollo-extra-adventure4:1.2.0")
|
||||
|
||||
compileOnly("org.popcraft:chunky-common:1.3.38")
|
||||
|
||||
implementation("club.mcscrims:core:1.4.3.2")
|
||||
implementation("club.mcscrims:spigot:1.4.3.2")
|
||||
|
||||
implementation("fr.mrmicky:fastboard:2.1.3")
|
||||
compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT")
|
||||
paperweight.paperDevBundle("1.21.1-R0.1-SNAPSHOT")
|
||||
}
|
||||
|
||||
tasks {
|
||||
@@ -65,10 +39,6 @@ tasks {
|
||||
archiveVersion.set(project.version.toString())
|
||||
}
|
||||
|
||||
assemble {
|
||||
dependsOn( reobfJar )
|
||||
}
|
||||
|
||||
build {
|
||||
dependsOn( shadowJar )
|
||||
}
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -1,291 +1,61 @@
|
||||
package club.mcscrims.speedhg
|
||||
|
||||
import club.mcscrims.core.config.ConfigData
|
||||
import club.mcscrims.core.config.ConfigFormat
|
||||
import club.mcscrims.core.config.ConfigLoader
|
||||
import club.mcscrims.core.database.DatabaseConfig
|
||||
import club.mcscrims.core.database.mongodb.MongoManager
|
||||
import club.mcscrims.speedhg.ability.AbilityContext
|
||||
import club.mcscrims.speedhg.ability.AbilityHitListener
|
||||
import club.mcscrims.speedhg.ability.CooldownManager
|
||||
import club.mcscrims.speedhg.ability.HitCounterManager
|
||||
import club.mcscrims.speedhg.config.KitConfig
|
||||
import club.mcscrims.speedhg.config.MessageConfig
|
||||
import club.mcscrims.speedhg.config.PluginConfig
|
||||
import club.mcscrims.speedhg.database.StatsRepository
|
||||
import club.mcscrims.speedhg.config.LanguageManager
|
||||
import club.mcscrims.speedhg.game.GameManager
|
||||
import club.mcscrims.speedhg.command.KitsCommand
|
||||
import club.mcscrims.speedhg.database.PlayerRepository
|
||||
import club.mcscrims.speedhg.kit.KitInventoryListener
|
||||
import club.mcscrims.speedhg.kit.KitInventoryManager
|
||||
import club.mcscrims.speedhg.kit.KitListener
|
||||
import club.mcscrims.speedhg.kit.KitManager
|
||||
import club.mcscrims.speedhg.listener.GameStateListener
|
||||
import club.mcscrims.speedhg.listener.LunarClientListener
|
||||
import club.mcscrims.speedhg.recraft.RecraftInspector
|
||||
import club.mcscrims.speedhg.recraft.RecraftUtils
|
||||
import club.mcscrims.speedhg.world.WorldManager
|
||||
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.kyori.adventure.text.Component
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
|
||||
import net.luckperms.api.LuckPerms
|
||||
import club.mcscrims.speedhg.game.modules.AntiRunningManager
|
||||
import club.mcscrims.speedhg.listener.ConnectListener
|
||||
import club.mcscrims.speedhg.scoreboard.ScoreboardManager
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
|
||||
class SpeedHG : JavaPlugin() {
|
||||
|
||||
companion object {
|
||||
|
||||
internal lateinit var instance: SpeedHG
|
||||
|
||||
fun Component.content(): String
|
||||
{
|
||||
return LegacyComponentSerializer.legacySection().serialize( this )
|
||||
}
|
||||
lateinit var instance: SpeedHG
|
||||
private set
|
||||
|
||||
}
|
||||
|
||||
private lateinit var configLoader: ConfigLoader
|
||||
internal lateinit var pluginConfig: ConfigData<PluginConfig>
|
||||
internal lateinit var messageConfig: ConfigData<MessageConfig>
|
||||
internal lateinit var kitConfig: ConfigData<KitConfig>
|
||||
internal lateinit var databaseConfig: ConfigData<DatabaseConfig>
|
||||
lateinit var languageManager: LanguageManager
|
||||
private set
|
||||
|
||||
internal lateinit var chatManager: ChatManager<MessageConfig>
|
||||
internal lateinit var chatFormatter: ChatFormatter<MessageConfig>
|
||||
lateinit var gameManager: GameManager
|
||||
private set
|
||||
|
||||
private lateinit var mongoManager: MongoManager
|
||||
internal lateinit var statsRepository: StatsRepository
|
||||
internal lateinit var playerRepository: PlayerRepository
|
||||
lateinit var antiRunningManager: AntiRunningManager
|
||||
private set
|
||||
|
||||
internal lateinit var networkManager: SpigotNetworkManager
|
||||
internal lateinit var schedulerManager: SchedulerManager
|
||||
|
||||
internal lateinit var gameManager: GameManager
|
||||
internal lateinit var worldManager: WorldManager
|
||||
|
||||
internal lateinit var abilityContext: AbilityContext
|
||||
internal lateinit var kitManager: KitManager
|
||||
internal lateinit var kitInventoryManager: KitInventoryManager
|
||||
|
||||
internal lateinit var worldEditUtils: WorldEditUtils
|
||||
|
||||
internal lateinit var luckPerms: LuckPerms
|
||||
internal var isReady: Boolean = false
|
||||
|
||||
override fun onLoad()
|
||||
{
|
||||
instance = this
|
||||
|
||||
worldManager = WorldManager( this )
|
||||
worldManager.deleteWorld()
|
||||
}
|
||||
lateinit var scoreboardManager: ScoreboardManager
|
||||
private set
|
||||
|
||||
override fun onEnable()
|
||||
{
|
||||
loadConfigurations()
|
||||
setupDatabase()
|
||||
networkManager = SpigotNetworkManager.getInstance()!!
|
||||
instance = this
|
||||
|
||||
worldManager.setupWorld()
|
||||
|
||||
chatFormatter = ChatFormatter.create(
|
||||
plugin = this,
|
||||
configClass = MessageConfig::class,
|
||||
messageExtractor = { config -> config.getAllMessages() },
|
||||
listExtractor = { config -> config.getListMessages() }
|
||||
)
|
||||
|
||||
chatManager = ChatManager.withCustomConfig( this, chatFormatter )
|
||||
chatManager.initialize()
|
||||
|
||||
schedulerManager = SchedulerManager( this )
|
||||
|
||||
worldEditUtils = WorldEditUtils( this )
|
||||
saveDefaultConfig()
|
||||
languageManager = LanguageManager( this )
|
||||
|
||||
gameManager = GameManager( this )
|
||||
gameManager.initialize()
|
||||
antiRunningManager = AntiRunningManager( this )
|
||||
|
||||
val cooldownManager = CooldownManager()
|
||||
val hitCounterManager = HitCounterManager()
|
||||
abilityContext = AbilityContext( cooldownManager, hitCounterManager )
|
||||
scoreboardManager = ScoreboardManager( this )
|
||||
|
||||
kitManager = KitManager( this )
|
||||
kitManager.initialize()
|
||||
|
||||
kitInventoryManager = KitInventoryManager( this, kitManager )
|
||||
|
||||
setupLuckPerms()
|
||||
registerListener()
|
||||
registerCommands()
|
||||
|
||||
RecraftUtils.registerRecipes()
|
||||
RecraftInspector( this ).startRunnable()
|
||||
logger.info("SpeedHG wurde geladen!")
|
||||
}
|
||||
|
||||
override fun onDisable()
|
||||
{
|
||||
kitManager.clearAll()
|
||||
closeDatabase()
|
||||
networkManager.shutdown()
|
||||
super.onDisable()
|
||||
}
|
||||
|
||||
private fun registerListener()
|
||||
{
|
||||
server.pluginManager.registerEvents(GameStateListener( this, gameManager ), this )
|
||||
server.pluginManager.registerEvents(KitListener( this, kitManager ), this )
|
||||
server.pluginManager.registerEvents(KitInventoryListener( this, kitManager, kitInventoryManager ), this )
|
||||
server.pluginManager.registerEvents(AbilityHitListener( this, abilityContext ), this )
|
||||
LunarClientListener( this )
|
||||
}
|
||||
val pm = Bukkit.getPluginManager()
|
||||
|
||||
private fun registerCommands()
|
||||
{
|
||||
getCommand("kits")?.setExecutor(KitsCommand( this, kitInventoryManager ))
|
||||
}
|
||||
|
||||
fun getAlivePlayers(): List<Player>
|
||||
{
|
||||
val alivePlayers = mutableListOf<Player>()
|
||||
|
||||
runBlocking {
|
||||
val players = playerRepository.findAlivePlayers( server.name )
|
||||
alivePlayers.addAll(players.map { Bukkit.getPlayer( it.uuid )!! })
|
||||
}
|
||||
|
||||
return alivePlayers
|
||||
}
|
||||
|
||||
/*
|
||||
* LUCKPERMS >>
|
||||
*/
|
||||
|
||||
private fun setupLuckPerms()
|
||||
{
|
||||
val provider = server.servicesManager.getRegistration( LuckPerms::class.java )
|
||||
|
||||
if ( provider != null )
|
||||
luckPerms = provider.provider
|
||||
|
||||
if ( !::luckPerms.isInitialized )
|
||||
logger.warning( "LuckPerms could not be loaded." )
|
||||
else
|
||||
logger.info( "LuckPerms has successfully been loaded." )
|
||||
}
|
||||
|
||||
/*
|
||||
* DATABASE >>
|
||||
*/
|
||||
|
||||
private fun setupDatabase()
|
||||
{
|
||||
// MongoManager initialisieren
|
||||
mongoManager = MongoManager.getInstance( name, logger )
|
||||
val connection = mongoManager.createConnection( "speedhg", databaseConfig.data )
|
||||
|
||||
// Repositories initialisieren
|
||||
statsRepository = StatsRepository( connection )
|
||||
playerRepository = PlayerRepository( connection )
|
||||
|
||||
// Indizes erstellen
|
||||
runBlocking {
|
||||
try
|
||||
{
|
||||
connection.createIndex( "player_stats", Indexes.ascending( "kills" ))
|
||||
connection.createIndex( "player_stats", Indexes.descending( "deaths" ))
|
||||
connection.createIndex( "player_stats", Indexes.ascending( "wins" ))
|
||||
connection.createIndex( "player_stats", Indexes.ascending( "unathleticIndex" ))
|
||||
connection.createIndex( "player_stats", Indexes.ascending( "ironFarmed" ))
|
||||
connection.createIndex( "kit_players", Indexes.text( "server" ))
|
||||
}
|
||||
catch ( ex: Exception ) {
|
||||
logger.warning( "Failed to create MongoDB indexes: ${ex.message}" )
|
||||
return@runBlocking
|
||||
}
|
||||
}
|
||||
|
||||
logger.info( "Successfully enabled MongoDB" )
|
||||
}
|
||||
|
||||
private fun closeDatabase()
|
||||
{
|
||||
// Alle Server von Kit-Spielern auf NULL setzen
|
||||
runBlocking {
|
||||
try
|
||||
{
|
||||
val players = Bukkit.getOnlinePlayers()
|
||||
players.forEach { player ->
|
||||
playerRepository.updateServer( player.uniqueId, "NULL" )
|
||||
}
|
||||
logger.info( "Updated ${players.size} players server to NULL." )
|
||||
}
|
||||
catch ( ex: Exception ) {
|
||||
logger.warning( "Failed to update player server: ${ex.message}" )
|
||||
}
|
||||
}.also {
|
||||
// MongoManager beenden
|
||||
mongoManager.shutdown()
|
||||
|
||||
logger.info( "Successfully disabled MongoDB" )
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* CONFIG >>
|
||||
*/
|
||||
|
||||
private fun loadConfigurations()
|
||||
{
|
||||
configLoader = ConfigLoader.getInstance( name, logger, dataFolder )
|
||||
createConfigurations()
|
||||
}
|
||||
|
||||
private fun createConfigurations()
|
||||
{
|
||||
pluginConfig = configLoader.loadConfig<PluginConfig>(
|
||||
fileName = "config.yml",
|
||||
format = ConfigFormat.YAML,
|
||||
autoReload = true
|
||||
)
|
||||
|
||||
messageConfig = configLoader.loadConfig<MessageConfig>(
|
||||
fileName = "messages.yml",
|
||||
format = ConfigFormat.YAML,
|
||||
autoReload = false
|
||||
)
|
||||
|
||||
kitConfig = configLoader.loadConfig<KitConfig>(
|
||||
fileName = "kits.yml",
|
||||
format = ConfigFormat.YAML,
|
||||
autoReload = false
|
||||
)
|
||||
|
||||
databaseConfig = configLoader.loadConfig<DatabaseConfig>(
|
||||
fileName = "database.json",
|
||||
format = ConfigFormat.JSON,
|
||||
autoReload = false
|
||||
)
|
||||
}
|
||||
|
||||
fun reloadConfigurations()
|
||||
{
|
||||
try
|
||||
{
|
||||
pluginConfig.reload()
|
||||
messageConfig.reload()
|
||||
kitConfig.reload()
|
||||
databaseConfig.reload()
|
||||
}
|
||||
catch ( ex: Exception ) {
|
||||
logger.severe( "Failed to reload configurations: ${ex.message}" )
|
||||
}
|
||||
pm.registerEvents( ConnectListener(), this )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package club.mcscrims.speedhg.ability
|
||||
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class AbilityContext(
|
||||
val cooldownManager: CooldownManager,
|
||||
val hitCounterManager: HitCounterManager
|
||||
) {
|
||||
|
||||
fun canUseAbility(
|
||||
player: Player,
|
||||
key: String,
|
||||
requiredHits: Int? = null,
|
||||
cooldownSeconds: Int? = null
|
||||
): AbilityResult
|
||||
{
|
||||
if ( cooldownSeconds != null && cooldownManager.isOnCooldown( player, key ))
|
||||
{
|
||||
val remaining = cooldownManager.getRemainingSeconds( player, key )
|
||||
return AbilityResult.onCooldown( remaining )
|
||||
}
|
||||
|
||||
if ( requiredHits != null && !hitCounterManager.hasReachedThreshold( player, key, requiredHits ))
|
||||
{
|
||||
val missing = hitCounterManager.getRemainingHits( player, key, requiredHits )
|
||||
return AbilityResult.insufficientHits( missing )
|
||||
}
|
||||
|
||||
if ( requiredHits != null )
|
||||
hitCounterManager.resetHits( player, key )
|
||||
|
||||
if ( cooldownSeconds != null )
|
||||
cooldownManager.startCooldown( player, key, cooldownSeconds )
|
||||
|
||||
return AbilityResult.success()
|
||||
}
|
||||
|
||||
fun incrementHit(
|
||||
player: Player,
|
||||
key: String
|
||||
): Int
|
||||
{
|
||||
return hitCounterManager.incrementHit( player, key )
|
||||
}
|
||||
|
||||
fun getHits(
|
||||
player: Player,
|
||||
key: String
|
||||
): Int
|
||||
{
|
||||
return hitCounterManager.getHits( player, key )
|
||||
}
|
||||
|
||||
fun getRemainingCooldown(
|
||||
player: Player,
|
||||
key: String
|
||||
): Double
|
||||
{
|
||||
return cooldownManager.getRemainingSeconds( player, key )
|
||||
}
|
||||
|
||||
fun clearPlayerData(
|
||||
player: Player
|
||||
) {
|
||||
cooldownManager.clearAllCooldowns( player )
|
||||
hitCounterManager.clearAllHits( player )
|
||||
}
|
||||
|
||||
fun clearAll()
|
||||
{
|
||||
cooldownManager.clearAll()
|
||||
hitCounterManager.clearAll()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package club.mcscrims.speedhg.ability
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
|
||||
class AbilityHitListener(
|
||||
private val plugin: SpeedHG,
|
||||
private val abilityContext: AbilityContext
|
||||
) : Listener {
|
||||
|
||||
@EventHandler
|
||||
fun onEntityDamage(
|
||||
event: EntityDamageByEntityEvent
|
||||
) {
|
||||
val damager = event.damager
|
||||
val victim = event.entity
|
||||
|
||||
if ( damager !is Player || victim !is Player )
|
||||
return
|
||||
|
||||
val hitCount = abilityContext.incrementHit( damager, "melee_hit" )
|
||||
|
||||
val result = abilityContext.canUseAbility(
|
||||
player = damager,
|
||||
key = "example_ability",
|
||||
requiredHits = 3,
|
||||
cooldownSeconds = 10
|
||||
)
|
||||
|
||||
if ( result.success )
|
||||
{
|
||||
plugin.chatManager.sendMessage( damager, "ability.activated", "{player}" to victim.name )
|
||||
}
|
||||
else if ( result.missingHits > 0 )
|
||||
{
|
||||
plugin.chatManager.sendMessage( damager, "ability.more_hits", "{current}" to hitCount.toString(), "{needed}" to result.missingHits.toString() )
|
||||
}
|
||||
else if ( result.remainingCooldown > 0 )
|
||||
{
|
||||
plugin.chatManager.sendMessage( damager, "ability.cooldown", "{cooldown}" to result.remainingCooldown.toString() )
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package club.mcscrims.speedhg.ability
|
||||
|
||||
data class AbilityResult(
|
||||
val success: Boolean,
|
||||
val reason: String?,
|
||||
val remainingCooldown: Double = 0.0,
|
||||
val missingHits: Int = 0
|
||||
) {
|
||||
companion object
|
||||
{
|
||||
|
||||
fun success(): AbilityResult = AbilityResult( true, null )
|
||||
|
||||
fun onCooldown( remaining: Double ): AbilityResult =
|
||||
AbilityResult( false, "Ability is on cooldown", remainingCooldown = remaining )
|
||||
|
||||
fun insufficientHits( missing: Int ): AbilityResult =
|
||||
AbilityResult( false, "Not enough hits", missingHits = missing )
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package club.mcscrims.speedhg.ability
|
||||
|
||||
import org.bukkit.entity.Player
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class CooldownManager {
|
||||
|
||||
private val cooldowns = ConcurrentHashMap<UUID, ConcurrentHashMap<String, Long>>()
|
||||
|
||||
fun startCooldown(
|
||||
player: Player,
|
||||
key: String,
|
||||
seconds: Int
|
||||
) {
|
||||
val expiryTime = System.currentTimeMillis() + ( seconds * 1000L )
|
||||
cooldowns.computeIfAbsent( player.uniqueId ) { ConcurrentHashMap() }[ key ] = expiryTime
|
||||
}
|
||||
|
||||
fun isOnCooldown(
|
||||
player: Player,
|
||||
key: String
|
||||
): Boolean
|
||||
{
|
||||
val playerCooldowns = cooldowns[player.uniqueId] ?: return false
|
||||
val expiryTime = playerCooldowns[key] ?: return false
|
||||
|
||||
if ( System.currentTimeMillis() >= expiryTime )
|
||||
{
|
||||
playerCooldowns.remove( key )
|
||||
if ( playerCooldowns.isEmpty() ) cooldowns.remove( player.uniqueId )
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun getRemainingSeconds(
|
||||
player: Player,
|
||||
key: String
|
||||
): Double
|
||||
{
|
||||
val playerCooldowns = cooldowns[player.uniqueId] ?: return 0.0
|
||||
val expiryTime = playerCooldowns[key] ?: return 0.0
|
||||
|
||||
val remaining = ( expiryTime - System.currentTimeMillis() ) / 1000.0
|
||||
return if ( remaining > 0 ) remaining else 0.0
|
||||
}
|
||||
|
||||
fun clearCooldown(
|
||||
player: Player,
|
||||
key: String
|
||||
) {
|
||||
cooldowns[player.uniqueId]?.remove( key )
|
||||
}
|
||||
|
||||
fun clearAllCooldowns(
|
||||
player: Player
|
||||
) {
|
||||
cooldowns.remove( player.uniqueId )
|
||||
}
|
||||
|
||||
fun clearAll()
|
||||
{
|
||||
cooldowns.clear()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package club.mcscrims.speedhg.ability
|
||||
|
||||
import org.bukkit.entity.Player
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class HitCounterManager {
|
||||
|
||||
private val hitCounts = ConcurrentHashMap<UUID, ConcurrentHashMap<String, Int>>()
|
||||
|
||||
fun incrementHit(
|
||||
player: Player,
|
||||
key: String
|
||||
): Int
|
||||
{
|
||||
val playerHits = hitCounts.computeIfAbsent( player.uniqueId ) { ConcurrentHashMap() }
|
||||
val newCount = playerHits.compute( key ) { _, current -> ( current ?: 0 ) + 1 } ?: 1
|
||||
return newCount
|
||||
}
|
||||
|
||||
fun getHits(
|
||||
player: Player,
|
||||
key: String
|
||||
): Int
|
||||
{
|
||||
return hitCounts[player.uniqueId]?.get( key ) ?: 0
|
||||
}
|
||||
|
||||
fun resetHits(
|
||||
player: Player,
|
||||
key: String
|
||||
) {
|
||||
hitCounts[player.uniqueId]?.remove( key )
|
||||
}
|
||||
|
||||
fun hasReachedThreshold(
|
||||
player: Player,
|
||||
key: String,
|
||||
requiredHits: Int
|
||||
): Boolean
|
||||
{
|
||||
return getHits( player, key ) >= requiredHits
|
||||
}
|
||||
|
||||
fun getRemainingHits(
|
||||
player: Player,
|
||||
key: String,
|
||||
requiredHits: Int
|
||||
): Int
|
||||
{
|
||||
val current = getHits( player, key )
|
||||
return maxOf( 0, requiredHits - current )
|
||||
}
|
||||
|
||||
fun clearAllHits(
|
||||
player: Player
|
||||
) {
|
||||
hitCounts.remove( player.uniqueId )
|
||||
}
|
||||
|
||||
fun clearAll()
|
||||
{
|
||||
hitCounts.clear()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package club.mcscrims.speedhg.command
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.speedhg.kit.KitInventoryManager
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class KitsCommand(
|
||||
private val plugin: SpeedHG,
|
||||
private val kitInventoryManager: KitInventoryManager
|
||||
) : CommandExecutor {
|
||||
|
||||
override fun onCommand(
|
||||
sender: CommandSender,
|
||||
command: Command,
|
||||
label: String,
|
||||
args: Array<out String>
|
||||
): Boolean {
|
||||
if ( sender !is Player )
|
||||
{
|
||||
plugin.chatManager.sendSenderMessage( sender, "default.only_players" )
|
||||
return true
|
||||
}
|
||||
|
||||
kitInventoryManager.openKitInventory( sender, 1 )
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
package club.mcscrims.speedhg.config
|
||||
|
||||
import club.mcscrims.core.config.annotations.ConfigClass
|
||||
import club.mcscrims.core.config.annotations.ConfigField
|
||||
|
||||
@ConfigClass(
|
||||
name = "kits",
|
||||
description = "Kit configuration",
|
||||
version = "1.0"
|
||||
)
|
||||
data class KitConfig(
|
||||
|
||||
@ConfigField(name = "anchor", description = "Anchor configurations")
|
||||
val anchor: Map<String, Double> = getAnchorConfigurations(),
|
||||
|
||||
@ConfigField(name = "armorer", description = "Armorer configurations")
|
||||
val armorer: Map<String, Double> = getArmorerConfigurations(),
|
||||
|
||||
@ConfigField(name = "blackpanther", description = "BlackPanther configurations")
|
||||
val blackPanther: Map<String, Double> = getBlackPantherConfigurations(),
|
||||
|
||||
@ConfigField(name = "blitzcrank", description = "Blitzcrank configurations")
|
||||
val blitzcrank: Map<String, Double> = getBlitzcrankConfigurations(),
|
||||
|
||||
@ConfigField(name = "gladiator", description = "Gladiator configurations")
|
||||
val gladiator: Map<String, Double> = getGladiatorConfigurations(),
|
||||
|
||||
@ConfigField(name = "goblin", description = "Goblin configurations")
|
||||
val goblin: Map<String, Double> = getGoblinConfigurations(),
|
||||
|
||||
@ConfigField(name = "icemage", description = "IceMage configurations")
|
||||
val iceMage: Map<String, Double> = getIceMageConfigurations(),
|
||||
|
||||
@ConfigField(name = "poseidon", description = "Poseidon configurations")
|
||||
val poseidon: Map<String, Double> = getPoseidonConfigurations(),
|
||||
|
||||
@ConfigField(name = "rattlesnake", description = "Rattlesnake configurations")
|
||||
val rattlesnake: Map<String, Double> = getRattlesnakeConfigurations(),
|
||||
|
||||
@ConfigField(name = "tesla", description = "Tesla configurations")
|
||||
val tesla: Map<String, Double> = getTeslaConfigurations(),
|
||||
|
||||
@ConfigField(name = "voodoo", description = "Voodoo configurations")
|
||||
val voodoo: Map<String, Double> = getVoodooConfigurations(),
|
||||
|
||||
@ConfigField(name = "perks", description = "Perk configuration")
|
||||
val perks: Map<String, Pair<String, Double>> = getPerkConfiguration()
|
||||
) {
|
||||
|
||||
fun getAllKitConfigurations(): Map<String, Double>
|
||||
{
|
||||
return anchor + armorer + blackPanther + gladiator + goblin + iceMage + poseidon +
|
||||
rattlesnake + tesla + voodoo
|
||||
}
|
||||
|
||||
fun getConfigForKit(id: String): Map<String, Double>
|
||||
{
|
||||
return when (id.lowercase()) {
|
||||
"anchor" -> anchor
|
||||
"armorer" -> armorer
|
||||
"blackpanther" -> blackPanther
|
||||
"gladiator" -> gladiator
|
||||
"goblin" -> goblin
|
||||
"icemage" -> iceMage
|
||||
"poseidon" -> poseidon
|
||||
"rattlesnake" -> rattlesnake
|
||||
"tesla" -> tesla
|
||||
"voodoo" -> voodoo
|
||||
else -> emptyMap()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun getAnchorConfigurations() = mapOf(
|
||||
"offensive extra damage" to 1.0
|
||||
)
|
||||
|
||||
private fun getArmorerConfigurations() = mapOf(
|
||||
"kills until new armor" to 2.0
|
||||
)
|
||||
|
||||
private fun getBlackPantherConfigurations() = mapOf(
|
||||
"enderpearl hit damage" to 3.0,
|
||||
"extra damage on top" to 0.5,
|
||||
"default hit radius" to 3.0,
|
||||
"explosion multiplier" to 3.0
|
||||
)
|
||||
|
||||
private fun getBlitzcrankConfigurations() = mapOf(
|
||||
"ultimate damage" to 10.0,
|
||||
"ultimate radius" to 5.0,
|
||||
"ultimate stun duration" to 0.5,
|
||||
"hook range" to 8.0,
|
||||
"stun height" to 4.0,
|
||||
"stun radius" to 3.0,
|
||||
"stun slow duration" to 5.0
|
||||
)
|
||||
|
||||
private fun getGladiatorConfigurations() = mapOf(
|
||||
"cage radius" to 23.0,
|
||||
"cage height" to 10.0,
|
||||
"wither effect after x seconds" to 180.0
|
||||
)
|
||||
|
||||
private fun getGoblinConfigurations() = mapOf(
|
||||
"bunker radius" to 10.0,
|
||||
"bunker time until disappear" to 15.0,
|
||||
"knockback and pullin radius" to 7.0,
|
||||
"kit steal time" to 60.0,
|
||||
"soup steal chance" to 20.0
|
||||
)
|
||||
|
||||
private fun getIceMageConfigurations() = mapOf(
|
||||
"chance for slowness" to 2.0
|
||||
)
|
||||
|
||||
private fun getPoseidonConfigurations() = mapOf(
|
||||
"default hit radius" to 3.0,
|
||||
"lightning hit damage" to 4.0
|
||||
)
|
||||
|
||||
private fun getRattlesnakeConfigurations() = mapOf(
|
||||
"maximum jump distance" to 10.0,
|
||||
"speed duration" to 10.0,
|
||||
"poison duration" to 8.0,
|
||||
"maximum negative effect duration" to 16.0,
|
||||
"default jump radius" to 10.0
|
||||
)
|
||||
|
||||
private fun getTeslaConfigurations() = mapOf(
|
||||
"disable push at height" to 50.0,
|
||||
"default thunder radius" to 5.0,
|
||||
"push strength" to 1.0,
|
||||
"fire tick duration" to 5.0,
|
||||
"time until thunder disables" to 7.0,
|
||||
"thunder damage" to 1.5
|
||||
)
|
||||
|
||||
private fun getVoodooConfigurations() = mapOf(
|
||||
"default curse radius" to 3.0,
|
||||
"maximum effect duration" to 15.0,
|
||||
"clicked players minimum health" to 10.0,
|
||||
"voodoo hold duration" to 5.0,
|
||||
"chance for wither effect" to 5.0
|
||||
)
|
||||
|
||||
private fun getPerkConfiguration() = mapOf(
|
||||
"knockback" to Pair( "knockback strength", 1.5 ),
|
||||
"pullin" to Pair( "pullin strength", 0.5 ),
|
||||
"radiusincrease" to Pair( "new radius", 5.0 )
|
||||
)
|
||||
@@ -0,0 +1,96 @@
|
||||
package club.mcscrims.speedhg.config
|
||||
|
||||
import net.kyori.adventure.text.Component
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder
|
||||
import org.bukkit.configuration.file.YamlConfiguration
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
import java.io.File
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class LanguageManager(
|
||||
private val plugin: JavaPlugin
|
||||
) {
|
||||
|
||||
// Map: Sprachcode -> (Key -> Nachricht)
|
||||
private val languages = ConcurrentHashMap<String, Map<String, String>>()
|
||||
private val miniMessage = MiniMessage.miniMessage()
|
||||
private val defaultLanguage = plugin.config.getString("default.language", "en_US")!!
|
||||
|
||||
init {
|
||||
loadLanguages()
|
||||
}
|
||||
|
||||
fun loadLanguages()
|
||||
{
|
||||
languages.clear()
|
||||
val folder = File( plugin.dataFolder, "languages" )
|
||||
|
||||
if ( !folder.exists() ) {
|
||||
folder.mkdirs()
|
||||
createDefault("de_DE")
|
||||
createDefault("en_US")
|
||||
}
|
||||
|
||||
folder.walk().filter { it.extension == "yml" }.forEach { file ->
|
||||
val langCode = file.nameWithoutExtension
|
||||
val config = YamlConfiguration.loadConfiguration( file )
|
||||
|
||||
val messages = config.getKeys( true )
|
||||
.filter { config.isString( it ) }
|
||||
.associateWith { config.getString( it ) }
|
||||
|
||||
languages[ langCode ] = messages as Map<String, String>
|
||||
plugin.logger.info("Sprache geladen: $langCode (${messages.size} Nachrichten)")
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDefault(
|
||||
locale: String
|
||||
) {
|
||||
val fileName = "languages/$locale.yml"
|
||||
if (plugin.getResource( fileName ) != null) {
|
||||
plugin.saveResource( fileName, false )
|
||||
}
|
||||
}
|
||||
|
||||
fun getRawMessage(
|
||||
player: Player,
|
||||
key: String
|
||||
): String
|
||||
{
|
||||
val locale = player.locale().toString()
|
||||
val langMap = languages[ locale ] ?: languages[ defaultLanguage ]
|
||||
return langMap?.get( key ) ?: "<red>Missing Key: $key</red>"
|
||||
}
|
||||
|
||||
fun getRawMessageList(
|
||||
player: Player,
|
||||
key: String
|
||||
): List<String>
|
||||
{
|
||||
var locale = player.locale().toString()
|
||||
val langMap = languages[ locale ]
|
||||
|
||||
if ( langMap == null ) {
|
||||
locale = defaultLanguage
|
||||
}
|
||||
|
||||
val file = File( plugin.dataFolder, "languages/$locale.yml" )
|
||||
val config = YamlConfiguration.loadConfiguration( file )
|
||||
return if (config.contains( key )) config.getStringList( key ) else listOf("<red>Missing List: $key</red>")
|
||||
}
|
||||
|
||||
fun getComponent(
|
||||
player: Player,
|
||||
key: String,
|
||||
placeholders: Map<String, String>
|
||||
): Component
|
||||
{
|
||||
val raw = getRawMessage( player, key )
|
||||
val tags = placeholders.map { (k, v) -> Placeholder.parsed( k, v ) }
|
||||
return miniMessage.deserialize( raw, *tags.toTypedArray() )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
package club.mcscrims.speedhg.config
|
||||
|
||||
import club.mcscrims.core.config.annotations.ConfigClass
|
||||
import club.mcscrims.core.config.annotations.ConfigField
|
||||
|
||||
@ConfigClass(
|
||||
name = "messages",
|
||||
description = "Messages configuration",
|
||||
version = "1.0"
|
||||
)
|
||||
data class MessageConfig(
|
||||
@ConfigField(name = "default", description = "Default messages")
|
||||
val defaultMessages: Map<String, String> = getDefaultMessages(),
|
||||
|
||||
@ConfigField(name = "commands", description = "Command messages")
|
||||
val commandMessages: Map<String, String> = getCommandMessages(),
|
||||
|
||||
@ConfigField(name = "death", description = "Death messages")
|
||||
val deathMessages: Map<String, List<String>> = getDeathMessages(),
|
||||
|
||||
@ConfigField(name = "kits", description = "Kit messages")
|
||||
val kitMessages: Map<String, KitConfig> = getKitMessages(),
|
||||
|
||||
@ConfigField(name = "kits-default", description = "Default kit messages")
|
||||
val defaultKitMessages: Map<String, String> = getDefaultKitMessages()
|
||||
) {
|
||||
|
||||
data class KitConfig(
|
||||
val name: String = "",
|
||||
val description: List<String>,
|
||||
val items: List<KitItemConfig>,
|
||||
val messages: Map<String, String>
|
||||
)
|
||||
|
||||
data class KitItemConfig(
|
||||
val itemName: String,
|
||||
val playStyleNames: Map<String, String>
|
||||
)
|
||||
|
||||
fun getAllMessages(): Map<String, String>
|
||||
{
|
||||
return defaultMessages + commandMessages + defaultKitMessages + kitMessages.flatMap { it.value.messages.entries }.associate { it.key to it.value }
|
||||
}
|
||||
|
||||
fun getListMessages(): Map<String, List<String>>
|
||||
{
|
||||
return deathMessages
|
||||
}
|
||||
|
||||
fun getKitItemNames(
|
||||
kit: String,
|
||||
itemKey: String
|
||||
): Map<String, String>?
|
||||
{
|
||||
return kitMessages[ kit ]?.items?.find { it.itemName == itemKey }?.playStyleNames
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun getDefaultMessages(): Map<String, String> = mapOf(
|
||||
"default.prefix" to "<gradient:dark_green:green>McScrims</gradient> <dark_gray>┃</dark_gray><reset>",
|
||||
"default.no_permission" to "%prefix% <red>You don't have permission to do that!</red>",
|
||||
"default.player_not_found" to "%prefix% <red>This player could not be found!</red>",
|
||||
"default.command_cooldown" to "%prefix% <red>Please wait {time} seconds before using this command again!</red>",
|
||||
"default.reload" to "%prefix% <green>Successfully reloaded the plugin.</green>",
|
||||
"default.only_players" to "%prefix% <red>Only players can execute this command.</red>"
|
||||
)
|
||||
|
||||
private fun getCommandMessages(): Map<String, String> = mapOf(
|
||||
"commands.unknown" to "%prefix% <red>Unknown subcommand: {unknown}</red> \n%prefix% <gray>Use /{command} for an overview.</gray>"
|
||||
)
|
||||
|
||||
private fun getDeathMessages(): Map<String, List<String>> = mapOf(
|
||||
"player" to listOf(
|
||||
"<black>☠</black> <red>{player} was killed by {killer}!</red>"
|
||||
),
|
||||
"entity" to listOf(
|
||||
"<black>☠</black> <red>{player} was killed by {entity}!</red>"
|
||||
),
|
||||
"world" to listOf(
|
||||
"<black>☠</black> <red>{player} has died!</red>"
|
||||
)
|
||||
)
|
||||
|
||||
private fun getDefaultKitMessages(): Map<String, String> = mapOf(
|
||||
"kits.missingHits" to ""
|
||||
)
|
||||
|
||||
private fun getKitMessages(): Map<String, MessageConfig.KitConfig> = mapOf(
|
||||
"anchor" to MessageConfig.KitConfig(
|
||||
name = "<dark_gray>Anchor</dark_gray>",
|
||||
description = listOf(
|
||||
"Create an anchor where",
|
||||
"you are lookin and gain no",
|
||||
"knockback in your radius."
|
||||
),
|
||||
items = listOf(MessageConfig.KitItemConfig(
|
||||
itemName = "anvil",
|
||||
playStyleNames = mapOf(
|
||||
"offensive" to "<gray>Anchor (right-click)</gray>",
|
||||
"defensive" to "<gray>Anchor (right-click)</gray>"
|
||||
)
|
||||
)),
|
||||
messages = mapOf(
|
||||
"tooFarAway" to "%prefix% <red>You can only place your anchor in a {radius} block radius!</red>",
|
||||
"alreadyActivated" to "%prefix% <red>You have already placed an anchor!</red>",
|
||||
"broken" to "%prefix% "
|
||||
)
|
||||
),
|
||||
"armorer" to MessageConfig.KitConfig(
|
||||
name = "<gray>Armorer</gray>",
|
||||
description = listOf(
|
||||
"Gain a stronger armor the",
|
||||
"more kills you gain. Every 2",
|
||||
"kills your armor gets better.",
|
||||
"All the way up to iron."
|
||||
),
|
||||
items = emptyList(),
|
||||
messages = mapOf(
|
||||
"upgrade.normal" to "%prefix% <green>Your armor has been upgraded to {armorType}.</green>",
|
||||
"upgrade.enchanted" to "%prefix% <purple>Your armor has been enchanted.</purple>"
|
||||
)
|
||||
),
|
||||
"blackpanther" to MessageConfig.KitConfig(
|
||||
name = "<gradient:purple:blue>Black Panther</gradient>",
|
||||
description = listOf(
|
||||
"Use your abilities to either",
|
||||
"do more damage and push enemies",
|
||||
"away or jump on enemies and",
|
||||
"give them instant damage."
|
||||
),
|
||||
items = listOf(
|
||||
MessageConfig.KitItemConfig(
|
||||
itemName = "blackDye",
|
||||
playStyleNames = mapOf(
|
||||
"offensive" to "<dark_gray>Push</dark_gray> <gray>(right-click)</gray>",
|
||||
"defensive" to "<purple>Wakanda Forever!</purple> <gray>(right-click)</gray>"
|
||||
)
|
||||
),
|
||||
MessageConfig.KitItemConfig(
|
||||
itemName = "blazePowder",
|
||||
playStyleNames = mapOf(
|
||||
"offensive" to "<yellow>Extra Damage</yellow> <gray>(right-click)</gray>",
|
||||
"defensive" to "<yellow>Extra Damage</yellow> <gray>(right-click)</gray>"
|
||||
)
|
||||
)
|
||||
),
|
||||
messages = mapOf(
|
||||
"wakandaForever.hit" to "%prefix% <purple>You have hit {hit} players with WAKANDA FOREVER!</purple>",
|
||||
"extraDamage.activated" to "%prefix% <green>Your extra damage is now activated.</green>",
|
||||
"extraDamage.deactivated" to "%prefix% <red>Your extra damage is now deactivated.</red>"
|
||||
)
|
||||
),
|
||||
"blitzcrank" to MessageConfig.KitConfig(
|
||||
name = "<gradient:orange:yellow>Blitzcrank</gradient>",
|
||||
description = listOf(
|
||||
"Use your abilities to",
|
||||
"slow down enemies and",
|
||||
"either stun or hook them."
|
||||
),
|
||||
items = listOf(
|
||||
MessageConfig.KitItemConfig(
|
||||
itemName = "hots",
|
||||
playStyleNames = mapOf(
|
||||
"defensive" to "<blue>Slow</blue> <gray>(right-click)</gray>",
|
||||
"offensive" to "<blue>Slow</blue> <gray>(right-click)</gray>"
|
||||
)
|
||||
),
|
||||
MessageConfig.KitItemConfig(
|
||||
itemName = "fishingrod",
|
||||
playStyleNames = mapOf(
|
||||
"defensive" to "<gold>Hook</gold> <gray>(right-click)</gray>",
|
||||
"offensive" to "<gold>Hook</gold> <gray>(right-click)</gray>"
|
||||
)
|
||||
),
|
||||
MessageConfig.KitItemConfig(
|
||||
itemName = "pufferfish",
|
||||
playStyleNames = mapOf(
|
||||
"defensive" to "<yellow>Stun</yellow> <gray>(right-click)</gray>",
|
||||
"offensive" to "<yellow>Stun</yellow> <gray>(right-click)</gray>"
|
||||
)
|
||||
)
|
||||
),
|
||||
messages = mapOf(
|
||||
"ultimate.target" to "%prefix% <yellow>You have been slowed by {player}!</yellow>",
|
||||
"ultimate.player" to "%prefix% <blue>You have slowed {nearby} players.</blue>",
|
||||
"no_player_in_sight" to "%prefix% <red>There is no player in your radius and/or sight to hook!</red>",
|
||||
"hook.player" to "%prefix% <gold>You have hooked {player}!</gold>",
|
||||
"hook.target" to "%prefix% <gold>You have been hooked to a Blitzcrank!</gold>",
|
||||
"stun.target" to "%prefix% <light_blue>You have been stunned!</light_blue>",
|
||||
"stun.player" to "%prefix% <light_blue>You have stunned {nearby} nearby players.</light_blue>"
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -1,147 +0,0 @@
|
||||
package club.mcscrims.speedhg.config
|
||||
|
||||
import club.mcscrims.core.config.DurationEntry
|
||||
import club.mcscrims.core.config.DurationType
|
||||
import club.mcscrims.core.config.annotations.ConfigClass
|
||||
import club.mcscrims.core.config.annotations.ConfigField
|
||||
import club.mcscrims.core.config.annotations.DefaultValue
|
||||
import club.mcscrims.core.network.NetworkConfig
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
|
||||
@ConfigClass(
|
||||
name = "config",
|
||||
description = "Main plugin configuration",
|
||||
version = "1.0"
|
||||
)
|
||||
data class PluginConfig(
|
||||
@ConfigField(name = "debug", description = "Enable debug mode")
|
||||
@DefaultValue("false")
|
||||
val debug: Boolean = false,
|
||||
|
||||
@ConfigField(name = "language", description = "Default player language")
|
||||
@DefaultValue("en_US")
|
||||
val language: String = "en_US",
|
||||
|
||||
@ConfigField(name = "restart_time", description = "Time after server restarts if playerList is empty")
|
||||
@DefaultValue("3")
|
||||
val restartTime: Int = 3,
|
||||
|
||||
@ConfigField(name = "network", description = "Network configuration for server communication")
|
||||
val network: NetworkConfig = NetworkConfig(),
|
||||
|
||||
@ConfigField(name = "cooldown", description = "Default cooldown for kit items")
|
||||
@DefaultValue("30")
|
||||
val cooldown: Int = 30,
|
||||
|
||||
@ConfigField(name = "needed_hits", description = "Default needed hits for kit items")
|
||||
@DefaultValue("15")
|
||||
val neededHits: Int = 15,
|
||||
|
||||
@ConfigField(name = "world", description = "World configuration")
|
||||
val world: WorldConfig = WorldConfig(),
|
||||
|
||||
@ConfigField(name = "announcement", description = "Announcement configuration")
|
||||
val announcement: Map<String, Any> = getAnnouncementConfiguration(),
|
||||
|
||||
@ConfigField(name = "game", description = "Game configuration")
|
||||
val game: GameConfig = GameConfig()
|
||||
) {
|
||||
|
||||
data class WorldConfig(
|
||||
val name: String = "Default",
|
||||
val border: Map<String, Double> = getBorderConfiguration()
|
||||
)
|
||||
|
||||
data class GameConfig(
|
||||
val name: String = "SpeedHG",
|
||||
val variantName: String = "Solo - Single Kit",
|
||||
val minimumPlayers: Int = 2,
|
||||
val competitiveGame: Boolean = false,
|
||||
val competitiveCommands: List<String> = emptyList(),
|
||||
val playerStates: Map<String, StateConfig> = getPlayerStates(),
|
||||
val recraftNerf: Map<String, Any> = getRecraftNerf(),
|
||||
val teams: Map<String, Any> = getTeams(),
|
||||
val blockedKits: List<String> = emptyList(),
|
||||
val blockedPerks: List<String> = emptyList(),
|
||||
val perks: Map<String, Any> = getPerks()
|
||||
)
|
||||
|
||||
fun isDurationIncreasing(
|
||||
entry: DurationEntry
|
||||
): Boolean
|
||||
{
|
||||
return entry.type == DurationType.INCREASING
|
||||
}
|
||||
|
||||
fun getDuration(
|
||||
playerState: String
|
||||
): DurationEntry
|
||||
{
|
||||
return (getPlayerStates()[ playerState ]?.duration as DurationEntry )
|
||||
}
|
||||
|
||||
data class StateConfig(
|
||||
val duration: Any,
|
||||
val scoreboard: String
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private fun getPlayerStates() = mapOf(
|
||||
"waiting" to PluginConfig.StateConfig(
|
||||
DurationEntry( DurationType.FIXED, -1 ),
|
||||
"Waiting - %time%"
|
||||
),
|
||||
"pre_start" to PluginConfig.StateConfig(
|
||||
DurationEntry( DurationType.FIXED, 300 ),
|
||||
"Waiting - %time%"
|
||||
),
|
||||
"immunity" to PluginConfig.StateConfig(
|
||||
DurationEntry( DurationType.FIXED, 90 ),
|
||||
"Playing - %time%"
|
||||
),
|
||||
"battle" to PluginConfig.StateConfig(
|
||||
DurationEntry( DurationType.INCREASING ),
|
||||
"Playing - %time%"
|
||||
),
|
||||
"feast" to PluginConfig.StateConfig(
|
||||
DurationEntry( DurationType.FIXED, 300 ),
|
||||
"Playing - %time%"
|
||||
),
|
||||
"deathmatch" to PluginConfig.StateConfig(
|
||||
DurationEntry( DurationType.INCREASING ),
|
||||
"Playing - %time%"
|
||||
),
|
||||
"end" to PluginConfig.StateConfig(
|
||||
DurationEntry( DurationType.FIXED, 60 ),
|
||||
"Ending - %time%"
|
||||
),
|
||||
)
|
||||
|
||||
private fun getRecraftNerf() = mapOf(
|
||||
"enabled" to false,
|
||||
"max_amount" to 64,
|
||||
"before_state" to "FEAST"
|
||||
)
|
||||
|
||||
private fun getTeams() = mapOf(
|
||||
"enabled" to false,
|
||||
"maximum_players" to 2
|
||||
)
|
||||
|
||||
private fun getPerks() = mapOf(
|
||||
"maximum_amount" to 2
|
||||
)
|
||||
|
||||
private fun getBorderConfiguration() = mapOf(
|
||||
"size" to 1000.0,
|
||||
"warning_distance" to 5.0,
|
||||
"damage" to 5.0,
|
||||
"decrease" to 100.0
|
||||
)
|
||||
|
||||
private fun getAnnouncementConfiguration() = mapOf(
|
||||
"enabled" to true,
|
||||
"after" to 10,
|
||||
"minimumPlayers" to 6
|
||||
)
|
||||
@@ -1,125 +0,0 @@
|
||||
package club.mcscrims.speedhg.database
|
||||
|
||||
import club.mcscrims.core.database.mongodb.MongoConnection
|
||||
import club.mcscrims.core.database.mongodb.MongoRepository
|
||||
import com.mongodb.client.model.Filters
|
||||
import com.mongodb.client.model.Updates
|
||||
import org.bson.codecs.pojo.annotations.BsonId
|
||||
import org.bson.codecs.pojo.annotations.BsonProperty
|
||||
import org.bson.conversions.Bson
|
||||
import org.bson.types.ObjectId
|
||||
import org.bukkit.Bukkit
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* MongoDB-Entity für einen Spieler
|
||||
*/
|
||||
data class KitPlayer(
|
||||
@BsonId
|
||||
val id: ObjectId = ObjectId(),
|
||||
|
||||
@BsonProperty
|
||||
val uuid: String,
|
||||
|
||||
@BsonProperty
|
||||
val isAlive: Boolean,
|
||||
|
||||
@BsonProperty
|
||||
val unlockedKits: List<String>,
|
||||
|
||||
@BsonProperty
|
||||
val server: String
|
||||
)
|
||||
|
||||
/**
|
||||
* MongoDB-Repository für Spieler-Daten
|
||||
*/
|
||||
class PlayerRepository(
|
||||
connection: MongoConnection
|
||||
): MongoRepository<KitPlayer>( connection, "kit_players", KitPlayer::class.java ) {
|
||||
|
||||
override fun getId(
|
||||
entity: KitPlayer
|
||||
): ObjectId
|
||||
{
|
||||
return entity.id
|
||||
}
|
||||
|
||||
override fun setId(
|
||||
entity: KitPlayer,
|
||||
id: ObjectId
|
||||
): KitPlayer
|
||||
{
|
||||
return entity.copy( id = id )
|
||||
}
|
||||
|
||||
override fun entityToUpdateDocument(
|
||||
entity: KitPlayer
|
||||
): Bson = Updates.combine(
|
||||
Updates.set("isAlive", entity.isAlive),
|
||||
Updates.set("unlockedKits", entity.unlockedKits),
|
||||
Updates.set("server", entity.server)
|
||||
)
|
||||
|
||||
/**
|
||||
* Findet einen Spieler anhand seiner UUID
|
||||
*/
|
||||
suspend fun findByUuid(
|
||||
uuid: UUID
|
||||
): KitPlayer?
|
||||
{
|
||||
val filter = Filters.eq("uuid", uuid.toString())
|
||||
return findFirst(filter)
|
||||
}
|
||||
|
||||
/**
|
||||
* Findet alle lebenden Spieler für einen Server
|
||||
*/
|
||||
suspend fun findAlivePlayers(
|
||||
server: String
|
||||
): List<KitPlayer>
|
||||
{
|
||||
val filter = Filters.and(
|
||||
Filters.eq("server", server),
|
||||
Filters.eq("isAlive", true)
|
||||
)
|
||||
return find(filter, Bukkit.getMaxPlayers())
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert den Alive-Status eines Spielers
|
||||
*/
|
||||
suspend fun updateAliveStatus(
|
||||
uuid: UUID,
|
||||
isAlive: Boolean
|
||||
) {
|
||||
val filter = Filters.eq("uuid", uuid.toString())
|
||||
val update = Updates.set("isAlive", isAlive)
|
||||
connection.updateOne(collectionName, filter, update)
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert den Server eines Spielers
|
||||
*/
|
||||
suspend fun updateServer(
|
||||
uuid: UUID,
|
||||
server: String
|
||||
) {
|
||||
val filter = Filters.eq("uuid", uuid.toString())
|
||||
val update = Updates.set("server", server)
|
||||
connection.updateOne(collectionName, filter, update)
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert die freigeschalteten Kits eines Spielers
|
||||
*/
|
||||
suspend fun updateUnlockedKits(
|
||||
uuid: UUID,
|
||||
unlockedKits: List<String>
|
||||
) {
|
||||
val filter = Filters.eq("uuid", uuid.toString())
|
||||
val update = Updates.set("unlockedKits", unlockedKits)
|
||||
connection.updateOne(collectionName, filter, update)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
package club.mcscrims.speedhg.database
|
||||
|
||||
import club.mcscrims.core.database.mongodb.MongoConnection
|
||||
import club.mcscrims.core.database.mongodb.MongoRepository
|
||||
import com.mongodb.client.model.Aggregates
|
||||
import com.mongodb.client.model.Filters
|
||||
import com.mongodb.client.model.Sorts
|
||||
import com.mongodb.client.model.Updates
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import org.bson.codecs.pojo.annotations.BsonId
|
||||
import org.bson.codecs.pojo.annotations.BsonProperty
|
||||
import org.bson.conversions.Bson
|
||||
import org.bson.types.ObjectId
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* MongoDB-Entity für die Stats von einem Spieler
|
||||
*/
|
||||
data class PlayerStats(
|
||||
@BsonId
|
||||
val id: ObjectId? = null,
|
||||
|
||||
@BsonProperty("uuid")
|
||||
val uuid: String,
|
||||
|
||||
@BsonProperty("kills")
|
||||
val kills: Int,
|
||||
|
||||
@BsonProperty("deaths")
|
||||
val deaths: Int,
|
||||
|
||||
@BsonProperty("wins")
|
||||
val wins: Int,
|
||||
|
||||
@BsonProperty("gamesPlayed")
|
||||
val gamesPlayed: Int,
|
||||
|
||||
@BsonProperty("unathleticIndex")
|
||||
val unathleticIndex: Double,
|
||||
|
||||
@BsonProperty("ironFarmed")
|
||||
val ironFarmed: Double
|
||||
)
|
||||
|
||||
/**
|
||||
* MongoDB-Repository für Stats-Daten
|
||||
*/
|
||||
class StatsRepository(
|
||||
connection: MongoConnection
|
||||
): MongoRepository<PlayerStats>( connection, "player_stats", PlayerStats::class.java ) {
|
||||
|
||||
override fun getId(
|
||||
entity: PlayerStats
|
||||
): ObjectId?
|
||||
{
|
||||
return entity.id
|
||||
}
|
||||
|
||||
override fun setId(
|
||||
entity: PlayerStats,
|
||||
id: ObjectId
|
||||
): PlayerStats
|
||||
{
|
||||
return entity.copy( id = id )
|
||||
}
|
||||
|
||||
override fun entityToUpdateDocument(
|
||||
entity: PlayerStats
|
||||
): Bson = Updates.combine(
|
||||
Updates.set( "kills", entity.kills ),
|
||||
Updates.set( "deaths", entity.deaths ),
|
||||
Updates.set( "wins", entity.wins ),
|
||||
Updates.set( "gamesPlayed", entity.gamesPlayed ),
|
||||
Updates.set( "unathleticIndex", entity.unathleticIndex ),
|
||||
Updates.set( "ironFarmed", entity.ironFarmed )
|
||||
)
|
||||
|
||||
/**
|
||||
* Findet einen Spieler anhand seiner UUID
|
||||
*/
|
||||
suspend fun findByUuid(
|
||||
uuid: UUID
|
||||
): PlayerStats?
|
||||
{
|
||||
val filter = Filters.eq( "uuid", uuid.toString() )
|
||||
return findFirst( filter )
|
||||
}
|
||||
|
||||
/**
|
||||
* Findet Top-Spieler nach Kills
|
||||
*/
|
||||
suspend fun findTopPlayersByKills(
|
||||
limit: Int = 10
|
||||
): List<PlayerStats>
|
||||
{
|
||||
return connection.getCollection( collectionName ).aggregate(listOf(
|
||||
Aggregates.sort(Sorts.descending( "kills" )),
|
||||
Aggregates.limit( limit )
|
||||
), PlayerStats::class.java ).toList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Findet Top-Spieler nach Deaths
|
||||
*/
|
||||
suspend fun findTopPlayersByDeaths(
|
||||
limit: Int = 10
|
||||
): List<PlayerStats>
|
||||
{
|
||||
return connection.getCollection( collectionName ).aggregate(listOf(
|
||||
Aggregates.sort(Sorts.ascending( "deaths" )),
|
||||
Aggregates.limit( limit )
|
||||
), PlayerStats::class.java ).toList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Findet Top-Spieler nach Wins
|
||||
*/
|
||||
suspend fun findTopPlayersByWins(
|
||||
limit: Int = 10
|
||||
): List<PlayerStats>
|
||||
{
|
||||
return connection.getCollection( collectionName ).aggregate(listOf(
|
||||
Aggregates.sort(Sorts.descending( "wins" )),
|
||||
Aggregates.limit( limit )
|
||||
), PlayerStats::class.java ).toList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt Kills zu einem Spieler hinzu
|
||||
*/
|
||||
suspend fun addKills(
|
||||
uuid: UUID,
|
||||
kills: Int
|
||||
) {
|
||||
val filter = Filters.eq( "uuid", uuid.toString() )
|
||||
val update = Updates.inc( "kills", kills )
|
||||
connection.updateOne( collectionName, filter, update )
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt Deaths zu einem Spieler hinzu
|
||||
*/
|
||||
suspend fun addDeaths(
|
||||
uuid: UUID,
|
||||
deaths: Int
|
||||
) {
|
||||
val filter = Filters.eq( "uuid", uuid.toString() )
|
||||
val update = Updates.inc( "deaths", deaths )
|
||||
connection.updateOne( collectionName, filter, update )
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt Wins zu einem Spieler hinzu
|
||||
*/
|
||||
suspend fun addWins(
|
||||
uuid: UUID,
|
||||
wins: Int
|
||||
) {
|
||||
val filter = Filters.eq( "uuid", uuid.toString() )
|
||||
val update = Updates.inc( "wins", wins )
|
||||
connection.updateOne( collectionName, filter, update )
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt Spiele zu einem Spieler hinzu
|
||||
*/
|
||||
suspend fun addGames(
|
||||
uuid: UUID,
|
||||
gamesPlayed: Int
|
||||
) {
|
||||
val filter = Filters.eq( "uuid", uuid.toString() )
|
||||
val update = Updates.inc( "gamesPlayed", gamesPlayed )
|
||||
connection.updateOne( collectionName, filter, update )
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt Unathletic-Index zu einem Spieler hinzu
|
||||
*/
|
||||
suspend fun addUnathleticIndex(
|
||||
uuid: UUID,
|
||||
unathleticIndex: Double
|
||||
) {
|
||||
val filter = Filters.eq( "uuid", uuid.toString() )
|
||||
val update = Updates.inc( "unathleticIndex", unathleticIndex )
|
||||
connection.updateOne( collectionName, filter, update )
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt Eisen zu einem Spieler hinzu
|
||||
*/
|
||||
suspend fun addIronFarmed(
|
||||
uuid: UUID,
|
||||
ironFarmed: Double
|
||||
) {
|
||||
val filter = Filters.eq( "uuid", uuid.toString() )
|
||||
val update = Updates.inc( "ironFarmed", ironFarmed )
|
||||
connection.updateOne( collectionName, filter, update )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,138 +1,370 @@
|
||||
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
|
||||
import club.mcscrims.speedhg.game.impl.WaitingState
|
||||
import org.bukkit.Location
|
||||
import club.mcscrims.speedhg.util.sendMsg
|
||||
import club.mcscrims.speedhg.util.trans
|
||||
import net.kyori.adventure.title.Title
|
||||
import org.bukkit.*
|
||||
import org.bukkit.attribute.Attribute
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.util.BoundingBox
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.event.entity.EntityDamageEvent
|
||||
import org.bukkit.event.entity.PlayerDeathEvent
|
||||
import org.bukkit.event.player.PlayerQuitEvent
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.potion.PotionEffect
|
||||
import org.bukkit.potion.PotionEffectType
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
import java.util.*
|
||||
import kotlin.random.Random
|
||||
|
||||
class GameManager(
|
||||
private val plugin: SpeedHG
|
||||
) {
|
||||
): Listener {
|
||||
|
||||
private var currentState: GameState? = null
|
||||
internal val gameStateTypes = ConcurrentHashMap<GameStateTypes, GameState>()
|
||||
var currentState: GameState = GameState.LOBBY
|
||||
private set
|
||||
|
||||
private val winners = ArrayList<Player>()
|
||||
var timer = 0
|
||||
|
||||
internal lateinit var feastLocation: Location
|
||||
internal lateinit var feastBox: BoundingBox
|
||||
internal var feastHeight: Int = 1
|
||||
val alivePlayers = mutableSetOf<UUID>()
|
||||
|
||||
fun initialize()
|
||||
private var gameTask: BukkitTask? = null
|
||||
|
||||
// Einstellungen aus Config (gecached für Performance)
|
||||
private val minPlayers = plugin.config.getInt("game.min-players", 2)
|
||||
private val lobbyTime = plugin.config.getInt("game.lobby-time", 60)
|
||||
private val invincibilityTime = plugin.config.getInt("game.invincibility-time", 60)
|
||||
private val startBorder = plugin.config.getDouble("game.border-start", 300.0)
|
||||
private val endBorder = plugin.config.getDouble("game.border-end", 20.0)
|
||||
// Zeit in Sekunden, bis Border komplett klein ist (z.B. 10 Min)
|
||||
private val borderShrinkTime = plugin.config.getLong("game.border-shrink-time", 600)
|
||||
|
||||
init {
|
||||
plugin.server.pluginManager.registerEvents( this, plugin )
|
||||
|
||||
gameTask = Bukkit.getScheduler().runTaskTimer( plugin, { ->
|
||||
gameLoop()
|
||||
}, 20L, 20L )
|
||||
}
|
||||
|
||||
private fun gameLoop()
|
||||
{
|
||||
currentState = WaitingState(
|
||||
this,
|
||||
plugin,
|
||||
plugin.schedulerManager,
|
||||
plugin.pluginConfig.data.getDuration( "waiting" ).seconds
|
||||
)
|
||||
when( currentState )
|
||||
{
|
||||
GameState.LOBBY ->
|
||||
{
|
||||
if ( Bukkit.getOnlinePlayers().size >= minPlayers )
|
||||
{
|
||||
setGameState( GameState.STARTING )
|
||||
timer = lobbyTime
|
||||
}
|
||||
}
|
||||
|
||||
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 )
|
||||
GameState.STARTING ->
|
||||
{
|
||||
if ( Bukkit.getOnlinePlayers().size < minPlayers )
|
||||
{
|
||||
setGameState( GameState.LOBBY )
|
||||
Bukkit.getOnlinePlayers().forEach { player ->
|
||||
player.sendMsg( "game.start-aborted" )
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
currentState?.onEnter( null )
|
||||
} catch ( e: Exception ) {
|
||||
plugin.logger.severe("Error during onEnter for state ${currentState?.name}: ${e.message}")
|
||||
e.printStackTrace()
|
||||
timer--
|
||||
|
||||
if (timer in listOf( 60, 30, 10, 5, 4, 3, 2, 1 ))
|
||||
{
|
||||
Bukkit.getOnlinePlayers().forEach { p ->
|
||||
p.sendMsg( "timer.lobby", "time" to timer.toString() )
|
||||
p.playSound( p.location, Sound.BLOCK_NOTE_BLOCK_HAT, 1f, 1f )
|
||||
}
|
||||
}
|
||||
|
||||
if ( timer <= 0 )
|
||||
startGame()
|
||||
}
|
||||
|
||||
GameState.INVINCIBILITY ->
|
||||
{
|
||||
timer--
|
||||
|
||||
if ( timer <= 0 )
|
||||
startFighting()
|
||||
else
|
||||
{
|
||||
Bukkit.getOnlinePlayers().forEach { p ->
|
||||
p.sendActionBar(p.trans( "timer.actionbar-invincibility", "time" to timer.toString() ))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameState.INGAME ->
|
||||
{
|
||||
timer++
|
||||
updateCompass()
|
||||
checkWin()
|
||||
}
|
||||
|
||||
GameState.ENDING ->
|
||||
{
|
||||
timer--
|
||||
|
||||
if ( timer <= 0 )
|
||||
Bukkit.shutdown()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun transitionTo(
|
||||
stateType: GameStateTypes
|
||||
fun setGameState(
|
||||
newState: GameState
|
||||
) {
|
||||
val previousState = currentState
|
||||
val nextState = gameStateTypes[ stateType ]!!
|
||||
this.currentState = newState
|
||||
}
|
||||
|
||||
try {
|
||||
currentState?.onExit( nextState )
|
||||
} catch ( e: Exception ) {
|
||||
plugin.logger.severe("Error during onExit for state ${currentState?.name}: ${e.message}")
|
||||
e.printStackTrace()
|
||||
}
|
||||
private fun startGame()
|
||||
{
|
||||
setGameState( GameState.INVINCIBILITY )
|
||||
timer = invincibilityTime
|
||||
|
||||
if ( nextState is FeastState )
|
||||
{
|
||||
feastLocation = nextState.feastLocation
|
||||
feastBox = nextState.feastBox
|
||||
feastHeight = nextState.feastHeight
|
||||
}
|
||||
val world = Bukkit.getWorld( "world" ) ?: return
|
||||
world.time = 0
|
||||
world.setStorm( false )
|
||||
|
||||
currentState = nextState
|
||||
val border = world.worldBorder
|
||||
border.center = Location( world, 0.0, 0.0, 0.0 )
|
||||
border.size = startBorder
|
||||
border.damageBuffer = 0.0
|
||||
border.damageAmount = 1.0
|
||||
|
||||
try {
|
||||
nextState.onEnter( previousState )
|
||||
} catch ( e: Exception ) {
|
||||
plugin.logger.severe("Error during onEnter for state ${nextState.name}: ${e.message}")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
val speedEffect = PotionEffect(
|
||||
PotionEffectType.SPEED,
|
||||
timer,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
)
|
||||
|
||||
fun addWinners(
|
||||
vararg winners: Player
|
||||
val hasteEffect = PotionEffect(
|
||||
PotionEffectType.HASTE,
|
||||
timer,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
)
|
||||
|
||||
alivePlayers.clear()
|
||||
Bukkit.getOnlinePlayers().forEach { player ->
|
||||
alivePlayers.add( player.uniqueId )
|
||||
|
||||
player.gameMode = GameMode.SURVIVAL
|
||||
player.health = player.getAttribute( Attribute.GENERIC_MAX_HEALTH )?.value ?: 20.0
|
||||
player.foodLevel = 20
|
||||
player.inventory.clear()
|
||||
player.activePotionEffects.forEach { player.removePotionEffect( it.type ) }
|
||||
player.addPotionEffects(listOf( speedEffect, hasteEffect ))
|
||||
|
||||
teleportRandomly( player, world, startBorder / 2 )
|
||||
|
||||
// TODO: Kit Items geben
|
||||
// plugin.kitManager.giveKit( player )
|
||||
|
||||
player.inventory.addItem(ItemStack( Material.COMPASS ))
|
||||
player.sendMsg( "game.started" )
|
||||
}
|
||||
|
||||
Bukkit.getOnlinePlayers().forEach { player ->
|
||||
player.sendMsg( "game.invincibility-start" )
|
||||
}
|
||||
}
|
||||
|
||||
private fun startFighting()
|
||||
{
|
||||
setGameState( GameState.INGAME )
|
||||
timer = 0 // Reset Timer für "Ingame"
|
||||
|
||||
val world = Bukkit.getWorld( "world" ) ?: return
|
||||
world.worldBorder.setSize( endBorder, borderShrinkTime )
|
||||
|
||||
plugin.antiRunningManager.resetTimers()
|
||||
|
||||
Bukkit.getOnlinePlayers().forEach { p ->
|
||||
p.sendMsg( "game.fighting-started" )
|
||||
p.playSound( p.location, Sound.ENTITY_ENDER_DRAGON_GROWL, 1f, 1f )
|
||||
|
||||
p.showTitle(Title.title(
|
||||
p.trans( "title.fight-main" ),
|
||||
p.trans( "title.fight-sub" )
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fun onPlayerEliminated(
|
||||
player: Player,
|
||||
killer: Player?
|
||||
) {
|
||||
winners.forEach { this.winners.add( it ) }
|
||||
if (!alivePlayers.contains( player.uniqueId )) return
|
||||
|
||||
alivePlayers.remove( player.uniqueId )
|
||||
player.gameMode = GameMode.SPECTATOR
|
||||
|
||||
player.inventory.contents.filterNotNull().forEach {
|
||||
player.world.dropItemNaturally( player.location, it )
|
||||
}
|
||||
|
||||
val msgKey = if ( killer != null ) "game.death-killed" else "game.death-pve"
|
||||
val killerName = killer?.name ?: "Environment"
|
||||
|
||||
Bukkit.getOnlinePlayers().forEach { p ->
|
||||
p.sendMsg( msgKey, "player" to player.name, "killer" to killerName, "left" to alivePlayers.size.toString() )
|
||||
}
|
||||
|
||||
checkWin()
|
||||
}
|
||||
|
||||
fun getWinners(): List<Player> = winners.toList()
|
||||
|
||||
fun getCurrentState(): GameState? = currentState
|
||||
|
||||
fun getCurrentStateType(): GameStateTypes? = gameStateTypes.filter { it.value.name == currentState?.name }.keys.firstOrNull()
|
||||
|
||||
fun isRunning(): Boolean
|
||||
private fun checkWin()
|
||||
{
|
||||
return getCurrentStateType() == GameStateTypes.IMMUNITY ||
|
||||
getCurrentStateType() == GameStateTypes.BATTLE ||
|
||||
getCurrentStateType() == GameStateTypes.FEAST ||
|
||||
getCurrentStateType() == GameStateTypes.DEATHMATCH
|
||||
if ( currentState != GameState.INGAME && currentState != GameState.INVINCIBILITY ) return
|
||||
|
||||
if ( alivePlayers.size <= 1 )
|
||||
{
|
||||
val winnerUUID = alivePlayers.firstOrNull()
|
||||
val winnerName = if ( winnerUUID != null ) Bukkit.getPlayer( winnerUUID )?.name ?: "N/A" else "N/A"
|
||||
endGame( winnerName )
|
||||
}
|
||||
}
|
||||
|
||||
fun isBeforeFeast(): Boolean
|
||||
{
|
||||
return getCurrentStateType() == GameStateTypes.WAITING ||
|
||||
getCurrentStateType() == GameStateTypes.PRE_START ||
|
||||
getCurrentStateType() == GameStateTypes.IMMUNITY ||
|
||||
(getCurrentStateType() == GameStateTypes.BATTLE &&
|
||||
!( currentState as BattleState ).afterFeast )
|
||||
private fun endGame(
|
||||
winnerName: String
|
||||
) {
|
||||
setGameState( GameState.ENDING )
|
||||
timer = 15
|
||||
|
||||
Bukkit.getOnlinePlayers().forEach { p ->
|
||||
p.showTitle(Title.title(
|
||||
p.trans( "title.win-main", "winner" to winnerName ),
|
||||
p.trans( "title.win-sub" )
|
||||
))
|
||||
p.sendMsg( "game.win-chat", "winner" to winnerName )
|
||||
}
|
||||
}
|
||||
|
||||
fun isBefore(
|
||||
stateType: GameStateTypes
|
||||
): Boolean
|
||||
{
|
||||
return getCurrentStateType()?.points!! < stateType.points
|
||||
// --- Helfer Methoden ---
|
||||
|
||||
private fun teleportRandomly(
|
||||
player: Player,
|
||||
world: World,
|
||||
maxRadius: Double
|
||||
) {
|
||||
var loc: Location
|
||||
var safe = false
|
||||
var attempts = 0
|
||||
|
||||
do {
|
||||
val x = Random.nextDouble( -maxRadius, maxRadius )
|
||||
val z = Random.nextDouble( -maxRadius, maxRadius )
|
||||
val y = world.getHighestBlockYAt( x.toInt(), z.toInt() ) + 1.0
|
||||
loc = Location( world, x, y, z )
|
||||
|
||||
val block = loc.block.type
|
||||
val below = loc.subtract( 0.0, 1.0, 0.0 ).block.type
|
||||
|
||||
if ( below.isSolid && below != Material.LAVA && below != Material.CACTUS && block == Material.AIR )
|
||||
safe = true
|
||||
attempts++
|
||||
} while ( !safe && attempts < 20 )
|
||||
|
||||
player.teleport(loc.add( 0.0, 1.0, 0.0 ))
|
||||
}
|
||||
|
||||
fun shutdown()
|
||||
private fun updateCompass()
|
||||
{
|
||||
currentState?.onExit( null )
|
||||
currentState = null
|
||||
}
|
||||
val players = Bukkit.getOnlinePlayers().filter { alivePlayers.contains( it.uniqueId ) }
|
||||
|
||||
for ( p in players )
|
||||
{
|
||||
var nearest: Player? = null
|
||||
var minDistance = Double.MAX_VALUE
|
||||
|
||||
for ( target in players )
|
||||
{
|
||||
if ( p == target ) continue
|
||||
|
||||
val dist = p.location.distanceSquared( target.location )
|
||||
if ( dist < minDistance )
|
||||
{
|
||||
minDistance = dist
|
||||
nearest = target
|
||||
}
|
||||
}
|
||||
|
||||
if ( nearest != null )
|
||||
p.compassTarget = nearest.location
|
||||
else
|
||||
p.compassTarget = p.world.spawnLocation
|
||||
}
|
||||
}
|
||||
|
||||
// --- Event Listener Integration ---
|
||||
|
||||
@EventHandler
|
||||
fun onDeath(
|
||||
event: PlayerDeathEvent
|
||||
) {
|
||||
if ( currentState == GameState.INGAME || currentState == GameState.INVINCIBILITY )
|
||||
{
|
||||
event.deathMessage( null )
|
||||
event.drops.clear()
|
||||
|
||||
Bukkit.getScheduler().runTask( plugin ) { ->
|
||||
event.entity.spigot().respawn()
|
||||
}
|
||||
|
||||
onPlayerEliminated( event.entity, event.entity.killer )
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onQuit(
|
||||
event: PlayerQuitEvent
|
||||
) {
|
||||
if (alivePlayers.contains( event.player.uniqueId ))
|
||||
{
|
||||
if ( currentState == GameState.INGAME || currentState == GameState.INVINCIBILITY )
|
||||
{
|
||||
val lastDamageCause = event.player.lastDamageCause
|
||||
|
||||
if ( lastDamageCause != null && lastDamageCause is EntityDamageByEntityEvent )
|
||||
{
|
||||
val attacker = lastDamageCause.damager
|
||||
|
||||
if ( attacker is Player )
|
||||
{
|
||||
onPlayerEliminated( event.player, attacker )
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
onPlayerEliminated( event.player, null ) // PVE Tod
|
||||
}
|
||||
else alivePlayers.remove( event.player.uniqueId )
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onDamage(
|
||||
event: EntityDamageEvent
|
||||
) {
|
||||
if ( currentState == GameState.INVINCIBILITY && event.entity is Player )
|
||||
event.isCancelled = true
|
||||
|
||||
if ( currentState == GameState.LOBBY || currentState == GameState.STARTING || currentState == GameState.ENDING )
|
||||
event.isCancelled = true // Nie Schaden in Lobby/Ende
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum class GameStateTypes(
|
||||
val points: Int
|
||||
) {
|
||||
WAITING( 0 ),
|
||||
PRE_START( 1 ),
|
||||
IMMUNITY( 2 ),
|
||||
BATTLE( 3 ),
|
||||
FEAST( 4 ),
|
||||
DEATHMATCH( 5 ),
|
||||
END( 6 )
|
||||
}
|
||||
|
||||
@@ -1,109 +1,9 @@
|
||||
package club.mcscrims.speedhg.game
|
||||
|
||||
import club.mcscrims.core.config.DurationType
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.spigot.scheduler.SchedulerManager
|
||||
import club.mcscrims.spigot.scheduler.TaskRegistration
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
|
||||
abstract class GameState(
|
||||
val name: String,
|
||||
protected val gameManager: GameManager,
|
||||
protected val plugin: SpeedHG,
|
||||
protected val schedulerManager: SchedulerManager,
|
||||
protected val durationSeconds: Int? = null
|
||||
) {
|
||||
|
||||
private var tickTask: BukkitTask? = null
|
||||
private var remainingSeconds: Int = durationSeconds ?: 0
|
||||
private var isActive: Boolean = false
|
||||
|
||||
open fun onEnter(
|
||||
previous: GameState?
|
||||
) {
|
||||
isActive = true
|
||||
remainingSeconds = durationSeconds ?: 0
|
||||
|
||||
if ( durationSeconds != null )
|
||||
startTicking()
|
||||
}
|
||||
|
||||
abstract fun onTick()
|
||||
|
||||
abstract fun onEndOfDuration()
|
||||
|
||||
open fun onExit(
|
||||
next: GameState?
|
||||
) {
|
||||
isActive = false
|
||||
stopTicking()
|
||||
}
|
||||
|
||||
private fun startTicking()
|
||||
{
|
||||
tickTask = Bukkit.getScheduler().runTaskTimer( plugin, { ->
|
||||
if ( !isActive )
|
||||
{
|
||||
stopTicking()
|
||||
return@runTaskTimer
|
||||
}
|
||||
|
||||
try {
|
||||
onTick()
|
||||
} catch ( e: Exception ) {
|
||||
plugin.logger.severe("Error during onTick for state $name: ${e.message}")
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
if ( durationSeconds != null && remainingSeconds > 0 )
|
||||
{
|
||||
if (plugin.pluginConfig.data.getDuration( name ).type == DurationType.INCREASING )
|
||||
{
|
||||
remainingSeconds++
|
||||
return@runTaskTimer
|
||||
}
|
||||
|
||||
remainingSeconds--
|
||||
|
||||
if ( remainingSeconds == 0)
|
||||
try {
|
||||
onEndOfDuration()
|
||||
} catch ( e: Exception ) {
|
||||
plugin.logger.severe("Error during onEndOfDuration for state $name: ${e.message}")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}, 20L, 20L )
|
||||
}
|
||||
|
||||
private fun stopTicking() {
|
||||
tickTask?.cancel()
|
||||
tickTask = null
|
||||
}
|
||||
|
||||
protected fun broadcast(
|
||||
messageKey: String,
|
||||
vararg placeholders: Pair<String, String>
|
||||
) {
|
||||
plugin.chatManager.broadcast( messageKey, *placeholders )
|
||||
}
|
||||
|
||||
protected fun forAlivePlayers(
|
||||
action: (Player) -> Unit
|
||||
) {
|
||||
Bukkit.getOnlinePlayers()
|
||||
.filter { !it.isDead }
|
||||
.forEach { player ->
|
||||
try {
|
||||
action( player )
|
||||
} catch ( e: Exception ) {
|
||||
plugin.logger.warning("Error executing action for player ${player.name}: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getRemainingSeconds(): Int = remainingSeconds
|
||||
|
||||
enum class GameState {
|
||||
LOBBY, // Warten auf Spieler
|
||||
STARTING, // Countdown läuft
|
||||
INVINCIBILITY, // Schutzzeit (Spieler verteilt, kein Schaden)
|
||||
INGAME, // Kampfphase (Schaden an, Border schrumpft)
|
||||
ENDING // Gewinner steht fest, Server startet neu
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
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.spigot.scheduler.SchedulerManager
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class BattleState(
|
||||
gameManager: GameManager,
|
||||
plugin: SpeedHG,
|
||||
schedulerManager: SchedulerManager,
|
||||
durationSeconds: Int? = null
|
||||
) : GameState( "battle", gameManager, plugin, schedulerManager, durationSeconds ) {
|
||||
|
||||
var afterFeast: Boolean = false
|
||||
|
||||
override fun onEnter(
|
||||
previous: GameState?
|
||||
) {
|
||||
super.onEnter( previous )
|
||||
Bukkit.getOnlinePlayers().forEach( Player::clearActivePotionEffects )
|
||||
}
|
||||
|
||||
override fun onTick()
|
||||
{
|
||||
val win = checkForWinners()
|
||||
|
||||
when( getRemainingSeconds() )
|
||||
{
|
||||
300 ->
|
||||
{
|
||||
gameManager.gameStateTypes[ GameStateTypes.BATTLE ] = this
|
||||
gameManager.transitionTo( GameStateTypes.FEAST )
|
||||
afterFeast = true
|
||||
}
|
||||
|
||||
1800 ->
|
||||
{
|
||||
if ( !win )
|
||||
{
|
||||
gameManager.transitionTo( GameStateTypes.DEATHMATCH )
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onEndOfDuration() {}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
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( getRemainingSeconds() )
|
||||
{
|
||||
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 )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
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()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,209 +0,0 @@
|
||||
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.*
|
||||
|
||||
class FeastState(
|
||||
gameManager: GameManager,
|
||||
plugin: SpeedHG,
|
||||
schedulerManager: SchedulerManager,
|
||||
durationSeconds: Int? = null
|
||||
) : GameState( "feast", gameManager, plugin, schedulerManager, durationSeconds ) {
|
||||
|
||||
private val world = plugin.worldManager.getWorld()
|
||||
private val random = Random()
|
||||
|
||||
internal var feastLocation: Location
|
||||
internal 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()
|
||||
{
|
||||
when( getRemainingSeconds() )
|
||||
{
|
||||
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()
|
||||
{
|
||||
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<Location>( 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<ItemStack>()
|
||||
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<ItemStack>()
|
||||
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<ItemStack>()
|
||||
netheriteItems.add( 1.0, ItemStack( Material.NETHERITE_INGOT ))
|
||||
netheriteItems.add( 1.0, ItemStack( Material.SMITHING_TABLE ))
|
||||
|
||||
val sizeableItems = RandomCollection<ItemStack>()
|
||||
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<ItemStack>()
|
||||
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<RandomCollection<ItemStack>>()
|
||||
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() )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
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.Material
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.potion.PotionEffect
|
||||
import org.bukkit.potion.PotionEffectType
|
||||
|
||||
class ImmunityState(
|
||||
gameManager: GameManager,
|
||||
plugin: SpeedHG,
|
||||
schedulerManager: SchedulerManager,
|
||||
durationSeconds: Int? = null
|
||||
) : GameState( "immunity", gameManager, plugin, schedulerManager, durationSeconds ) {
|
||||
|
||||
override fun onEnter(
|
||||
previous: GameState?
|
||||
) {
|
||||
super.onEnter( previous )
|
||||
|
||||
val effects = listOf(
|
||||
PotionEffect( PotionEffectType.HASTE, durationSeconds?.times( 20 ) ?: 0, 0 ),
|
||||
PotionEffect( PotionEffectType.SPEED, durationSeconds?.times( 20 ) ?: 0, 0 )
|
||||
)
|
||||
|
||||
val players = Bukkit.getOnlinePlayers()
|
||||
players.forEach { it.addPotionEffects( effects ) }
|
||||
|
||||
for ( player in players )
|
||||
{
|
||||
player.inventory.clear()
|
||||
player.inventory.armorContents = emptyArray()
|
||||
|
||||
player.inventory.setItem( 8, ItemStack( Material.COMPASS ))
|
||||
|
||||
plugin.kitManager.startKitForPlayer( player )
|
||||
TODO( "Give perks" )
|
||||
}
|
||||
|
||||
broadcast( "gameStates.immunity.warnings.butterfly" )
|
||||
}
|
||||
|
||||
override fun onTick()
|
||||
{
|
||||
when( getRemainingSeconds() )
|
||||
{
|
||||
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()
|
||||
{
|
||||
broadcast( "gameStates.immunity.ended" )
|
||||
gameManager.transitionTo( GameStateTypes.BATTLE )
|
||||
}
|
||||
|
||||
private fun announce(
|
||||
type: AnnouncementType,
|
||||
time: Int
|
||||
) {
|
||||
val arg = if ( type == AnnouncementType.MINUTES ) "M" else "S"
|
||||
broadcast( "gameStates.immunity.ending$arg", "{time}" to time.toString() )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
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.spigot.scheduler.SchedulerManager
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Location
|
||||
|
||||
class PreStartState(
|
||||
gameManager: GameManager,
|
||||
plugin: SpeedHG,
|
||||
schedulerManager: SchedulerManager,
|
||||
durationSeconds: Int? = null
|
||||
) : GameState( "pre_start", gameManager, plugin, schedulerManager, durationSeconds ) {
|
||||
|
||||
private lateinit var previous: GameState
|
||||
|
||||
override fun onEnter(
|
||||
previous: GameState?
|
||||
) {
|
||||
super.onEnter( previous )
|
||||
|
||||
if ( previous != null )
|
||||
this.previous = previous
|
||||
}
|
||||
|
||||
var isStarting: Boolean = false
|
||||
|
||||
override fun onTick()
|
||||
{
|
||||
val playerSize = Bukkit.getOnlinePlayers().size
|
||||
|
||||
if ( playerSize < plugin.pluginConfig.data.game.minimumPlayers )
|
||||
{
|
||||
isStarting = false
|
||||
gameManager.transitionTo( GameStateTypes.WAITING )
|
||||
}
|
||||
else isStarting = true
|
||||
|
||||
if ( !isStarting )
|
||||
return
|
||||
|
||||
if ( getRemainingSeconds() == 15 )
|
||||
teleport()
|
||||
|
||||
when( getRemainingSeconds() )
|
||||
{
|
||||
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()
|
||||
{
|
||||
broadcast( "gameStates.preStart.started" )
|
||||
isStarting = false
|
||||
gameManager.transitionTo( GameStateTypes.IMMUNITY )
|
||||
}
|
||||
|
||||
override fun onExit(
|
||||
next: GameState?
|
||||
) {
|
||||
super.onExit( next )
|
||||
Bukkit.getOnlinePlayers().forEach { it.inventory.clear() }
|
||||
}
|
||||
|
||||
private fun announce(
|
||||
type: AnnouncementType,
|
||||
time: Int
|
||||
) {
|
||||
val arg = if ( type == AnnouncementType.MINUTES ) "M" else "S"
|
||||
broadcast( "gameStates.preStart.starting$arg", "{time}" to time.toString() )
|
||||
}
|
||||
|
||||
private fun teleport()
|
||||
{
|
||||
for ( player in Bukkit.getOnlinePlayers() )
|
||||
{
|
||||
val world = player.world
|
||||
val loc = Location( world, 0.0, world.getHighestBlockYAt( 0, 0 ).toDouble(), 0.0 )
|
||||
player.teleport( loc )
|
||||
}
|
||||
}
|
||||
|
||||
internal enum class AnnouncementType {
|
||||
MINUTES, SECONDS
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
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.spigot.scheduler.SchedulerManager
|
||||
import org.bukkit.Bukkit
|
||||
|
||||
class WaitingState(
|
||||
gameManager: GameManager,
|
||||
plugin: SpeedHG,
|
||||
schedulerManager: SchedulerManager,
|
||||
durationSeconds: Int? = null
|
||||
) : GameState( "waiting", gameManager, plugin, schedulerManager, durationSeconds ) {
|
||||
|
||||
private var secondsCounter: Int = 0
|
||||
|
||||
override fun onTick()
|
||||
{
|
||||
val playerSize = Bukkit.getOnlinePlayers().size
|
||||
|
||||
if ( playerSize < plugin.pluginConfig.data.game.minimumPlayers )
|
||||
if ( secondsCounter == 15 )
|
||||
{
|
||||
broadcast( "gameStates.waiting.awaiting_players", "{min_players}" to plugin.pluginConfig.data.game.minimumPlayers.toString() )
|
||||
secondsCounter = 0
|
||||
}
|
||||
else secondsCounter++
|
||||
else gameManager.transitionTo( GameStateTypes.PRE_START )
|
||||
}
|
||||
|
||||
override fun onEndOfDuration() {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package club.mcscrims.speedhg.game.modules
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.speedhg.game.GameState
|
||||
import club.mcscrims.speedhg.util.sendMsg
|
||||
import club.mcscrims.speedhg.util.trans
|
||||
import net.kyori.adventure.bossbar.BossBar
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.GameMode
|
||||
import org.bukkit.Sound
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.potion.PotionEffect
|
||||
import org.bukkit.potion.PotionEffectType
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.math.abs
|
||||
|
||||
class AntiRunningManager(
|
||||
private val plugin: SpeedHG
|
||||
): Listener
|
||||
{
|
||||
|
||||
private val lastCombatAction = ConcurrentHashMap<UUID, Long>()
|
||||
|
||||
private val warningBar = BossBar.bossBar(
|
||||
Component.text("FIGHT!"),
|
||||
1.0f,
|
||||
BossBar.Color.RED,
|
||||
BossBar.Overlay.PROGRESS
|
||||
)
|
||||
|
||||
init {
|
||||
Bukkit.getScheduler().runTaskTimer( plugin, { ->
|
||||
checkPlayers()
|
||||
}, 20L, 20L )
|
||||
|
||||
plugin.server.pluginManager.registerEvents( this, plugin )
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onDamage(
|
||||
event: EntityDamageByEntityEvent
|
||||
) {
|
||||
if (plugin.gameManager.currentState != GameState.INGAME)
|
||||
return
|
||||
|
||||
val victim = event.entity
|
||||
val attacker = event.damager
|
||||
|
||||
if ( victim is Player && attacker is Player)
|
||||
{
|
||||
val now = System.currentTimeMillis()
|
||||
lastCombatAction[ victim.uniqueId ] = now
|
||||
lastCombatAction[ attacker.uniqueId ] = now
|
||||
|
||||
removePunishment( victim )
|
||||
removePunishment( attacker )
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkPlayers()
|
||||
{
|
||||
if (plugin.gameManager.currentState != GameState.INGAME)
|
||||
return
|
||||
|
||||
val config = plugin.config.getConfigurationSection( "anti-runner" ) ?: return
|
||||
if (!config.getBoolean( "enabled" )) return
|
||||
|
||||
val radius = config.getDouble( "check-radius" )
|
||||
val maxYDiff = config.getDouble( "ignore-vertical-distance", 15.0 )
|
||||
val ignoreCaveMix = config.getBoolean( "ignore-cave-surface-mix", true )
|
||||
|
||||
val warnTime = config.getLong( "warn-time" ) * 1000
|
||||
val punishTime = config.getLong( "punish-time" ) * 1000
|
||||
|
||||
val players = Bukkit.getOnlinePlayers().filter { it.gameMode == GameMode.SURVIVAL }
|
||||
|
||||
for ( player in players )
|
||||
{
|
||||
val nearbyEnemy = players
|
||||
.filter { other ->
|
||||
other != player &&
|
||||
other.world == player.world &&
|
||||
other.location.distanceSquared( player.location ) <= ( radius * radius )
|
||||
}
|
||||
.minByOrNull { it.location.distanceSquared( player.location ) }
|
||||
|
||||
if ( nearbyEnemy == null )
|
||||
{
|
||||
resetPlayerTimer( player )
|
||||
continue
|
||||
}
|
||||
|
||||
val yDiff = abs(player.location.y - nearbyEnemy.location.y)
|
||||
|
||||
if ( yDiff > maxYDiff )
|
||||
{
|
||||
resetPlayerTimer( player )
|
||||
continue
|
||||
}
|
||||
|
||||
if ( ignoreCaveMix && player.world.isDayTime )
|
||||
{
|
||||
val lightA = player.location.block.lightFromSky
|
||||
val lightB = nearbyEnemy.location.block.lightFromSky
|
||||
|
||||
val isPlayerOutside = lightA > 12
|
||||
val isEnemyInCave = lightB < 4
|
||||
|
||||
val isPlayerInCave = lightA < 4
|
||||
val isEnemyOutside = lightB > 12
|
||||
|
||||
if (( isPlayerOutside && isEnemyInCave ) || ( isPlayerInCave && isEnemyOutside ))
|
||||
{
|
||||
resetPlayerTimer( player )
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
val lastCombat = lastCombatAction.getOrDefault( player.uniqueId, System.currentTimeMillis() )
|
||||
val timeDiff = System.currentTimeMillis() - lastCombat
|
||||
|
||||
if ( timeDiff > warnTime )
|
||||
player.showBossBar(warningBar.name(player.trans( "antirunner.warning" )))
|
||||
else
|
||||
player.hideBossBar( warningBar )
|
||||
|
||||
if ( timeDiff > punishTime )
|
||||
applyPunishment( player )
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyPunishment(
|
||||
player: Player
|
||||
) {
|
||||
player.addPotionEffect(
|
||||
PotionEffect(
|
||||
/* type = */ PotionEffectType.SLOWNESS,
|
||||
/* duration = */ 60,
|
||||
/* amplifier = */ 2,
|
||||
/* ambient = */ false,
|
||||
/* particles = */ false,
|
||||
/* icon = */ true
|
||||
)
|
||||
)
|
||||
|
||||
player.addPotionEffect(
|
||||
PotionEffect(
|
||||
/* type = */ PotionEffectType.GLOWING,
|
||||
/* duration = */ 60,
|
||||
/* amplifier = */ 0,
|
||||
/* ambient = */ false,
|
||||
/* particles = */ false,
|
||||
/* icon = */ false
|
||||
)
|
||||
)
|
||||
|
||||
if (!player.hasPotionEffect( PotionEffectType.GLOWING ))
|
||||
{
|
||||
player.sendMsg( "antirunner.punish" )
|
||||
player.playSound( player.location, Sound.ENTITY_ZOMBIE_VILLAGER_CURE, 1f, 0.5f )
|
||||
}
|
||||
}
|
||||
|
||||
private fun removePunishment(
|
||||
player: Player
|
||||
) {
|
||||
player.removePotionEffect( PotionEffectType.SLOWNESS )
|
||||
player.removePotionEffect( PotionEffectType.GLOWING )
|
||||
player.hideBossBar( warningBar )
|
||||
|
||||
lastCombatAction[ player.uniqueId ] = System.currentTimeMillis()
|
||||
}
|
||||
|
||||
private fun resetPlayerTimer(
|
||||
player: Player
|
||||
) {
|
||||
lastCombatAction[ player.uniqueId ] = System.currentTimeMillis()
|
||||
player.hideBossBar( warningBar )
|
||||
|
||||
if (player.hasPotionEffect( PotionEffectType.GLOWING ))
|
||||
removePunishment( player )
|
||||
}
|
||||
|
||||
fun resetTimers()
|
||||
{
|
||||
val now = System.currentTimeMillis()
|
||||
|
||||
Bukkit.getOnlinePlayers()
|
||||
.filter { it.gameMode == GameMode.SURVIVAL }
|
||||
.forEach {
|
||||
lastCombatAction[ it.uniqueId ] = now
|
||||
it.hideBossBar( warningBar )
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
package club.mcscrims.speedhg.kit
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.speedhg.ability.AbilityContext
|
||||
import club.mcscrims.speedhg.ability.AbilityResult
|
||||
import club.mcscrims.speedhg.game.GameManager
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.event.player.PlayerMoveEvent
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
abstract class AbstractKit(
|
||||
val id: String,
|
||||
val displayName: Component,
|
||||
val description: List<Component>,
|
||||
val icon: Material,
|
||||
val playStyle: PlayStyle,
|
||||
protected val plugin: SpeedHG,
|
||||
protected val abilityContext: AbilityContext,
|
||||
protected val gameManager: GameManager
|
||||
) {
|
||||
|
||||
lateinit var config: Map<String, Double>
|
||||
val items = mutableListOf<ItemStack>()
|
||||
|
||||
abstract fun onSelect( player: Player )
|
||||
|
||||
abstract fun onStart( player: Player )
|
||||
|
||||
abstract fun onHit( attacker: Player, victim: Player, event: EntityDamageByEntityEvent )
|
||||
|
||||
abstract fun onDamaged( attacker: Player, victim: Player, event: EntityDamageByEntityEvent )
|
||||
|
||||
abstract fun onInteract( player: Player, event: PlayerInteractEvent )
|
||||
|
||||
abstract fun onMove( player: Player, event: PlayerMoveEvent )
|
||||
|
||||
open fun cleanup(
|
||||
player: Player
|
||||
) {
|
||||
abilityContext.clearPlayerData( player )
|
||||
}
|
||||
|
||||
protected fun hasCooldown(
|
||||
player: Player,
|
||||
key: String
|
||||
): Boolean
|
||||
{
|
||||
return abilityContext.getRemainingCooldown( player, key ) > 0
|
||||
}
|
||||
|
||||
protected fun startCooldown(
|
||||
player: Player,
|
||||
key: String,
|
||||
seconds: Int
|
||||
) {
|
||||
abilityContext.cooldownManager.startCooldown( player, key, seconds )
|
||||
}
|
||||
|
||||
protected fun getRemainingCooldown(
|
||||
player: Player,
|
||||
key: String
|
||||
): Double
|
||||
{
|
||||
return abilityContext.getRemainingCooldown( player, key )
|
||||
}
|
||||
|
||||
protected fun getHits(
|
||||
player: Player,
|
||||
key: String
|
||||
): Int
|
||||
{
|
||||
return abilityContext.getHits(player, key)
|
||||
}
|
||||
|
||||
protected fun resetHits(
|
||||
player: Player,
|
||||
key: String
|
||||
) {
|
||||
abilityContext.hitCounterManager.resetHits( player, key )
|
||||
}
|
||||
|
||||
protected fun abilityResult(
|
||||
player: Player,
|
||||
abilityKey: String,
|
||||
requiredHits: Int? = null,
|
||||
cooldownSeconds: Int? = null
|
||||
): AbilityResult {
|
||||
return abilityContext.canUseAbility( player, abilityKey, requiredHits, cooldownSeconds )
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum class PlayStyle {
|
||||
OFFENSIVE, DEFENSIVE
|
||||
}
|
||||
|
||||
enum class KitMetaData {
|
||||
IN_GLADIATOR,
|
||||
GLADIATOR_BLOCK,
|
||||
IS_ANVIL,
|
||||
IS_BLACK_PANTHER,
|
||||
BP_EXTRA_DAMAGE,
|
||||
VOODOO_HOLD,
|
||||
ICEMAGE_SNOWBALL,
|
||||
ICEMAGE_SPEED;
|
||||
|
||||
fun getKey(): String
|
||||
{
|
||||
return name
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package club.mcscrims.speedhg.kit
|
||||
|
||||
import org.bukkit.inventory.Inventory
|
||||
import org.bukkit.inventory.InventoryHolder
|
||||
|
||||
class KitInventoryHolder(
|
||||
val page: Int
|
||||
) : InventoryHolder {
|
||||
|
||||
private lateinit var inventory: Inventory
|
||||
|
||||
override fun getInventory(): Inventory = inventory
|
||||
|
||||
fun setInventory(
|
||||
inventory: Inventory
|
||||
) {
|
||||
this.inventory = inventory
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package club.mcscrims.speedhg.kit
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.speedhg.SpeedHG.Companion.content
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.Sound
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.inventory.InventoryClickEvent
|
||||
import org.bukkit.event.inventory.InventoryDragEvent
|
||||
|
||||
class KitInventoryListener(
|
||||
private val plugin: SpeedHG,
|
||||
private val kitManager: KitManager,
|
||||
private val kitInventoryManager: KitInventoryManager
|
||||
) : Listener {
|
||||
|
||||
@EventHandler
|
||||
fun onInventoryClick(
|
||||
event: InventoryClickEvent
|
||||
) {
|
||||
val holder = event.inventory.holder
|
||||
|
||||
if ( holder !is KitInventoryHolder )
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
|
||||
val player = event.whoClicked as? Player ?: return
|
||||
val clickedItem = event.currentItem ?: return
|
||||
|
||||
if ( clickedItem.type == Material.AIR )
|
||||
return
|
||||
|
||||
when( event.rawSlot )
|
||||
{
|
||||
45 -> {
|
||||
if ( holder.page > 1 )
|
||||
{
|
||||
player.playSound( player.location, Sound.UI_BUTTON_CLICK, 1f, 1f )
|
||||
kitInventoryManager.openKitInventory( player, holder.page - 1 )
|
||||
}
|
||||
}
|
||||
49 -> {
|
||||
player.playSound( player.location, Sound.UI_BUTTON_CLICK, 1f, 0.8f )
|
||||
player.closeInventory()
|
||||
}
|
||||
53 -> {
|
||||
val totalKits = kitManager.getAllKits().size
|
||||
val totalPages = ( totalKits + 27 ) / 28
|
||||
if ( holder.page < totalPages )
|
||||
{
|
||||
player.playSound( player.location, Sound.UI_BUTTON_CLICK, 1f, 1f )
|
||||
kitInventoryManager.openKitInventory( player, holder.page + 1 )
|
||||
}
|
||||
}
|
||||
in 10..43 -> {
|
||||
val allKits = kitManager.getAllKits().toList()
|
||||
val startIndex = ( holder.page - 1 ) * 28
|
||||
val endIndex = ( startIndex + 28 ).coerceAtMost( allKits.size )
|
||||
val kitsOnPage = allKits.subList( startIndex, endIndex )
|
||||
|
||||
val kitSlots = listOf(
|
||||
10, 11, 12, 13, 14, 15, 16,
|
||||
19, 20, 21, 22, 23, 24, 25,
|
||||
28, 29, 30, 31, 32, 33, 34,
|
||||
37, 38, 39, 40, 41, 42, 43
|
||||
)
|
||||
|
||||
val slotIndex = kitSlots.indexOf( event.rawSlot )
|
||||
if ( slotIndex != -1 && slotIndex < kitsOnPage.size )
|
||||
{
|
||||
val selectedKit = kitsOnPage[slotIndex]
|
||||
|
||||
if (kitManager.selectKit( player, selectedKit.id ))
|
||||
{
|
||||
player.playSound( player.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1f, 1.2f )
|
||||
plugin.chatManager.sendMessage(
|
||||
player,
|
||||
"kits.selected",
|
||||
"{kit}" to selectedKit.displayName.content()
|
||||
)
|
||||
kitInventoryManager.openKitInventory( player, holder.page )
|
||||
} else {
|
||||
player.playSound( player.location, Sound.ENTITY_VILLAGER_NO, 1f, 1f )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onInventoryDrag(
|
||||
event: InventoryDragEvent
|
||||
) {
|
||||
val holder = event.inventory.holder
|
||||
|
||||
if ( holder is KitInventoryHolder )
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
package club.mcscrims.speedhg.kit
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.kyori.adventure.text.Component
|
||||
import net.kyori.adventure.text.format.NamedTextColor
|
||||
import net.kyori.adventure.text.format.TextDecoration
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.enchantments.Enchantment
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemFlag
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
class KitInventoryManager(
|
||||
private val plugin: SpeedHG,
|
||||
private val kitManager: KitManager
|
||||
) {
|
||||
|
||||
private val kitsPerPage = 28
|
||||
private val rows = 6
|
||||
|
||||
fun openKitInventory(
|
||||
player: Player,
|
||||
page: Int = 1
|
||||
) {
|
||||
val allKits = kitManager.getAllKits().toList()
|
||||
val totalPages = ( allKits.size + kitsPerPage - 1 ) / kitsPerPage
|
||||
val validPage = page.coerceIn( 1, totalPages.coerceAtLeast( 1 ))
|
||||
|
||||
val holder = KitInventoryHolder( validPage )
|
||||
val title = Component.text("Kits - Page $validPage/$totalPages")
|
||||
.color( NamedTextColor.DARK_PURPLE )
|
||||
.decoration( TextDecoration.BOLD, true )
|
||||
|
||||
val inventory = Bukkit.createInventory( holder, rows * 9, title )
|
||||
holder.setInventory( inventory )
|
||||
|
||||
fillBorder( inventory )
|
||||
fillKits( inventory, allKits, validPage, player )
|
||||
fillNavigationItems( inventory, validPage, totalPages )
|
||||
|
||||
player.openInventory( inventory )
|
||||
}
|
||||
|
||||
private fun fillBorder(
|
||||
inventory: org.bukkit.inventory.Inventory
|
||||
) {
|
||||
val borderItem = createBorderItem()
|
||||
|
||||
for ( i in 0..8 )
|
||||
inventory.setItem( i, borderItem )
|
||||
|
||||
for ( i in 45..53 )
|
||||
inventory.setItem( i, borderItem )
|
||||
}
|
||||
|
||||
private fun fillKits(
|
||||
inventory: org.bukkit.inventory.Inventory,
|
||||
allKits: List<AbstractKit>,
|
||||
page: Int,
|
||||
player: Player
|
||||
) {
|
||||
val startIndex = ( page - 1 ) * kitsPerPage
|
||||
val endIndex = ( startIndex + kitsPerPage ).coerceAtMost( allKits.size )
|
||||
val kitsOnPage = allKits.subList( startIndex, endIndex )
|
||||
|
||||
val selectedKit = kitManager.getSelectedKit( player )
|
||||
|
||||
val kitSlots = listOf(
|
||||
10, 11, 12, 13, 14, 15, 16,
|
||||
19, 20, 21, 22, 23, 24, 25,
|
||||
28, 29, 30, 31, 32, 33, 34,
|
||||
37, 38, 39, 40, 41, 42, 43
|
||||
)
|
||||
|
||||
kitsOnPage.forEachIndexed { index, kit ->
|
||||
if ( index < kitSlots.size )
|
||||
{
|
||||
val isSelected = selectedKit?.id == kit.id
|
||||
val kitItem = createKitItem( kit, isSelected, player )
|
||||
inventory.setItem(kitSlots[ index ], kitItem )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fillNavigationItems(
|
||||
inventory: org.bukkit.inventory.Inventory,
|
||||
page: Int,
|
||||
totalPages: Int
|
||||
) {
|
||||
if ( page > 1 )
|
||||
inventory.setItem( 45, createPreviousPageItem() )
|
||||
|
||||
inventory.setItem( 49, createCloseItem() )
|
||||
|
||||
if ( page < totalPages )
|
||||
inventory.setItem( 53, createNextPageItem() )
|
||||
}
|
||||
|
||||
private fun createBorderItem(): ItemStack
|
||||
{
|
||||
val item = ItemStack( Material.GRAY_STAINED_GLASS_PANE )
|
||||
val meta = item.itemMeta
|
||||
meta.displayName(Component.text( " " ))
|
||||
item.itemMeta = meta
|
||||
return item
|
||||
}
|
||||
|
||||
private fun createKitItem(
|
||||
kit: AbstractKit,
|
||||
isSelected: Boolean,
|
||||
player: Player
|
||||
): ItemStack
|
||||
{
|
||||
val item = ItemStack( kit.icon )
|
||||
val meta = item.itemMeta
|
||||
|
||||
meta.displayName(kit.displayName.decoration( TextDecoration.ITALIC, false ))
|
||||
|
||||
val lore = mutableListOf<Component>()
|
||||
|
||||
if ( isSelected ) {
|
||||
lore.add(
|
||||
Component.text("✔ Currently Selected")
|
||||
.color( NamedTextColor.GREEN )
|
||||
.decoration( TextDecoration.ITALIC, false )
|
||||
)
|
||||
} else {
|
||||
lore.add(
|
||||
Component.text("Click to select")
|
||||
.color( NamedTextColor.YELLOW )
|
||||
.decoration( TextDecoration.ITALIC, false )
|
||||
)
|
||||
}
|
||||
|
||||
lore.add( Component.empty() )
|
||||
|
||||
kit.description.forEach { line ->
|
||||
lore.add(
|
||||
line.color( NamedTextColor.GRAY )
|
||||
.decoration( TextDecoration.ITALIC, false )
|
||||
)
|
||||
}
|
||||
|
||||
if (canUseKit( player, kit )) {
|
||||
if ( isSelected )
|
||||
{
|
||||
meta.addEnchant( Enchantment.UNBREAKING, 1, true )
|
||||
meta.addItemFlags( ItemFlag.HIDE_ENCHANTS )
|
||||
}
|
||||
} else {
|
||||
lore.add( Component.empty() )
|
||||
lore.add(
|
||||
Component.text("⚠ Locked")
|
||||
.color( NamedTextColor.RED )
|
||||
.decoration( TextDecoration.ITALIC, false )
|
||||
.decoration( TextDecoration.BOLD, true )
|
||||
)
|
||||
}
|
||||
|
||||
meta.lore( lore )
|
||||
meta.addItemFlags( ItemFlag.HIDE_ATTRIBUTES )
|
||||
item.itemMeta = meta
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
private fun createPreviousPageItem(): ItemStack
|
||||
{
|
||||
val item = ItemStack( Material.ARROW )
|
||||
val meta = item.itemMeta
|
||||
meta.displayName(
|
||||
Component.text("← Previous Page")
|
||||
.color( NamedTextColor.YELLOW )
|
||||
.decoration( TextDecoration.ITALIC, false )
|
||||
)
|
||||
item.itemMeta = meta
|
||||
return item
|
||||
}
|
||||
|
||||
private fun createNextPageItem(): ItemStack
|
||||
{
|
||||
val item = ItemStack( Material.ARROW )
|
||||
val meta = item.itemMeta
|
||||
meta.displayName(
|
||||
Component.text("Next Page →")
|
||||
.color( NamedTextColor.YELLOW )
|
||||
.decoration( TextDecoration.ITALIC, false )
|
||||
)
|
||||
item.itemMeta = meta
|
||||
return item
|
||||
}
|
||||
|
||||
private fun createCloseItem(): ItemStack
|
||||
{
|
||||
val item = ItemStack( Material.BARRIER )
|
||||
val meta = item.itemMeta
|
||||
meta.displayName(
|
||||
Component.text("Close")
|
||||
.color( NamedTextColor.RED )
|
||||
.decoration( TextDecoration.ITALIC, false )
|
||||
)
|
||||
item.itemMeta = meta
|
||||
return item
|
||||
}
|
||||
|
||||
private fun canUseKit(
|
||||
player: Player,
|
||||
kit: AbstractKit
|
||||
): Boolean
|
||||
{
|
||||
val unlockedKits = mutableListOf<String>()
|
||||
|
||||
runBlocking {
|
||||
val kitPlayer = plugin.playerRepository.findByUuid( player.uniqueId )
|
||||
if ( kitPlayer != null ) unlockedKits.addAll( kitPlayer.unlockedKits )
|
||||
}
|
||||
|
||||
return unlockedKits.contains( kit.id )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package club.mcscrims.speedhg.kit
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.Sound
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.block.BlockBreakEvent
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.event.player.PlayerMoveEvent
|
||||
|
||||
class KitListener(
|
||||
private val plugin: SpeedHG,
|
||||
private val kitManager: KitManager
|
||||
) : Listener {
|
||||
|
||||
@EventHandler
|
||||
fun onDamage(
|
||||
event: EntityDamageByEntityEvent
|
||||
) {
|
||||
val attacker = event.damager as? Player ?: return
|
||||
val victim = event.entity as? Player ?: return
|
||||
|
||||
if (kitManager.getSelectedKit( attacker ) != null )
|
||||
kitManager.triggerHit( attacker, victim, event )
|
||||
|
||||
if (kitManager.getSelectedKit( victim ) != null )
|
||||
kitManager.triggerDamaged( victim, attacker, event )
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onPlayerInteract(
|
||||
event: PlayerInteractEvent
|
||||
) {
|
||||
val player = event.player
|
||||
|
||||
if (kitManager.getSelectedKit( player ) != null )
|
||||
kitManager.triggerInteract( player, event )
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onPlayerMove(
|
||||
event: PlayerMoveEvent
|
||||
) {
|
||||
val player = event.player
|
||||
|
||||
if (kitManager.getSelectedKit( player ) != null )
|
||||
kitManager.triggerMove( player, event )
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onAnvilBreak(
|
||||
event: BlockBreakEvent
|
||||
) {
|
||||
if ( !plugin.gameManager.isRunning() )
|
||||
return
|
||||
|
||||
val block = event.block
|
||||
|
||||
if ( block.type != Material.ANVIL ||
|
||||
!block.hasMetadata( KitMetaData.IS_ANVIL.getKey() ))
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
|
||||
block.type = Material.AIR
|
||||
block.removeMetadata( KitMetaData.IS_ANVIL.getKey(), plugin )
|
||||
|
||||
block.world.playSound( block.location, Sound.ENTITY_IRON_GOLEM_DEATH, 3f, 3f )
|
||||
plugin.chatManager.broadcast( "kits.anchor.messages.broken" )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,224 +0,0 @@
|
||||
package club.mcscrims.speedhg.kit
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.speedhg.ability.AbilityContext
|
||||
import club.mcscrims.speedhg.game.GameManager
|
||||
import club.mcscrims.speedhg.kit.impl.AnchorKit
|
||||
import club.mcscrims.speedhg.kit.impl.ArmorerKit
|
||||
import club.mcscrims.speedhg.kit.impl.BlackPantherKit
|
||||
import club.mcscrims.speedhg.kit.impl.BlitzcrankKit
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.event.player.PlayerMoveEvent
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class KitManager(
|
||||
private val plugin: SpeedHG
|
||||
) {
|
||||
|
||||
private val kits = ConcurrentHashMap<String, AbstractKit>()
|
||||
private val selectedKits = ConcurrentHashMap<UUID, AbstractKit>()
|
||||
|
||||
fun initialize()
|
||||
{
|
||||
registerKit(
|
||||
kitClass = AnchorKit::class.java,
|
||||
id = "anchor",
|
||||
displayName = plugin.chatFormatter.format( "kits.anchor.displayName" ),
|
||||
description = plugin.chatFormatter.formatList( "kits.anchor.lore" ),
|
||||
icon = Material.ANVIL
|
||||
)
|
||||
|
||||
registerKit(
|
||||
kitClass = ArmorerKit::class.java,
|
||||
id = "armorer",
|
||||
displayName = plugin.chatFormatter.format( "kits.armorer.displayName" ),
|
||||
description = plugin.chatFormatter.formatList( "kits.armorer.lore" ),
|
||||
icon = Material.IRON_CHESTPLATE
|
||||
)
|
||||
|
||||
registerKit(
|
||||
kitClass = BlackPantherKit::class.java,
|
||||
id = "blackpanther",
|
||||
displayName = plugin.chatFormatter.format( "kits.blackpanther.displayName" ),
|
||||
description = plugin.chatFormatter.formatList( "kits.blackpanther.lore" ),
|
||||
icon = Material.DRAGON_EGG
|
||||
)
|
||||
|
||||
registerKit(
|
||||
kitClass = BlitzcrankKit::class.java,
|
||||
id = "blitzcrank",
|
||||
displayName = plugin.chatFormatter.format( "kits.blitzcrank.displayName" ),
|
||||
description = plugin.chatFormatter.formatList( "kits.blitzcrank.lore" ),
|
||||
icon = Material.FISHING_ROD
|
||||
)
|
||||
}
|
||||
|
||||
fun registerKit(
|
||||
kitClass: Class<out AbstractKit>,
|
||||
id: String,
|
||||
displayName: Component,
|
||||
description: List<Component>,
|
||||
icon: Material
|
||||
) {
|
||||
val constructor = kitClass.getDeclaredConstructor(
|
||||
String::class.java,
|
||||
Component::class.java,
|
||||
List::class.java,
|
||||
Material::class.java,
|
||||
PlayStyle::class.java,
|
||||
SpeedHG::class.java,
|
||||
AbilityContext::class.java,
|
||||
GameManager::class.java
|
||||
)
|
||||
|
||||
val kit = constructor.newInstance(
|
||||
id,
|
||||
displayName,
|
||||
description,
|
||||
icon,
|
||||
PlayStyle.DEFENSIVE,
|
||||
plugin,
|
||||
plugin.abilityContext,
|
||||
plugin.gameManager
|
||||
)
|
||||
|
||||
kit.config = plugin.kitConfig.data.getConfigForKit( kit.id )
|
||||
kits[kit.id.lowercase()] = kit
|
||||
plugin.logger.info("Registered kit: ${kit.displayName} (${kit.id})")
|
||||
}
|
||||
|
||||
fun getKit(
|
||||
id: String
|
||||
): AbstractKit?
|
||||
{
|
||||
return kits[id.lowercase()]
|
||||
}
|
||||
|
||||
fun getAllKits(): Collection<AbstractKit>
|
||||
{
|
||||
return kits.values
|
||||
}
|
||||
|
||||
fun selectKit(
|
||||
player: Player,
|
||||
kitId: String
|
||||
): Boolean
|
||||
{
|
||||
val kit = getKit( kitId ) ?: return false
|
||||
|
||||
val previousKit = selectedKits[player.uniqueId]
|
||||
previousKit?.cleanup( player )
|
||||
|
||||
selectedKits[player.uniqueId] = kit
|
||||
|
||||
try {
|
||||
kit.onSelect( player )
|
||||
} catch (e: Exception) {
|
||||
plugin.logger.severe("Error during onSelect for kit ${kit.id} and player ${player.name}: ${e.message}")
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun getSelectedKit(
|
||||
player: Player
|
||||
): AbstractKit?
|
||||
{
|
||||
return selectedKits[player.uniqueId]
|
||||
}
|
||||
|
||||
fun startKitForPlayer(
|
||||
player: Player
|
||||
) {
|
||||
val kit = selectedKits[player.uniqueId] ?: return
|
||||
|
||||
try {
|
||||
kit.onStart( player )
|
||||
} catch (e: Exception) {
|
||||
plugin.logger.severe("Error during onStart for kit ${kit.id} and player ${player.name}: ${e.message}")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun triggerHit(
|
||||
attacker: Player,
|
||||
victim: Player,
|
||||
event: EntityDamageByEntityEvent
|
||||
) {
|
||||
val kit = selectedKits[attacker.uniqueId] ?: return
|
||||
|
||||
try {
|
||||
kit.onHit( attacker, victim, event )
|
||||
} catch (e: Exception) {
|
||||
plugin.logger.severe("Error during onHit for kit ${kit.id} and player ${attacker.name}: ${e.message}")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun triggerDamaged(
|
||||
attacker: Player,
|
||||
victim: Player,
|
||||
event: EntityDamageByEntityEvent
|
||||
) {
|
||||
val kit = selectedKits[victim.uniqueId] ?: return
|
||||
|
||||
try {
|
||||
kit.onDamaged( attacker, victim, event )
|
||||
} catch (e: Exception) {
|
||||
plugin.logger.severe("Error during onDamaged for kit ${kit.id} and player ${victim.name}: ${e.message}")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun triggerInteract(
|
||||
player: Player,
|
||||
event: PlayerInteractEvent
|
||||
) {
|
||||
val kit = selectedKits[player.uniqueId] ?: return
|
||||
|
||||
try {
|
||||
kit.onInteract( player, event )
|
||||
} catch (e: Exception) {
|
||||
plugin.logger.severe("Error during onInteract for kit ${kit.id} and player ${player.name}: ${e.message}")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun triggerMove(
|
||||
player: Player,
|
||||
event: PlayerMoveEvent
|
||||
) {
|
||||
val kit = selectedKits[player.uniqueId] ?: return
|
||||
|
||||
try {
|
||||
kit.onMove( player, event )
|
||||
} catch (e: Exception) {
|
||||
plugin.logger.severe("Error during onMove for kit ${kit.id} and player ${player.name}: ${e.message}")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun clearPlayerSelection(
|
||||
player: Player
|
||||
) {
|
||||
val kit = selectedKits.remove( player.uniqueId )
|
||||
kit?.cleanup( player )
|
||||
}
|
||||
|
||||
fun clearAll()
|
||||
{
|
||||
selectedKits.values.forEach { kit ->
|
||||
plugin.server.onlinePlayers.forEach { player ->
|
||||
if ( selectedKits[player.uniqueId] == kit ) kit.cleanup( player )
|
||||
}
|
||||
}
|
||||
selectedKits.clear()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
package club.mcscrims.speedhg.kit.impl
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.speedhg.SpeedHG.Companion.content
|
||||
import club.mcscrims.speedhg.ability.AbilityContext
|
||||
import club.mcscrims.speedhg.game.GameManager
|
||||
import club.mcscrims.speedhg.kit.AbstractKit
|
||||
import club.mcscrims.speedhg.kit.KitMetaData
|
||||
import club.mcscrims.speedhg.kit.PlayStyle
|
||||
import club.mcscrims.spigot.item.ItemBuilder
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.Sound
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.block.Action
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.event.player.PlayerMoveEvent
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.metadata.FixedMetadataValue
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class AnchorKit(
|
||||
id: String,
|
||||
displayName: Component,
|
||||
description: List<Component>,
|
||||
icon: Material,
|
||||
playStyle: PlayStyle,
|
||||
plugin: SpeedHG,
|
||||
abilityContext: AbilityContext,
|
||||
gameManager: GameManager
|
||||
) : AbstractKit( id, displayName, description, icon, playStyle, plugin, abilityContext, gameManager ) {
|
||||
|
||||
private lateinit var anvilItem: ItemStack
|
||||
|
||||
private val extraDamage: Double = plugin.kitConfig.data.anchor[ "offensive extra damage" ]!!
|
||||
|
||||
private val radius = if ( playStyle == PlayStyle.DEFENSIVE ) 7.5 else 5.0
|
||||
private val anvilList = ConcurrentHashMap<UUID, Location>()
|
||||
|
||||
override fun onSelect( player: Player ) {}
|
||||
|
||||
override fun onStart(
|
||||
player: Player
|
||||
) {
|
||||
anvilItem = ItemBuilder( plugin, Material.ANVIL )
|
||||
.name(plugin.messageConfig.data.getKitItemNames( "anchor", "anvil" )!![ playStyle.name.lowercase() ]!!)
|
||||
.unbreakable( true )
|
||||
.hideAttributes()
|
||||
.build()
|
||||
|
||||
items.add( anvilItem )
|
||||
player.inventory.setItem( 0, anvilItem )
|
||||
}
|
||||
|
||||
override fun onHit(
|
||||
attacker: Player,
|
||||
victim: Player,
|
||||
event: EntityDamageByEntityEvent
|
||||
) {
|
||||
if ( !gameManager.isRunning() )
|
||||
return
|
||||
|
||||
if (!anvilList.contains( attacker.uniqueId ))
|
||||
return
|
||||
|
||||
if ( playStyle != PlayStyle.OFFENSIVE )
|
||||
return
|
||||
|
||||
event.damage += extraDamage
|
||||
}
|
||||
|
||||
override fun onDamaged(
|
||||
attacker: Player,
|
||||
victim: Player,
|
||||
event: EntityDamageByEntityEvent
|
||||
) {
|
||||
if ( !gameManager.isRunning() )
|
||||
return
|
||||
|
||||
if (!anvilList.contains( attacker.uniqueId ))
|
||||
return
|
||||
|
||||
victim.velocity.setX( 0.0 )
|
||||
victim.velocity.setZ( 0.0 )
|
||||
victim.world.playSound( victim.location, Sound.BLOCK_ANVIL_HIT, 3f, 3f )
|
||||
}
|
||||
|
||||
override fun onInteract(
|
||||
player: Player,
|
||||
event: PlayerInteractEvent
|
||||
) {
|
||||
if ( !gameManager.isRunning() )
|
||||
return
|
||||
|
||||
val action = event.action
|
||||
|
||||
if ( action != Action.RIGHT_CLICK_AIR &&
|
||||
action != Action.RIGHT_CLICK_BLOCK )
|
||||
return
|
||||
|
||||
val item = event.item ?: return
|
||||
|
||||
if ( item != anvilItem )
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
|
||||
val eyeLocation = player.eyeLocation
|
||||
|
||||
if (eyeLocation.distance( player.location ) > radius )
|
||||
{
|
||||
plugin.chatManager.sendMessage( player, "kits.anchor.messages.tooFarAway" )
|
||||
return
|
||||
}
|
||||
|
||||
if (anvilList.contains( player.uniqueId ))
|
||||
{
|
||||
plugin.chatManager.sendMessage( player, "kits.anchor.messages.alreadyActivated" )
|
||||
return
|
||||
}
|
||||
|
||||
val result = abilityContext.canUseAbility( player, "anchor-anvil", 15 )
|
||||
|
||||
if ( result.missingHits > 0 )
|
||||
{
|
||||
plugin.chatManager.sendMessage( player, "kits.missingHits", "{hits]" to result.missingHits.toString() )
|
||||
return
|
||||
}
|
||||
|
||||
val anvilLoc = eyeLocation.toBlockLocation()
|
||||
anvilLoc.add( 0.0, 1.0, 0.0 )
|
||||
|
||||
anvilLoc.block.type = Material.ANVIL
|
||||
anvilLoc.block.setMetadata( KitMetaData.IS_ANVIL.getKey(), FixedMetadataValue( plugin, true ))
|
||||
|
||||
anvilList[ player.uniqueId ]= anvilLoc
|
||||
|
||||
plugin.schedulerManager.runLater( 20 * 30L ) {
|
||||
if (anvilList.contains( player.uniqueId ))
|
||||
{
|
||||
anvilList.remove( player.uniqueId )
|
||||
anvilLoc.block.type = Material.AIR
|
||||
anvilLoc.block.removeMetadata( KitMetaData.IS_ANVIL.getKey(), plugin )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMove(
|
||||
player: Player,
|
||||
event: PlayerMoveEvent
|
||||
) {
|
||||
if ( !gameManager.isRunning() )
|
||||
return
|
||||
|
||||
val anvilLoc = anvilList[ player.uniqueId ]
|
||||
?: return
|
||||
|
||||
if (player.location.distance( anvilLoc ) <= radius )
|
||||
return
|
||||
|
||||
player.teleport( player.location )
|
||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package club.mcscrims.speedhg.kit.impl
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.speedhg.ability.AbilityContext
|
||||
import club.mcscrims.speedhg.game.GameManager
|
||||
import club.mcscrims.speedhg.kit.AbstractKit
|
||||
import club.mcscrims.speedhg.kit.PlayStyle
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.Sound
|
||||
import org.bukkit.Statistic
|
||||
import org.bukkit.enchantments.Enchantment
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.event.player.PlayerMoveEvent
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class ArmorerKit(
|
||||
id: String,
|
||||
displayName: Component,
|
||||
description: List<Component>,
|
||||
icon: Material,
|
||||
playStyle: PlayStyle,
|
||||
plugin: SpeedHG,
|
||||
abilityContext: AbilityContext,
|
||||
gameManager: GameManager
|
||||
) : AbstractKit( id, displayName, description, icon, playStyle, plugin, abilityContext, gameManager ) {
|
||||
|
||||
private val killsUntilNew: Double = plugin.kitConfig.data.armorer[ "kills until new armor" ]!!
|
||||
|
||||
override fun onSelect( player: Player ) {}
|
||||
|
||||
override fun onStart( player: Player ) {}
|
||||
|
||||
override fun onHit(
|
||||
attacker: Player,
|
||||
victim: Player,
|
||||
event: EntityDamageByEntityEvent
|
||||
) {
|
||||
if ( !gameManager.isRunning() )
|
||||
return
|
||||
|
||||
if ( victim.health > 0.0 )
|
||||
return
|
||||
|
||||
val kills = attacker.getStatistic( Statistic.PLAYER_KILLS )
|
||||
|
||||
if (( kills.toDouble() / killsUntilNew ) % 2 != 0.0 )
|
||||
return
|
||||
|
||||
upgradeArmor( attacker, kills )
|
||||
attacker.playSound( attacker, Sound.BLOCK_NOTE_BLOCK_PLING, 1f, 1f )
|
||||
}
|
||||
|
||||
override fun onDamaged( attacker: Player, victim: Player, event: EntityDamageByEntityEvent ) {}
|
||||
|
||||
override fun onInteract( player: Player, event: PlayerInteractEvent ) {}
|
||||
|
||||
override fun onMove( player: Player, event: PlayerMoveEvent ) {}
|
||||
|
||||
private fun upgradeArmor(
|
||||
player: Player,
|
||||
killCount: Int
|
||||
) {
|
||||
val kills = killsUntilNew.roundToInt()
|
||||
|
||||
val armorType = when( killCount / kills )
|
||||
{
|
||||
1, 2 -> ArmorType.LEATHER
|
||||
3, 4 -> ArmorType.CHAINMAIL
|
||||
5, 6 -> ArmorType.GOLD
|
||||
7, 8 -> ArmorType.IRON
|
||||
else -> return
|
||||
}
|
||||
|
||||
val enchanted = ( killCount / kills ) % 2 == 0
|
||||
|
||||
val armor = createArmor( armorType, enchanted )
|
||||
player.inventory.armorContents = arrayOf( null, armor[0], null, armor[1] )
|
||||
|
||||
if ( !enchanted )
|
||||
{
|
||||
plugin.chatManager.sendMessage( player, "kits.armorer.messages.upgrade.normal", "{armorType}" to armorType.name )
|
||||
return
|
||||
}
|
||||
|
||||
plugin.chatManager.sendMessage( player, "kits.armorer.upgrade.enchanted" )
|
||||
}
|
||||
|
||||
private fun createArmor(
|
||||
type: ArmorType,
|
||||
enchanted: Boolean
|
||||
) = listOf(
|
||||
ItemStack( type.materialChestplate ).apply {
|
||||
if ( enchanted ) addEnchantment( Enchantment.PROTECTION, 1 )
|
||||
},
|
||||
ItemStack( type.materialBoots ).apply {
|
||||
if ( enchanted ) addEnchantment( Enchantment.PROTECTION, 1 )
|
||||
}
|
||||
)
|
||||
|
||||
enum class ArmorType(
|
||||
val materialChestplate: Material,
|
||||
val materialBoots: Material
|
||||
) {
|
||||
LEATHER( Material.LEATHER_CHESTPLATE, Material.LEATHER_BOOTS ),
|
||||
CHAINMAIL( Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_BOOTS ),
|
||||
GOLD( Material.GOLDEN_CHESTPLATE, Material.GOLDEN_BOOTS ),
|
||||
IRON( Material.IRON_CHESTPLATE, Material.IRON_BOOTS )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,276 +0,0 @@
|
||||
package club.mcscrims.speedhg.kit.impl
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.speedhg.ability.AbilityContext
|
||||
import club.mcscrims.speedhg.game.GameManager
|
||||
import club.mcscrims.speedhg.kit.AbstractKit
|
||||
import club.mcscrims.speedhg.kit.KitMetaData
|
||||
import club.mcscrims.speedhg.kit.PlayStyle
|
||||
import club.mcscrims.spigot.item.ItemBuilder
|
||||
import club.mcscrims.spigot.util.GroundDetector
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.GameMode
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.Particle
|
||||
import org.bukkit.entity.EnderPearl
|
||||
import org.bukkit.entity.EntityType
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.block.Action
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.event.player.PlayerMoveEvent
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.metadata.FixedMetadataValue
|
||||
import org.bukkit.potion.PotionEffect
|
||||
import org.bukkit.potion.PotionEffectType
|
||||
import org.bukkit.scheduler.BukkitRunnable
|
||||
import org.bukkit.util.Vector
|
||||
import kotlin.math.max
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class BlackPantherKit(
|
||||
id: String,
|
||||
displayName: Component,
|
||||
description: List<Component>,
|
||||
icon: Material,
|
||||
playStyle: PlayStyle,
|
||||
plugin: SpeedHG,
|
||||
abilityContext: AbilityContext,
|
||||
gameManager: GameManager
|
||||
) : AbstractKit( id, displayName, description, icon, playStyle, plugin, abilityContext, gameManager ) {
|
||||
|
||||
private lateinit var blackDye: ItemStack
|
||||
private lateinit var blazePowder: ItemStack
|
||||
|
||||
private val extraDamageAddition = plugin.kitConfig.data.blackPanther[ "extra damage on top" ]!!
|
||||
private val defaultRadius = plugin.kitConfig.data.blackPanther[ "default hit radius" ]!!
|
||||
private val explosionMultiplier = plugin.kitConfig.data.blackPanther[ "explosion multiplier" ]!!
|
||||
|
||||
override fun onSelect( player: Player ) {}
|
||||
|
||||
override fun onStart(
|
||||
player: Player
|
||||
) {
|
||||
when( playStyle )
|
||||
{
|
||||
PlayStyle.DEFENSIVE ->
|
||||
{
|
||||
blackDye = ItemBuilder( plugin, Material.BLACK_DYE )
|
||||
.name(plugin.messageConfig.data.getKitItemNames( "blackpanther", "blackDye" )!![ "null" ]!!)
|
||||
.unbreakable( true )
|
||||
.hideAttributes()
|
||||
.build()
|
||||
|
||||
items.add( blackDye )
|
||||
player.inventory.setItem( 0, blackDye )
|
||||
}
|
||||
|
||||
PlayStyle.OFFENSIVE ->
|
||||
{
|
||||
blackDye = ItemBuilder( plugin, Material.BLACK_DYE )
|
||||
.name(plugin.messageConfig.data.getKitItemNames( "blackpanther", "blackDye" )!![ playStyle.name.lowercase() ]!!)
|
||||
.unbreakable( true )
|
||||
.hideAttributes()
|
||||
.build()
|
||||
|
||||
blazePowder = ItemBuilder( plugin, Material.BLAZE_POWDER )
|
||||
.name(plugin.messageConfig.data.getKitItemNames( "blackpanther", "blazePowder" )!![ playStyle.name.lowercase() ]!!)
|
||||
.unbreakable( true )
|
||||
.hideAttributes()
|
||||
.build()
|
||||
|
||||
items.addAll(listOf( blackDye, blazePowder ))
|
||||
player.inventory.setItem( 0, blackDye )
|
||||
player.inventory.setItem( 1, blazePowder )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHit(
|
||||
attacker: Player,
|
||||
victim: Player,
|
||||
event: EntityDamageByEntityEvent
|
||||
) {
|
||||
if ( !gameManager.isRunning() )
|
||||
return
|
||||
|
||||
if (!attacker.hasMetadata( KitMetaData.BP_EXTRA_DAMAGE.getKey() ))
|
||||
return
|
||||
|
||||
event.damage += extraDamageAddition
|
||||
}
|
||||
|
||||
override fun onDamaged( attacker: Player, victim: Player, event: EntityDamageByEntityEvent ) {}
|
||||
|
||||
override fun onInteract(
|
||||
player: Player,
|
||||
event: PlayerInteractEvent
|
||||
) {
|
||||
if ( !gameManager.isRunning() )
|
||||
return
|
||||
|
||||
val action = event.action
|
||||
|
||||
if ( action != Action.RIGHT_CLICK_AIR &&
|
||||
action != Action.RIGHT_CLICK_BLOCK )
|
||||
return
|
||||
|
||||
val item = event.item ?: return
|
||||
|
||||
if ( item != blackDye &&
|
||||
item != blazePowder )
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
|
||||
when( item.type )
|
||||
{
|
||||
Material.BLACK_DYE ->
|
||||
{
|
||||
val result = abilityContext.canUseAbility( player, "blackDye-blackPanther", 15 )
|
||||
|
||||
if ( result.missingHits > 0 )
|
||||
{
|
||||
plugin.chatManager.sendMessage( player, "kits.missingHits", "{hits]" to result.missingHits.toString() )
|
||||
return
|
||||
}
|
||||
|
||||
if ( playStyle == PlayStyle.DEFENSIVE )
|
||||
{
|
||||
launchAndDash( player )
|
||||
return
|
||||
}
|
||||
|
||||
push( player )
|
||||
}
|
||||
|
||||
Material.BLAZE_POWDER ->
|
||||
{
|
||||
val result = abilityContext.canUseAbility( player, "blazePowder-blackPanther", 15 )
|
||||
|
||||
if ( result.missingHits > 0 )
|
||||
{
|
||||
plugin.chatManager.sendMessage( player, "kits.missingHits", "{hits]" to result.missingHits.toString() )
|
||||
return
|
||||
}
|
||||
|
||||
extraDamage( player )
|
||||
}
|
||||
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMove( player: Player, event: PlayerMoveEvent ) {}
|
||||
|
||||
private fun push(
|
||||
player: Player
|
||||
) {
|
||||
plugin.getAlivePlayers().stream()
|
||||
.filter { it != player }
|
||||
.filter { it.location.distance( player.location ) <= defaultRadius }
|
||||
.forEach { nearby ->
|
||||
val pushDirection = nearby.location.toVector().subtract( player.location.toVector() ).normalize()
|
||||
pushDirection.multiply( 1.0 )
|
||||
pushDirection.setY( 0.5 )
|
||||
nearby.velocity = pushDirection
|
||||
|
||||
val enderPearl = player.world.spawnEntity( player.location, EntityType.ENDER_PEARL ) as EnderPearl
|
||||
enderPearl.velocity = pushDirection
|
||||
enderPearl.setMetadata( KitMetaData.IS_BLACK_PANTHER.getKey(), FixedMetadataValue( plugin, true ))
|
||||
|
||||
object : BukkitRunnable()
|
||||
{
|
||||
|
||||
override fun run()
|
||||
{
|
||||
if (GroundDetector.isOnGround( nearby ))
|
||||
{
|
||||
this.cancel()
|
||||
return
|
||||
}
|
||||
|
||||
nearby.world.spawnParticle( Particle.END_ROD, nearby.location, 5, 0.2, 0.2, 0.2 )
|
||||
}
|
||||
|
||||
}.runTaskTimer( plugin, 0L, 2L )
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchAndDash(
|
||||
player: Player,
|
||||
upwardVelocity: Double = 2.2,
|
||||
waitTicks: Long = 60L,
|
||||
dashSpeed: Double = 2.8,
|
||||
horizontalOnly: Boolean = true,
|
||||
yBoost: Double = 0.2,
|
||||
noFallDamageMillis: Double = 1.0
|
||||
) {
|
||||
if ( !player.isOnline ) return
|
||||
if ( player.isInsideVehicle ) player.leaveVehicle()
|
||||
if ( player.gameMode == GameMode.SPECTATOR ) return
|
||||
|
||||
player.velocity = Vector( 0.0, upwardVelocity, 0.0 )
|
||||
player.fallDistance = 0f
|
||||
|
||||
if ( noFallDamageMillis > 0 )
|
||||
player.addPotionEffect(PotionEffect( PotionEffectType.RESISTANCE, ( noFallDamageMillis * 20 ).toInt(), 999, false, false, false ))
|
||||
|
||||
Bukkit.getScheduler().runTaskLater( plugin, { ->
|
||||
val p = Bukkit.getPlayer( player.uniqueId ) ?: return@runTaskLater
|
||||
if ( !p.isOnline ) return@runTaskLater
|
||||
|
||||
var dir = p.eyeLocation.direction
|
||||
if ( horizontalOnly ) dir = Vector( dir.x, 0.0, dir.z )
|
||||
dir = if ( dir.lengthSquared() < 1e-6 ) Vector( 0, 0, 0 ) else dir.normalize()
|
||||
|
||||
val dash = dir.multiply( dashSpeed ).add(Vector( 0.0, yBoost, 0.0 ))
|
||||
p.velocity = dash
|
||||
}, max( 0L, waitTicks ))
|
||||
|
||||
object : BukkitRunnable()
|
||||
{
|
||||
|
||||
override fun run()
|
||||
{
|
||||
if (GroundDetector.isOnGround( player ))
|
||||
{
|
||||
player.world.createExplosion(
|
||||
player.location,
|
||||
explosionMultiplier.roundToInt().toFloat(),
|
||||
false, true
|
||||
)
|
||||
|
||||
val alivePlayers = plugin.getAlivePlayers().stream()
|
||||
.filter { it != player }
|
||||
.filter { it.location.distance( player.location ) <= defaultRadius }
|
||||
.toList()
|
||||
|
||||
alivePlayers.forEach { nearby ->
|
||||
nearby.damage( 6.0, player )
|
||||
}
|
||||
|
||||
plugin.chatManager.sendMessage( player, "kits.blackPanther.messages.wakandaForever.hit", "{hit}" to alivePlayers.size.toString() )
|
||||
this.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
}.runTaskTimer( plugin, max( 0L, waitTicks ) + 5L, 5L )
|
||||
}
|
||||
|
||||
private fun extraDamage(
|
||||
player: Player
|
||||
) {
|
||||
player.setMetadata( KitMetaData.BP_EXTRA_DAMAGE.getKey(), FixedMetadataValue( plugin, true ))
|
||||
plugin.chatManager.sendMessage( player, "kits.blackPanther.messages.extraDamage.activated" )
|
||||
|
||||
plugin.schedulerManager.runLater( 12 * 30L ) {
|
||||
|
||||
player.removeMetadata( KitMetaData.BP_EXTRA_DAMAGE.getKey(), plugin )
|
||||
plugin.chatManager.sendMessage( player, "kits.blackPanther.messages.extraDamage.deactivated" )
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
package club.mcscrims.speedhg.kit.impl
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.speedhg.SpeedHG.Companion.content
|
||||
import club.mcscrims.speedhg.ability.AbilityContext
|
||||
import club.mcscrims.speedhg.game.GameManager
|
||||
import club.mcscrims.speedhg.kit.AbstractKit
|
||||
import club.mcscrims.speedhg.kit.PlayStyle
|
||||
import club.mcscrims.speedhg.util.DirectionUtil
|
||||
import club.mcscrims.spigot.chat.getDisplayName
|
||||
import club.mcscrims.spigot.item.ItemBuilder
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.block.Action
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.event.player.PlayerMoveEvent
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.potion.PotionEffect
|
||||
import org.bukkit.potion.PotionEffectType
|
||||
import org.bukkit.util.Vector
|
||||
|
||||
class BlitzcrankKit(
|
||||
id: String,
|
||||
displayName: Component,
|
||||
description: List<Component>,
|
||||
icon: Material,
|
||||
playStyle: PlayStyle,
|
||||
plugin: SpeedHG,
|
||||
abilityContext: AbilityContext,
|
||||
gameManager: GameManager
|
||||
) : AbstractKit( id, displayName, description, icon, playStyle, plugin, abilityContext, gameManager ) {
|
||||
|
||||
override fun onSelect( player: Player ) {}
|
||||
|
||||
private lateinit var hotsItem: ItemStack
|
||||
private lateinit var fishingRodItem: ItemStack
|
||||
private lateinit var pufferfishItem: ItemStack
|
||||
|
||||
override fun onStart(
|
||||
player: Player
|
||||
) {
|
||||
hotsItem = ItemBuilder( plugin, Material.HEART_OF_THE_SEA )
|
||||
.name(plugin.messageConfig.data.getKitItemNames( "blitzcrank", "hots" )!![ playStyle.name.lowercase() ]!!)
|
||||
.unbreakable( true )
|
||||
.hideAttributes()
|
||||
.build()
|
||||
|
||||
items.add( hotsItem )
|
||||
player.inventory.setItem( 0, hotsItem )
|
||||
|
||||
when( playStyle )
|
||||
{
|
||||
PlayStyle.DEFENSIVE ->
|
||||
{
|
||||
fishingRodItem = ItemBuilder( plugin, Material.FISHING_ROD )
|
||||
.name(plugin.messageConfig.data.getKitItemNames( "blitzcrank", "fishingrod" )!![ playStyle.name.lowercase() ]!!)
|
||||
.unbreakable( true )
|
||||
.hideAttributes()
|
||||
.build()
|
||||
|
||||
items.add( fishingRodItem )
|
||||
player.inventory.setItem( 1, fishingRodItem )
|
||||
}
|
||||
|
||||
PlayStyle.OFFENSIVE ->
|
||||
{
|
||||
pufferfishItem = ItemBuilder( plugin, Material.PUFFERFISH )
|
||||
.name(plugin.messageConfig.data.getKitItemNames( "blitzcrank", "pufferfish" )!![ playStyle.name.lowercase() ]!!)
|
||||
.unbreakable( true )
|
||||
.hideAttributes()
|
||||
.build()
|
||||
|
||||
items.add( pufferfishItem )
|
||||
player.inventory.setItem( 1, pufferfishItem )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHit( attacker: Player, victim: Player, event: EntityDamageByEntityEvent ) {}
|
||||
|
||||
override fun onDamaged( attacker: Player, victim: Player, event: EntityDamageByEntityEvent ) {}
|
||||
|
||||
// Ultimate
|
||||
private val ultimateDamage = plugin.kitConfig.data.blitzcrank[ "ultimate damage" ]!!
|
||||
private val ultimateRadius = plugin.kitConfig.data.blitzcrank[ "ultimate radius" ]!!
|
||||
private val ultimateStunDuration = plugin.kitConfig.data.blitzcrank[ "ultimate stun duration" ]!!
|
||||
|
||||
// Hook
|
||||
private val hookRange = plugin.kitConfig.data.blitzcrank[ "hook range" ]!!
|
||||
|
||||
// Stun
|
||||
private val stunHeight = plugin.kitConfig.data.blitzcrank[ "stun height" ]!!
|
||||
private val stunRadius = plugin.kitConfig.data.blitzcrank[ "stun radius" ]!!
|
||||
private val stunSlowDuration = plugin.kitConfig.data.blitzcrank[ "stun slow duration" ]!!
|
||||
|
||||
override fun onInteract(
|
||||
player: Player,
|
||||
event: PlayerInteractEvent
|
||||
) {
|
||||
if ( !gameManager.isRunning() )
|
||||
return
|
||||
|
||||
val action = event.action
|
||||
|
||||
if ( action != Action.RIGHT_CLICK_AIR &&
|
||||
action != Action.RIGHT_CLICK_BLOCK )
|
||||
return
|
||||
|
||||
val item = event.item ?: return
|
||||
|
||||
if ( item != hotsItem &&
|
||||
item != fishingRodItem &&
|
||||
item != pufferfishItem )
|
||||
return
|
||||
|
||||
when( item.type )
|
||||
{
|
||||
Material.HEART_OF_THE_SEA ->
|
||||
{
|
||||
val result = abilityContext.canUseAbility( player, "hots-blitzcrank", 15 )
|
||||
|
||||
if ( result.missingHits > 0 )
|
||||
{
|
||||
plugin.chatManager.sendMessage( player, "kits.missingHits", "{hits]" to result.missingHits.toString() )
|
||||
return
|
||||
}
|
||||
|
||||
ultimate( player, ultimateRadius )
|
||||
}
|
||||
|
||||
Material.FISHING_ROD ->
|
||||
{
|
||||
val result = abilityContext.canUseAbility( player, "hook-blitzcrank", 15 )
|
||||
|
||||
if ( result.missingHits > 0 )
|
||||
{
|
||||
plugin.chatManager.sendMessage( player, "kits.missingHits", "{hits]" to result.missingHits.toString() )
|
||||
return
|
||||
}
|
||||
|
||||
hookPlayer( player )
|
||||
}
|
||||
|
||||
Material.PUFFERFISH ->
|
||||
{
|
||||
val result = abilityContext.canUseAbility( player, "stun-blitzcrank", 15 )
|
||||
|
||||
if ( result.missingHits > 0 )
|
||||
{
|
||||
plugin.chatManager.sendMessage( player, "kits.missingHits", "{hits]" to result.missingHits.toString() )
|
||||
return
|
||||
}
|
||||
|
||||
stunNearby( player, stunRadius )
|
||||
}
|
||||
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMove( player: Player, event: PlayerMoveEvent ) {}
|
||||
|
||||
private fun ultimate(
|
||||
player: Player,
|
||||
radius: Double
|
||||
) {
|
||||
val nearbyPlayers = player.world.getNearbyPlayers( player.location, radius )
|
||||
|
||||
nearbyPlayers.forEach { nearby ->
|
||||
|
||||
nearby.damage( ultimateDamage, player )
|
||||
|
||||
nearby.addPotionEffect(PotionEffect(
|
||||
PotionEffectType.SLOWNESS,
|
||||
ultimateStunDuration.toInt() * 20,
|
||||
255,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
))
|
||||
|
||||
plugin.chatManager.sendMessage( nearby, "kits.blitzcrank.messages.ultimate.target", "{player}" to player.getDisplayName )
|
||||
}
|
||||
|
||||
plugin.chatManager.sendMessage( player, "kits.blitzcrank.messages.ultimate.player", "{nearby}" to nearbyPlayers.size.toString() )
|
||||
}
|
||||
|
||||
private fun hookPlayer(
|
||||
player: Player
|
||||
) {
|
||||
val target = DirectionUtil.getTargetPlayerInLineOfSight( player, hookRange, 0.5 )
|
||||
|
||||
if ( target == null )
|
||||
{
|
||||
plugin.chatManager.sendMessage( player, "kits.blitzcrank.messages.no_player_in_sight" )
|
||||
return
|
||||
}
|
||||
|
||||
val hookDirection = target.location.toVector().add( player.location.toVector() ).normalize()
|
||||
hookDirection.multiply( 1.0 )
|
||||
hookDirection.setY( 0.5 )
|
||||
target.velocity = hookDirection
|
||||
|
||||
plugin.chatManager.sendMessage( player, "kits.blitzcrank.messages.hook.player", "{player}" to target.getDisplayName )
|
||||
plugin.chatManager.sendMessage( target, "kits.blitzcrank.messages.hook.target" )
|
||||
}
|
||||
|
||||
private fun stunNearby(
|
||||
player: Player,
|
||||
radius: Double
|
||||
) {
|
||||
val nearbyPlayers = player.world.getNearbyPlayers( player.location, radius )
|
||||
|
||||
nearbyPlayers.forEach { nearby ->
|
||||
|
||||
val velocity = nearby.velocity
|
||||
velocity.add(Vector( 0.0, stunHeight, 0.0 ))
|
||||
nearby.velocity = velocity
|
||||
|
||||
nearby.addPotionEffect(PotionEffect(
|
||||
PotionEffectType.SLOWNESS,
|
||||
20 * stunSlowDuration.toInt(),
|
||||
4, false, false, false
|
||||
))
|
||||
|
||||
plugin.chatManager.sendMessage( nearby, "kits.blitzcrank.messages.stun.target" )
|
||||
}
|
||||
|
||||
plugin.chatManager.sendMessage( player, "kits.blitzcrank.messages.stun.player", "{nearby}" to nearbyPlayers.size.toString() )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package club.mcscrims.speedhg.listener
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.speedhg.game.GameState
|
||||
import club.mcscrims.speedhg.util.getDisplayName
|
||||
import club.mcscrims.speedhg.util.sendMsg
|
||||
import club.mcscrims.speedhg.util.trans
|
||||
import net.kyori.adventure.text.Component
|
||||
import net.kyori.adventure.title.Title
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.player.PlayerJoinEvent
|
||||
import org.bukkit.event.player.PlayerQuitEvent
|
||||
|
||||
class ConnectListener : Listener {
|
||||
|
||||
private val plugin = SpeedHG.instance
|
||||
|
||||
@EventHandler
|
||||
fun onJoin(
|
||||
event: PlayerJoinEvent
|
||||
) {
|
||||
val player = event.player
|
||||
event.joinMessage( null )
|
||||
|
||||
if ( plugin.gameManager.currentState == GameState.INGAME ||
|
||||
plugin.gameManager.currentState == GameState.INVINCIBILITY )
|
||||
return
|
||||
|
||||
Bukkit.getOnlinePlayers().forEach { p ->
|
||||
p.sendMsg( "game.join", "<name>" to player.name )
|
||||
}
|
||||
|
||||
player.showTitle(Title.title(
|
||||
player.trans( "player.welcome" ),
|
||||
Component.empty()
|
||||
))
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onQuit(
|
||||
event: PlayerQuitEvent
|
||||
) {
|
||||
val player = event.player
|
||||
event.quitMessage( null )
|
||||
|
||||
if ( plugin.gameManager.currentState == GameState.INGAME ||
|
||||
plugin.gameManager.currentState == GameState.INVINCIBILITY )
|
||||
return
|
||||
|
||||
Bukkit.getOnlinePlayers().forEach { p ->
|
||||
p.sendMsg( "game.quit", "<name>" to player.name )
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +1,47 @@
|
||||
package club.mcscrims.speedhg.listener
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.speedhg.game.GameManager
|
||||
import club.mcscrims.speedhg.game.GameStateTypes
|
||||
import club.mcscrims.speedhg.util.DirectionUtil
|
||||
import club.mcscrims.spigot.chat.getDisplayName
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.bukkit.Bukkit
|
||||
import club.mcscrims.speedhg.game.GameState
|
||||
import club.mcscrims.speedhg.util.sendMsg
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.Sound
|
||||
import org.bukkit.attribute.Attribute
|
||||
import org.bukkit.entity.Entity
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.entity.Projectile
|
||||
import org.bukkit.entity.Tameable
|
||||
import org.bukkit.event.Event
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.block.Action
|
||||
import org.bukkit.event.block.BlockBreakEvent
|
||||
import org.bukkit.event.block.BlockPlaceEvent
|
||||
import org.bukkit.event.block.BlockSpreadEvent
|
||||
import org.bukkit.event.block.LeavesDecayEvent
|
||||
import org.bukkit.event.enchantment.EnchantItemEvent
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.event.entity.EntityDamageEvent
|
||||
import org.bukkit.event.entity.FoodLevelChangeEvent
|
||||
import org.bukkit.event.entity.PlayerDeathEvent
|
||||
import org.bukkit.event.inventory.ClickType
|
||||
import org.bukkit.event.inventory.CraftItemEvent
|
||||
import org.bukkit.event.inventory.InventoryClickEvent
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent
|
||||
import org.bukkit.event.inventory.InventoryOpenEvent
|
||||
import org.bukkit.event.inventory.InventoryType
|
||||
import org.bukkit.event.player.PlayerAttemptPickupItemEvent
|
||||
import org.bukkit.event.player.PlayerBucketEmptyEvent
|
||||
import org.bukkit.event.player.PlayerDropItemEvent
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.event.player.PlayerItemDamageEvent
|
||||
import org.bukkit.event.player.PlayerJoinEvent
|
||||
import org.bukkit.event.player.PlayerQuitEvent
|
||||
import org.bukkit.inventory.EnchantingInventory
|
||||
import org.bukkit.inventory.EquipmentSlot
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.meta.Damageable
|
||||
import java.util.Random
|
||||
import kotlin.math.min
|
||||
|
||||
class GameStateListener(
|
||||
private val plugin: SpeedHG,
|
||||
private val gameManager: GameManager
|
||||
) : Listener {
|
||||
class GameStateListener : Listener {
|
||||
|
||||
private val plugin = SpeedHG.instance
|
||||
private val gameManager = plugin.gameManager
|
||||
|
||||
@EventHandler
|
||||
fun onLeavesDecay(
|
||||
event: LeavesDecayEvent
|
||||
) {
|
||||
if ( gameManager.isRunning() )
|
||||
if ( gameManager.currentState == GameState.INVINCIBILITY ||
|
||||
gameManager.currentState == GameState.INGAME )
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
@@ -68,40 +53,29 @@ class GameStateListener(
|
||||
) {
|
||||
val player = event.player
|
||||
|
||||
if ( gameManager.getCurrentStateType() == GameStateTypes.FEAST )
|
||||
{
|
||||
val block = event.block
|
||||
|
||||
if (!gameManager.feastBox.contains( block.location.toVector() ))
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
return
|
||||
}
|
||||
|
||||
if ( gameManager.isRunning() )
|
||||
if ( gameManager.currentState == GameState.INVINCIBILITY ||
|
||||
gameManager.currentState == GameState.INGAME )
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
player.playSound( player.location, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
}
|
||||
|
||||
private val beforeInvisMaterials = setOf(
|
||||
Material.OAK_LOG,
|
||||
Material.DARK_OAK_LOG,
|
||||
Material.BIRCH_LOG,
|
||||
Material.ACACIA_LOG,
|
||||
Material.JUNGLE_LOG,
|
||||
Material.SPRUCE_LOG,
|
||||
Material.STONE
|
||||
private val beforeInvisMaterials = mapOf(
|
||||
Material.OAK_LOG to Sound.BLOCK_WOOD_BREAK,
|
||||
Material.DARK_OAK_LOG to Sound.BLOCK_WOOD_BREAK,
|
||||
Material.BIRCH_LOG to Sound.BLOCK_WOOD_BREAK,
|
||||
Material.ACACIA_LOG to Sound.BLOCK_WOOD_BREAK,
|
||||
Material.JUNGLE_LOG to Sound.BLOCK_WOOD_BREAK,
|
||||
Material.SPRUCE_LOG to Sound.BLOCK_WOOD_BREAK,
|
||||
Material.STONE to Sound.BLOCK_STONE_BREAK
|
||||
)
|
||||
|
||||
private val alwaysMaterials = setOf(
|
||||
Material.RED_MUSHROOM,
|
||||
Material.BROWN_MUSHROOM,
|
||||
Material.COCOA_BEANS,
|
||||
Material.CACTUS
|
||||
private val alwaysMaterials = mapOf(
|
||||
Material.RED_MUSHROOM to Sound.BLOCK_GRASS_BREAK,
|
||||
Material.BROWN_MUSHROOM to Sound.BLOCK_GRASS_BREAK,
|
||||
Material.COCOA_BEANS to Sound.BLOCK_WOOD_BREAK,
|
||||
Material.CACTUS to Sound.BLOCK_WOOL_BREAK
|
||||
)
|
||||
|
||||
@EventHandler
|
||||
@@ -110,35 +84,26 @@ class GameStateListener(
|
||||
) {
|
||||
val player = event.player
|
||||
|
||||
if ( !gameManager.isRunning() )
|
||||
if ( gameManager.currentState != GameState.INVINCIBILITY &&
|
||||
gameManager.currentState != GameState.INGAME )
|
||||
{
|
||||
event.isCancelled = true
|
||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
player.playSound( player.location, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
return
|
||||
}
|
||||
|
||||
val block = event.block
|
||||
|
||||
if ( gameManager.getCurrentStateType() == GameStateTypes.FEAST )
|
||||
if ( gameManager.currentState == GameState.INVINCIBILITY &&
|
||||
beforeInvisMaterials.containsKey( block.type ))
|
||||
{
|
||||
if (!gameManager.feastBox.contains( block.location.toVector() ))
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
pickupBlock( event, player )
|
||||
return
|
||||
}
|
||||
|
||||
if ( gameManager.getCurrentStateType() == GameStateTypes.IMMUNITY &&
|
||||
beforeInvisMaterials.contains( block.type ))
|
||||
if (alwaysMaterials.containsKey( block.type ))
|
||||
{
|
||||
pickup( event, player )
|
||||
return
|
||||
}
|
||||
|
||||
if (alwaysMaterials.contains( block.type ))
|
||||
{
|
||||
pickup( event, player )
|
||||
pickupBlock( event, player )
|
||||
return
|
||||
}
|
||||
|
||||
@@ -148,46 +113,51 @@ class GameStateListener(
|
||||
event.block.type = Material.AIR
|
||||
event.block.tick()
|
||||
|
||||
plugin.chatManager.sendMessage( player, "build.no_diamonds" )
|
||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
player.sendMsg( "build.no_diamonds" )
|
||||
player.playSound( player.location, Sound.ENTITY_VILLAGER_NO, 1f, 1f )
|
||||
return
|
||||
}
|
||||
|
||||
if ( block.type == Material.IRON_ORE && gameManager.isBeforeFeast() )
|
||||
// TODO: add feast check
|
||||
if ( block.type == Material.IRON_ORE && TODO( "Add before feast check" ))
|
||||
{
|
||||
event.isCancelled = true
|
||||
plugin.chatManager.sendMessage( player, "build.no_iron_before_feast" )
|
||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
player.sendMsg( "build.no_iron_before_feast" )
|
||||
player.playSound( player.location, Sound.ENTITY_VILLAGER_NO, 1f, 1f )
|
||||
}
|
||||
else if ( block.type == Material.IRON_ORE && !gameManager.isBeforeFeast() )
|
||||
else if ( block.type == Material.IRON_ORE && TODO( "Add after feast check" ))
|
||||
{
|
||||
runBlocking { plugin.statsRepository.addIronFarmed( player.uniqueId, 0.1 ) }
|
||||
// TODO: add 0.1 to ironFarmed in database
|
||||
}
|
||||
}
|
||||
|
||||
private fun pickup(
|
||||
private fun pickupBlock(
|
||||
event: BlockBreakEvent,
|
||||
player: Player
|
||||
) {
|
||||
val block = event.block
|
||||
|
||||
event.isCancelled = true
|
||||
|
||||
val sound = if (beforeInvisMaterials.containsKey( block.type ))
|
||||
beforeInvisMaterials[ block.type ]!!
|
||||
else alwaysMaterials[ block.type ]!!
|
||||
|
||||
if (!hasInventorySpace( player ))
|
||||
{
|
||||
event.block.drops.forEach { player.world.dropItem( event.block.location, it ) }
|
||||
event.block.type = Material.AIR
|
||||
block.drops.forEach { player.world.dropItem( block.location, it ) }
|
||||
player.playSound( player.location, sound, 1f, 1f )
|
||||
block.type = Material.AIR
|
||||
return
|
||||
}
|
||||
|
||||
event.block.drops.forEach { player.inventory.addItem( it ) }
|
||||
event.block.type = Material.AIR
|
||||
block.drops.forEach { player.inventory.addItem( it ) }
|
||||
player.playSound( player.location, sound, 1f, 1f )
|
||||
block.type = Material.AIR
|
||||
}
|
||||
|
||||
private fun hasInventorySpace(
|
||||
player: Player
|
||||
): Boolean
|
||||
{
|
||||
return player.inventory.any { it == null || it.type == Material.AIR }
|
||||
}
|
||||
private fun hasInventorySpace( player: Player ): Boolean
|
||||
= player.inventory.any { it == null || it.type == Material.AIR }
|
||||
|
||||
@EventHandler
|
||||
fun onDropItem(
|
||||
@@ -195,75 +165,15 @@ class GameStateListener(
|
||||
) {
|
||||
val player = event.player
|
||||
|
||||
if ( !gameManager.isRunning() )
|
||||
if ( gameManager.currentState != GameState.INVINCIBILITY &&
|
||||
gameManager.currentState != GameState.INGAME )
|
||||
{
|
||||
event.isCancelled = true
|
||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
player.playSound( player.location, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
return
|
||||
}
|
||||
|
||||
val kit = plugin.kitManager.getSelectedKit( player )
|
||||
?: return
|
||||
|
||||
val items = kit.items.ifEmpty { return }
|
||||
|
||||
if (items.contains( event.itemDrop.itemStack ))
|
||||
{
|
||||
event.isCancelled = true
|
||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onPickupItem(
|
||||
event: PlayerAttemptPickupItemEvent
|
||||
) {
|
||||
if ( gameManager.isRunning() )
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onInteractCompass(
|
||||
event: PlayerInteractEvent
|
||||
) {
|
||||
if ( !gameManager.isRunning() )
|
||||
return
|
||||
|
||||
val player = event.player
|
||||
val action = event.action
|
||||
|
||||
if ( action != Action.RIGHT_CLICK_AIR &&
|
||||
action != Action.RIGHT_CLICK_BLOCK )
|
||||
return
|
||||
|
||||
val item = event.item
|
||||
?: return
|
||||
|
||||
if ( item.type != Material.COMPASS )
|
||||
return
|
||||
|
||||
val nearestPlayer = Bukkit.getOnlinePlayers().stream()
|
||||
.filter { other -> other != player }
|
||||
.map { other -> other.location.distance( player.location ) to other }
|
||||
.filter { pair -> pair.first > 5.0 }
|
||||
.toList()
|
||||
.firstOrNull()
|
||||
?.second
|
||||
|
||||
if ( nearestPlayer == null )
|
||||
{
|
||||
plugin.chatManager.sendMessage( player, "compass.no_nearby_players" )
|
||||
return
|
||||
}
|
||||
|
||||
player.compassTarget = nearestPlayer.location
|
||||
|
||||
val direction = DirectionUtil.getDirectionToPlayer( player, nearestPlayer )
|
||||
var actionBar = plugin.chatFormatter.format( "compass.actionBar" )
|
||||
actionBar = actionBar.replaceText { it.match( "<direction>" ).replacement( direction ).once() }
|
||||
plugin.chatManager.getAudience( player ).sendActionBar( actionBar )
|
||||
// TODO: add kit item check
|
||||
}
|
||||
|
||||
private val swordNerf = 0.5
|
||||
@@ -277,11 +187,7 @@ class GameStateListener(
|
||||
fun onDamageEntity(
|
||||
event: EntityDamageByEntityEvent
|
||||
) {
|
||||
val damager = event.damager
|
||||
|
||||
if ( damager !is Player )
|
||||
return
|
||||
|
||||
val damager = event.damager as? Player ?: return
|
||||
val itemName = damager.inventory.itemInMainHand.type.name
|
||||
|
||||
if (itemName.endsWith( "_SWORD" ))
|
||||
@@ -312,26 +218,16 @@ class GameStateListener(
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onJoin(
|
||||
event: PlayerJoinEvent
|
||||
) {
|
||||
disableCooldown( event.player )
|
||||
}
|
||||
fun onJoin( event: PlayerJoinEvent ) { disableHitCooldown( event.player ) }
|
||||
|
||||
@EventHandler
|
||||
fun onQuit(
|
||||
event: PlayerQuitEvent
|
||||
) {
|
||||
disableCooldown( event.player )
|
||||
}
|
||||
fun onQuit( event: PlayerQuitEvent ) { disableHitCooldown( event.player ) }
|
||||
|
||||
private fun disableCooldown(
|
||||
private fun disableHitCooldown(
|
||||
player: Player
|
||||
) {
|
||||
val attackSpeed = player.getAttribute( Attribute.GENERIC_ATTACK_SPEED )
|
||||
|
||||
if ( attackSpeed != null )
|
||||
attackSpeed.baseValue = 40.0
|
||||
if ( attackSpeed != null ) attackSpeed.baseValue = 40.0
|
||||
}
|
||||
|
||||
private val lapisLazuli = Material.LAPIS_LAZULI
|
||||
@@ -354,10 +250,9 @@ class GameStateListener(
|
||||
val item = event.currentItem
|
||||
?: return
|
||||
|
||||
// prevent taking it out
|
||||
if ( item.type == lapisLazuli && event.rawSlot == 1 )
|
||||
event.isCancelled = true
|
||||
else if ( event.cursor.type == lapisLazuli && event.click == ClickType.DOUBLE_CLICK)
|
||||
else if ( event.cursor.type == lapisLazuli && event.click == ClickType.DOUBLE_CLICK )
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
@@ -385,52 +280,12 @@ class GameStateListener(
|
||||
( inventory as EnchantingInventory ).secondary = ItemStack( lapisLazuli, 64 )
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onInteractSoup(
|
||||
event: PlayerInteractEvent
|
||||
) {
|
||||
val player = event.player
|
||||
val action = event.action
|
||||
|
||||
if ( action != Action.RIGHT_CLICK_AIR &&
|
||||
action != Action.RIGHT_CLICK_BLOCK )
|
||||
return
|
||||
|
||||
if ( !event.hasItem() ||
|
||||
event.material != Material.MUSHROOM_STEW )
|
||||
return
|
||||
|
||||
if ( event.hand == EquipmentSlot.OFF_HAND )
|
||||
return
|
||||
|
||||
if ( player.health < requireNotNull(player.getAttribute( Attribute.GENERIC_MAX_HEALTH )!!.defaultValue))
|
||||
{
|
||||
player.health = min( player.health + 7, requireNotNull(player.getAttribute( Attribute.GENERIC_MAX_HEALTH )!!.defaultValue))
|
||||
player.inventory.setItemInMainHand(ItemStack( Material.BOWL ))
|
||||
}
|
||||
else if ( player.foodLevel < 20 )
|
||||
{
|
||||
player.foodLevel += 6
|
||||
player.saturation += 7
|
||||
player.inventory.setItemInMainHand(ItemStack( Material.BOWL ))
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onEntityDamage(
|
||||
event: EntityDamageEvent
|
||||
) {
|
||||
if ( gameManager.isRunning() )
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onFoodLevelChange(
|
||||
event: FoodLevelChangeEvent
|
||||
) {
|
||||
if ( gameManager.isRunning() )
|
||||
if ( gameManager.currentState == GameState.INVINCIBILITY ||
|
||||
gameManager.currentState == GameState.INGAME )
|
||||
return
|
||||
|
||||
event.foodLevel = 20
|
||||
@@ -441,244 +296,40 @@ class GameStateListener(
|
||||
fun onCraftItem(
|
||||
event: CraftItemEvent
|
||||
) {
|
||||
if ( !gameManager.isRunning() )
|
||||
return
|
||||
|
||||
val player = event.whoClicked
|
||||
|
||||
if ( player !is Player )
|
||||
if ( gameManager.currentState == GameState.INVINCIBILITY ||
|
||||
gameManager.currentState == GameState.INGAME )
|
||||
return
|
||||
|
||||
val player = event.whoClicked as? Player ?: return
|
||||
val item = event.recipe.result
|
||||
|
||||
if ( event.isShiftClick )
|
||||
{
|
||||
player.sendMsg( "craft.no_shift_click" )
|
||||
player.playSound( player.location, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
return
|
||||
}
|
||||
|
||||
if ( item.type == Material.SHIELD )
|
||||
{
|
||||
if ( event.isShiftClick )
|
||||
{
|
||||
plugin.chatManager.sendMessage( player, "craft.no_shift_click" )
|
||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
return
|
||||
}
|
||||
|
||||
event.result = Event.Result.DENY
|
||||
plugin.chatManager.sendMessage( player, "craft.no_shield" )
|
||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
player.sendMsg( "craft.no_shield" )
|
||||
player.playSound( player.location, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
return
|
||||
}
|
||||
|
||||
if (!item.type.name.contains( "iron", true ))
|
||||
return
|
||||
|
||||
if ( gameManager.isBeforeFeast() )
|
||||
{
|
||||
event.result = Event.Result.DENY
|
||||
plugin.chatManager.sendMessage( player, "craft.no_iron_before_feast" )
|
||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
return
|
||||
}
|
||||
// TODO: add before feast check and deny item crafting
|
||||
|
||||
if ( item.type.maxDurability > 0 )
|
||||
{
|
||||
item.editMeta { meta -> ( meta as Damageable ).damage /= 2 }
|
||||
plugin.chatManager.sendMessage( player, "craft.iron_nerf" )
|
||||
player.sendMsg( "craft.iron_nerf" )
|
||||
}
|
||||
|
||||
runBlocking { plugin.statsRepository.addIronFarmed( player.uniqueId, 0.1 ) }
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onInteractCleanse(
|
||||
event: PlayerInteractEvent
|
||||
) {
|
||||
if ( gameManager.isBeforeFeast() )
|
||||
return
|
||||
|
||||
val player = event.player
|
||||
val action = event.action
|
||||
|
||||
val item = event.item ?: return
|
||||
val block = event.clickedBlock
|
||||
|
||||
if ( block != null && gameManager.feastBox.contains( block.location.toVector() ))
|
||||
{
|
||||
event.isCancelled = true
|
||||
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
return
|
||||
}
|
||||
|
||||
if ( action != Action.RIGHT_CLICK_AIR &&
|
||||
action != Action.RIGHT_CLICK_BLOCK )
|
||||
return
|
||||
|
||||
if ( item.type != Material.SUGAR ||
|
||||
!item.itemMeta.isUnbreakable )
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
|
||||
player.inventory.removeItemAnySlot( item )
|
||||
player.clearActivePotionEffects()
|
||||
|
||||
plugin.chatManager.sendMessage( player, "feast.cleanser.cleaned" )
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onBucketEmpty(
|
||||
event: PlayerBucketEmptyEvent
|
||||
) {
|
||||
if ( gameManager.getCurrentStateType() != GameStateTypes.FEAST )
|
||||
return
|
||||
|
||||
val location = event.blockClicked.location.toVector()
|
||||
|
||||
if (!gameManager.feastBox.contains( location ))
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
event.player.playSound( event.player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onLiquidSpread(
|
||||
event: BlockSpreadEvent
|
||||
) {
|
||||
if ( gameManager.getCurrentStateType() != GameStateTypes.FEAST )
|
||||
return
|
||||
|
||||
val block = event.block
|
||||
|
||||
if ( !block.isLiquid )
|
||||
return
|
||||
|
||||
if (!gameManager.feastBox.contains( block.location.toVector() ))
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
enum class DeathType {
|
||||
PLAYER,
|
||||
ENTITY,
|
||||
WORLD
|
||||
}
|
||||
|
||||
private val playerDeathMessages: Int = plugin.messageConfig.data.deathMessages["player"]!!.size
|
||||
private val entityDeathMessages: Int = plugin.messageConfig.data.deathMessages["entity"]!!.size
|
||||
private val worldDeathMessages: Int = plugin.messageConfig.data.deathMessages["world"]!!.size
|
||||
|
||||
@EventHandler
|
||||
fun onDeath(
|
||||
event: PlayerDeathEvent
|
||||
) {
|
||||
val player = event.entity
|
||||
suppressEvent( event )
|
||||
|
||||
val lastDamageCause = player.lastDamageCause
|
||||
var killer: Entity? = null
|
||||
var deathType = DeathType.WORLD
|
||||
|
||||
if ( lastDamageCause is EntityDamageByEntityEvent )
|
||||
{
|
||||
val damager = lastDamageCause.damager
|
||||
|
||||
if ( damager !is Player )
|
||||
{
|
||||
if ( damager is Projectile )
|
||||
{
|
||||
if ( damager.shooter is Player )
|
||||
{
|
||||
deathType = DeathType.PLAYER
|
||||
killer = damager.shooter as Player
|
||||
}
|
||||
else
|
||||
{
|
||||
deathType = DeathType.ENTITY
|
||||
killer = damager.shooter as Entity
|
||||
}
|
||||
}
|
||||
else if ( damager is Tameable && damager.isTamed && damager.owner is Player )
|
||||
{
|
||||
deathType = DeathType.PLAYER
|
||||
killer = damager.owner as Player
|
||||
}
|
||||
else
|
||||
{
|
||||
deathType = DeathType.ENTITY
|
||||
killer = damager
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
deathType = DeathType.PLAYER
|
||||
killer = damager
|
||||
}
|
||||
}
|
||||
|
||||
if ( killer != null && killer is Player )
|
||||
{
|
||||
killer.exp += 0.5f
|
||||
runBlocking { plugin.statsRepository.addKills( killer.uniqueId, 1 ) }
|
||||
}
|
||||
|
||||
when( deathType )
|
||||
{
|
||||
DeathType.PLAYER ->
|
||||
{
|
||||
val random = this.random.nextInt( 0, playerDeathMessages )
|
||||
|
||||
val message = plugin.chatFormatter.formatList( "death.player",
|
||||
"{player}" to player.getDisplayName, "{killer}" to (killer as Player).getDisplayName
|
||||
)[ random ]
|
||||
|
||||
for ( p in Bukkit.getOnlinePlayers() )
|
||||
plugin.chatManager.sendInteractiveMessage( p, message )
|
||||
}
|
||||
|
||||
DeathType.ENTITY ->
|
||||
{
|
||||
val random = this.random.nextInt( 0, entityDeathMessages )
|
||||
|
||||
val message = plugin.chatFormatter.formatList( "death.entity",
|
||||
"{player}" to player.getDisplayName, "{entity}" to killer!!.type.name
|
||||
)[ random ]
|
||||
|
||||
for ( p in Bukkit.getOnlinePlayers() )
|
||||
plugin.chatManager.sendInteractiveMessage( p, message )
|
||||
}
|
||||
|
||||
DeathType.WORLD ->
|
||||
{
|
||||
val random = this.random.nextInt( 0, worldDeathMessages )
|
||||
|
||||
val message = plugin.chatFormatter.formatList( "death.world",
|
||||
"{player}" to player.getDisplayName
|
||||
)[ random ]
|
||||
|
||||
for ( p in Bukkit.getOnlinePlayers() )
|
||||
plugin.chatManager.sendInteractiveMessage( p, message )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun suppressEvent(
|
||||
event: PlayerDeathEvent
|
||||
) {
|
||||
val player = event.entity
|
||||
|
||||
event.deathMessage( null )
|
||||
|
||||
event.setShouldDropExperience( false )
|
||||
|
||||
event.setShouldPlayDeathSound( false )
|
||||
player.world.strikeLightningEffect( player.location )
|
||||
|
||||
runBlocking {
|
||||
plugin.statsRepository.addDeaths( player.uniqueId, 1 )
|
||||
plugin.playerRepository.updateAliveStatus( player.uniqueId, false )
|
||||
}
|
||||
|
||||
if ( player.isOnline )
|
||||
player.kick(plugin.chatFormatter.format( "death.kick" ))
|
||||
// TODO: add 0.1 to ironFarmed in database
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package club.mcscrims.speedhg.listener
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.speedhg.game.GameStateTypes
|
||||
import club.mcscrims.speedhg.util.LuckPermsUtils
|
||||
import club.mcscrims.speedhg.util.TimeUtils
|
||||
import com.lunarclient.apollo.Apollo
|
||||
import com.lunarclient.apollo.event.ApolloListener
|
||||
import com.lunarclient.apollo.event.Listen
|
||||
import com.lunarclient.apollo.event.player.ApolloRegisterPlayerEvent
|
||||
import com.lunarclient.apollo.mods.impl.ModFreelook
|
||||
import com.lunarclient.apollo.mods.impl.ModMinimap
|
||||
import com.lunarclient.apollo.mods.impl.ModSnaplook
|
||||
import com.lunarclient.apollo.mods.impl.ModTeamView
|
||||
import com.lunarclient.apollo.mods.impl.ModWaypoints
|
||||
import com.lunarclient.apollo.module.modsetting.ModSettingModule
|
||||
import com.lunarclient.apollo.module.richpresence.RichPresenceModule
|
||||
import com.lunarclient.apollo.module.richpresence.ServerRichPresence
|
||||
import com.lunarclient.apollo.module.serverrule.ServerRuleModule
|
||||
import com.lunarclient.apollo.module.staffmod.StaffMod
|
||||
import com.lunarclient.apollo.module.staffmod.StaffModModule
|
||||
import com.lunarclient.apollo.player.ApolloPlayer
|
||||
|
||||
class LunarClientListener(
|
||||
private val plugin: SpeedHG
|
||||
) : ApolloListener {
|
||||
|
||||
private val modSettingModule = Apollo.getModuleManager().getModule( ModSettingModule::class.java )
|
||||
private val staffModModule = Apollo.getModuleManager().getModule( StaffModModule::class.java )
|
||||
|
||||
private val richPresenceModule = Apollo.getModuleManager().getModule( RichPresenceModule::class.java )
|
||||
|
||||
private val serverRuleModule = Apollo.getModuleManager().getModule( ServerRuleModule::class.java )
|
||||
|
||||
init {
|
||||
this.handle( ApolloRegisterPlayerEvent::class.java, this::onApolloRegister )
|
||||
}
|
||||
|
||||
@Listen
|
||||
fun onApolloRegister(
|
||||
event: ApolloRegisterPlayerEvent
|
||||
) {
|
||||
val player = event.player
|
||||
|
||||
setModSettings( player )
|
||||
setRichPresence( player )
|
||||
setServerRules( player )
|
||||
}
|
||||
|
||||
private fun setServerRules(
|
||||
player: ApolloPlayer
|
||||
) {
|
||||
serverRuleModule.options.set( player, ServerRuleModule.COMPETITIVE_GAME, plugin.pluginConfig.data.game.competitiveGame )
|
||||
serverRuleModule.options.set( player, ServerRuleModule.COMPETITIVE_COMMANDS, plugin.pluginConfig.data.game.competitiveCommands )
|
||||
serverRuleModule.options.set( player, ServerRuleModule.ANTI_PORTAL_TRAPS, true )
|
||||
}
|
||||
|
||||
private fun setRichPresence(
|
||||
player: ApolloPlayer
|
||||
) {
|
||||
val teamMaxSize = plugin.pluginConfig.data.game.teams["maximum_players"] as? Int ?: 2
|
||||
|
||||
val playerState = when( plugin.gameManager.getCurrentStateType() )
|
||||
{
|
||||
GameStateTypes.WAITING -> plugin.pluginConfig.data.game.playerStates[ "waiting" ]?.scoreboard ?: "N/A"
|
||||
GameStateTypes.PRE_START -> plugin.pluginConfig.data.game.playerStates[ "pre_start" ]?.scoreboard ?: "N/A"
|
||||
GameStateTypes.IMMUNITY -> plugin.pluginConfig.data.game.playerStates[ "immunity" ]?.scoreboard ?: "N/A"
|
||||
GameStateTypes.BATTLE -> plugin.pluginConfig.data.game.playerStates[ "battle" ]?.scoreboard ?: "N/A"
|
||||
GameStateTypes.FEAST -> plugin.pluginConfig.data.game.playerStates[ "feast" ]?.scoreboard ?: "N/A"
|
||||
GameStateTypes.DEATHMATCH -> plugin.pluginConfig.data.game.playerStates[ "deathmatch" ]?.scoreboard ?: "N/A"
|
||||
GameStateTypes.END -> plugin.pluginConfig.data.game.playerStates[ "end" ]?.scoreboard ?: "N/A"
|
||||
else -> throw IllegalStateException("Current game state is null!")
|
||||
}
|
||||
|
||||
val presence = ServerRichPresence.builder()
|
||||
.gameName( plugin.pluginConfig.data.game.name )
|
||||
.gameState( plugin.gameManager.getCurrentStateType()!!.name )
|
||||
.gameVariantName( plugin.pluginConfig.data.game.variantName )
|
||||
.playerState(playerState.replace( "%time%", TimeUtils.scoreboardTimeFromState() ))
|
||||
.teamCurrentSize( 0 ) // TODO: Add team manager
|
||||
.teamMaxSize( teamMaxSize )
|
||||
.build()
|
||||
|
||||
richPresenceModule.overrideServerRichPresence( player, presence )
|
||||
}
|
||||
|
||||
private fun setModSettings(
|
||||
player: ApolloPlayer
|
||||
) {
|
||||
if (LuckPermsUtils.hasPermission( player.uniqueId, "mcscrims.staff" ))
|
||||
staffModModule.enableStaffMods( player, listOf( StaffMod.XRAY ))
|
||||
else
|
||||
staffModModule.disableAllStaffMods( player )
|
||||
|
||||
if (LuckPermsUtils.hasPermission( player.uniqueId, "speedhg.bypass.modSettings" ))
|
||||
return
|
||||
|
||||
modSettingModule.options.set( player, ModMinimap.ENABLED, false )
|
||||
modSettingModule.options.set( player, ModFreelook.ENABLED, false )
|
||||
modSettingModule.options.set( player, ModSnaplook.ENABLED, false )
|
||||
modSettingModule.options.set( player, ModWaypoints.ENABLED, false )
|
||||
modSettingModule.options.set( player, ModTeamView.ENABLED, true )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package club.mcscrims.speedhg.listener
|
||||
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.attribute.Attribute
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.EventPriority
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.inventory.EquipmentSlot
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import kotlin.math.min
|
||||
|
||||
class SoupListener : Listener {
|
||||
|
||||
@EventHandler(
|
||||
priority = EventPriority.HIGHEST,
|
||||
ignoreCancelled = true
|
||||
)
|
||||
fun onSoup(
|
||||
event: PlayerInteractEvent
|
||||
) {
|
||||
val player = event.player
|
||||
val action = event.action
|
||||
|
||||
if ( !action.isRightClick )
|
||||
return
|
||||
|
||||
if ( !event.hasItem() ||
|
||||
event.material != Material.MUSHROOM_STEW )
|
||||
return
|
||||
|
||||
if ( event.hand == EquipmentSlot.OFF_HAND )
|
||||
return
|
||||
|
||||
if ( player.health < requireNotNull(player.getAttribute( Attribute.GENERIC_MAX_HEALTH )?.defaultValue ))
|
||||
{
|
||||
player.health = min( player.health + 7, requireNotNull(player.getAttribute( Attribute.GENERIC_MAX_HEALTH )?.defaultValue ))
|
||||
player.inventory.setItemInMainHand(ItemStack( Material.BOWL ))
|
||||
}
|
||||
else if ( player.foodLevel < 20 )
|
||||
{
|
||||
player.foodLevel += 6
|
||||
player.saturation += 7
|
||||
player.inventory.setItemInMainHand(ItemStack( Material.BOWL ))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package club.mcscrims.speedhg.recraft
|
||||
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
|
||||
class Recraft {
|
||||
|
||||
private val recraftMaterials = listOf(
|
||||
RecraftMaterial( 1, arrayOf( Material.RED_MUSHROOM, Material.BROWN_MUSHROOM )),
|
||||
RecraftMaterial( 1, arrayOf( Material.COCOA_BEANS )),
|
||||
RecraftMaterial( 1, arrayOf( Material.CACTUS ))
|
||||
)
|
||||
|
||||
fun calcRecraft(
|
||||
vararg items: ItemStack?
|
||||
) {
|
||||
recraftMaterials.forEach( RecraftMaterial::reset )
|
||||
|
||||
for ( item in items )
|
||||
{
|
||||
if ( item == null )
|
||||
return
|
||||
|
||||
for ( recraftMaterial in recraftMaterials )
|
||||
{
|
||||
val type = item.type
|
||||
|
||||
if (recraftMaterial.containsKey( type ))
|
||||
recraftMaterial[ type ] = recraftMaterial.getOrDefault( type , 0 ) + item.amount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun decrease(
|
||||
player: Player,
|
||||
amount: Int
|
||||
) {
|
||||
val lowestMaterials = mutableListOf<Material>()
|
||||
|
||||
for ( recraftMaterial in recraftMaterials )
|
||||
if ( recraftMaterial.getLowestMaterial() != null )
|
||||
lowestMaterials.add( recraftMaterial.getLowestMaterial()!! )
|
||||
|
||||
var highestMaterial: Material? = null
|
||||
var i = 0f
|
||||
|
||||
for ( lowestMaterial in lowestMaterials )
|
||||
{
|
||||
val recraftMaterial = byMaterial( lowestMaterial )
|
||||
|
||||
if (recraftMaterial!![ lowestMaterial ]!! * recraftMaterial.getMaterialValue() > i )
|
||||
{
|
||||
i = recraftMaterial[ lowestMaterial ]!! * recraftMaterial.getMaterialValue()
|
||||
highestMaterial = lowestMaterial
|
||||
}
|
||||
}
|
||||
|
||||
val recraftMaterial = byMaterial( highestMaterial!! )
|
||||
recraftMaterial?.decrease( highestMaterial, amount )
|
||||
|
||||
for ( item in player.inventory.contents )
|
||||
{
|
||||
if ( item == null )
|
||||
continue
|
||||
|
||||
if ( item.type == highestMaterial )
|
||||
{
|
||||
item.amount -= amount
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun byMaterial(
|
||||
material: Material
|
||||
): RecraftMaterial?
|
||||
{
|
||||
return recraftMaterials.stream().filter { it.containsKey( material ) }.findFirst().orElse( null )
|
||||
}
|
||||
|
||||
fun getRecraftPoints(): Float
|
||||
{
|
||||
var points = 0f
|
||||
|
||||
for ( recraftMaterial in recraftMaterials )
|
||||
points += recraftMaterial.getPoints()
|
||||
|
||||
return points
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package club.mcscrims.speedhg.recraft
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.speedhg.game.GameStateTypes
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.scheduler.BukkitRunnable
|
||||
|
||||
class RecraftInspector(
|
||||
private val plugin: SpeedHG
|
||||
) {
|
||||
|
||||
private val beforeState = plugin.pluginConfig.data.game.recraftNerf[ "before_state" ] as String
|
||||
private val recraftNerfEnabled = plugin.pluginConfig.data.game.recraftNerf[ "enabled" ] as Boolean
|
||||
private val maxRecraftAmount = plugin.pluginConfig.data.game.recraftNerf[ "max_amount" ] as Double
|
||||
|
||||
fun startRunnable()
|
||||
{
|
||||
if ( !recraftNerfEnabled )
|
||||
return
|
||||
|
||||
object : BukkitRunnable() {
|
||||
|
||||
val gameStateType = GameStateTypes.valueOf( beforeState.uppercase() )
|
||||
|
||||
override fun run()
|
||||
{
|
||||
if (!plugin.gameManager.isBefore( gameStateType ))
|
||||
{
|
||||
this.cancel()
|
||||
return
|
||||
}
|
||||
|
||||
Bukkit.getOnlinePlayers().stream()
|
||||
.filter { !it.isDead }
|
||||
.forEach { player ->
|
||||
val recraft = Recraft()
|
||||
recraft.calcRecraft( *player.inventory.contents )
|
||||
|
||||
if ( recraft.getRecraftPoints() > maxRecraftAmount )
|
||||
{
|
||||
plugin.chatManager.sendMessage( player, "recraftNerf.too_much" )
|
||||
|
||||
while ( recraft.getRecraftPoints() > maxRecraftAmount )
|
||||
recraft.decrease( player, 1 )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}.runTaskTimer( plugin, 10L, 20L )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package club.mcscrims.speedhg.recraft
|
||||
|
||||
import org.bukkit.Material
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class RecraftMaterial(
|
||||
val maxSoupAmount: Int,
|
||||
val materials: Array<Material>
|
||||
): ConcurrentHashMap<Material, Int>() {
|
||||
|
||||
fun getPoints(): Float
|
||||
{
|
||||
return getOrDefault( getLowestMaterial(), 0 ).toFloat()
|
||||
}
|
||||
|
||||
fun decrease(
|
||||
material: Material,
|
||||
amount: Int,
|
||||
) {
|
||||
put( material, get( material )!! - amount )
|
||||
}
|
||||
|
||||
fun getLowestMaterial(): Material?
|
||||
{
|
||||
if ( size > 1 )
|
||||
{
|
||||
if (values.stream().anyMatch { int -> int == 0 })
|
||||
return null
|
||||
|
||||
val materialIntegerEntry = entries.stream().min(Comparator.comparingInt { it.value })
|
||||
return materialIntegerEntry.map { it.key }.orElse( null )
|
||||
}
|
||||
else return keys.stream().findFirst().orElse( null )
|
||||
}
|
||||
|
||||
fun getMaterialValue() = ( maxSoupAmount / size ).toFloat()
|
||||
|
||||
fun reset()
|
||||
{
|
||||
replaceAll { _, _ -> 0 }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package club.mcscrims.speedhg.recraft
|
||||
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.NamespacedKey
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.ShapelessRecipe
|
||||
|
||||
object RecraftUtils {
|
||||
|
||||
fun registerRecipes()
|
||||
{
|
||||
val soup = ItemStack( Material.MUSHROOM_STEW )
|
||||
|
||||
val cocoRecipe = ShapelessRecipe(NamespacedKey.minecraft( "cocoa_soup" ), soup )
|
||||
cocoRecipe.addIngredient( Material.COCOA_BEANS )
|
||||
cocoRecipe.addIngredient( Material.BOWL )
|
||||
|
||||
val cactiRecipe = ShapelessRecipe(NamespacedKey.minecraft( "cacti_soup" ), soup )
|
||||
cactiRecipe.addIngredient( Material.CACTUS )
|
||||
cactiRecipe.addIngredient( Material.BOWL )
|
||||
|
||||
Bukkit.addRecipe( cocoRecipe )
|
||||
Bukkit.addRecipe( cactiRecipe )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package club.mcscrims.speedhg.scoreboard
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import club.mcscrims.speedhg.game.GameState
|
||||
import club.mcscrims.speedhg.util.trans
|
||||
import club.mcscrims.speedhg.util.transList
|
||||
import fr.mrmicky.fastboard.adventure.FastBoard
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Statistic
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.player.PlayerJoinEvent
|
||||
import org.bukkit.event.player.PlayerQuitEvent
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class ScoreboardManager(
|
||||
private val plugin: SpeedHG
|
||||
): Listener {
|
||||
|
||||
private val boards = ConcurrentHashMap<UUID, FastBoard>()
|
||||
|
||||
init {
|
||||
Bukkit.getScheduler().runTaskTimer( plugin, { ->
|
||||
updateAllBoards()
|
||||
}, 0L, 10L )
|
||||
|
||||
plugin.server.pluginManager.registerEvents( this, plugin )
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onJoin(
|
||||
event: PlayerJoinEvent
|
||||
) {
|
||||
val board = FastBoard( event.player )
|
||||
board.updateTitle(event.player.trans( "scoreboard.title" ))
|
||||
boards[ event.player.uniqueId ] = board
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onQuit(
|
||||
event: PlayerQuitEvent
|
||||
) {
|
||||
boards.remove( event.player.uniqueId )?.delete()
|
||||
}
|
||||
|
||||
private fun updateAllBoards()
|
||||
{
|
||||
boards.forEach { (key, value) ->
|
||||
val player = Bukkit.getPlayer( key )
|
||||
|
||||
if ( player != null )
|
||||
updateBoard( player, value )
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateBoard(
|
||||
player: Player,
|
||||
board: FastBoard
|
||||
) {
|
||||
val gm = plugin.gameManager
|
||||
val state = gm.currentState
|
||||
|
||||
board.updateTitle(player.trans( "scoreboard.title" ))
|
||||
|
||||
val online = Bukkit.getOnlinePlayers().size.toString()
|
||||
val max = Bukkit.getMaxPlayers().toString()
|
||||
val kitName = "None" // TODO
|
||||
|
||||
val lines: List<Component>
|
||||
|
||||
if ( state == GameState.LOBBY || state == GameState.STARTING )
|
||||
{
|
||||
val timeString = if ( state == GameState.STARTING ) formatTime( gm.timer ) else "Waiting..."
|
||||
|
||||
lines = player.transList( "scoreboard.lobby", mapOf(
|
||||
"online" to online,
|
||||
"max" to max,
|
||||
"kit" to kitName,
|
||||
"time" to timeString
|
||||
))
|
||||
}
|
||||
else
|
||||
{
|
||||
val timeString = formatTime( gm.timer )
|
||||
val alive = gm.alivePlayers.size.toString()
|
||||
val kills = player.getStatistic( Statistic.PLAYER_KILLS ).toString()
|
||||
val border = String.format( "%.0f", player.world.worldBorder.size )
|
||||
|
||||
lines = player.transList( "scoreboard.ingame", mapOf(
|
||||
"timer" to timeString,
|
||||
"alive" to alive,
|
||||
"kills" to kills,
|
||||
"border" to border,
|
||||
"kit" to kitName
|
||||
))
|
||||
}
|
||||
|
||||
board.updateLines( lines )
|
||||
}
|
||||
|
||||
private fun formatTime(
|
||||
seconds: Int
|
||||
): String
|
||||
{
|
||||
val m = seconds / 60
|
||||
val s = seconds % 60
|
||||
return String.format( "%02d:%02d", m, s )
|
||||
}
|
||||
|
||||
}
|
||||
101
src/main/kotlin/club/mcscrims/speedhg/util/AbilityUtils.kt
Normal file
101
src/main/kotlin/club/mcscrims/speedhg/util/AbilityUtils.kt
Normal file
@@ -0,0 +1,101 @@
|
||||
package club.mcscrims.speedhg.util
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import org.bukkit.Color
|
||||
import org.bukkit.GameMode
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.Particle
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.scheduler.BukkitRunnable
|
||||
import org.bukkit.util.Vector
|
||||
import java.util.function.Consumer
|
||||
|
||||
object AbilityUtils {
|
||||
|
||||
private val plugin = SpeedHG.instance
|
||||
|
||||
fun createBeam(
|
||||
startLocation: Location,
|
||||
direction: Vector,
|
||||
particle: Particle,
|
||||
range: Double,
|
||||
step: Double,
|
||||
onHit: (Player) -> Unit
|
||||
) {
|
||||
val normalizedDirection = direction.normalize()
|
||||
|
||||
object : BukkitRunnable()
|
||||
{
|
||||
var traveledDistance = 0.0
|
||||
var currentLocation = startLocation.clone()
|
||||
|
||||
override fun run()
|
||||
{
|
||||
if ( traveledDistance >= range)
|
||||
{
|
||||
this.cancel()
|
||||
return
|
||||
}
|
||||
|
||||
currentLocation.world.spawnParticle( particle, currentLocation, 5, 0.0, 0.0, 0.0, 0.0 )
|
||||
|
||||
val nearestPlayer = currentLocation.world.getNearbyEntities( currentLocation, 0.5, 0.5, 0.5 )
|
||||
.filterIsInstance<Player>().minByOrNull { it.location.distance( currentLocation ) }
|
||||
|
||||
if ( nearestPlayer != null )
|
||||
{
|
||||
onHit( nearestPlayer )
|
||||
this.cancel()
|
||||
return
|
||||
}
|
||||
|
||||
currentLocation.add(normalizedDirection.multiply( step ))
|
||||
traveledDistance += step
|
||||
}
|
||||
|
||||
}.runTaskTimer( plugin, 0L, 1L )
|
||||
}
|
||||
|
||||
fun drawParticleLine(
|
||||
startLocation: Location,
|
||||
endLocation: Location,
|
||||
particle: Particle,
|
||||
steps: Int,
|
||||
dustColor: Color
|
||||
) {
|
||||
if ( steps <= 0 ) throw IllegalArgumentException( "Steps must be greater than 0." )
|
||||
val world = startLocation.world ?: throw IllegalStateException( "World cannot be null." )
|
||||
if ( startLocation.world != endLocation.world ) throw IllegalStateException( "Locations must be in the same world." )
|
||||
|
||||
val diffX = ( endLocation.x - startLocation.x ) / steps
|
||||
val diffY = ( endLocation.y - startLocation.y ) / steps
|
||||
val diffZ = ( endLocation.z - startLocation.z ) / steps
|
||||
|
||||
for ( i in 0..steps )
|
||||
{
|
||||
val x = startLocation.x + diffX * i
|
||||
val y = startLocation.y + diffY * i
|
||||
val z = startLocation.z + diffZ * i
|
||||
|
||||
world.spawnParticle( particle, x, y, z, 1, Particle.DustOptions( dustColor, 1f ))
|
||||
}
|
||||
}
|
||||
|
||||
fun runForNearbyPlayers(
|
||||
player: Player,
|
||||
radius: Double,
|
||||
filter: (Player) -> Boolean,
|
||||
runnable: Consumer<in Player>
|
||||
): MutableCollection<Player>
|
||||
{
|
||||
if ( radius <= 0.0 ) throw IllegalArgumentException( "Radius must be greater than 0.0." )
|
||||
|
||||
val world = player.world
|
||||
val nearbyPlayers = world.getNearbyPlayers( player.location, radius ).filter( filter )
|
||||
.filter { it != player && it.gameMode == GameMode.SURVIVAL }.toMutableList()
|
||||
|
||||
nearbyPlayers.forEach( runnable )
|
||||
return nearbyPlayers
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package club.mcscrims.speedhg.util
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.util.Vector
|
||||
import kotlin.math.atan2
|
||||
|
||||
object DirectionUtil {
|
||||
|
||||
private val plugin = SpeedHG.instance
|
||||
private val directions = arrayOf("north", "northEast", "east", "southEast", "south", "southWest", "west", "northWest")
|
||||
|
||||
fun getDirectionToPlayer(
|
||||
player: Player,
|
||||
nearestPlayer: Player
|
||||
): Component
|
||||
{
|
||||
val yaw = getDirection( player, nearestPlayer )
|
||||
var normalizedYaw = yaw % 360
|
||||
|
||||
if ( normalizedYaw < 0 )
|
||||
normalizedYaw += 360
|
||||
|
||||
val index = (( normalizedYaw + 22.5 ) / 45 ).toInt() % 8
|
||||
return plugin.chatFormatter.format( "compass.directions.${directions[ index ]}" )
|
||||
}
|
||||
|
||||
private fun getDirection(
|
||||
fromPlayer: Player,
|
||||
toPlayer: Player
|
||||
): Double
|
||||
{
|
||||
val fromLocation = fromPlayer.location
|
||||
val toLocation = toPlayer.location
|
||||
|
||||
val directionVector = Vector( toLocation.x - fromLocation.x, 0.0, toLocation.z - fromLocation.z ).normalize()
|
||||
|
||||
val angle = atan2( directionVector.x, directionVector.z )
|
||||
val yaw = Math.toDegrees( angle )
|
||||
|
||||
var adjustedYaw = yaw + 180
|
||||
|
||||
if ( adjustedYaw < 0)
|
||||
adjustedYaw += 360
|
||||
|
||||
return adjustedYaw
|
||||
}
|
||||
|
||||
fun getTargetPlayerInLineOfSight(
|
||||
player: Player,
|
||||
maxDistance: Double,
|
||||
width: Double
|
||||
): Player?
|
||||
{
|
||||
val direction = player.eyeLocation.direction.normalize()
|
||||
val origin = player.eyeLocation.toVector()
|
||||
val world = player.world
|
||||
|
||||
val nearbyPlayers = world.getNearbyEntitiesByType( Player::class.java, player.location, maxDistance, maxDistance, maxDistance )
|
||||
|
||||
return nearbyPlayers
|
||||
.filter { it.uniqueId != player.uniqueId }
|
||||
.filter { nearby ->
|
||||
val nearbyLocation = nearby.location.add( 0.0, 0.5, 0.0 ).toVector()
|
||||
|
||||
val toEntitiy = nearbyLocation.subtract( origin )
|
||||
|
||||
val distanceAlongLine = toEntitiy.dot( direction )
|
||||
if ( distanceAlongLine !in 0.0..maxDistance ) return@filter false
|
||||
|
||||
val perpendicularDistance = toEntitiy.subtract(direction.multiply( distanceAlongLine )).length()
|
||||
perpendicularDistance <= width
|
||||
}
|
||||
.minByOrNull { it.location.distanceSquared( player.location ) }
|
||||
}
|
||||
|
||||
}
|
||||
55
src/main/kotlin/club/mcscrims/speedhg/util/Extensions.kt
Normal file
55
src/main/kotlin/club/mcscrims/speedhg/util/Extensions.kt
Normal file
@@ -0,0 +1,55 @@
|
||||
package club.mcscrims.speedhg.util
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import net.kyori.adventure.text.Component
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
private val langManager get() = SpeedHG.instance.languageManager
|
||||
|
||||
private val legacySerializer = LegacyComponentSerializer.builder()
|
||||
.character('§')
|
||||
.hexColors()
|
||||
.useUnusualXRepeatedCharacterHexFormat()
|
||||
.build()
|
||||
|
||||
fun Player.sendMsg(
|
||||
key: String,
|
||||
vararg placeholders: Pair<String, String>
|
||||
) {
|
||||
val component = langManager.getComponent( this, key, placeholders.toMap() )
|
||||
this.sendMessage( component )
|
||||
}
|
||||
|
||||
fun Player.trans(
|
||||
key: String,
|
||||
vararg placeholders: Pair<String, String>
|
||||
): Component
|
||||
{
|
||||
return langManager.getComponent( this, key, placeholders.toMap() )
|
||||
}
|
||||
|
||||
fun Player.transList(
|
||||
key: String,
|
||||
placeholders: Map<String, String>
|
||||
): List<Component>
|
||||
{
|
||||
val rawList = langManager.getRawMessageList( this, key )
|
||||
|
||||
return rawList.map { line ->
|
||||
var replaced = line
|
||||
placeholders.forEach { (k, v) ->
|
||||
replaced = replaced.replace( "<$k>", v )
|
||||
}
|
||||
MiniMessage.miniMessage().deserialize( replaced )
|
||||
}
|
||||
}
|
||||
|
||||
fun Component.toLegacyString(): String
|
||||
{
|
||||
return legacySerializer.serialize( this )
|
||||
}
|
||||
|
||||
val Player.getDisplayName: String
|
||||
get() = legacySerializer.serialize( this.displayName() )
|
||||
@@ -1,61 +0,0 @@
|
||||
package club.mcscrims.speedhg.util
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import net.luckperms.api.cacheddata.CachedDataManager
|
||||
import net.luckperms.api.model.group.Group
|
||||
import net.luckperms.api.model.user.User
|
||||
import org.bukkit.entity.Player
|
||||
import java.util.UUID
|
||||
|
||||
object LuckPermsUtils {
|
||||
|
||||
private val plugin = SpeedHG.instance
|
||||
private val luckPerms = plugin.luckPerms
|
||||
|
||||
fun getUser(
|
||||
player: Player
|
||||
): User?
|
||||
{
|
||||
return luckPerms.userManager.getUser( player.uniqueId )
|
||||
}
|
||||
|
||||
fun editUser(
|
||||
player: Player,
|
||||
action: (User) -> Unit
|
||||
) {
|
||||
luckPerms.userManager.loadUser( player.uniqueId ).thenAcceptAsync( action )
|
||||
}
|
||||
|
||||
fun getGroup(
|
||||
groupName: String
|
||||
): Group?
|
||||
{
|
||||
return luckPerms.groupManager.getGroup( groupName )
|
||||
}
|
||||
|
||||
fun getCachedData(
|
||||
player: Player
|
||||
): CachedDataManager?
|
||||
{
|
||||
return getUser( player )?.cachedData
|
||||
}
|
||||
|
||||
fun hasPermission(
|
||||
uniqueId: UUID,
|
||||
permission: String
|
||||
): Boolean
|
||||
{
|
||||
val cachedData = luckPerms.userManager.loadUser( uniqueId ).get().cachedData
|
||||
return cachedData.permissionData.checkPermission( permission ).asBoolean()
|
||||
}
|
||||
|
||||
fun hasPermission(
|
||||
player: Player,
|
||||
permission: String
|
||||
): Boolean
|
||||
{
|
||||
return getCachedData( player )?.permissionData?.checkPermission( permission )?.asBoolean()
|
||||
?: player.hasPermission( permission )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package club.mcscrims.speedhg.util
|
||||
|
||||
import java.util.*
|
||||
|
||||
class RandomCollection<E> {
|
||||
|
||||
private val map = TreeMap<Double, List<E>>()
|
||||
private val names = hashMapOf<List<E>, 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<E>
|
||||
) {
|
||||
if ( weight <= 0 ) return
|
||||
total += weight
|
||||
map[ total ] = result
|
||||
}
|
||||
|
||||
fun add(
|
||||
name: String,
|
||||
weight: Double,
|
||||
result: List<E>
|
||||
) {
|
||||
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<E>
|
||||
): String
|
||||
{
|
||||
return names.getOrDefault( key, "" )
|
||||
}
|
||||
|
||||
fun getRandom(): List<E>
|
||||
{
|
||||
val value = random.nextDouble() * total
|
||||
return map.higherEntry( value ).value
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package club.mcscrims.speedhg.util
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
|
||||
object TimeUtils {
|
||||
|
||||
private val plugin = SpeedHG.instance
|
||||
|
||||
fun scoreboardTimeFromState(): String
|
||||
{
|
||||
val currentTime = plugin.gameManager.getCurrentState()?.getRemainingSeconds()
|
||||
?: throw IllegalArgumentException("Remaining seconds for state is null!")
|
||||
return scoreboardTime( currentTime )
|
||||
}
|
||||
|
||||
fun scoreboardTime(
|
||||
totalSeconds: Int
|
||||
): String
|
||||
{
|
||||
val hours = totalSeconds / 3600
|
||||
val minutes = (totalSeconds % 3600) / 60
|
||||
val seconds = totalSeconds % 60
|
||||
|
||||
if ( totalSeconds > 3600 )
|
||||
return String.format( "%02d:%02d:%02d", hours, minutes, seconds )
|
||||
return String.format( "%02d:%02d", minutes, seconds )
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
package club.mcscrims.speedhg.world
|
||||
|
||||
import club.mcscrims.speedhg.SpeedHG
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.GameRule
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.World
|
||||
import org.popcraft.chunky.api.ChunkyAPI
|
||||
import java.io.File
|
||||
|
||||
class WorldManager(
|
||||
private val plugin: SpeedHG
|
||||
) {
|
||||
|
||||
private var worldName = "world"
|
||||
private lateinit var world: World
|
||||
|
||||
fun highestLocationWithRadius(
|
||||
center: Location,
|
||||
radius: Int
|
||||
): Location
|
||||
{
|
||||
getWorld()
|
||||
val minX = center.blockX - radius
|
||||
val minZ = center.blockZ - radius
|
||||
val maxX = center.blockX + radius
|
||||
val maxZ = center.blockZ + radius
|
||||
|
||||
var highestY = center.blockY
|
||||
var highestX = minX
|
||||
var highestZ = minZ
|
||||
|
||||
for ( x in minX..maxX )
|
||||
for ( z in minZ..maxZ )
|
||||
{
|
||||
val y = world.getHighestBlockYAt( x, z )
|
||||
|
||||
if ( y > highestY )
|
||||
{
|
||||
highestY = y
|
||||
highestX = x
|
||||
highestZ = z
|
||||
}
|
||||
}
|
||||
|
||||
val highest = Location( world, highestX.toDouble(), highestY.toDouble(), highestZ.toDouble() )
|
||||
return highest
|
||||
}
|
||||
|
||||
/*
|
||||
* DELETION >>
|
||||
*/
|
||||
|
||||
fun deleteWorld()
|
||||
{
|
||||
getWorld()
|
||||
Bukkit.unloadWorld( worldName, false )
|
||||
val folder = File( worldName )
|
||||
deleteFolder( folder )
|
||||
}
|
||||
|
||||
private fun deleteFolder(
|
||||
folder: File
|
||||
) {
|
||||
val files = folder.listFiles()
|
||||
|
||||
if ( files != null )
|
||||
for ( f in files )
|
||||
{
|
||||
if ( f.isDirectory )
|
||||
deleteFolder( f )
|
||||
else
|
||||
f.delete()
|
||||
}
|
||||
|
||||
folder.delete()
|
||||
}
|
||||
|
||||
/*
|
||||
* WORLD >>
|
||||
*/
|
||||
|
||||
lateinit var spawnLocation: Location
|
||||
var borderDecrease: Double = 100.0
|
||||
|
||||
fun setupWorld()
|
||||
{
|
||||
val world = getWorld() ?: return
|
||||
plugin.logger.info("Setting up world...")
|
||||
|
||||
// BORDER >>
|
||||
|
||||
plugin.logger.info("Setting up world... [STAGE [1]: WORLDBORDER]")
|
||||
|
||||
spawnLocation = Location( world, 0.0, world.getHighestBlockYAt( 0, 0).toDouble(), 0.0 )
|
||||
world.worldBorder.center = spawnLocation
|
||||
|
||||
world.worldBorder.size = plugin.pluginConfig.data.world.border["size"]!!
|
||||
world.worldBorder.warningDistance = plugin.pluginConfig.data.world.border["warning_distance"]!!.toInt()
|
||||
world.worldBorder.damageAmount = plugin.pluginConfig.data.world.border["damage"]!!
|
||||
|
||||
borderDecrease = plugin.pluginConfig.data.world.border["decrease"]!!
|
||||
|
||||
// GAMERULES >>
|
||||
|
||||
plugin.logger.info("Setting up world... [Stage [2]: GAMERULES]")
|
||||
|
||||
world.setGameRule( GameRule.ANNOUNCE_ADVANCEMENTS, false )
|
||||
world.setGameRule( GameRule.DO_INSOMNIA, false )
|
||||
world.setGameRule( GameRule.DISABLE_RAIDS, true )
|
||||
world.setGameRule( GameRule.DO_PATROL_SPAWNING, false )
|
||||
world.setGameRule( GameRule.DO_TRADER_SPAWNING, false )
|
||||
|
||||
// CHUNKY >>
|
||||
|
||||
// plugin.logger.info("Setting up world... [Stage [3]: CHUNKY]")
|
||||
// val chunky = Bukkit.getServicesManager().load( ChunkyAPI::class.java )
|
||||
//
|
||||
// if ( chunky == null || chunky.version() != 0 )
|
||||
// {
|
||||
// plugin.isReady = true
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// val radius = world.worldBorder.size / 2
|
||||
//
|
||||
// chunky.startTask( worldName, "square", 0.0, 0.0, radius, radius, "concentric" )
|
||||
// chunky.onGenerationComplete { plugin.isReady = true }
|
||||
//
|
||||
// plugin.server.dispatchCommand( Bukkit.getConsoleSender(), "chunky silent" )
|
||||
|
||||
// FINISH >>
|
||||
|
||||
plugin.logger.info("World has been set up!")
|
||||
}
|
||||
|
||||
private fun setWorld(
|
||||
worldName: String
|
||||
): World?
|
||||
{
|
||||
this.worldName = worldName
|
||||
val world = Bukkit.getWorld( worldName )
|
||||
|
||||
if ( world != null )
|
||||
this.world = world
|
||||
|
||||
return world
|
||||
}
|
||||
|
||||
fun getWorld(): World?
|
||||
{
|
||||
return if ( !::world.isInitialized )
|
||||
try {
|
||||
setWorld( plugin.pluginConfig.data.world.name )
|
||||
} catch ( _: Exception ) { null }
|
||||
else this.world
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,94 +1,21 @@
|
||||
#
|
||||
# |-----| |-----| |-----| |-----| |---\ | | |-----|
|
||||
# | | | | | | \ | | |
|
||||
# |-----| |-----| |---| |---| | | |-----| | |--|
|
||||
# | | | | | / | | | |
|
||||
# |-----| | |-----| |-----| |---/ | | |-----|
|
||||
# v1.0.0 by TDSTOS
|
||||
# SpeedHG v1.0.0 by McScrims-Network
|
||||
# https://github.com/McScrims-Network
|
||||
#
|
||||
# Organization: McScrims-Network (https://github.com/McScrims-Network/)
|
||||
# Owner: TDSTOS (https://github.com/TDSTOS)
|
||||
# Contributors: stavgun (https://github.com/stavgun)
|
||||
#
|
||||
|
||||
debug: false
|
||||
language: 'en_US'
|
||||
|
||||
restart_time: 3
|
||||
|
||||
network:
|
||||
enabled: false
|
||||
serverId: 'server-1'
|
||||
type: REDIS
|
||||
redis:
|
||||
host: 'localhost'
|
||||
port: 6379
|
||||
user: 'default'
|
||||
password: ''
|
||||
database: 0
|
||||
timeout: 5000
|
||||
poolSize: 10
|
||||
|
||||
cooldown: 30
|
||||
needed_hits: 15
|
||||
|
||||
world:
|
||||
name: 'Default'
|
||||
border:
|
||||
size: 1000.0
|
||||
warning_distance: 5.0
|
||||
damage: 5.0
|
||||
decrease: 100.0
|
||||
|
||||
game:
|
||||
name: 'SpeedHG'
|
||||
variantName: 'Solo - Single Kit'
|
||||
min-players: 2
|
||||
lobby-time: 60
|
||||
invincibility-time: 60
|
||||
border-start: 300.0
|
||||
border-end: 20.0
|
||||
border-shrink-time: 600 # 10 Minuten
|
||||
|
||||
minimumPlayers: 8
|
||||
|
||||
competitiveGame: false
|
||||
competitiveCommands:
|
||||
- 'server'
|
||||
- 'servers'
|
||||
- 'hub'
|
||||
- 'lobby'
|
||||
- 'l'
|
||||
|
||||
playerStates:
|
||||
waiting:
|
||||
scoreboard: 'Waiting - %time%'
|
||||
duration: "FIXED:-1"
|
||||
preStart:
|
||||
scoreboard: 'Waiting - %time%'
|
||||
duration: "FIXED:300"
|
||||
immunity:
|
||||
scoreboard: 'Playing - %time%'
|
||||
duration: "FIXED:90"
|
||||
battle:
|
||||
scoreboard: 'Playing - %time%'
|
||||
duration: "INCREASING"
|
||||
feast:
|
||||
scoreboard: 'Playing - %time%'
|
||||
duration: "FIXED:300"
|
||||
deathmatch:
|
||||
scoreboard: 'Playing - %time%'
|
||||
duration: "INCREASING"
|
||||
end:
|
||||
scoreboard: 'Ending - %time%'
|
||||
duration: "FIXED:60"
|
||||
|
||||
recraftNerf:
|
||||
enabled: false
|
||||
maxAmount: 64
|
||||
beforeState: 'FEAST'
|
||||
|
||||
teams:
|
||||
enabled: false
|
||||
maximumPlayers: 2
|
||||
|
||||
blockedKits: []
|
||||
|
||||
blockedPerks: []
|
||||
|
||||
perks:
|
||||
maximumAmount: 2
|
||||
anti-runner:
|
||||
enabled: true
|
||||
check-radius: 20.0
|
||||
warn-time: 15
|
||||
punish-time: 25
|
||||
# Einstellungen für die Cave-Erkennung
|
||||
ignore-vertical-distance: 15.0 # Wenn Höhenunterschied > 15, Timer ignorieren
|
||||
ignore-cave-surface-mix: true # Ignorieren, wenn einer Sonne hat und der andere nicht
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"connectionString": "",
|
||||
"host": "localhost",
|
||||
"port": 27017,
|
||||
"database": "minecraft",
|
||||
"username": "root",
|
||||
"password": "pass",
|
||||
"authDatabase": "admin",
|
||||
"ssl": false,
|
||||
"replicaSet": "",
|
||||
"connectionTimeout": 30,
|
||||
"poolSize": 10
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
anchor:
|
||||
offensive extra damage: 1.0
|
||||
|
||||
armorer:
|
||||
kills until new armor: 2.0
|
||||
|
||||
blackpanther:
|
||||
enderpearl hit damage: 3.0
|
||||
extra damage on top: 0.5
|
||||
default hit radius: 3.0
|
||||
explosion multiplier: 3.0
|
||||
|
||||
gladiator:
|
||||
cage radius: 23.0
|
||||
cage height: 10.0
|
||||
wither effect after x seconds: 180.0
|
||||
|
||||
goblin:
|
||||
bunker radius: 10.0
|
||||
bunker time until disappear: 15.0
|
||||
knockback and pullin radius: 7.0
|
||||
kit steal time: 60.0
|
||||
soup steal chance: 20.0
|
||||
|
||||
icemage:
|
||||
chance for slowness: 2.0
|
||||
|
||||
poseidon:
|
||||
default hit radius: 3.0
|
||||
lightning hit damage: 4.0
|
||||
|
||||
rattlesnake:
|
||||
maximum jump distance: 10.0
|
||||
speed duration: 10.0
|
||||
poison duration: 8.0
|
||||
maximum negative effect duration: 16.0
|
||||
default jump radius: 10.0
|
||||
|
||||
tesla:
|
||||
disable push at height: 50.0
|
||||
default thunder radius: 5.0
|
||||
push strength: 1.0
|
||||
fire tick duration: 5.0
|
||||
time until thunder disables: 7.0
|
||||
thunder damage: 1.5
|
||||
|
||||
voodoo:
|
||||
default curse radius: 3.0
|
||||
maximum effect duration: 15.0
|
||||
clicked players minimum health: 10.0
|
||||
voodoo hold duration: 5.0
|
||||
chance for wither effect: 5.0
|
||||
|
||||
perks:
|
||||
knockback:
|
||||
knockback strength: 1.5
|
||||
pullin:
|
||||
pullin strength: 0.5
|
||||
radiusincrease:
|
||||
new radius: 5.0
|
||||
34
src/main/resources/languages/en_US.yml
Normal file
34
src/main/resources/languages/en_US.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# SpeedHG v1.0.0 by McScrims-Network
|
||||
# https://github.com/McScrims-Network
|
||||
#
|
||||
|
||||
default:
|
||||
prefix: '<gradient:dark_green:gold>McScrims</gradient> <dark_gray>|</dark_gray> <reset>'
|
||||
|
||||
game:
|
||||
join: '<prefix><green><name></green> <gray>has joined the game.</gray>'
|
||||
quit: '<prefix><red><name></red> <gray>has quit the game.</gray>'
|
||||
|
||||
player:
|
||||
welcome: 'Welcome to <gradient:red:gold>SpeedHG</gradient>!'
|
||||
|
||||
scoreboard:
|
||||
title: '<gradient:gold:yellow><bold>SpeedHG</bold></gradient>'
|
||||
lobby:
|
||||
- "<gray><st> "
|
||||
- "Spieler: <green><online>/<max>"
|
||||
- "Kit: <yellow><kit>"
|
||||
- ""
|
||||
- "<gray>Waiting for start..."
|
||||
- ""
|
||||
- "<yellow>play.mcscrims.club"
|
||||
ingame:
|
||||
- "<gray><st> "
|
||||
- "Time: <green><timer>"
|
||||
- "Players: <red><alive>"
|
||||
- "Kills: <green><kills>"
|
||||
- ""
|
||||
- "Border: <red><border>"
|
||||
- ""
|
||||
- "<yellow>play.mcscrims.club"
|
||||
@@ -1,23 +0,0 @@
|
||||
#
|
||||
# |-----| |-----| |-----| |-----| |---\ | | |-----|
|
||||
# | | | | | | \ | | |
|
||||
# |-----| |-----| |---| |---| | | |-----| | |--|
|
||||
# | | | | | / | | | |
|
||||
# |-----| | |-----| |-----| |---/ | | |-----|
|
||||
# v1.0.0 by TDSTOS
|
||||
#
|
||||
# Organization: McScrims-Network (https://github.com/McScrims-Network/)
|
||||
# Owner: TDSTOS (https://github.com/TDSTOS)
|
||||
# Contributors: stavgun (https://github.com/stavgun)
|
||||
#
|
||||
|
||||
default:
|
||||
prefix: '<gradient:dark_green:green>McScrims</gradient> <dark_gray>┃</dark_gray><reset>'
|
||||
no_permission: '%prefix% <red>You don''t have permission to do that!</red>'
|
||||
player_not_found: '%prefix% <red>This player could not be found!</red>'
|
||||
command_cooldown: '%prefix% <red>Please wait {time} seconds before using this command again!</red>'
|
||||
|
||||
commands:
|
||||
unknown: |-
|
||||
%prefix% <red>Unknown subcommand: {unknown}</red>
|
||||
%prefix% <gray>Use /{command} for an overview.</gray>
|
||||
@@ -7,8 +7,3 @@ depend:
|
||||
- "WorldEdit"
|
||||
- "Apollo-Bukkit"
|
||||
- "McScrims-CoreSystem"
|
||||
|
||||
commands:
|
||||
kits:
|
||||
description: Open the kit selection menu
|
||||
usage: /kits
|
||||
|
||||
Reference in New Issue
Block a user