From e199ae24d4739dea9d059f2c82df0248814fd83d Mon Sep 17 00:00:00 2001 From: TDSTOS Date: Wed, 25 Mar 2026 17:47:42 +0100 Subject: [PATCH] Add BackupKit and mid-game kit selection Introduce a BackupKit and allow players holding it to change kits mid-game while preventing normal kits from being picked once the game started. Changes: - Add BackupKit implementation (kit with no abilities/items used for mid-round kit selection). - Update KitCommand: import BackupKit and GameState, add isIngame helper, disallow normal kit picks during INGAME/INVINCIBILITY, permit BackupKit to swap kits mid-game (but prevent picking the same kit) and apply playstyles accordingly. - Fix GoblinKit to also copy/restore the target's playstyle when stealing a kit and restore the player's original playstyle after timeout. - Tweak IceMageKit slow effect chance (now ~1/3 chance using random.nextInt(3) < 1). - Update en_US.yml: add messages and kit strings for backup and icemage, adjust ability_charged color, and add game/cannot-pick messages. Also includes small import and formatting adjustments. --- .../mcscrims/speedhg/command/KitCommand.kt | 32 +++++++ .../mcscrims/speedhg/kit/impl/BackupKit.kt | 85 +++++++++++++++++++ .../mcscrims/speedhg/kit/impl/GoblinKit.kt | 10 ++- .../mcscrims/speedhg/kit/impl/IceMageKit.kt | 2 +- src/main/resources/languages/en_US.yml | 34 +++++++- 5 files changed, 157 insertions(+), 6 deletions(-) create mode 100644 src/main/kotlin/club/mcscrims/speedhg/kit/impl/BackupKit.kt diff --git a/src/main/kotlin/club/mcscrims/speedhg/command/KitCommand.kt b/src/main/kotlin/club/mcscrims/speedhg/command/KitCommand.kt index 0f900ff..09e30b9 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/command/KitCommand.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/command/KitCommand.kt @@ -1,7 +1,9 @@ package club.mcscrims.speedhg.command import club.mcscrims.speedhg.SpeedHG +import club.mcscrims.speedhg.game.GameState import club.mcscrims.speedhg.kit.Playstyle +import club.mcscrims.speedhg.kit.impl.BackupKit import club.mcscrims.speedhg.util.legacySerializer import club.mcscrims.speedhg.util.sendMsg import org.bukkit.command.Command @@ -52,6 +54,30 @@ class KitCommand : CommandExecutor, TabCompleter { return true } + val playerKit = plugin.kitManager.getSelectedKit( player ) + val isBackup = playerKit != null && playerKit is BackupKit + + if ( !isBackup && isIngame() ) + { + player.sendMsg("commands.kit.gameHasStarted") + return true + } + else if ( isBackup && isIngame() ) + { + if ( kit is BackupKit ) + { + player.sendMsg( "commands.kit.cannotPickSameKit" ) + return true + } + + plugin.kitManager.selectKit( player, kit ) + plugin.kitManager.selectPlaystyle( player, playstyle ) + plugin.kitManager.applyKit( player ) + + player.sendMsg( "commands.kit.selected", "playstyle" to playstyle.displayName, "kit" to legacySerializer.serialize( kit.displayName )) + return true + } + plugin.kitManager.selectKit( player, kit ) plugin.kitManager.selectPlaystyle( player, playstyle ) @@ -78,4 +104,10 @@ class KitCommand : CommandExecutor, TabCompleter { return listOf() } + private fun isIngame(): Boolean = when ( plugin.gameManager.currentState ) + { + GameState.INGAME, GameState.INVINCIBILITY -> true + else -> false + } + } \ No newline at end of file diff --git a/src/main/kotlin/club/mcscrims/speedhg/kit/impl/BackupKit.kt b/src/main/kotlin/club/mcscrims/speedhg/kit/impl/BackupKit.kt new file mode 100644 index 0000000..6dfa344 --- /dev/null +++ b/src/main/kotlin/club/mcscrims/speedhg/kit/impl/BackupKit.kt @@ -0,0 +1,85 @@ +package club.mcscrims.speedhg.kit.impl + +import club.mcscrims.speedhg.SpeedHG +import club.mcscrims.speedhg.kit.Kit +import club.mcscrims.speedhg.kit.Playstyle +import club.mcscrims.speedhg.kit.ability.AbilityResult +import club.mcscrims.speedhg.kit.ability.ActiveAbility +import club.mcscrims.speedhg.kit.ability.PassiveAbility +import net.kyori.adventure.text.Component +import org.bukkit.Material +import org.bukkit.entity.Player + +class BackupKit : Kit() { + + private val plugin get() = SpeedHG.instance + + override val id: String + get() = "backup" + + override val displayName: Component + get() = plugin.languageManager.getDefaultComponent( "kits.backup.name", mapOf() ) + + override val lore: List + get() = plugin.languageManager.getDefaultRawMessageList( "kits.backup.lore" ) + + override val icon: Material + get() = Material.CHEST + + // ── Cached ability instances (avoid allocating per event call) ──────────── + private val aggressiveNoActive = NoActive( Playstyle.AGGRESSIVE ) + private val defensiveNoActive = NoActive( Playstyle.DEFENSIVE ) + private val aggressiveNoPassive = NoPassive( Playstyle.AGGRESSIVE ) + private val defensiveNoPassive = NoPassive( Playstyle.DEFENSIVE ) + + // ── Playstyle routing ───────────────────────────────────────────────────── + + override fun getActiveAbility( + playstyle: Playstyle + ): ActiveAbility = when( playstyle ) + { + Playstyle.AGGRESSIVE -> aggressiveNoActive + Playstyle.DEFENSIVE -> defensiveNoActive + } + + override fun getPassiveAbility( + playstyle: Playstyle + ): PassiveAbility = when( playstyle ) + { + Playstyle.AGGRESSIVE -> aggressiveNoPassive + Playstyle.DEFENSIVE -> defensiveNoPassive + } + + // ── Item distribution ───────────────────────────────────────────────────── + + override fun giveItems( player: Player, playstyle: Playstyle ) {} + + private class NoActive( playstyle: Playstyle ) : ActiveAbility( playstyle ) { + + override val name: String + get() = "None" + + override val description: String + get() = "None" + + override val hitsRequired: Int + get() = 0 + + override val triggerMaterial: Material + get() = Material.BARRIER + + override fun execute( player: Player ): AbilityResult { return AbilityResult.Success } + + } + + private class NoPassive( playstyle: Playstyle ) : PassiveAbility( playstyle ) { + + override val name: String + get() = "None" + + override val description: String + get() = "None" + + } + +} \ No newline at end of file diff --git a/src/main/kotlin/club/mcscrims/speedhg/kit/impl/GoblinKit.kt b/src/main/kotlin/club/mcscrims/speedhg/kit/impl/GoblinKit.kt index 8cae706..20d39b7 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/kit/impl/GoblinKit.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/kit/impl/GoblinKit.kt @@ -129,16 +129,17 @@ class GoblinKit : Kit() { val lineOfSight = player.getTargetEntity( 3 ) as? Player ?: return AbilityResult.ConditionNotMet( "No player in line of sight" ) - val targetKit = plugin.kitManager.getSelectedKit( lineOfSight ) - ?: return AbilityResult.ConditionNotMet( "Target has no kit" ) + val targetKit = plugin.kitManager.getSelectedKit( lineOfSight ) ?: return AbilityResult.ConditionNotMet( "Target has no kit" ) + val targetPlaystyle = plugin.kitManager.getSelectedPlaystyle( lineOfSight ) - val currentKit = plugin.kitManager.getSelectedKit( player ) - ?: return AbilityResult.ConditionNotMet( "Error while copying kit" ) + val currentKit = plugin.kitManager.getSelectedKit( player ) ?: return AbilityResult.ConditionNotMet( "Error while copying kit" ) + val currentPlaystyle = plugin.kitManager.getSelectedPlaystyle( player ) activeStealTasks.remove( player.uniqueId ) plugin.kitManager.removeKit( player ) plugin.kitManager.selectKit( player, targetKit ) + plugin.kitManager.selectPlaystyle( player, targetPlaystyle ) plugin.kitManager.applyKit( player ) val task = Bukkit.getScheduler().runTaskLater( plugin, { -> @@ -148,6 +149,7 @@ class GoblinKit : Kit() { { plugin.kitManager.removeKit( player ) plugin.kitManager.selectKit( player, currentKit ) + plugin.kitManager.selectPlaystyle( player, currentPlaystyle ) plugin.kitManager.applyKit( player ) } }, 20L * 60) diff --git a/src/main/kotlin/club/mcscrims/speedhg/kit/impl/IceMageKit.kt b/src/main/kotlin/club/mcscrims/speedhg/kit/impl/IceMageKit.kt index 59166e5..77488c9 100644 --- a/src/main/kotlin/club/mcscrims/speedhg/kit/impl/IceMageKit.kt +++ b/src/main/kotlin/club/mcscrims/speedhg/kit/impl/IceMageKit.kt @@ -184,7 +184,7 @@ class IceMageKit : Kit() { victim: Player, event: EntityDamageByEntityEvent ) { - if ( random.nextBoolean() ) + if (random.nextInt( 3 ) < 1 ) victim.addPotionEffect(PotionEffect( PotionEffectType.SLOWNESS, 60, 0 )) } diff --git a/src/main/resources/languages/en_US.yml b/src/main/resources/languages/en_US.yml index f472cdf..7c02242 100644 --- a/src/main/resources/languages/en_US.yml +++ b/src/main/resources/languages/en_US.yml @@ -48,6 +48,8 @@ commands: usage: 'Usage: /kit ' kitNotFound: ' is not a registered kit!' playstyleNotFound: ' is not an available playstyle!' + gameHasStarted: 'The game has already started. You cannot select a kit right now!' + cannotPickSameKit: 'You cannot pick the same kit!' selected: 'You have selected as your Kit with playstyle !' scoreboard: @@ -71,6 +73,17 @@ scoreboard: - "play.mcscrims.club" kits: + backup: + name: 'Backup' + lore: + - ' ' + - 'Select a kit mid-round at any time.' + - 'All kits are available to pick.' + - ' ' + - 'PlayStyle: §e%playstyle%' + - ' ' + - 'Left-click to select' + - 'Right-click to change playstyle' goblin: name: 'Goblin' lore: @@ -92,4 +105,23 @@ kits: messages: stole_kit: 'You have stolen the kit of your opponent (Kit: )!' spawn_bunker: 'You have created a bunker around yourself!' - ability_charged: 'Your ability has been recharged!' \ No newline at end of file + ability_charged: 'Your ability has been recharged!' + icemage: + name: 'IceMage' + lore: + - ' ' + - 'Use your abilities to freeze players' + - 'or gain speed in ice biomes and slow' + - 'enemies.' + - ' ' + - 'PlayStyle: §e%playstyle%' + - ' ' + - 'Left-click to select' + - 'Right-click to change playstyle' + items: + snowball: + name: '§bFreeze' + description: 'Freeze your enemies by throwing snowballs in all directions' + messages: + shoot_snowballs: 'You have shot frozen snowballs in all directions!' + ability_charged: 'Your ability has been recharged!' \ No newline at end of file