Add new kits & recraft nerf

This commit is contained in:
TDSTOS
2025-12-09 16:06:17 +01:00
parent cb788930ad
commit 7e54c8e9f1
9 changed files with 532 additions and 14 deletions

View File

@@ -110,6 +110,13 @@ class GameManager(
!( currentState as BattleState ).afterFeast ) !( currentState as BattleState ).afterFeast )
} }
fun isBefore(
stateType: GameStateTypes
): Boolean
{
return getCurrentStateType()?.points!! < stateType.points
}
fun shutdown() fun shutdown()
{ {
currentState?.onExit( null ) currentState?.onExit( null )
@@ -118,6 +125,14 @@ class GameManager(
} }
enum class GameStateTypes { enum class GameStateTypes(
WAITING, PRE_START, IMMUNITY, BATTLE, FEAST, DEATHMATCH, END val points: Int
) {
WAITING( 0 ),
PRE_START( 1 ),
IMMUNITY( 2 ),
BATTLE( 3 ),
FEAST( 4 ),
DEATHMATCH( 5 ),
END( 6 )
} }

View File

@@ -4,6 +4,7 @@ import club.mcscrims.speedhg.SpeedHG
import club.mcscrims.speedhg.ability.AbilityContext import club.mcscrims.speedhg.ability.AbilityContext
import club.mcscrims.speedhg.game.GameManager import club.mcscrims.speedhg.game.GameManager
import club.mcscrims.speedhg.kit.impl.AnchorKit import club.mcscrims.speedhg.kit.impl.AnchorKit
import club.mcscrims.speedhg.kit.impl.ArmorerKit
import net.kyori.adventure.text.Component import net.kyori.adventure.text.Component
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.entity.Player import org.bukkit.entity.Player
@@ -29,6 +30,14 @@ class KitManager(
description = emptyList(), description = emptyList(),
icon = Material.ANVIL icon = Material.ANVIL
) )
registerKit(
kitClass = ArmorerKit::class.java,
id = "armorer",
displayName = plugin.chatFormatter.format( "kits.armorer.displayName" ),
description = emptyList(),
icon = Material.IRON_CHESTPLATE
)
} }
fun registerKit( fun registerKit(

View File

@@ -19,6 +19,8 @@ import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.event.player.PlayerMoveEvent import org.bukkit.event.player.PlayerMoveEvent
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.metadata.FixedMetadataValue import org.bukkit.metadata.FixedMetadataValue
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
class AnchorKit( class AnchorKit(
id: String, id: String,
@@ -33,12 +35,10 @@ class AnchorKit(
private lateinit var anvilItem: ItemStack private lateinit var anvilItem: ItemStack
private var anvilPlaced: Boolean = false
private val extraDamage: Double = plugin.kitConfig.data.anchor[ "offensive extra damage" ]!! 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 radius = if ( playStyle == PlayStyle.DEFENSIVE ) 7.5 else 5.0
private lateinit var anvilLoc: Location private val anvilList = ConcurrentHashMap<UUID, Location>()
override fun onSelect( player: Player ) {} override fun onSelect( player: Player ) {}
@@ -62,7 +62,7 @@ class AnchorKit(
if ( !gameManager.isRunning() ) if ( !gameManager.isRunning() )
return return
if ( !anvilPlaced ) if (!anvilList.contains( attacker.uniqueId ))
return return
if ( playStyle != PlayStyle.OFFENSIVE ) if ( playStyle != PlayStyle.OFFENSIVE )
@@ -79,7 +79,7 @@ class AnchorKit(
if ( !gameManager.isRunning() ) if ( !gameManager.isRunning() )
return return
if ( !anvilPlaced ) if (!anvilList.contains( attacker.uniqueId ))
return return
victim.velocity.setX( 0.0 ) victim.velocity.setX( 0.0 )
@@ -115,7 +115,7 @@ class AnchorKit(
return return
} }
if ( anvilPlaced ) if (anvilList.contains( player.uniqueId ))
{ {
plugin.chatManager.sendMessage( player, "kits.anchor.messages.alreadyActivated" ) plugin.chatManager.sendMessage( player, "kits.anchor.messages.alreadyActivated" )
return return
@@ -129,18 +129,18 @@ class AnchorKit(
return return
} }
anvilLoc = eyeLocation.toBlockLocation() val anvilLoc = eyeLocation.toBlockLocation()
anvilLoc.add( 0.0, 1.0, 0.0 ) anvilLoc.add( 0.0, 1.0, 0.0 )
anvilLoc.block.type = Material.ANVIL anvilLoc.block.type = Material.ANVIL
anvilLoc.block.setMetadata( KitMetaData.IS_ANVIL.getKey(), FixedMetadataValue( plugin, true )) anvilLoc.block.setMetadata( KitMetaData.IS_ANVIL.getKey(), FixedMetadataValue( plugin, true ))
anvilPlaced = true anvilList[ player.uniqueId ]= anvilLoc
plugin.schedulerManager.runLater( 20 * 30L ) { plugin.schedulerManager.runLater( 20 * 30L ) {
if ( anvilPlaced ) if (anvilList.contains( player.uniqueId ))
{ {
anvilPlaced = false anvilList.remove( player.uniqueId )
anvilLoc.block.type = Material.AIR anvilLoc.block.type = Material.AIR
anvilLoc.block.removeMetadata( KitMetaData.IS_ANVIL.getKey(), plugin ) anvilLoc.block.removeMetadata( KitMetaData.IS_ANVIL.getKey(), plugin )
} }
@@ -154,8 +154,8 @@ class AnchorKit(
if ( !gameManager.isRunning() ) if ( !gameManager.isRunning() )
return return
if ( !anvilPlaced ) val anvilLoc = anvilList[ player.uniqueId ]
return ?: return
if (player.location.distance( anvilLoc ) <= radius ) if (player.location.distance( anvilLoc ) <= radius )
return return

View File

@@ -0,0 +1,114 @@
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<String>,
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 )
}
}

View File

@@ -0,0 +1,165 @@
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.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.metadata.FixedMetadataValue
class BlackPantherKit(
id: String,
displayName: Component,
description: List<String>,
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.chatFormatter.format( "kits.anchor.items.blackDye.${playStyle.name.lowercase()}" ).content())
.unbreakable( true )
.hideAttributes()
.build()
}
PlayStyle.OFFENSIVE ->
{
blackDye = ItemBuilder( plugin, Material.BLACK_DYE )
.name(plugin.chatFormatter.format( "kits.anchor.items.blackDye.${playStyle.name.lowercase()}" ).content())
.unbreakable( true )
.hideAttributes()
.build()
blazePowder = ItemBuilder( plugin, Material.BLAZE_POWDER )
.name(plugin.chatFormatter.format( "kits.anchor.items.blazePowder" ).content())
.unbreakable( true )
.hideAttributes()
.build()
}
else -> {}
}
}
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 )
{
return
}
}
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 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" )
}
}
}

View File

@@ -0,0 +1,93 @@
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
}
}

View File

@@ -0,0 +1,52 @@
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 Int
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 )
}
}

View File

@@ -0,0 +1,43 @@
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 }
}
}

View File

@@ -0,0 +1,27 @@
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 )
}
}