From 6d364fa3eb5cd1e116a08965a8c362c7ed11f53f Mon Sep 17 00:00:00 2001 From: Moritz Ruth Date: Sun, 7 Jun 2020 20:03:17 +0200 Subject: [PATCH] Add sidekick deagle and sidekick functionality --- .../de/moritzruth/spigot_ttt/CustomItems.kt | 2 +- .../moritzruth/spigot_ttt/game/GameManager.kt | 4 +- .../spigot_ttt/game/players/Role.kt | 2 +- .../spigot_ttt/game/players/TTTPlayer.kt | 74 ++++++++++++------- .../spigot_ttt/items/ItemManager.kt | 14 ++-- .../de/moritzruth/spigot_ttt/items/TTTItem.kt | 3 +- .../spigot_ttt/items/impl/CloakingDevice.kt | 1 + .../spigot_ttt/items/impl/EnderPearl.kt | 1 + .../spigot_ttt/items/impl/HealingPotion.kt | 1 + .../moritzruth/spigot_ttt/items/impl/Radar.kt | 1 + .../spigot_ttt/items/weapons/guns/Gun.kt | 31 ++++---- .../items/weapons/guns/impl/GoldenDeagle.kt | 27 ------- .../items/weapons/guns/impl/Shotgun.kt | 6 +- .../items/weapons/guns/impl/SidekickDeagle.kt | 73 ++++++++++++++++++ .../items/weapons/impl/BaseballBat.kt | 1 + .../spigot_ttt/items/weapons/impl/Knife.kt | 1 + .../de/moritzruth/spigot_ttt/shop/Shop.kt | 31 +++++--- .../spigot_ttt/shop/ShopListener.kt | 26 ++++--- 18 files changed, 197 insertions(+), 102 deletions(-) delete mode 100644 src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/impl/GoldenDeagle.kt create mode 100644 src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/impl/SidekickDeagle.kt diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/CustomItems.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/CustomItems.kt index 116e6b4..56ba1bf 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/CustomItems.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/CustomItems.kt @@ -21,7 +21,7 @@ object CustomItems { // Weapons val deagle = Material.IRON_HOE - val goldenDeagle = Material.GOLDEN_HOE + val sidekickDeagle = Material.GOLDEN_HOE val glock = Material.STONE_HOE val pistol = Material.WOODEN_HOE val shotgun = Material.IRON_AXE diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/game/GameManager.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/game/GameManager.kt index f78dfd7..94a27ff 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/game/GameManager.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/game/GameManager.kt @@ -36,7 +36,7 @@ object GameManager { PlayerManager.tttPlayers.forEach { it.setMuted(false) - Shop.hide(it) + Shop.clear(it) } Timers.startOverPhaseTimer(plugin.config.getInt("duration.over", 10)) { @@ -96,7 +96,7 @@ object GameManager { ensurePhase(GamePhase.PREPARING) phase = GamePhase.COMBAT - PlayerManager.tttPlayers.forEach { Shop.show(it) } + PlayerManager.tttPlayers.forEach { Shop.setItems(it) } ScoreboardHelper.forEveryScoreboard { it.updateTeams() } Shop.startCreditsTimer() diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/game/players/Role.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/game/players/Role.kt index 450461e..43dd6bc 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/game/players/Role.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/game/players/Role.kt @@ -15,7 +15,7 @@ enum class Role( DETECTIVE(ChatColor.YELLOW, "Detective", CustomItems.detective, true), TRAITOR(ChatColor.RED, "Traitor", CustomItems.traitor, true), JACKAL(ChatColor.AQUA, "Jackal", CustomItems.jackal, true), - SIDEKICK(ChatColor.AQUA, "Sidekick", CustomItems.sidekick, true); + SIDEKICK(ChatColor.AQUA, "Sidekick", CustomItems.sidekick, false); val coloredDisplayName = "$chatColor$displayName${ChatColor.RESET}" diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/game/players/TTTPlayer.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/game/players/TTTPlayer.kt index ef6312e..d097fa0 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/game/players/TTTPlayer.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/game/players/TTTPlayer.kt @@ -13,6 +13,7 @@ import de.moritzruth.spigot_ttt.shop.Shop import de.moritzruth.spigot_ttt.utils.hotbarContents import de.moritzruth.spigot_ttt.utils.secondsToTicks import de.moritzruth.spigot_ttt.utils.teleportPlayerToWorldSpawn +import org.bukkit.ChatColor import org.bukkit.GameMode import org.bukkit.Material import org.bukkit.entity.Player @@ -23,15 +24,25 @@ import kotlin.properties.Delegates class TTTPlayer(player: Player, role: Role) { var alive = true - var player by Delegates.observable(player) { _, _, _ -> initializePlayer() } + var player by Delegates.observable(player) { _, _, _ -> adjustPlayer() } - var role by Delegates.observable(role) { _, _, _ -> scoreboard.updateRole() } + var role = role + private set(value) { + if (value !== field) { + field = value + scoreboard.updateRole() + scoreboard.showCorrectSidebarScoreboard() + Shop.setItems(this) + } + } val roleHistory = mutableListOf() var itemInHand by Delegates.observable(null) { _, oldItem, newItem -> if (oldItem !== newItem) onItemInHandChanged(oldItem, newItem) } var credits by Delegates.observable(10) { _, _, _ -> scoreboard.updateCredits() } + val boughtItems = mutableListOf() + var invisible by Delegates.observable(false) { _, _, value -> if (value) { PlayerManager.tttPlayers.forEach { @@ -58,18 +69,11 @@ class TTTPlayer(player: Player, role: Role) { private val discordUser get() = DiscordInterface.getUserByPlayerUUID(player.uniqueId) init { - initializePlayer() + adjustPlayer() scoreboard.initialize() } - private fun initializePlayer() { - player.scoreboard = scoreboard.scoreboard - } - private fun onItemInHandChanged(oldItem: TTTItem?, newItem: TTTItem?) { - println(oldItem) - println(newItem) - if (oldItem !== null && oldItem is Selectable) { oldItem.onDeselect(this) } @@ -79,6 +83,27 @@ class TTTPlayer(player: Player, role: Role) { } } + fun onDeath(reason: DeathReason = DeathReason.SUICIDE) { + GameManager.ensurePhase(GamePhase.COMBAT) + + player.gameMode = GameMode.SPECTATOR + alive = false + + TTTCorpse.spawn(this, reason) + credits = 0 + + Shop.clear(this) + setMuted(true) + + PlayerManager.letRemainingRoleGroupWin() + } + + private fun adjustPlayer() { + player.scoreboard = scoreboard.scoreboard + } + + private fun getOwningTTTItems() = player.inventory.hotbarContents.mapNotNull { it?.run { ItemManager.getItemByItemStack(this) } } + fun activateStamina() { if (staminaTask != null) return @@ -96,21 +121,23 @@ class TTTPlayer(player: Player, role: Role) { }, 0, secondsToTicks(0.5).toLong()) } - fun onDeath(reason: DeathReason = DeathReason.SUICIDE) { - GameManager.ensurePhase(GamePhase.COMBAT) + fun changeRole(newRole: Role) { + roleHistory.add(role) + role = newRole - player.gameMode = GameMode.SPECTATOR - alive = false + val message = if (role == Role.SIDEKICK) { + val jackal = PlayerManager.tttPlayers.find { it.role == Role.JACKAL } + ?: throw NoJackalLivingException() - TTTCorpse.spawn(this, reason) - credits = 0 - - Shop.hide(this) - setMuted(true) + "${ChatColor.WHITE}Du bist jetzt ${role.coloredDisplayName} von ${jackal.role.chatColor}${jackal.player.displayName}" + } else "${ChatColor.WHITE}Du bist jetzt ${role.coloredDisplayName}" + player.sendTitle("", message, secondsToTicks(0.2), secondsToTicks(3), secondsToTicks(0.5)) PlayerManager.letRemainingRoleGroupWin() } + class NoJackalLivingException: Exception("There is no living jackal for this sidekick") + fun resetAfterGameEnd() { if (!alive) { teleportToSpawn() @@ -138,7 +165,6 @@ class TTTPlayer(player: Player, role: Role) { setMuted(false) invisible = false - alive = true player.gameMode = GameMode.SURVIVAL player.activePotionEffects.forEach { player.removePotionEffect(it.type) } player.health = 20.0 @@ -182,6 +208,9 @@ class TTTPlayer(player: Player, role: Role) { throw TooManyItemsOfTypeException() } } + class AlreadyHasItemException: Exception("The player already owns this item") + + class TooManyItemsOfTypeException: Exception("The player already owns too much items of this type") fun addItem(item: TTTItem) { checkAddItemPreconditions(item) @@ -189,10 +218,5 @@ class TTTPlayer(player: Player, role: Role) { updateItemInHand() } - class AlreadyHasItemException: Exception("The player already owns this item") - class TooManyItemsOfTypeException: Exception("The player already owns too much items of this type") - - private fun getOwningTTTItems() = player.inventory.hotbarContents.mapNotNull { it?.run { ItemManager.getItemByItemStack(this) } } - override fun toString() = "TTTPlayer(${player.name} is $role)" } diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/items/ItemManager.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/items/ItemManager.kt index ef6b0d7..39569e1 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/items/ItemManager.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/items/ItemManager.kt @@ -9,12 +9,7 @@ import de.moritzruth.spigot_ttt.items.impl.CloakingDevice import de.moritzruth.spigot_ttt.items.impl.EnderPearl import de.moritzruth.spigot_ttt.items.impl.HealingPotion import de.moritzruth.spigot_ttt.items.impl.Radar -import de.moritzruth.spigot_ttt.items.weapons.guns.impl.GoldenDeagle -import de.moritzruth.spigot_ttt.items.weapons.guns.impl.Deagle -import de.moritzruth.spigot_ttt.items.weapons.guns.impl.Glock -import de.moritzruth.spigot_ttt.items.weapons.guns.impl.Pistol -import de.moritzruth.spigot_ttt.items.weapons.guns.impl.Shotgun -import de.moritzruth.spigot_ttt.items.weapons.guns.impl.Rifle +import de.moritzruth.spigot_ttt.items.weapons.guns.impl.* import de.moritzruth.spigot_ttt.items.weapons.impl.BaseballBat import de.moritzruth.spigot_ttt.items.weapons.impl.Knife import de.moritzruth.spigot_ttt.plugin @@ -33,7 +28,7 @@ import org.bukkit.inventory.ItemStack object ItemManager { val ITEMS: Set = setOf( Pistol, - Knife, Glock, Deagle, Shotgun, GoldenDeagle, + Knife, Glock, Deagle, Shotgun, SidekickDeagle, BaseballBat, CloakingDevice, Rifle, EnderPearl, Radar, HealingPotion @@ -78,7 +73,10 @@ object ItemManager { if (tttItem.type != TTTItem.Type.SPECIAL) { if (tttItem is DropHandler) { - tttItem.onDrop(tttPlayer, event.itemDrop) + if (!tttItem.onDrop(tttPlayer, event.itemDrop)) { + event.isCancelled = true + return + } } plugin.server.scheduler.runTask(plugin, fun() { diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/items/TTTItem.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/items/TTTItem.kt index 1e9ec84..d085b92 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/items/TTTItem.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/items/TTTItem.kt @@ -17,13 +17,14 @@ interface Selectable { } interface DropHandler { - fun onDrop(tttPlayer: TTTPlayer, itemEntity: Item) + fun onDrop(tttPlayer: TTTPlayer, itemEntity: Item): Boolean fun onPickup(tttPlayer: TTTPlayer, itemEntity: Item) } interface Buyable { val buyableBy: EnumSet val price: Int + val buyLimit: Int? } // Marker diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/CloakingDevice.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/CloakingDevice.kt index 982a74d..01419c5 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/CloakingDevice.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/CloakingDevice.kt @@ -33,6 +33,7 @@ object CloakingDevice: TTTItem, override val type = TTTItem.Type.SPECIAL override val price = 2 override val buyableBy = roles(Role.TRAITOR, Role.JACKAL) + override val buyLimit = 1 val isc = InversedStateContainer(State::class) diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/EnderPearl.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/EnderPearl.kt index 886f641..450efd3 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/EnderPearl.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/EnderPearl.kt @@ -20,6 +20,7 @@ object EnderPearl: TTTItem, Buyable { } override val buyableBy = roles(Role.TRAITOR, Role.JACKAL, Role.DETECTIVE) override val price = 1 + override val buyLimit: Int? = null override val listener = object : Listener { @EventHandler diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/HealingPotion.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/HealingPotion.kt index 944bc20..1deef1d 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/HealingPotion.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/HealingPotion.kt @@ -37,6 +37,7 @@ object HealingPotion: TTTItem, Buyable { override val type = TTTItem.Type.SPECIAL override val buyableBy = roles(Role.TRAITOR, Role.JACKAL, Role.DETECTIVE) override val price = 1 + override val buyLimit = 2 override val listener = object : Listener { @EventHandler diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/Radar.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/Radar.kt index 7b02108..b93053a 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/Radar.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/items/impl/Radar.kt @@ -48,6 +48,7 @@ object Radar: TTTItem, Buyable { override val type = TTTItem.Type.SPECIAL override val buyableBy: EnumSet = EnumSet.of(Role.TRAITOR, Role.DETECTIVE, Role.JACKAL) override val price = 2 + override val buyLimit: Int? = null val isc = InversedStateContainer(State::class) diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/Gun.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/Gun.kt index 5a64d2d..7f687f0 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/Gun.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/Gun.kt @@ -59,7 +59,7 @@ abstract class Gun( } fun shoot(tttPlayer: TTTPlayer, itemStack: ItemStack, state: State = isc.getOrCreate(tttPlayer)) { - onBeforeShoot(tttPlayer, itemStack, state) + if (!onBeforeShoot(tttPlayer, itemStack, state)) return if (state.remainingShots == 0) { GameManager.world.playSound(tttPlayer.player.location, Sound.BLOCK_ANVIL_PLACE, SoundCategory.PLAYERS, 1f, 1.3f) @@ -89,14 +89,7 @@ abstract class Gun( val damagedTTTPlayer = PlayerManager.getTTTPlayer(entity) if (damagedTTTPlayer != null) { - damagedTTTPlayer.damageInfo = DamageInfo(tttPlayer, DeathReason.Item(this)) - val actualDamage = computeActualDamage(tttPlayer, entity) - - entity.damage(actualDamage) - tttPlayer.player.playSound(tttPlayer.player.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.MASTER, 2f, 1.2f) - entity.velocity = tttPlayer.player.location.direction.multiply( - (actualDamage / 20).coerceAtMost(3.0) - ) + onHit(tttPlayer, damagedTTTPlayer) } } } @@ -116,8 +109,20 @@ abstract class Gun( open fun computeActualDamage(tttPlayer: TTTPlayer, receiver: Player) = if (damage < 0 ) 1000.0 else damage - open fun onBeforeShoot(tttPlayer: TTTPlayer, item: ItemStack, state: State = isc.getOrCreate(tttPlayer)) { + open fun onBeforeShoot(tttPlayer: TTTPlayer, item: ItemStack, state: State = isc.getOrCreate(tttPlayer)): Boolean { if (state.currentAction !== null) throw ActionInProgressError() + return true + } + + open fun onHit(tttPlayer: TTTPlayer, hitTTTPlayer: TTTPlayer) { + hitTTTPlayer.damageInfo = DamageInfo(tttPlayer, DeathReason.Item(this)) + val actualDamage = computeActualDamage(tttPlayer, hitTTTPlayer.player) + + hitTTTPlayer.player.damage(actualDamage) + tttPlayer.player.playSound(tttPlayer.player.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.MASTER, 2f, 1.2f) + hitTTTPlayer.player.velocity = tttPlayer.player.location.direction.multiply( + (actualDamage / 20).coerceAtMost(3.0) + ) } override fun onSelect(tttPlayer: TTTPlayer) { @@ -140,8 +145,8 @@ abstract class Gun( } } - override fun onDrop(tttPlayer: TTTPlayer, itemEntity: Item) { - val state = isc.get(tttPlayer) ?: return + override fun onDrop(tttPlayer: TTTPlayer, itemEntity: Item): Boolean { + val state = isc.get(tttPlayer) ?: return true when(val currentAction = state.currentAction) { is Action.Reloading -> { @@ -157,7 +162,7 @@ abstract class Gun( ItemManager.droppedItemStates[itemEntity.entityId] = state isc.remove(tttPlayer) - return + return true } override fun onPickup(tttPlayer: TTTPlayer, itemEntity: Item) { diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/impl/GoldenDeagle.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/impl/GoldenDeagle.kt deleted file mode 100644 index b22512f..0000000 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/impl/GoldenDeagle.kt +++ /dev/null @@ -1,27 +0,0 @@ -package de.moritzruth.spigot_ttt.items.weapons.guns.impl - -import de.moritzruth.spigot_ttt.CustomItems -import de.moritzruth.spigot_ttt.game.players.Role -import de.moritzruth.spigot_ttt.game.players.roles -import de.moritzruth.spigot_ttt.items.Buyable -import de.moritzruth.spigot_ttt.items.TTTItem -import de.moritzruth.spigot_ttt.items.weapons.guns.Gun -import org.bukkit.ChatColor - -object GoldenDeagle: Gun( - stateClass = State::class, - displayName = "${ChatColor.GOLD}${ChatColor.BOLD}Golden Deagle", - damage = INFINITE_DAMAGE, - cooldown = 1.0, - magazineSize = 1, - reloadTime = 20.0, - itemMaterial = CustomItems.goldenDeagle -), Buyable { - override val buyableBy = roles(Role.TRAITOR, Role.JACKAL, Role.DETECTIVE) - override val price = 3 - override val type = TTTItem.Type.PISTOL_LIKE - - class State: Gun.State(magazineSize) -} - - diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/impl/Shotgun.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/impl/Shotgun.kt index 5fe7484..150a7f1 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/impl/Shotgun.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/impl/Shotgun.kt @@ -66,9 +66,9 @@ object Shotgun: Gun( ownState.currentAction = ReloadingAction(itemStack, ownState, tttPlayer).also { it.start() } } - override fun onBeforeShoot(tttPlayer: TTTPlayer, item: ItemStack, state: Gun.State) { + override fun onBeforeShoot(tttPlayer: TTTPlayer, item: ItemStack, state: Gun.State): Boolean { val ownState = state as State - if (ownState.remainingShots == 0) return + if (ownState.remainingShots == 0) return true when(val currentAction = ownState.currentAction) { is Action.Cooldown -> throw ActionInProgressError() @@ -82,6 +82,8 @@ object Shotgun: Gun( item.itemMeta = damageMeta as ItemMeta } } + + return true } class State: Gun.State(magazineSize) diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/impl/SidekickDeagle.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/impl/SidekickDeagle.kt new file mode 100644 index 0000000..7b8ef7a --- /dev/null +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/guns/impl/SidekickDeagle.kt @@ -0,0 +1,73 @@ +package de.moritzruth.spigot_ttt.items.weapons.guns.impl + +import com.connorlinfoot.actionbarapi.ActionBarAPI +import de.moritzruth.spigot_ttt.CustomItems +import de.moritzruth.spigot_ttt.game.players.Role +import de.moritzruth.spigot_ttt.game.players.TTTPlayer +import de.moritzruth.spigot_ttt.game.players.roles +import de.moritzruth.spigot_ttt.items.Buyable +import de.moritzruth.spigot_ttt.items.TTTItem +import de.moritzruth.spigot_ttt.items.weapons.guns.Gun +import de.moritzruth.spigot_ttt.utils.applyMeta +import de.moritzruth.spigot_ttt.utils.hideInfo +import org.bukkit.ChatColor +import org.bukkit.entity.Item +import org.bukkit.inventory.ItemStack + +object SidekickDeagle: Gun( + stateClass = State::class, + displayName = "${ChatColor.AQUA}${ChatColor.BOLD}Sidekick Deagle", + damage = 0.1, // Not really + cooldown = 1.0, + magazineSize = 1, + reloadTime = 0.0, + itemMaterial = CustomItems.sidekickDeagle +), Buyable { + override val buyableBy = roles(Role.JACKAL) + override val price = 1 + override val type = TTTItem.Type.PISTOL_LIKE + override val buyLimit = 1 + + override val itemStack = ItemStack(CustomItems.sidekickDeagle).applyMeta { + hideInfo() + setDisplayName("${ChatColor.AQUA}${ChatColor.BOLD}Sidekick Deagle") + lore = listOf( + "", + "${ChatColor.GOLD}Mache einen Spieler zu deinem Sidekick", + "", + "${ChatColor.RED}Nur ein Schuss" + ) + } + + override fun reload(tttPlayer: TTTPlayer, itemStack: ItemStack, state: Gun.State) { + ActionBarAPI.sendActionBar(tttPlayer.player, "${ChatColor.RED}Du kannst diese Waffe nicht nachladen") + } + + override fun onHit(tttPlayer: TTTPlayer, hitTTTPlayer: TTTPlayer) { + hitTTTPlayer.changeRole(Role.SIDEKICK) + } + + override fun onDrop(tttPlayer: TTTPlayer, itemEntity: Item): Boolean { + val state = isc.get(tttPlayer) ?: return true + + return if (tttPlayer.role != Role.JACKAL || state.remainingShots == 0) { + isc.remove(tttPlayer) + itemEntity.remove() + state.currentAction?.task?.cancel() + true + } else false + } + + override fun onBeforeShoot(tttPlayer: TTTPlayer, item: ItemStack, state: Gun.State): Boolean { + if (tttPlayer.role != Role.JACKAL) { + ActionBarAPI.sendActionBar(tttPlayer.player, "${ChatColor.RED}Diese Waffe kann nur der Jackal benutzen") + return false + } + + return super.onBeforeShoot(tttPlayer, item, state) + } + + class State: Gun.State(magazineSize) +} + + diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/impl/BaseballBat.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/impl/BaseballBat.kt index a1581dc..560ebb7 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/impl/BaseballBat.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/impl/BaseballBat.kt @@ -36,6 +36,7 @@ object BaseballBat: TTTItem, Buyable, Selectable { } override val buyableBy = roles(Role.TRAITOR, Role.JACKAL) override val price = 1 + override val buyLimit: Int? = null override fun onSelect(tttPlayer: TTTPlayer) { tttPlayer.player.walkSpeed = 0.3F diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/impl/Knife.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/impl/Knife.kt index 5176b74..08205c3 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/impl/Knife.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/items/weapons/impl/Knife.kt @@ -34,6 +34,7 @@ object Knife: TTTItem, Buyable { override val buyableBy = roles(Role.TRAITOR, Role.JACKAL) override val price = 1 override val type = TTTItem.Type.MELEE + override val buyLimit = 1 override val listener = object : Listener { @EventHandler diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/shop/Shop.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/shop/Shop.kt index a752378..b100a55 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/shop/Shop.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/shop/Shop.kt @@ -5,7 +5,9 @@ import de.moritzruth.spigot_ttt.game.players.PlayerManager import de.moritzruth.spigot_ttt.game.players.TTTPlayer import de.moritzruth.spigot_ttt.items.Buyable import de.moritzruth.spigot_ttt.items.ItemManager +import de.moritzruth.spigot_ttt.items.TTTItem import de.moritzruth.spigot_ttt.plugin +import de.moritzruth.spigot_ttt.utils.applyMeta import de.moritzruth.spigot_ttt.utils.secondsToTicks import org.bukkit.ChatColor import org.bukkit.scheduler.BukkitTask @@ -21,29 +23,29 @@ object Shop { private var creditsTimer: BukkitTask? = null - fun getBuyableItems(tttPlayer: TTTPlayer) = ItemManager.ITEMS.filter { it is Buyable && it.buyableBy.contains(tttPlayer.role) }.toSet() + private fun getBuyableItems(tttPlayer: TTTPlayer) = ItemManager.ITEMS.filter { it is Buyable && it.buyableBy.contains(tttPlayer.role) }.toSet() - fun show(tttPlayer: TTTPlayer) { + fun setItems(tttPlayer: TTTPlayer) { + clear(tttPlayer) val itemsIterator = getBuyableItems(tttPlayer).iterator() for(index in SHOP_SLOTS) { if (!itemsIterator.hasNext()) break val tttItem = itemsIterator.next() - val itemStack = tttItem.itemStack.clone() - val meta = itemStack.itemMeta!! - meta.setDisplayName(meta.displayName + "${ChatColor.RESET} - ${ChatColor.BOLD}$${(tttItem as Buyable).price}") - itemStack.itemMeta = meta + if (tttItem !is Buyable) throw Error("Item is not buyable") - tttPlayer.player.inventory.setItem(index, itemStack) + tttPlayer.player.inventory.setItem(index, tttItem.itemStack.clone().applyMeta { + val displayNameSuffix = + if (isOutOfStock(tttPlayer, tttItem)) "${ChatColor.RED}Ausverkauft" + else "$${tttItem.price}" + + setDisplayName("$displayName${ChatColor.RESET} - ${ChatColor.BOLD}$displayNameSuffix") + }) } } - fun hide(tttPlayer: TTTPlayer) { - val range = 9..19 - - range + (1..8) - + fun clear(tttPlayer: TTTPlayer) { for(index in 9..35) tttPlayer.player.inventory.clear(index) // All slots except the hotbar and armor } @@ -62,4 +64,9 @@ object Shop { fun stopCreditsTimer() { creditsTimer?.cancel() } + + fun isOutOfStock(tttPlayer: TTTPlayer, tttItem: TTTItem): Boolean { + if (tttItem !is Buyable) throw Error("Item is not buyable") + return tttItem.buyLimit != null && tttPlayer.boughtItems.filter { it == tttItem }.count() >= tttItem.buyLimit!! + } } diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/shop/ShopListener.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/shop/ShopListener.kt index 68e1b7b..0b8ef78 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/shop/ShopListener.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/shop/ShopListener.kt @@ -36,17 +36,23 @@ object ShopListener: Listener { val tttItem = ItemManager.getItemByItemStack(itemStack) if (tttItem === null || tttItem !is Buyable || !tttItem.buyableBy.contains(tttPlayer.role)) return - if (tttPlayer.credits < tttItem.price) { - ActionBarAPI.sendActionBar(tttPlayer.player, "${ChatColor.RED}Du hast nicht genug Credits") - } + when { + Shop.isOutOfStock(tttPlayer, tttItem) -> + ActionBarAPI.sendActionBar(tttPlayer.player, "${ChatColor.RED}Dieses Item ist ausverkauft") - try { - tttPlayer.addItem(tttItem) - tttPlayer.credits -= tttItem.price - } catch (e: TTTPlayer.AlreadyHasItemException) { - ActionBarAPI.sendActionBar(tttPlayer.player, "${ChatColor.RED}Du hast dieses Item bereits") - } catch (e: TTTPlayer.TooManyItemsOfTypeException) { - ActionBarAPI.sendActionBar(tttPlayer.player, "${ChatColor.RED}Du hast keinen Platz dafür") + tttPlayer.credits < tttItem.price -> + ActionBarAPI.sendActionBar(tttPlayer.player, "${ChatColor.RED}Du hast nicht genug Credits") + + else -> try { + tttPlayer.addItem(tttItem) + tttPlayer.boughtItems.add(tttItem) + tttPlayer.credits -= tttItem.price + Shop.setItems(tttPlayer) + } catch (e: TTTPlayer.AlreadyHasItemException) { + ActionBarAPI.sendActionBar(tttPlayer.player, "${ChatColor.RED}Du hast dieses Item bereits") + } catch (e: TTTPlayer.TooManyItemsOfTypeException) { + ActionBarAPI.sendActionBar(tttPlayer.player, "${ChatColor.RED}Du hast keinen Platz dafür") + } } } }