Change the way items (and classes) work
This commit is contained in:
parent
d4b337e661
commit
87d0e6c43c
47 changed files with 1483 additions and 1516 deletions
|
@ -1,190 +1,28 @@
|
||||||
package de.moritzruth.spigot_ttt.game
|
package de.moritzruth.spigot_ttt.game
|
||||||
|
|
||||||
import com.comphenix.packetwrapper.WrapperPlayServerPlayerInfo
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
||||||
import com.comphenix.protocol.PacketType
|
|
||||||
import com.comphenix.protocol.events.PacketAdapter
|
|
||||||
import com.comphenix.protocol.events.PacketEvent
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers
|
|
||||||
import com.comphenix.protocol.wrappers.PlayerInfoData
|
|
||||||
import de.moritzruth.spigot_ttt.TTTPlugin
|
|
||||||
import de.moritzruth.spigot_ttt.game.players.*
|
|
||||||
import de.moritzruth.spigot_ttt.plugin
|
|
||||||
import de.moritzruth.spigot_ttt.utils.call
|
|
||||||
import de.moritzruth.spigot_ttt.utils.nextTick
|
|
||||||
import org.bukkit.ChatColor
|
|
||||||
import org.bukkit.GameMode
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.event.EventHandler
|
|
||||||
import org.bukkit.event.EventPriority
|
|
||||||
import org.bukkit.event.Listener
|
import org.bukkit.event.Listener
|
||||||
import org.bukkit.event.block.Action
|
import org.bukkit.event.inventory.InventoryClickEvent
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
import org.bukkit.event.inventory.InventoryCloseEvent
|
||||||
import org.bukkit.event.entity.EntityDamageEvent
|
import org.bukkit.event.player.PlayerEvent
|
||||||
import org.bukkit.event.entity.PlayerDeathEvent
|
|
||||||
import org.bukkit.event.player.*
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
object GameListener : Listener {
|
abstract class GameListener: Listener {
|
||||||
private val BLOCKED_COMMANDS = setOf("me", "tell", "msg")
|
protected fun handle(event: InventoryClickEvent, handler: (tttPlayer: TTTPlayer) -> Unit) {
|
||||||
|
val whoClicked = event.whoClicked
|
||||||
@EventHandler
|
if (whoClicked is Player) {
|
||||||
fun onPlayerJoin(event: PlayerJoinEvent) = PlayerManager.onPlayerJoin(event.player)
|
handler(TTTPlayer.of(whoClicked) ?: return)
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onPlayerQuit(event: PlayerQuitEvent) = PlayerManager.onPlayerQuit(event.player)
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onPlayerCommandPreprocess(event: PlayerCommandPreprocessEvent) {
|
|
||||||
if (event.message.startsWith("/rl") && GameManager.phase != null) { // /reload is not blocked
|
|
||||||
event.player.sendMessage(TTTPlugin.prefix + "${ChatColor.RED}The server may not be reloaded while the game is running")
|
|
||||||
event.player.sendMessage(TTTPlugin.prefix + "${ChatColor.RED}You can force reload by using ${ChatColor.WHITE}/reload")
|
|
||||||
event.isCancelled = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BLOCKED_COMMANDS.find { event.message.startsWith("/$it") } != null) {
|
|
||||||
if (GameManager.phase != null) {
|
|
||||||
event.player.sendMessage(TTTPlugin.prefix + "${ChatColor.RED}Dieser Befehl ist blockiert.")
|
|
||||||
event.isCancelled = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
protected open fun handle(event: InventoryCloseEvent, handler: (tttPlayer: TTTPlayer) -> Unit) {
|
||||||
fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
|
val player = event.player
|
||||||
val player = event.damager
|
|
||||||
if (player is Player) {
|
if (player is Player) {
|
||||||
if (player.inventory.itemInMainHand.type == Material.AIR) {
|
handler(TTTPlayer.of(player) ?: return)
|
||||||
event.damage = 0.2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ZERO_NO_DAMAGE_TICKS_CAUSES = EnumSet.of(
|
protected fun <T: PlayerEvent> handle(event: T, handler: (tttPlayer: TTTPlayer) -> Unit) {
|
||||||
EntityDamageEvent.DamageCause.ENTITY_ATTACK,
|
handler(TTTPlayer.of(event.player) ?: return)
|
||||||
EntityDamageEvent.DamageCause.CUSTOM,
|
|
||||||
EntityDamageEvent.DamageCause.ENTITY_EXPLOSION,
|
|
||||||
EntityDamageEvent.DamageCause.BLOCK_EXPLOSION,
|
|
||||||
EntityDamageEvent.DamageCause.FALL,
|
|
||||||
EntityDamageEvent.DamageCause.ENTITY_SWEEP_ATTACK,
|
|
||||||
EntityDamageEvent.DamageCause.FALLING_BLOCK,
|
|
||||||
EntityDamageEvent.DamageCause.SUICIDE
|
|
||||||
)!!
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
|
||||||
fun onEntityDamageLow(event: EntityDamageEvent) {
|
|
||||||
if (ZERO_NO_DAMAGE_TICKS_CAUSES.contains(event.cause)) {
|
|
||||||
val player = event.entity
|
|
||||||
if (player is Player) {
|
|
||||||
nextTick { player.noDamageTicks = 0 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
|
||||||
fun onEntityDamageHighest(event: EntityDamageEvent) {
|
|
||||||
if (event.entity !is Player) return
|
|
||||||
val tttPlayer = TTTPlayer.of(event.entity as Player) ?: return
|
|
||||||
if (event.cause == EntityDamageEvent.DamageCause.CUSTOM) return
|
|
||||||
|
|
||||||
val reason = when (event.cause) {
|
|
||||||
EntityDamageEvent.DamageCause.FALL -> DeathReason.FALL
|
|
||||||
EntityDamageEvent.DamageCause.BLOCK_EXPLOSION,
|
|
||||||
EntityDamageEvent.DamageCause.ENTITY_EXPLOSION -> DeathReason.EXPLOSION
|
|
||||||
EntityDamageEvent.DamageCause.DROWNING -> DeathReason.DROWNED
|
|
||||||
EntityDamageEvent.DamageCause.FIRE,
|
|
||||||
EntityDamageEvent.DamageCause.FIRE_TICK,
|
|
||||||
EntityDamageEvent.DamageCause.LAVA,
|
|
||||||
EntityDamageEvent.DamageCause.HOT_FLOOR -> DeathReason.FIRE
|
|
||||||
EntityDamageEvent.DamageCause.POISON,
|
|
||||||
EntityDamageEvent.DamageCause.WITHER -> DeathReason.POISON
|
|
||||||
else -> DeathReason.SUICIDE
|
|
||||||
}
|
|
||||||
|
|
||||||
val e = TTTPlayerDamageEvent(tttPlayer, event.finalDamage, reason).call()
|
|
||||||
|
|
||||||
if (tttPlayer.player.health - e.damage <= 0) {
|
|
||||||
tttPlayer.onDeath(reason, null)
|
|
||||||
event.damage = 0.0
|
|
||||||
} else {
|
|
||||||
event.damage = e.damage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onPlayerDeath(event: PlayerDeathEvent) {
|
|
||||||
event.deathMessage = null
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onPlayerInteract(event: PlayerInteractEvent) {
|
|
||||||
if (event.player.inventory.itemInMainHand.type == Material.AIR && event.action == Action.LEFT_CLICK_BLOCK) {
|
|
||||||
GameManager.destroyBlock(event.clickedBlock!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
|
||||||
fun onPlayerSwapHandItemsLowest(event: PlayerSwapHandItemsEvent) {
|
|
||||||
event.isCancelled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onAsyncPlayerChat(event: AsyncPlayerChatEvent) {
|
|
||||||
val senderTTTPlayer = TTTPlayer.of(event.player) ?: return
|
|
||||||
|
|
||||||
if (!senderTTTPlayer.alive) {
|
|
||||||
PlayerManager.tttPlayers.filter { !it.alive }.forEach {
|
|
||||||
it.player.sendMessage("${ChatColor.GRAY}[${ChatColor.RED}TOT${ChatColor.GRAY}] <${event.player.displayName}> ${event.message}")
|
|
||||||
}
|
|
||||||
|
|
||||||
event.isCancelled = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
|
||||||
fun onTTTPlayerTrueDeath(event: TTTPlayerTrueDeathEvent) {
|
|
||||||
if (event.winnerRoleGroup != RoleGroup.JACKAL && event.tttPlayer.role == Role.JACKAL) {
|
|
||||||
val sidekicks = PlayerManager.tttPlayers.filter { it.role == Role.SIDEKICK }
|
|
||||||
|
|
||||||
if (sidekicks.isNotEmpty()) {
|
|
||||||
val newJackal = sidekicks.random()
|
|
||||||
newJackal.changeRole(Role.JACKAL)
|
|
||||||
|
|
||||||
event.tttPlayer.changeRole(Role.SIDEKICK) // The old Jackal
|
|
||||||
|
|
||||||
sidekicks.forEach { sidekick ->
|
|
||||||
if (sidekick != newJackal) {
|
|
||||||
sidekick.player.sendMessage(TTTPlugin.prefix + "${newJackal.player.displayName} ${ChatColor.GREEN}ist der neue Jackal")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val packetListener = object : PacketAdapter(plugin, PacketType.Play.Server.PLAYER_INFO) {
|
|
||||||
override fun onPacketSending(event: PacketEvent) {
|
|
||||||
val packet = WrapperPlayServerPlayerInfo(event.packet)
|
|
||||||
|
|
||||||
if (
|
|
||||||
packet.action == EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE ||
|
|
||||||
packet.action == EnumWrappers.PlayerInfoAction.ADD_PLAYER
|
|
||||||
) {
|
|
||||||
packet.data = packet.data.map { info ->
|
|
||||||
val tttPlayer = PlayerManager.tttPlayers.find { it.player.uniqueId == info.profile.uuid }
|
|
||||||
|
|
||||||
if (tttPlayer == null) info
|
|
||||||
else PlayerInfoData(
|
|
||||||
info.profile,
|
|
||||||
info.latency,
|
|
||||||
if (event.player.uniqueId == info.profile.uuid) {
|
|
||||||
if (event.player.gameMode == GameMode.SPECTATOR) EnumWrappers.NativeGameMode.SPECTATOR
|
|
||||||
else EnumWrappers.NativeGameMode.SURVIVAL
|
|
||||||
} else EnumWrappers.NativeGameMode.SURVIVAL,
|
|
||||||
info.displayName
|
|
||||||
)
|
|
||||||
}.toMutableList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,13 +31,13 @@ object GameManager {
|
||||||
val destroyedBlocks = mutableMapOf<Location, Material>()
|
val destroyedBlocks = mutableMapOf<Location, Material>()
|
||||||
|
|
||||||
private val listeners = ItemManager.listeners
|
private val listeners = ItemManager.listeners
|
||||||
.plus(GameListener)
|
.plus(GeneralGameListener)
|
||||||
.plus(ShopListener)
|
.plus(ShopListener)
|
||||||
.plus(CorpseListener)
|
.plus(CorpseListener)
|
||||||
.plus(TTTClassManager.listeners)
|
.plus(TTTClassManager.listeners)
|
||||||
|
|
||||||
private val packetListeners = ItemManager.packetListeners
|
private val packetListeners = ItemManager.packetListeners
|
||||||
.plus(GameListener.packetListener)
|
.plus(GeneralGameListener.packetListener)
|
||||||
|
|
||||||
fun initialize() {
|
fun initialize() {
|
||||||
adjustWorld()
|
adjustWorld()
|
||||||
|
|
|
@ -0,0 +1,190 @@
|
||||||
|
package de.moritzruth.spigot_ttt.game
|
||||||
|
|
||||||
|
import com.comphenix.packetwrapper.WrapperPlayServerPlayerInfo
|
||||||
|
import com.comphenix.protocol.PacketType
|
||||||
|
import com.comphenix.protocol.events.PacketAdapter
|
||||||
|
import com.comphenix.protocol.events.PacketEvent
|
||||||
|
import com.comphenix.protocol.wrappers.EnumWrappers
|
||||||
|
import com.comphenix.protocol.wrappers.PlayerInfoData
|
||||||
|
import de.moritzruth.spigot_ttt.TTTPlugin
|
||||||
|
import de.moritzruth.spigot_ttt.game.players.*
|
||||||
|
import de.moritzruth.spigot_ttt.plugin
|
||||||
|
import de.moritzruth.spigot_ttt.utils.call
|
||||||
|
import de.moritzruth.spigot_ttt.utils.nextTick
|
||||||
|
import org.bukkit.ChatColor
|
||||||
|
import org.bukkit.GameMode
|
||||||
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.event.EventHandler
|
||||||
|
import org.bukkit.event.EventPriority
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
import org.bukkit.event.block.Action
|
||||||
|
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||||
|
import org.bukkit.event.entity.EntityDamageEvent
|
||||||
|
import org.bukkit.event.entity.PlayerDeathEvent
|
||||||
|
import org.bukkit.event.player.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
object GeneralGameListener : Listener {
|
||||||
|
private val BLOCKED_COMMANDS = setOf("me", "tell", "msg")
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onPlayerJoin(event: PlayerJoinEvent) = PlayerManager.onPlayerJoin(event.player)
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onPlayerQuit(event: PlayerQuitEvent) = PlayerManager.onPlayerQuit(event.player)
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onPlayerCommandPreprocess(event: PlayerCommandPreprocessEvent) {
|
||||||
|
if (event.message.startsWith("/rl") && GameManager.phase != null) { // /reload is not blocked
|
||||||
|
event.player.sendMessage(TTTPlugin.prefix + "${ChatColor.RED}The server may not be reloaded while the game is running")
|
||||||
|
event.player.sendMessage(TTTPlugin.prefix + "${ChatColor.RED}You can force reload by using ${ChatColor.WHITE}/reload")
|
||||||
|
event.isCancelled = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BLOCKED_COMMANDS.find { event.message.startsWith("/$it") } != null) {
|
||||||
|
if (GameManager.phase != null) {
|
||||||
|
event.player.sendMessage(TTTPlugin.prefix + "${ChatColor.RED}Dieser Befehl ist blockiert.")
|
||||||
|
event.isCancelled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
|
||||||
|
val player = event.damager
|
||||||
|
if (player is Player) {
|
||||||
|
if (player.inventory.itemInMainHand.type == Material.AIR) {
|
||||||
|
event.damage = 0.2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val ZERO_NO_DAMAGE_TICKS_CAUSES = EnumSet.of(
|
||||||
|
EntityDamageEvent.DamageCause.ENTITY_ATTACK,
|
||||||
|
EntityDamageEvent.DamageCause.CUSTOM,
|
||||||
|
EntityDamageEvent.DamageCause.ENTITY_EXPLOSION,
|
||||||
|
EntityDamageEvent.DamageCause.BLOCK_EXPLOSION,
|
||||||
|
EntityDamageEvent.DamageCause.FALL,
|
||||||
|
EntityDamageEvent.DamageCause.ENTITY_SWEEP_ATTACK,
|
||||||
|
EntityDamageEvent.DamageCause.FALLING_BLOCK,
|
||||||
|
EntityDamageEvent.DamageCause.SUICIDE
|
||||||
|
)!!
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||||
|
fun onEntityDamageLow(event: EntityDamageEvent) {
|
||||||
|
if (ZERO_NO_DAMAGE_TICKS_CAUSES.contains(event.cause)) {
|
||||||
|
val player = event.entity
|
||||||
|
if (player is Player) {
|
||||||
|
nextTick { player.noDamageTicks = 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
|
fun onEntityDamageHighest(event: EntityDamageEvent) {
|
||||||
|
if (event.entity !is Player) return
|
||||||
|
val tttPlayer = TTTPlayer.of(event.entity as Player) ?: return
|
||||||
|
if (event.cause == EntityDamageEvent.DamageCause.CUSTOM) return
|
||||||
|
|
||||||
|
val reason = when (event.cause) {
|
||||||
|
EntityDamageEvent.DamageCause.FALL -> DeathReason.FALL
|
||||||
|
EntityDamageEvent.DamageCause.BLOCK_EXPLOSION,
|
||||||
|
EntityDamageEvent.DamageCause.ENTITY_EXPLOSION -> DeathReason.EXPLOSION
|
||||||
|
EntityDamageEvent.DamageCause.DROWNING -> DeathReason.DROWNED
|
||||||
|
EntityDamageEvent.DamageCause.FIRE,
|
||||||
|
EntityDamageEvent.DamageCause.FIRE_TICK,
|
||||||
|
EntityDamageEvent.DamageCause.LAVA,
|
||||||
|
EntityDamageEvent.DamageCause.HOT_FLOOR -> DeathReason.FIRE
|
||||||
|
EntityDamageEvent.DamageCause.POISON,
|
||||||
|
EntityDamageEvent.DamageCause.WITHER -> DeathReason.POISON
|
||||||
|
else -> DeathReason.SUICIDE
|
||||||
|
}
|
||||||
|
|
||||||
|
val e = TTTPlayerDamageEvent(tttPlayer, event.finalDamage, reason).call()
|
||||||
|
|
||||||
|
if (tttPlayer.player.health - e.damage <= 0) {
|
||||||
|
tttPlayer.onDeath(reason, null)
|
||||||
|
event.damage = 0.0
|
||||||
|
} else {
|
||||||
|
event.damage = e.damage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onPlayerDeath(event: PlayerDeathEvent) {
|
||||||
|
event.deathMessage = null
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onPlayerInteract(event: PlayerInteractEvent) {
|
||||||
|
if (event.player.inventory.itemInMainHand.type == Material.AIR && event.action == Action.LEFT_CLICK_BLOCK) {
|
||||||
|
GameManager.destroyBlock(event.clickedBlock!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
fun onPlayerSwapHandItemsLowest(event: PlayerSwapHandItemsEvent) {
|
||||||
|
event.isCancelled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onAsyncPlayerChat(event: AsyncPlayerChatEvent) {
|
||||||
|
val senderTTTPlayer = TTTPlayer.of(event.player) ?: return
|
||||||
|
|
||||||
|
if (!senderTTTPlayer.alive) {
|
||||||
|
PlayerManager.tttPlayers.filter { !it.alive }.forEach {
|
||||||
|
it.player.sendMessage("${ChatColor.GRAY}[${ChatColor.RED}TOT${ChatColor.GRAY}] <${event.player.displayName}> ${event.message}")
|
||||||
|
}
|
||||||
|
|
||||||
|
event.isCancelled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
fun onTTTPlayerTrueDeath(event: TTTPlayerTrueDeathEvent) {
|
||||||
|
if (event.winnerRoleGroup != RoleGroup.JACKAL && event.tttPlayer.role == Role.JACKAL) {
|
||||||
|
val sidekicks = PlayerManager.tttPlayers.filter { it.role == Role.SIDEKICK }
|
||||||
|
|
||||||
|
if (sidekicks.isNotEmpty()) {
|
||||||
|
val newJackal = sidekicks.random()
|
||||||
|
newJackal.changeRole(Role.JACKAL)
|
||||||
|
|
||||||
|
event.tttPlayer.changeRole(Role.SIDEKICK) // The old Jackal
|
||||||
|
|
||||||
|
sidekicks.forEach { sidekick ->
|
||||||
|
if (sidekick != newJackal) {
|
||||||
|
sidekick.player.sendMessage(TTTPlugin.prefix + "${newJackal.player.displayName} ${ChatColor.GREEN}ist der neue Jackal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val packetListener = object : PacketAdapter(plugin, PacketType.Play.Server.PLAYER_INFO) {
|
||||||
|
override fun onPacketSending(event: PacketEvent) {
|
||||||
|
val packet = WrapperPlayServerPlayerInfo(event.packet)
|
||||||
|
|
||||||
|
if (
|
||||||
|
packet.action == EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE ||
|
||||||
|
packet.action == EnumWrappers.PlayerInfoAction.ADD_PLAYER
|
||||||
|
) {
|
||||||
|
packet.data = packet.data.map { info ->
|
||||||
|
val tttPlayer = PlayerManager.tttPlayers.find { it.player.uniqueId == info.profile.uuid }
|
||||||
|
|
||||||
|
if (tttPlayer == null) info
|
||||||
|
else PlayerInfoData(
|
||||||
|
info.profile,
|
||||||
|
info.latency,
|
||||||
|
if (event.player.uniqueId == info.profile.uuid) {
|
||||||
|
if (event.player.gameMode == GameMode.SPECTATOR) EnumWrappers.NativeGameMode.SPECTATOR
|
||||||
|
else EnumWrappers.NativeGameMode.SURVIVAL
|
||||||
|
} else EnumWrappers.NativeGameMode.SURVIVAL,
|
||||||
|
info.displayName
|
||||||
|
)
|
||||||
|
}.toMutableList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,23 +1,19 @@
|
||||||
package de.moritzruth.spigot_ttt.game.classes
|
package de.moritzruth.spigot_ttt.game.classes
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
|
||||||
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.event.Listener
|
|
||||||
|
|
||||||
abstract class TTTClass(
|
abstract class TTTClass {
|
||||||
val displayName: String,
|
lateinit var tttPlayer: TTTPlayer
|
||||||
val chatColor: ChatColor,
|
|
||||||
val defaultItems: Set<TTTItem> = emptySet()
|
|
||||||
) {
|
|
||||||
val coloredDisplayName = "$chatColor$displayName"
|
|
||||||
|
|
||||||
open val listener: Listener? = null
|
open fun init() {}
|
||||||
|
open fun reset() {}
|
||||||
|
|
||||||
open fun onInit(tttPlayer: TTTPlayer) {}
|
object None: TTTClassCompanion(
|
||||||
|
|
||||||
object None: TTTClass(
|
|
||||||
"Keine",
|
"Keine",
|
||||||
ChatColor.GRAY
|
ChatColor.GRAY,
|
||||||
)
|
Instance::class
|
||||||
|
) {
|
||||||
|
class Instance: TTTClass()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package de.moritzruth.spigot_ttt.game.classes
|
||||||
|
|
||||||
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
||||||
|
import org.bukkit.ChatColor
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
import kotlin.reflect.full.primaryConstructor
|
||||||
|
|
||||||
|
abstract class TTTClassCompanion(
|
||||||
|
val displayName: String,
|
||||||
|
val chatColor: ChatColor,
|
||||||
|
private val instanceType: KClass<out TTTClass>,
|
||||||
|
val defaultItems: Set<TTTItem<*>> = emptySet()
|
||||||
|
) {
|
||||||
|
val coloredDisplayName = "$chatColor$displayName"
|
||||||
|
fun createInstance(tttPlayer: TTTPlayer): TTTClass {
|
||||||
|
val instance = instanceType.primaryConstructor!!.call()
|
||||||
|
instance.tttPlayer = tttPlayer
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
|
||||||
|
open val listener: Listener? = null
|
||||||
|
}
|
|
@ -1,21 +1,17 @@
|
||||||
package de.moritzruth.spigot_ttt.game.classes
|
package de.moritzruth.spigot_ttt.game.classes
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.game.classes.impl.Gambler
|
import de.moritzruth.spigot_ttt.game.classes.impl.*
|
||||||
import de.moritzruth.spigot_ttt.game.classes.impl.Ninja
|
|
||||||
import de.moritzruth.spigot_ttt.game.classes.impl.Stuntman
|
|
||||||
import de.moritzruth.spigot_ttt.game.classes.impl.Warrior
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
object TTTClassManager {
|
object TTTClassManager {
|
||||||
private val TTT_CLASSES = setOf(
|
private val TTT_CLASSES = setOf(
|
||||||
Warrior, Gambler, Stuntman, Ninja
|
Warrior, Gambler, Stuntman, Ninja, Oracle
|
||||||
// Oracle is disabled because of the bug with the radar
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val listeners = TTT_CLASSES.mapNotNull { it.listener }
|
val listeners = TTT_CLASSES.mapNotNull { it.listener }
|
||||||
|
|
||||||
fun createClassesIterator(count: Int): Iterator<TTTClass> {
|
fun createClassesIterator(count: Int): Iterator<TTTClassCompanion> {
|
||||||
val set: MutableSet<TTTClass> = TTT_CLASSES.toMutableSet()
|
val set: MutableSet<TTTClassCompanion> = TTT_CLASSES.toMutableSet()
|
||||||
|
|
||||||
val playersWithoutClass = count - TTT_CLASSES.size
|
val playersWithoutClass = count - TTT_CLASSES.size
|
||||||
if (playersWithoutClass > 0) set.addAll(Collections.nCopies(playersWithoutClass, TTTClass.None))
|
if (playersWithoutClass > 0) set.addAll(Collections.nCopies(playersWithoutClass, TTTClass.None))
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
package de.moritzruth.spigot_ttt.game.classes.impl
|
package de.moritzruth.spigot_ttt.game.classes.impl
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.game.classes.TTTClass
|
import de.moritzruth.spigot_ttt.game.classes.TTTClass
|
||||||
|
import de.moritzruth.spigot_ttt.game.classes.TTTClassCompanion
|
||||||
import de.moritzruth.spigot_ttt.game.items.impl.SecondChance
|
import de.moritzruth.spigot_ttt.game.items.impl.SecondChance
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
|
|
||||||
object Gambler: TTTClass(
|
class Gambler: TTTClass() {
|
||||||
"Gambler",
|
companion object: TTTClassCompanion(
|
||||||
ChatColor.YELLOW,
|
"Gambler",
|
||||||
setOf(SecondChance)
|
ChatColor.YELLOW,
|
||||||
)
|
Gambler::class,
|
||||||
|
setOf(SecondChance)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package de.moritzruth.spigot_ttt.game.classes.impl
|
package de.moritzruth.spigot_ttt.game.classes.impl
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.game.GameEndEvent
|
|
||||||
import de.moritzruth.spigot_ttt.game.classes.TTTClass
|
import de.moritzruth.spigot_ttt.game.classes.TTTClass
|
||||||
import de.moritzruth.spigot_ttt.game.players.*
|
import de.moritzruth.spigot_ttt.game.classes.TTTClassCompanion
|
||||||
|
import de.moritzruth.spigot_ttt.game.players.DeathReason
|
||||||
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
||||||
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayerDamageEvent
|
||||||
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayerReviveEvent
|
||||||
import de.moritzruth.spigot_ttt.plugin
|
import de.moritzruth.spigot_ttt.plugin
|
||||||
import de.moritzruth.spigot_ttt.utils.nextTick
|
import de.moritzruth.spigot_ttt.utils.nextTick
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
|
@ -14,13 +17,11 @@ import org.bukkit.potion.PotionEffectType
|
||||||
import org.bukkit.scheduler.BukkitTask
|
import org.bukkit.scheduler.BukkitTask
|
||||||
import org.bukkit.util.Vector
|
import org.bukkit.util.Vector
|
||||||
|
|
||||||
object Ninja: TTTClass(
|
class Ninja: TTTClass() {
|
||||||
"Ninja",
|
var jumpsRemaining = 1
|
||||||
ChatColor.LIGHT_PURPLE
|
var checkOnGroundTask: BukkitTask? = null
|
||||||
) {
|
|
||||||
private val isc = InversedStateContainer(State::class)
|
|
||||||
|
|
||||||
override fun onInit(tttPlayer: TTTPlayer) {
|
override fun init() {
|
||||||
tttPlayer.player.allowFlight = true
|
tttPlayer.player.allowFlight = true
|
||||||
tttPlayer.player.addPotionEffect(PotionEffect(
|
tttPlayer.player.addPotionEffect(PotionEffect(
|
||||||
PotionEffectType.JUMP,
|
PotionEffectType.JUMP,
|
||||||
|
@ -31,70 +32,58 @@ object Ninja: TTTClass(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
override val listener = object : Listener {
|
override fun reset() {
|
||||||
@EventHandler(ignoreCancelled = true)
|
checkOnGroundTask?.cancel()
|
||||||
fun onPlayerToggleFlight(event: PlayerToggleFlightEvent) {
|
checkOnGroundTask = null
|
||||||
val tttPlayer = TTTPlayer.of(event.player) ?: return
|
|
||||||
|
|
||||||
if (event.isFlying && tttPlayer.tttClass == Ninja) {
|
|
||||||
val state = isc.getOrCreate(tttPlayer)
|
|
||||||
|
|
||||||
val current = tttPlayer.player.velocity
|
|
||||||
tttPlayer.player.velocity = Vector(current.x * 3, 0.8, current.z * 3)
|
|
||||||
state.jumpsRemaining -= 1
|
|
||||||
|
|
||||||
if (state.jumpsRemaining == 0) {
|
|
||||||
tttPlayer.player.allowFlight = false
|
|
||||||
|
|
||||||
state.checkOnGroundTask = plugin.server.scheduler.runTaskTimer(plugin, fun() {
|
|
||||||
if (tttPlayer.player.isOnGround) {
|
|
||||||
state.jumpsRemaining = 1
|
|
||||||
tttPlayer.player.allowFlight = true
|
|
||||||
state.reset()
|
|
||||||
}
|
|
||||||
}, 1, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
event.isCancelled = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true)
|
|
||||||
fun onTTTPlayerDamage(event: TTTPlayerDamageEvent) {
|
|
||||||
if (event.tttPlayer.tttClass == Ninja) {
|
|
||||||
if (event.deathReason == DeathReason.FALL) event.damage = 0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onTTTPlayerDeath(event: TTTPlayerDeathEvent) {
|
|
||||||
isc.get(event.tttPlayer)?.reset()
|
|
||||||
isc.remove(event.tttPlayer)
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onTTTPlayerReviveEvent(event: TTTPlayerReviveEvent) {
|
|
||||||
if (event.tttPlayer.tttClass == Ninja) {
|
|
||||||
// This must be delayed for 2 ticks, idk why
|
|
||||||
nextTick { nextTick { event.tttPlayer.player.allowFlight = true } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onGameEnd(event: GameEndEvent) {
|
|
||||||
isc.forEveryState { state, _ ->
|
|
||||||
state.reset()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class State: IState {
|
companion object: TTTClassCompanion(
|
||||||
var jumpsRemaining = 1
|
"Ninja",
|
||||||
var checkOnGroundTask: BukkitTask? = null
|
ChatColor.LIGHT_PURPLE,
|
||||||
|
Ninja::class
|
||||||
|
) {
|
||||||
|
override val listener = object : Listener {
|
||||||
|
@EventHandler(ignoreCancelled = true)
|
||||||
|
fun onPlayerToggleFlight(event: PlayerToggleFlightEvent) {
|
||||||
|
val tttPlayer = TTTPlayer.of(event.player) ?: return
|
||||||
|
val instance = tttPlayer.tttClassInstance
|
||||||
|
if (instance !is Ninja) return
|
||||||
|
|
||||||
fun reset() {
|
if (event.isFlying) {
|
||||||
checkOnGroundTask?.cancel()
|
val vel = tttPlayer.player.velocity
|
||||||
checkOnGroundTask = null
|
tttPlayer.player.velocity = Vector(vel.x * 3, 0.8, vel.z * 3)
|
||||||
|
instance.jumpsRemaining -= 1
|
||||||
|
|
||||||
|
if (instance.jumpsRemaining == 0) {
|
||||||
|
tttPlayer.player.allowFlight = false
|
||||||
|
|
||||||
|
instance.checkOnGroundTask = plugin.server.scheduler.runTaskTimer(plugin, fun() {
|
||||||
|
if (tttPlayer.player.isOnGround) {
|
||||||
|
instance.jumpsRemaining = 1
|
||||||
|
tttPlayer.player.allowFlight = true
|
||||||
|
instance.reset()
|
||||||
|
}
|
||||||
|
}, 1, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
event.isCancelled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(ignoreCancelled = true)
|
||||||
|
fun onTTTPlayerDamage(event: TTTPlayerDamageEvent) {
|
||||||
|
if (event.tttPlayer.tttClass == Ninja) {
|
||||||
|
if (event.deathReason == DeathReason.FALL) event.damage = 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onTTTPlayerReviveEvent(event: TTTPlayerReviveEvent) {
|
||||||
|
if (event.tttPlayer.tttClass == Ninja) {
|
||||||
|
// This must be delayed for 2 ticks, idk why
|
||||||
|
nextTick { nextTick { event.tttPlayer.player.allowFlight = true } }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
package de.moritzruth.spigot_ttt.game.classes.impl
|
package de.moritzruth.spigot_ttt.game.classes.impl
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.game.classes.TTTClass
|
import de.moritzruth.spigot_ttt.game.classes.TTTClass
|
||||||
|
import de.moritzruth.spigot_ttt.game.classes.TTTClassCompanion
|
||||||
import de.moritzruth.spigot_ttt.game.items.impl.Radar
|
import de.moritzruth.spigot_ttt.game.items.impl.Radar
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
|
|
||||||
object Oracle: TTTClass(
|
class Oracle: TTTClass() {
|
||||||
"Oracle",
|
companion object: TTTClassCompanion(
|
||||||
ChatColor.DARK_AQUA,
|
"Oracle",
|
||||||
setOf(Radar)
|
ChatColor.DARK_AQUA,
|
||||||
)
|
Oracle::class,
|
||||||
|
setOf(Radar)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -1,23 +1,27 @@
|
||||||
package de.moritzruth.spigot_ttt.game.classes.impl
|
package de.moritzruth.spigot_ttt.game.classes.impl
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.game.classes.TTTClass
|
import de.moritzruth.spigot_ttt.game.classes.TTTClass
|
||||||
|
import de.moritzruth.spigot_ttt.game.classes.TTTClassCompanion
|
||||||
import de.moritzruth.spigot_ttt.game.players.DeathReason
|
import de.moritzruth.spigot_ttt.game.players.DeathReason
|
||||||
import de.moritzruth.spigot_ttt.game.players.TTTPlayerDamageEvent
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayerDamageEvent
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
import org.bukkit.event.Listener
|
import org.bukkit.event.Listener
|
||||||
|
|
||||||
object Stuntman: TTTClass(
|
class Stuntman: TTTClass() {
|
||||||
"Stuntman",
|
companion object: TTTClassCompanion(
|
||||||
ChatColor.DARK_RED
|
"Stuntman",
|
||||||
) {
|
ChatColor.DARK_RED,
|
||||||
val IMMUNE_DEATH_REASONS = setOf(DeathReason.FALL, DeathReason.EXPLOSION)
|
Stuntman::class
|
||||||
|
) {
|
||||||
|
val IMMUNE_DEATH_REASONS = setOf(DeathReason.FALL, DeathReason.EXPLOSION)
|
||||||
|
|
||||||
override val listener = object : Listener {
|
override val listener = object : Listener {
|
||||||
@EventHandler(ignoreCancelled = true)
|
@EventHandler(ignoreCancelled = true)
|
||||||
fun onEntityDamage(event: TTTPlayerDamageEvent) {
|
fun onEntityDamage(event: TTTPlayerDamageEvent) {
|
||||||
if (event.tttPlayer.tttClass == Stuntman) {
|
if (event.tttPlayer.tttClass == Stuntman) {
|
||||||
if (IMMUNE_DEATH_REASONS.contains(event.deathReason)) event.damage = 0.0
|
if (IMMUNE_DEATH_REASONS.contains(event.deathReason)) event.damage = 0.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,34 @@
|
||||||
package de.moritzruth.spigot_ttt.game.classes.impl
|
package de.moritzruth.spigot_ttt.game.classes.impl
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.game.classes.TTTClass
|
import de.moritzruth.spigot_ttt.game.classes.TTTClass
|
||||||
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
import de.moritzruth.spigot_ttt.game.classes.TTTClassCompanion
|
||||||
import de.moritzruth.spigot_ttt.game.players.TTTPlayerDamageEvent
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayerDamageEvent
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
import org.bukkit.event.Listener
|
import org.bukkit.event.Listener
|
||||||
|
|
||||||
object Warrior: TTTClass(
|
class Warrior: TTTClass() {
|
||||||
"Warrior",
|
override fun init() {
|
||||||
ChatColor.BLUE
|
tttPlayer.walkSpeed -= WALK_SPEED_DECREASE
|
||||||
) {
|
|
||||||
override fun onInit(tttPlayer: TTTPlayer) {
|
|
||||||
tttPlayer.walkSpeed -= 0.05F
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override val listener = object : Listener {
|
override fun reset() {
|
||||||
@EventHandler(ignoreCancelled = true)
|
tttPlayer.walkSpeed += WALK_SPEED_DECREASE
|
||||||
fun onEntityDamage(event: TTTPlayerDamageEvent) {
|
}
|
||||||
if (event.tttPlayer.tttClass == Warrior) {
|
|
||||||
event.damage *= 0.9
|
companion object: TTTClassCompanion(
|
||||||
|
"Warrior",
|
||||||
|
ChatColor.BLUE,
|
||||||
|
Warrior::class
|
||||||
|
) {
|
||||||
|
const val WALK_SPEED_DECREASE = 0.05F
|
||||||
|
|
||||||
|
override val listener = object : Listener {
|
||||||
|
@EventHandler(ignoreCancelled = true)
|
||||||
|
fun onEntityDamage(event: TTTPlayerDamageEvent) {
|
||||||
|
if (event.tttPlayer.tttClass == Warrior) {
|
||||||
|
event.damage *= 0.8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ object CorpseListener: Listener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler(priority = EventPriority.LOW)
|
||||||
fun onPlayerInteractEntity(event: PlayerInteractEntityEvent) {
|
fun onPlayerInteractEntity(event: PlayerInteractEntityEvent) {
|
||||||
val tttPlayer = TTTPlayer.of(event.player) ?: return
|
val tttPlayer = TTTPlayer.of(event.player) ?: return
|
||||||
val tttCorpse = CorpseManager.getTTTCorpse(event.rightClicked) ?: return
|
val tttCorpse = CorpseManager.getTTTCorpse(event.rightClicked) ?: return
|
||||||
|
|
|
@ -18,7 +18,6 @@ import org.bukkit.entity.Zombie
|
||||||
import org.bukkit.event.inventory.InventoryType
|
import org.bukkit.event.inventory.InventoryType
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.scheduler.BukkitTask
|
import org.bukkit.scheduler.BukkitTask
|
||||||
import org.bukkit.util.Vector
|
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
class TTTCorpse private constructor(
|
class TTTCorpse private constructor(
|
||||||
|
@ -26,10 +25,9 @@ class TTTCorpse private constructor(
|
||||||
location: Location,
|
location: Location,
|
||||||
private val role: Role,
|
private val role: Role,
|
||||||
private val reason: DeathReason,
|
private val reason: DeathReason,
|
||||||
private var credits: Int,
|
private var credits: Int
|
||||||
velocity: Vector = Vector()
|
|
||||||
) {
|
) {
|
||||||
var status = Status.UNIDENTIFIED; private set
|
private var status = Status.UNIDENTIFIED; private set
|
||||||
val entity: Zombie
|
val entity: Zombie
|
||||||
|
|
||||||
val inventory = tttPlayer.player.server.createInventory(null, InventoryType.HOPPER, "${role.chatColor}${tttPlayer.player.displayName}")
|
val inventory = tttPlayer.player.server.createInventory(null, InventoryType.HOPPER, "${role.chatColor}${tttPlayer.player.displayName}")
|
||||||
|
@ -83,7 +81,7 @@ class TTTCorpse private constructor(
|
||||||
|
|
||||||
private fun setReasonItem() {
|
private fun setReasonItem() {
|
||||||
if (status == Status.INSPECTED) {
|
if (status == Status.INSPECTED) {
|
||||||
val reasonItemStack = if (reason is DeathReason.Item) reason.item.itemStack.clone() else ItemStack(Resourcepack.Items.deathReason)
|
val reasonItemStack = if (reason is DeathReason.Item) reason.item.templateItemStack.clone() else ItemStack(Resourcepack.Items.deathReason)
|
||||||
inventory.setItem(REASON_SLOT, reasonItemStack.applyMeta {
|
inventory.setItem(REASON_SLOT, reasonItemStack.applyMeta {
|
||||||
setDisplayName("${ChatColor.RESET}" + reason.displayText)
|
setDisplayName("${ChatColor.RESET}" + reason.displayText)
|
||||||
lore = listOf("${ChatColor.GRAY}Grund des Todes")
|
lore = listOf("${ChatColor.GRAY}Grund des Todes")
|
||||||
|
@ -163,8 +161,7 @@ class TTTCorpse private constructor(
|
||||||
tttPlayer.player.location,
|
tttPlayer.player.location,
|
||||||
tttPlayer.role,
|
tttPlayer.role,
|
||||||
reason,
|
reason,
|
||||||
tttPlayer.credits,
|
tttPlayer.credits
|
||||||
tttPlayer.player.velocity
|
|
||||||
).also { CorpseManager.add(it) }
|
).also { CorpseManager.add(it) }
|
||||||
|
|
||||||
fun spawnFake(role: Role, tttPlayer: TTTPlayer, location: Location) {
|
fun spawnFake(role: Role, tttPlayer: TTTPlayer, location: Location) {
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package de.moritzruth.spigot_ttt.game.items
|
||||||
|
|
||||||
|
class ClickEvent {
|
||||||
|
var isCancelled = true
|
||||||
|
}
|
|
@ -1,117 +1,146 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items
|
package de.moritzruth.spigot_ttt.game.items
|
||||||
|
|
||||||
|
import de.moritzruth.spigot_ttt.game.GameListener
|
||||||
import de.moritzruth.spigot_ttt.game.GameManager
|
import de.moritzruth.spigot_ttt.game.GameManager
|
||||||
import de.moritzruth.spigot_ttt.game.items.impl.*
|
import de.moritzruth.spigot_ttt.game.items.impl.*
|
||||||
import de.moritzruth.spigot_ttt.game.items.impl.weapons.BaseballBat
|
import de.moritzruth.spigot_ttt.game.items.impl.weapons.BaseballBat
|
||||||
import de.moritzruth.spigot_ttt.game.items.impl.weapons.Knife
|
import de.moritzruth.spigot_ttt.game.items.impl.weapons.Knife
|
||||||
import de.moritzruth.spigot_ttt.game.items.impl.weapons.guns.*
|
import de.moritzruth.spigot_ttt.game.items.impl.weapons.guns.*
|
||||||
import de.moritzruth.spigot_ttt.game.players.IState
|
|
||||||
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
||||||
import de.moritzruth.spigot_ttt.plugin
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayerDeathEvent
|
||||||
import de.moritzruth.spigot_ttt.utils.nextTick
|
import de.moritzruth.spigot_ttt.utils.isLeftClick
|
||||||
|
import de.moritzruth.spigot_ttt.utils.isRightClick
|
||||||
import de.moritzruth.spigot_ttt.utils.sendActionBarMessage
|
import de.moritzruth.spigot_ttt.utils.sendActionBarMessage
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.Location
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.bukkit.entity.Item
|
import org.bukkit.entity.Item
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
import org.bukkit.event.Listener
|
import org.bukkit.event.EventPriority
|
||||||
|
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||||
import org.bukkit.event.entity.EntityPickupItemEvent
|
import org.bukkit.event.entity.EntityPickupItemEvent
|
||||||
import org.bukkit.event.entity.ItemDespawnEvent
|
import org.bukkit.event.entity.ItemDespawnEvent
|
||||||
import org.bukkit.event.player.PlayerDropItemEvent
|
import org.bukkit.event.player.PlayerDropItemEvent
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent
|
||||||
import org.bukkit.event.player.PlayerItemHeldEvent
|
import org.bukkit.event.player.PlayerItemHeldEvent
|
||||||
|
import org.bukkit.event.player.PlayerSwapHandItemsEvent
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
|
|
||||||
object ItemManager {
|
object ItemManager {
|
||||||
val ITEMS: Set<TTTItem> = setOf(
|
val ITEMS: Set<TTTItem<*>> = setOf(
|
||||||
Pistol,
|
Deagle, Glock, Pistol, Rifle, SidekickDeagle, BaseballBat, Knife, CloakingDevice, Defibrillator,
|
||||||
Knife, Glock, Deagle, Shotgun, SidekickDeagle,
|
EnderPearl, FakeCorpse, Fireball, HealingPotion, MartyrdomGrenade, Radar, SecondChance, Teleporter,
|
||||||
BaseballBat,
|
Shotgun, Radar, SecondChance
|
||||||
CloakingDevice, Rifle,
|
|
||||||
EnderPearl, Radar, HealingPotion, Fireball,
|
|
||||||
Teleporter, MartyrdomGrenade, FakeCorpse, Defibrillator, SecondChance
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val droppedItemStates = mutableMapOf<Int, IState>()
|
|
||||||
|
|
||||||
val listeners get () = ITEMS.mapNotNull { it.listener }.plus(listener)
|
val listeners get () = ITEMS.mapNotNull { it.listener }.plus(listener)
|
||||||
val packetListeners get () = ITEMS.mapNotNull { it.packetListener }
|
val packetListeners get () = ITEMS.mapNotNull { it.packetListener }
|
||||||
|
|
||||||
private fun getItemByMaterial(material: Material) = ITEMS.find { tttItem -> material === tttItem.itemStack.type }
|
private fun getTTTItemByMaterial(material: Material) = ITEMS.find { tttItem -> material == tttItem.material }
|
||||||
fun getItemByItemStack(itemStack: ItemStack) = getItemByMaterial(itemStack.type)
|
fun getTTTItemByItemStack(itemStack: ItemStack) = getTTTItemByMaterial(itemStack.type)
|
||||||
|
fun getInstanceByItemStack(itemStack: ItemStack) = getTTTItemByItemStack(itemStack)?.getInstance(itemStack)
|
||||||
|
|
||||||
fun reset() {
|
fun dropItem(location: Location, tttItem: TTTItem<*>) {
|
||||||
droppedItemStates.clear()
|
val instance = tttItem.createInstance()
|
||||||
GameManager.world.getEntitiesByClass(Item::class.java).forEach {
|
GameManager.world.dropItem(location, instance.createItemStack())
|
||||||
it.remove()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val listener = object : Listener {
|
fun reset() {
|
||||||
@EventHandler
|
GameManager.world.getEntitiesByClass(Item::class.java).forEach(Item::remove)
|
||||||
fun onPlayerItemHeld(event: PlayerItemHeldEvent) {
|
ITEMS.forEach(TTTItem<*>::reset)
|
||||||
val tttPlayer = TTTPlayer.of(event.player) ?: return
|
}
|
||||||
val itemStack = event.player.inventory.getItem(event.newSlot)
|
|
||||||
|
|
||||||
tttPlayer.itemInHand =
|
val listener = object : GameListener() {
|
||||||
if (itemStack == null || itemStack.type === Material.AIR) null
|
@EventHandler
|
||||||
else getItemByItemStack(itemStack)
|
fun onPlayerInteract(event: PlayerInteractEvent) = handle(event) {
|
||||||
|
val instance = event.item?.let { getInstanceByItemStack(it) } ?: return@handle
|
||||||
|
|
||||||
|
val clickEvent = ClickEvent()
|
||||||
|
if (event.action.isLeftClick) instance.onLeftClick(clickEvent)
|
||||||
|
else if (event.action.isRightClick) instance.onRightClick(clickEvent)
|
||||||
|
event.isCancelled = clickEvent.isCancelled
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler(ignoreCancelled = true)
|
||||||
fun onPlayerDropItem(event: PlayerDropItemEvent) {
|
fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
|
||||||
val tttPlayer = TTTPlayer.of(event.player) ?: return
|
val damager = event.damager
|
||||||
val tttItem = getItemByItemStack(event.itemDrop.itemStack) ?: return
|
if (damager is Player) {
|
||||||
|
TTTPlayer.of(damager) ?: return
|
||||||
if (tttItem.type != TTTItem.Type.SPECIAL) {
|
val item = damager.inventory.itemInMainHand
|
||||||
if (tttItem is DropHandler) {
|
if (item.type != Material.AIR) {
|
||||||
if (!tttItem.onDrop(tttPlayer, event.itemDrop)) {
|
val tttItem = getTTTItemByItemStack(item) ?: return
|
||||||
event.isCancelled = true
|
event.isCancelled = tttItem.disableDamage
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin.server.scheduler.runTask(plugin, fun() {
|
|
||||||
tttPlayer.updateItemInHand()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
event.player.sendActionBarMessage("${ChatColor.RED}Du kannst dieses Item nicht droppen")
|
|
||||||
event.isCancelled = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onItemDespawn(event: ItemDespawnEvent) {
|
fun onPlayerSwapHandItems(event: PlayerSwapHandItemsEvent) = handle(event) { _ ->
|
||||||
if (getItemByItemStack(event.entity.itemStack) != null) {
|
val instance = event.offHandItem?.let { getInstanceByItemStack(it) } ?: return@handle
|
||||||
event.entity.ticksLived = 1
|
instance.onHandSwap()
|
||||||
|
event.isCancelled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onPlayerItemHeld(event: PlayerItemHeldEvent) = handle(event) { tttPlayer ->
|
||||||
|
tttPlayer.player.inventory.getItem(event.previousSlot)
|
||||||
|
?.also { itemStack -> getInstanceByItemStack(itemStack)?.isSelected = false }
|
||||||
|
|
||||||
|
tttPlayer.player.inventory.getItem(event.newSlot)
|
||||||
|
?.also { itemStack -> getInstanceByItemStack(itemStack)?.isSelected = true }
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onPlayerDropItem(event: PlayerDropItemEvent) = handle(event) { tttPlayer ->
|
||||||
|
val instance = getInstanceByItemStack(event.itemDrop.itemStack) ?: return@handle
|
||||||
|
|
||||||
|
val notDroppableReason = instance.notDroppableReason
|
||||||
|
if (notDroppableReason == null) {
|
||||||
|
instance.carrier = null
|
||||||
|
} else {
|
||||||
|
tttPlayer.player.sendActionBarMessage(notDroppableReason)
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onEntityPickupItem(event: EntityPickupItemEvent) {
|
fun onEntityPickupItem(event: EntityPickupItemEvent) {
|
||||||
if (event.entity !is Player) {
|
val player = event.entity
|
||||||
return
|
if (player !is Player) return
|
||||||
}
|
|
||||||
|
|
||||||
val player = event.entity as Player
|
|
||||||
val tttPlayer = TTTPlayer.of(player) ?: return
|
val tttPlayer = TTTPlayer.of(player) ?: return
|
||||||
|
val instance = getInstanceByItemStack(event.item.itemStack)
|
||||||
|
|
||||||
val tttItem = getItemByItemStack(event.item.itemStack)
|
if (instance != null) {
|
||||||
|
if (runCatching { tttPlayer.checkAddItemPreconditions(instance.tttItem) }.isSuccess) {
|
||||||
if (tttItem != null) {
|
instance.carrier = tttPlayer
|
||||||
if (runCatching { tttPlayer.checkAddItemPreconditions(tttItem) }.isSuccess) {
|
|
||||||
nextTick { tttPlayer.updateItemInHand() }
|
|
||||||
|
|
||||||
if (tttItem is DropHandler) {
|
|
||||||
tttItem.onPickup(tttPlayer, event.item)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onItemDespawn(event: ItemDespawnEvent) {
|
||||||
|
if (getTTTItemByItemStack(event.entity.itemStack) != null) {
|
||||||
|
event.entity.ticksLived = 1
|
||||||
|
event.isCancelled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||||
|
fun onTTTPlayerDeath(event: TTTPlayerDeathEvent) {
|
||||||
|
val itemStackInHand = event.tttPlayer.player.inventory.itemInMainHand
|
||||||
|
if (itemStackInHand.type != Material.AIR) {
|
||||||
|
val instance = getInstanceByItemStack(itemStackInHand)
|
||||||
|
if (instance != null && instance.notDroppableReason == null)
|
||||||
|
GameManager.world.dropItem(event.location, instance.createItemStack())
|
||||||
|
|
||||||
|
event.tttPlayer.getOwningTTTItemInstances().forEach {
|
||||||
|
event.tttPlayer.removeItem(it.tttItem, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,15 @@ package de.moritzruth.spigot_ttt.game.items
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.game.GameManager
|
import de.moritzruth.spigot_ttt.game.GameManager
|
||||||
import de.moritzruth.spigot_ttt.utils.ConfigurationFile
|
import de.moritzruth.spigot_ttt.utils.ConfigurationFile
|
||||||
|
import de.moritzruth.spigot_ttt.utils.Probability
|
||||||
import de.moritzruth.spigot_ttt.utils.roundToCenter
|
import de.moritzruth.spigot_ttt.utils.roundToCenter
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
object ItemSpawner {
|
object ItemSpawner {
|
||||||
private const val CONFIG_PATH = "spawn-locations"
|
private const val CONFIG_PATH = "spawn-locations"
|
||||||
|
|
||||||
private val spawnLocationsConfig = ConfigurationFile("spawnLocations")
|
private val spawnLocationsConfig = ConfigurationFile("spawnLocations")
|
||||||
private val spawningItems = ItemManager.ITEMS.filter { it is Spawning }
|
|
||||||
|
|
||||||
private fun getSpawnLocations(): Set<Location> {
|
private fun getSpawnLocations(): Set<Location> {
|
||||||
return spawnLocationsConfig.getStringList(CONFIG_PATH).map {
|
return spawnLocationsConfig.getStringList(CONFIG_PATH).map {
|
||||||
|
@ -25,14 +26,19 @@ object ItemSpawner {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun spawnWeapons() {
|
fun spawnWeapons() {
|
||||||
var itemIterator = spawningItems.shuffled().iterator()
|
val spawningItems = mutableListOf<TTTItem<*>>()
|
||||||
|
loop@ for (tttItem in ItemManager.ITEMS) {
|
||||||
|
val count = Probability.values().indexOf(tttItem.spawnProbability) + 1
|
||||||
|
spawningItems.addAll(Collections.nCopies(count, tttItem))
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemsIterator = spawningItems.shuffled().iterator()
|
||||||
for (location in getSpawnLocations()) {
|
for (location in getSpawnLocations()) {
|
||||||
if (!itemIterator.hasNext()) {
|
if (!itemsIterator.hasNext()) {
|
||||||
itemIterator = spawningItems.shuffled().iterator()
|
itemsIterator = spawningItems.shuffled().iterator()
|
||||||
}
|
}
|
||||||
|
|
||||||
GameManager.world.dropItem(location, itemIterator.next().itemStack.clone())
|
ItemManager.dropItem(location, itemsIterator.next())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,46 +3,142 @@ package de.moritzruth.spigot_ttt.game.items
|
||||||
import com.comphenix.protocol.events.PacketListener
|
import com.comphenix.protocol.events.PacketListener
|
||||||
import de.moritzruth.spigot_ttt.game.players.Role
|
import de.moritzruth.spigot_ttt.game.players.Role
|
||||||
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
||||||
|
import de.moritzruth.spigot_ttt.plugin
|
||||||
|
import de.moritzruth.spigot_ttt.utils.Probability
|
||||||
|
import de.moritzruth.spigot_ttt.utils.applyMeta
|
||||||
|
import de.moritzruth.spigot_ttt.utils.nextTick
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.entity.Item
|
import org.bukkit.NamespacedKey
|
||||||
import org.bukkit.event.Listener
|
import org.bukkit.event.Listener
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import org.bukkit.persistence.PersistentDataType
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
import kotlin.reflect.full.primaryConstructor
|
||||||
|
|
||||||
interface Selectable {
|
open class TTTItem<InstanceT: TTTItem.Instance>(
|
||||||
fun onSelect(tttPlayer: TTTPlayer)
|
val type: Type,
|
||||||
fun onDeselect(tttPlayer: TTTPlayer)
|
val templateItemStack: ItemStack,
|
||||||
}
|
val instanceType: KClass<out InstanceT>,
|
||||||
|
val shopInfo: ShopInfo? = null,
|
||||||
|
val spawnProbability: Probability? = null,
|
||||||
|
val disableDamage: Boolean = true
|
||||||
|
) {
|
||||||
|
open val listener: Listener? = null
|
||||||
|
open val packetListener: PacketListener? = null
|
||||||
|
|
||||||
interface DropHandler {
|
val material = templateItemStack.type
|
||||||
fun onDrop(tttPlayer: TTTPlayer, itemEntity: Item): Boolean
|
|
||||||
fun onPickup(tttPlayer: TTTPlayer, itemEntity: Item)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Buyable {
|
val instancesByUUID = mutableMapOf<UUID, InstanceT>()
|
||||||
val buyableBy: EnumSet<Role>
|
fun getInstance(itemStack: ItemStack) =
|
||||||
val price: Int
|
itemStack.itemMeta?.persistentDataContainer?.get(ID_KEY, PersistentDataType.STRING)
|
||||||
val buyLimit: Int?
|
?.let { instancesByUUID[UUID.fromString(it)] }
|
||||||
}
|
|
||||||
|
|
||||||
val PASSIVE = "${ChatColor.RESET}${ChatColor.RED}(Passiv)"
|
fun getInstance(tttPlayer: TTTPlayer) = instancesByUUID.values.find { it.carrier === tttPlayer }
|
||||||
|
|
||||||
// Marker
|
fun reset() {
|
||||||
interface Spawning
|
instancesByUUID.values.forEach {
|
||||||
|
it.carrier?.removeItem(it.tttItem, removeInstance = false)
|
||||||
|
it.reset()
|
||||||
|
}
|
||||||
|
instancesByUUID.clear()
|
||||||
|
}
|
||||||
|
|
||||||
interface TTTItem {
|
fun createInstance(): InstanceT = instanceType.primaryConstructor!!.call()
|
||||||
val listener: Listener? get() = null
|
.also { instancesByUUID[it.uuid] = it }
|
||||||
val packetListener: PacketListener? get() = null
|
|
||||||
val itemStack: ItemStack
|
|
||||||
val type: Type
|
|
||||||
|
|
||||||
fun onOwn(tttPlayer: TTTPlayer) {}
|
|
||||||
fun onRemove(tttPlayer: TTTPlayer) {}
|
|
||||||
|
|
||||||
enum class Type(val maxItemsOfTypeInInventory: Int?) {
|
enum class Type(val maxItemsOfTypeInInventory: Int?) {
|
||||||
MELEE(1),
|
MELEE(1),
|
||||||
PISTOL_LIKE(1),
|
PISTOL_LIKE(2),
|
||||||
HEAVY_WEAPON(1),
|
HEAVY_WEAPON(1),
|
||||||
SPECIAL(null);
|
SPECIAL(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class ShopInfo(
|
||||||
|
val buyableBy: EnumSet<Role>,
|
||||||
|
val price: Int,
|
||||||
|
val buyLimit: Int = 0
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
if (buyLimit < 0) throw IllegalArgumentException("buyLimit must be positive")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val PASSIVE_SUFFIX = " ${ChatColor.RESET}${ChatColor.RED}(Passiv)"
|
||||||
|
val ID_KEY = NamespacedKey(plugin, "instance")
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Instance(val tttItem: TTTItem<*>, droppable: Boolean = true) {
|
||||||
|
val uuid = UUID.randomUUID()!!
|
||||||
|
|
||||||
|
fun createItemStack() = tttItem.templateItemStack.clone().applyMeta {
|
||||||
|
persistentDataContainer.set(ID_KEY, PersistentDataType.STRING, uuid.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isFirstCarrier = true
|
||||||
|
open var carrier: TTTPlayer? = null
|
||||||
|
set(newCarrier) {
|
||||||
|
if (newCarrier == field) return // Do nothing it does not get changed
|
||||||
|
|
||||||
|
if (newCarrier == null) {
|
||||||
|
val oldCarrier = field!!
|
||||||
|
isSelected = false
|
||||||
|
field = newCarrier
|
||||||
|
onCarrierRemoved(oldCarrier)
|
||||||
|
} else {
|
||||||
|
field = newCarrier
|
||||||
|
onCarrierSet(newCarrier, isFirstCarrier)
|
||||||
|
isFirstCarrier = false
|
||||||
|
nextTick {
|
||||||
|
if (newCarrier.player.inventory.itemInMainHand.type == tttItem.material) isSelected = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is called after onDeselect
|
||||||
|
*/
|
||||||
|
protected open fun onCarrierRemoved(oldCarrier: TTTPlayer) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is called before isSelected is set to true in the next tick (only if the item is in the main hand)
|
||||||
|
*/
|
||||||
|
protected open fun onCarrierSet(carrier: TTTPlayer, isFirst: Boolean) {}
|
||||||
|
|
||||||
|
protected fun requireCarrier() =
|
||||||
|
carrier ?: run {
|
||||||
|
throw IllegalStateException("The item must be carried to perform this action")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reason why the item can not be dropped or null if it can be dropped.
|
||||||
|
* Should be overridden with a dynamic getter.
|
||||||
|
*/
|
||||||
|
open val notDroppableReason: String? =
|
||||||
|
if (droppable) null
|
||||||
|
else "${ChatColor.RED}Du kannst dieses Item nicht droppen"
|
||||||
|
|
||||||
|
open fun onRightClick(event: ClickEvent) { event.isCancelled = false }
|
||||||
|
open fun onLeftClick(event: ClickEvent) { event.isCancelled = false }
|
||||||
|
open fun onHandSwap() {}
|
||||||
|
|
||||||
|
open fun reset() {}
|
||||||
|
|
||||||
|
var isSelected = false
|
||||||
|
set(value) {
|
||||||
|
if (value == isSelected) return
|
||||||
|
field = value
|
||||||
|
|
||||||
|
if (value) onSelect()
|
||||||
|
else onDeselect()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun onSelect() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this is called because the carrier is set to null, it is called before the field is changed
|
||||||
|
*/
|
||||||
|
protected open fun onDeselect() {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,66 +1,16 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items
|
package de.moritzruth.spigot_ttt.game.items
|
||||||
|
|
||||||
|
import de.moritzruth.spigot_ttt.game.GameListener
|
||||||
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
||||||
import de.moritzruth.spigot_ttt.game.players.TTTPlayerDeathEvent
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayerReviveEvent
|
||||||
import de.moritzruth.spigot_ttt.utils.isLeftClick
|
|
||||||
import de.moritzruth.spigot_ttt.utils.isRightClick
|
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.event.EventHandler
|
|
||||||
import org.bukkit.event.Listener
|
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent
|
import org.bukkit.event.inventory.InventoryClickEvent
|
||||||
import org.bukkit.event.inventory.InventoryCloseEvent
|
import org.bukkit.event.inventory.InventoryCloseEvent
|
||||||
import org.bukkit.event.player.PlayerEvent
|
import org.bukkit.event.player.PlayerEvent
|
||||||
import org.bukkit.event.player.PlayerInteractEvent
|
|
||||||
import org.bukkit.event.player.PlayerItemConsumeEvent
|
import org.bukkit.event.player.PlayerItemConsumeEvent
|
||||||
import org.bukkit.event.player.PlayerSwapHandItemsEvent
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
|
|
||||||
open class TTTItemListener(
|
|
||||||
private val tttItem: TTTItem,
|
|
||||||
private val cancelDamage: Boolean,
|
|
||||||
private val removeOnDeath: Boolean = true
|
|
||||||
): Listener {
|
|
||||||
@EventHandler
|
|
||||||
open fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) = handle(event) { _, _ ->
|
|
||||||
if (cancelDamage) event.isCancelled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
open fun onTTTPlayerDeath(event: TTTPlayerDeathEvent) {
|
|
||||||
if (removeOnDeath) event.tttPlayer.removeItem(tttItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onPlayerInteract(event: PlayerInteractEvent) = handle(event) { tttPlayer ->
|
|
||||||
event.isCancelled = true
|
|
||||||
val data = ClickEventData(tttPlayer, event.item!!, event)
|
|
||||||
if (event.action.isRightClick) onRightClick(data)
|
|
||||||
else if (event.action.isLeftClick) onLeftClick(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun onRightClick(data: ClickEventData) {
|
|
||||||
data.event.isCancelled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun onLeftClick(data: ClickEventData) {
|
|
||||||
data.event.isCancelled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun handle(event: PlayerInteractEvent, handler: (tttPlayer: TTTPlayer) -> Unit) {
|
|
||||||
if (event.item?.type == tttItem.itemStack.type) {
|
|
||||||
val tttPlayer = TTTPlayer.of(event.player) ?: return
|
|
||||||
handler(tttPlayer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun handle(event: PlayerSwapHandItemsEvent, handler: (tttPlayer: TTTPlayer) -> Unit) {
|
|
||||||
if (event.offHandItem?.type == tttItem.itemStack.type) {
|
|
||||||
val tttPlayer = TTTPlayer.of(event.player) ?: return
|
|
||||||
handler(tttPlayer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
open class TTTItemListener<InstanceT: TTTItem.Instance>(private val tttItem: TTTItem<InstanceT>): GameListener() {
|
||||||
protected fun handle(
|
protected fun handle(
|
||||||
event: EntityDamageByEntityEvent,
|
event: EntityDamageByEntityEvent,
|
||||||
handler: (damagerTTTPlayer: TTTPlayer, damagedTTTPlayer: TTTPlayer) -> Unit
|
handler: (damagerTTTPlayer: TTTPlayer, damagedTTTPlayer: TTTPlayer) -> Unit
|
||||||
|
@ -71,7 +21,7 @@ open class TTTItemListener(
|
||||||
if (
|
if (
|
||||||
damager is Player &&
|
damager is Player &&
|
||||||
damaged is Player &&
|
damaged is Player &&
|
||||||
damager.inventory.itemInMainHand.type == tttItem.itemStack.type
|
damager.inventory.itemInMainHand.type == tttItem.material
|
||||||
) {
|
) {
|
||||||
val damagerTTTPlayer = TTTPlayer.of(damager) ?: return
|
val damagerTTTPlayer = TTTPlayer.of(damager) ?: return
|
||||||
val damagedTTTPlayer = TTTPlayer.of(damaged) ?: return
|
val damagedTTTPlayer = TTTPlayer.of(damaged) ?: return
|
||||||
|
@ -79,33 +29,38 @@ open class TTTItemListener(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun handle(event: InventoryClickEvent, handler: (tttPlayer: TTTPlayer) -> Unit) {
|
|
||||||
val whoClicked = event.whoClicked
|
|
||||||
if (whoClicked is Player) {
|
|
||||||
handler(TTTPlayer.of(whoClicked) ?: return)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun handle(event: InventoryCloseEvent, handler: (tttPlayer: TTTPlayer) -> Unit) {
|
|
||||||
val player = event.player
|
|
||||||
if (player is Player) {
|
|
||||||
handler(TTTPlayer.of(player) ?: return)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun <T: PlayerEvent> handle(event: T, handler: (tttPlayer: TTTPlayer) -> Unit) {
|
|
||||||
handler(TTTPlayer.of(event.player) ?: return)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun handle(event: PlayerItemConsumeEvent, handler: (tttPlayer: TTTPlayer) -> Unit) {
|
protected fun handle(event: PlayerItemConsumeEvent, handler: (tttPlayer: TTTPlayer) -> Unit) {
|
||||||
if (event.item.type == tttItem.itemStack.type) {
|
if (event.item.type == tttItem.material) {
|
||||||
handler(TTTPlayer.of(event.player) ?: return)
|
handler(TTTPlayer.of(event.player) ?: return)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ClickEventData(
|
protected fun handleWithInstance(event: InventoryCloseEvent, handler: (instance: InstanceT) -> Unit) {
|
||||||
val tttPlayer: TTTPlayer,
|
val player = event.player
|
||||||
val itemStack: ItemStack,
|
if (player is Player) {
|
||||||
val event: PlayerInteractEvent
|
val tttPlayer = TTTPlayer.of(player) ?: return
|
||||||
)
|
val instance = tttItem.getInstance(tttPlayer) ?: return
|
||||||
|
handler(instance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun handleWithInstance(event: InventoryClickEvent, handler: (instance: InstanceT) -> Unit) {
|
||||||
|
val whoClicked = event.whoClicked
|
||||||
|
if (whoClicked is Player) {
|
||||||
|
val tttPlayer = TTTPlayer.of(whoClicked) ?: return
|
||||||
|
val instance = tttItem.getInstance(tttPlayer) ?: return
|
||||||
|
handler(instance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun handleWithInstance(event: PlayerEvent, handler: (instance: InstanceT) -> Unit) {
|
||||||
|
val player = event.player
|
||||||
|
val tttPlayer = TTTPlayer.of(player) ?: return
|
||||||
|
val instance = tttItem.getInstance(tttPlayer) ?: return
|
||||||
|
handler(instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun handle(event: TTTPlayerReviveEvent, handler: (instance: InstanceT) -> Unit) {
|
||||||
|
handler(tttItem.getInstance(event.tttPlayer) ?: return)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.impl
|
package de.moritzruth.spigot_ttt.game.items.impl
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.GameEndEvent
|
import de.moritzruth.spigot_ttt.game.items.ClickEvent
|
||||||
import de.moritzruth.spigot_ttt.game.items.Buyable
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.Selectable
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
||||||
import de.moritzruth.spigot_ttt.game.players.*
|
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.utils.applyMeta
|
import de.moritzruth.spigot_ttt.utils.applyMeta
|
||||||
import de.moritzruth.spigot_ttt.utils.startItemDamageProgress
|
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.SoundCategory
|
import org.bukkit.SoundCategory
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
|
@ -19,90 +18,67 @@ import org.bukkit.potion.PotionEffect
|
||||||
import org.bukkit.potion.PotionEffectType
|
import org.bukkit.potion.PotionEffectType
|
||||||
import org.bukkit.scheduler.BukkitTask
|
import org.bukkit.scheduler.BukkitTask
|
||||||
|
|
||||||
object CloakingDevice: TTTItem, Buyable, Selectable {
|
object CloakingDevice: TTTItem<CloakingDevice.Instance>(
|
||||||
override val itemStack = ItemStack(Resourcepack.Items.cloakingDevice).applyMeta {
|
type = Type.SPECIAL,
|
||||||
|
instanceType = Instance::class,
|
||||||
|
templateItemStack = ItemStack(Resourcepack.Items.cloakingDevice).applyMeta {
|
||||||
setDisplayName("${ChatColor.GRAY}${ChatColor.MAGIC}###${ChatColor.RESET}${ChatColor.GRAY} Cloaking Device ${ChatColor.MAGIC}###")
|
setDisplayName("${ChatColor.GRAY}${ChatColor.MAGIC}###${ChatColor.RESET}${ChatColor.GRAY} Cloaking Device ${ChatColor.MAGIC}###")
|
||||||
lore = listOf(
|
lore = listOf(
|
||||||
"",
|
"",
|
||||||
"${ChatColor.GOLD}Macht dich unsichtbar"
|
"${ChatColor.GOLD}Macht dich unsichtbar"
|
||||||
)
|
)
|
||||||
addItemFlags(ItemFlag.HIDE_ATTRIBUTES)
|
addItemFlags(ItemFlag.HIDE_ATTRIBUTES)
|
||||||
}
|
},
|
||||||
|
shopInfo = ShopInfo(
|
||||||
|
buyableBy = roles(Role.TRAITOR, Role.JACKAL),
|
||||||
|
buyLimit = 1,
|
||||||
|
price = 2
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
private const val WALK_SPEED_DECREASE = 0.1F
|
||||||
private const val COOLDOWN = 10.0
|
private const val COOLDOWN = 10.0
|
||||||
|
|
||||||
override val type = TTTItem.Type.SPECIAL
|
class Instance: TTTItem.Instance(CloakingDevice) {
|
||||||
override val price = 2
|
var enabled = false
|
||||||
override val buyableBy = roles(Role.TRAITOR, Role.JACKAL)
|
private var cooldownTask: BukkitTask? = null
|
||||||
override val buyLimit = 1
|
|
||||||
|
|
||||||
val isc = InversedStateContainer(State::class)
|
override fun onRightClick(event: ClickEvent) {
|
||||||
|
if (cooldownTask == null) setEnabled(carrier!!, !enabled)
|
||||||
override fun onSelect(tttPlayer: TTTPlayer) {}
|
|
||||||
override fun onDeselect(tttPlayer: TTTPlayer) = disable(tttPlayer)
|
|
||||||
|
|
||||||
private fun enable(tttPlayer: TTTPlayer, itemStack: ItemStack) {
|
|
||||||
val state = isc.getOrCreate(tttPlayer)
|
|
||||||
|
|
||||||
tttPlayer.player.apply {
|
|
||||||
isSprinting = false
|
|
||||||
walkSpeed = 0.1F
|
|
||||||
|
|
||||||
addPotionEffect(PotionEffect(PotionEffectType.INVISIBILITY, 1000000, 0, false, false))
|
|
||||||
playSound(location, Resourcepack.Sounds.Item.CloakingDevice.on, SoundCategory.PLAYERS, 1F, 1F)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.enabled = true
|
override fun onCarrierRemoved(oldCarrier: TTTPlayer) {
|
||||||
state.itemStack = itemStack
|
setEnabled(oldCarrier, false)
|
||||||
}
|
|
||||||
|
|
||||||
private fun disable(tttPlayer: TTTPlayer) {
|
|
||||||
val state = isc.get(tttPlayer) ?: return
|
|
||||||
if (!state.enabled) return
|
|
||||||
|
|
||||||
tttPlayer.player.apply {
|
|
||||||
walkSpeed = 0.2F
|
|
||||||
removePotionEffect(PotionEffectType.INVISIBILITY)
|
|
||||||
playSound(location, Resourcepack.Sounds.Item.CloakingDevice.off, SoundCategory.PLAYERS, 1F, 1F)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.enabled = false
|
private fun setEnabled(tttPlayer: TTTPlayer, value: Boolean) {
|
||||||
|
if (value == enabled) return
|
||||||
|
|
||||||
val itemStack = state.itemStack
|
if (value) {
|
||||||
if (itemStack != null) {
|
tttPlayer.walkSpeed -= WALK_SPEED_DECREASE
|
||||||
state.cooldownTask = startItemDamageProgress(itemStack, COOLDOWN) { state.cooldownTask = null }
|
tttPlayer.player.apply {
|
||||||
}
|
isSprinting = false
|
||||||
}
|
|
||||||
|
|
||||||
override val listener = object : TTTItemListener(this, true) {
|
addPotionEffect(PotionEffect(PotionEffectType.INVISIBILITY, 1000000, 0, false, false))
|
||||||
@EventHandler
|
playSound(location, Resourcepack.Sounds.Item.CloakingDevice.on, SoundCategory.PLAYERS, 1F, 1F)
|
||||||
fun onPlayerToggleSprint(event: PlayerToggleSprintEvent) = handle(event) { tttPlayer ->
|
}
|
||||||
if (event.isSprinting && isc.getOrCreate(tttPlayer).enabled) event.isCancelled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
override fun onTTTPlayerDeath(event: TTTPlayerDeathEvent) {
|
|
||||||
super.onTTTPlayerDeath(event)
|
|
||||||
isc.get(event.tttPlayer)?.cooldownTask?.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onGameEnd(event: GameEndEvent) = isc.forEveryState { state, _ -> state.cooldownTask?.cancel() }
|
|
||||||
|
|
||||||
override fun onRightClick(data: ClickEventData) {
|
|
||||||
val state = isc.getOrCreate(data.tttPlayer)
|
|
||||||
if (state.cooldownTask != null) return
|
|
||||||
|
|
||||||
if (state.enabled) {
|
|
||||||
disable(data.tttPlayer)
|
|
||||||
} else {
|
} else {
|
||||||
enable(data.tttPlayer, data.itemStack)
|
tttPlayer.walkSpeed += WALK_SPEED_DECREASE
|
||||||
|
tttPlayer.player.apply {
|
||||||
|
removePotionEffect(PotionEffectType.INVISIBILITY)
|
||||||
|
playSound(location, Resourcepack.Sounds.Item.CloakingDevice.off, SoundCategory.PLAYERS, 1F, 1F)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Show progress in level bar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enabled = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class State: IState {
|
override val listener = object : TTTItemListener<Instance>(CloakingDevice) {
|
||||||
var enabled: Boolean = false
|
@EventHandler
|
||||||
var cooldownTask: BukkitTask? = null
|
fun onPlayerToggleSprint(event: PlayerToggleSprintEvent) = handleWithInstance(event) { instance ->
|
||||||
var itemStack: ItemStack? = null
|
if (event.isSprinting && instance.enabled) event.isCancelled = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.impl
|
package de.moritzruth.spigot_ttt.game.items.impl
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.GameEndEvent
|
|
||||||
import de.moritzruth.spigot_ttt.game.GameManager
|
import de.moritzruth.spigot_ttt.game.GameManager
|
||||||
import de.moritzruth.spigot_ttt.game.corpses.CorpseClickEvent
|
import de.moritzruth.spigot_ttt.game.corpses.CorpseClickEvent
|
||||||
import de.moritzruth.spigot_ttt.game.items.Buyable
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
||||||
import de.moritzruth.spigot_ttt.game.players.*
|
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.plugin
|
import de.moritzruth.spigot_ttt.plugin
|
||||||
import de.moritzruth.spigot_ttt.utils.*
|
import de.moritzruth.spigot_ttt.utils.*
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
|
@ -20,49 +20,67 @@ import org.bukkit.scheduler.BukkitTask
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
object Defibrillator: TTTItem, Buyable {
|
object Defibrillator: TTTItem<Defibrillator.Instance>(
|
||||||
private const val REVIVE_DURATION = 10.0
|
type = Type.SPECIAL,
|
||||||
|
instanceType = Instance::class,
|
||||||
override val type = TTTItem.Type.SPECIAL
|
templateItemStack = ItemStack(Resourcepack.Items.defibrillator).applyMeta {
|
||||||
override val itemStack = ItemStack(Resourcepack.Items.defibrillator).applyMeta {
|
|
||||||
setDisplayName("${ChatColor.RESET}${ChatColor.BOLD}Defibrillator")
|
setDisplayName("${ChatColor.RESET}${ChatColor.BOLD}Defibrillator")
|
||||||
hideInfo()
|
hideInfo()
|
||||||
lore = listOf(
|
lore = listOf(
|
||||||
"",
|
"",
|
||||||
"${ChatColor.GOLD}Belebe einen Spieler wieder"
|
"${ChatColor.GOLD}Belebe einen Spieler wieder"
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
override val buyableBy = roles(Role.TRAITOR, Role.DETECTIVE, Role.JACKAL)
|
shopInfo = ShopInfo(
|
||||||
override val price = 2
|
buyLimit = 1,
|
||||||
override val buyLimit = 1
|
price = 2,
|
||||||
|
buyableBy = roles(Role.TRAITOR, Role.DETECTIVE, Role.JACKAL)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
private const val REVIVE_DURATION = 10.0
|
||||||
|
|
||||||
private val isc = InversedStateContainer(State::class)
|
class Instance: TTTItem.Instance(Defibrillator) {
|
||||||
|
var action: Action? = null
|
||||||
|
var bossBar = plugin.server.createBossBar(
|
||||||
|
"${ChatColor.BOLD}Defibrillator",
|
||||||
|
BarColor.GREEN,
|
||||||
|
BarStyle.SOLID
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun onCarrierSet(carrier: TTTPlayer, isFirst: Boolean) {
|
||||||
|
bossBar.addPlayer(carrier.player)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCarrierRemoved(oldCarrier: TTTPlayer) {
|
||||||
|
bossBar.removePlayer(oldCarrier.player)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reset() {
|
||||||
|
action?.reset()
|
||||||
|
stopSound()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun stopSound() = plugin.server.onlinePlayers.forEach {
|
fun stopSound() = plugin.server.onlinePlayers.forEach {
|
||||||
it.stopSound(Resourcepack.Sounds.Item.Defibrillator.use, SoundCategory.PLAYERS)
|
it.stopSound(Resourcepack.Sounds.Item.Defibrillator.use, SoundCategory.PLAYERS)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val listener = object : TTTItemListener(this, true) {
|
override val listener = object : TTTItemListener<Instance>(this) {
|
||||||
@EventHandler(ignoreCancelled = true)
|
@EventHandler(ignoreCancelled = true)
|
||||||
fun onCorpseClick(event: CorpseClickEvent) {
|
fun onCorpseClick(event: CorpseClickEvent) {
|
||||||
if (event.tttPlayer.player.inventory.itemInMainHand.type != itemStack.type) return
|
val instance = getInstance(event.tttPlayer.player.inventory.itemInMainHand) ?: return
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
|
|
||||||
val state = isc.getOrCreate(event.tttPlayer)
|
when(val action = instance.action) {
|
||||||
state.bossBar.addPlayer(event.tttPlayer.player)
|
null -> instance.action = Action.Reviving(event.tttPlayer, instance)
|
||||||
|
|
||||||
when(val action = state.action) {
|
|
||||||
null -> state.action = Action.Reviving(event.tttPlayer, state)
|
|
||||||
is Action.Reviving -> {
|
is Action.Reviving -> {
|
||||||
action.cancelTask.cancel()
|
action.cancelTask.cancel()
|
||||||
action.cancelTask = action.createCancelTask()
|
action.cancelTask = action.createCancelTask()
|
||||||
|
|
||||||
val progress = action.duration / REVIVE_DURATION
|
val progress = action.duration / REVIVE_DURATION
|
||||||
|
|
||||||
if (progress >= 1) {
|
if (progress >= 1) {
|
||||||
try {
|
try {
|
||||||
event.tttCorpse.revive()
|
event.tttCorpse.revive()
|
||||||
|
|
||||||
event.tttPlayer.player.sendActionBarMessage(
|
event.tttPlayer.player.sendActionBarMessage(
|
||||||
"${ChatColor.BOLD}${event.tttCorpse.tttPlayer.player.displayName} " +
|
"${ChatColor.BOLD}${event.tttCorpse.tttPlayer.player.displayName} " +
|
||||||
"${ChatColor.GREEN}wurde wiederbelebt"
|
"${ChatColor.GREEN}wurde wiederbelebt"
|
||||||
|
@ -70,25 +88,20 @@ object Defibrillator: TTTItem, Buyable {
|
||||||
|
|
||||||
action.cancelTask.cancel()
|
action.cancelTask.cancel()
|
||||||
event.tttPlayer.player.inventory.removeTTTItemNextTick(Defibrillator)
|
event.tttPlayer.player.inventory.removeTTTItemNextTick(Defibrillator)
|
||||||
state.reset(event.tttPlayer)
|
|
||||||
isc.remove(event.tttPlayer)
|
|
||||||
} catch(e: TTTPlayer.AlreadyLivingException) {
|
} catch(e: TTTPlayer.AlreadyLivingException) {
|
||||||
action.cancel()
|
action.cancel()
|
||||||
}
|
}
|
||||||
} else state.bossBar.progress = progress
|
} else instance.bossBar.progress = progress
|
||||||
}
|
}
|
||||||
is Action.Canceled -> noop()
|
is Action.Canceled -> noop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onGameEnd(event: GameEndEvent) = isc.forEveryState { state, tttPlayer -> state.reset(tttPlayer) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class Action(val tttPlayer: TTTPlayer) {
|
sealed class Action(val tttPlayer: TTTPlayer) {
|
||||||
open fun reset() {}
|
open fun reset() {}
|
||||||
|
|
||||||
class Reviving(tttPlayer: TTTPlayer, val state: State): Action(tttPlayer) {
|
class Reviving(tttPlayer: TTTPlayer, val instance: Instance): Action(tttPlayer) {
|
||||||
var cancelTask = createCancelTask()
|
var cancelTask = createCancelTask()
|
||||||
private val startedAt: Instant = Instant.now()
|
private val startedAt: Instant = Instant.now()
|
||||||
val duration get() = Duration.between(startedAt, Instant.now()).toMillis().toDouble() / 1000
|
val duration get() = Duration.between(startedAt, Instant.now()).toMillis().toDouble() / 1000
|
||||||
|
@ -99,7 +112,7 @@ object Defibrillator: TTTItem, Buyable {
|
||||||
|
|
||||||
fun cancel() {
|
fun cancel() {
|
||||||
cancelTask.cancel()
|
cancelTask.cancel()
|
||||||
state.action = Canceled(tttPlayer)
|
instance.action = Canceled(tttPlayer, instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -111,14 +124,14 @@ object Defibrillator: TTTItem, Buyable {
|
||||||
1F
|
1F
|
||||||
)
|
)
|
||||||
|
|
||||||
state.bossBar.color = BarColor.GREEN
|
instance.bossBar.color = BarColor.GREEN
|
||||||
state.bossBar.addPlayer(tttPlayer.player)
|
instance.bossBar.isVisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun reset() = cancelTask.cancel()
|
override fun reset() = cancelTask.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
class Canceled(tttPlayer: TTTPlayer): Action(tttPlayer) {
|
class Canceled(tttPlayer: TTTPlayer, val instance: Instance): Action(tttPlayer) {
|
||||||
private var switches: Int = 0
|
private var switches: Int = 0
|
||||||
private lateinit var task: BukkitTask
|
private lateinit var task: BukkitTask
|
||||||
|
|
||||||
|
@ -132,16 +145,15 @@ object Defibrillator: TTTItem, Buyable {
|
||||||
1F
|
1F
|
||||||
)
|
)
|
||||||
|
|
||||||
task = plugin.server.scheduler.runTaskTimer(plugin, fun() {
|
plugin.server.scheduler.runTaskTimer(plugin, { task ->
|
||||||
val state = isc.get(tttPlayer) ?: return@runTaskTimer
|
|
||||||
|
|
||||||
if (switches == SWITCHES_COUNT) {
|
if (switches == SWITCHES_COUNT) {
|
||||||
|
this@Canceled.task = task
|
||||||
task.cancel()
|
task.cancel()
|
||||||
state.action = null
|
instance.action = null
|
||||||
state.bossBar.removePlayer(tttPlayer.player)
|
instance.bossBar.isVisible = false
|
||||||
} else {
|
} else {
|
||||||
state.bossBar.progress = 1.0
|
instance.bossBar.progress = 1.0
|
||||||
state.bossBar.color = if (switches % 2 == 0) BarColor.RED else BarColor.WHITE
|
instance.bossBar.color = if (switches % 2 == 0) BarColor.RED else BarColor.WHITE
|
||||||
switches += 1
|
switches += 1
|
||||||
}
|
}
|
||||||
}, 0, secondsToTicks(0.2).toLong())
|
}, 0, secondsToTicks(0.2).toLong())
|
||||||
|
@ -154,19 +166,4 @@ object Defibrillator: TTTItem, Buyable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class State: IState {
|
|
||||||
var action: Action? = null
|
|
||||||
var bossBar = plugin.server.createBossBar(
|
|
||||||
"${ChatColor.BOLD}Defibrillator",
|
|
||||||
BarColor.GREEN,
|
|
||||||
BarStyle.SOLID
|
|
||||||
)
|
|
||||||
|
|
||||||
fun reset(tttPlayer: TTTPlayer) {
|
|
||||||
bossBar.removePlayer(tttPlayer.player)
|
|
||||||
action?.reset()
|
|
||||||
stopSound()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,25 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.impl
|
package de.moritzruth.spigot_ttt.game.items.impl
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
import de.moritzruth.spigot_ttt.game.players.Role
|
import de.moritzruth.spigot_ttt.game.players.Role
|
||||||
import de.moritzruth.spigot_ttt.game.players.roles
|
import de.moritzruth.spigot_ttt.game.players.roles
|
||||||
import de.moritzruth.spigot_ttt.game.items.Buyable
|
import de.moritzruth.spigot_ttt.utils.Probability
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
|
||||||
import de.moritzruth.spigot_ttt.utils.applyMeta
|
import de.moritzruth.spigot_ttt.utils.applyMeta
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
|
|
||||||
object EnderPearl: TTTItem, Buyable {
|
object EnderPearl : TTTItem<EnderPearl.Instance>(
|
||||||
override val type = TTTItem.Type.SPECIAL
|
instanceType = Instance::class,
|
||||||
override val itemStack = ItemStack(Material.ENDER_PEARL).applyMeta {
|
type = Type.SPECIAL,
|
||||||
|
templateItemStack = ItemStack(Material.ENDER_PEARL).applyMeta {
|
||||||
setDisplayName("${ChatColor.DARK_GREEN}Enderperle")
|
setDisplayName("${ChatColor.DARK_GREEN}Enderperle")
|
||||||
}
|
},
|
||||||
override val buyableBy = roles(Role.TRAITOR, Role.JACKAL, Role.DETECTIVE)
|
spawnProbability = Probability.VERY_LOW,
|
||||||
override val price = 1
|
shopInfo = ShopInfo(
|
||||||
override val buyLimit: Int? = null
|
buyableBy = roles(Role.TRAITOR, Role.JACKAL, Role.DETECTIVE),
|
||||||
|
price = 1
|
||||||
override val listener = object : TTTItemListener(this, true) {
|
)
|
||||||
override fun onRightClick(data: ClickEventData) {
|
) {
|
||||||
data.event.isCancelled = false
|
class Instance: TTTItem.Instance(EnderPearl)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,13 @@ package de.moritzruth.spigot_ttt.game.items.impl
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.corpses.TTTCorpse
|
import de.moritzruth.spigot_ttt.game.corpses.TTTCorpse
|
||||||
import de.moritzruth.spigot_ttt.game.items.Buyable
|
import de.moritzruth.spigot_ttt.game.items.ClickEvent
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
||||||
import de.moritzruth.spigot_ttt.game.players.*
|
import de.moritzruth.spigot_ttt.game.players.PlayerManager
|
||||||
|
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.plugin
|
import de.moritzruth.spigot_ttt.plugin
|
||||||
import de.moritzruth.spigot_ttt.utils.applyMeta
|
import de.moritzruth.spigot_ttt.utils.applyMeta
|
||||||
import de.moritzruth.spigot_ttt.utils.hideInfo
|
import de.moritzruth.spigot_ttt.utils.hideInfo
|
||||||
|
@ -21,24 +24,34 @@ import org.bukkit.inventory.Inventory
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.inventory.meta.SkullMeta
|
import org.bukkit.inventory.meta.SkullMeta
|
||||||
|
|
||||||
object FakeCorpse: TTTItem, Buyable {
|
object FakeCorpse: TTTItem<FakeCorpse.Instance>(
|
||||||
private val DISPLAY_NAME = "${ChatColor.YELLOW}${ChatColor.BOLD}Fake-Leiche"
|
type = Type.SPECIAL,
|
||||||
|
instanceType = Instance::class,
|
||||||
override val itemStack = ItemStack(Resourcepack.Items.fakeCorpse).applyMeta {
|
shopInfo = ShopInfo(
|
||||||
setDisplayName(DISPLAY_NAME)
|
buyableBy = roles(Role.TRAITOR, Role.JACKAL),
|
||||||
|
buyLimit = 3,
|
||||||
|
price = 2
|
||||||
|
),
|
||||||
|
templateItemStack = ItemStack(Resourcepack.Items.fakeCorpse).applyMeta {
|
||||||
|
setDisplayName(FakeCorpse.DISPLAY_NAME)
|
||||||
lore = listOf(
|
lore = listOf(
|
||||||
"",
|
"",
|
||||||
"${ChatColor.GOLD}Spawnt eine Fake-Leiche",
|
"${ChatColor.GOLD}Spawnt eine Fake-Leiche",
|
||||||
"${ChatColor.GOLD}Rolle und Spieler auswählbar"
|
"${ChatColor.GOLD}Rolle und Spieler auswählbar"
|
||||||
)
|
)
|
||||||
hideInfo()
|
hideInfo()
|
||||||
}
|
}
|
||||||
override val type = TTTItem.Type.SPECIAL
|
) {
|
||||||
override val buyableBy = roles(Role.TRAITOR, Role.JACKAL)
|
private val DISPLAY_NAME = "${ChatColor.YELLOW}${ChatColor.BOLD}Fake-Leiche"
|
||||||
override val price = 2
|
|
||||||
override val buyLimit: Int? = 3
|
|
||||||
|
|
||||||
val isc = InversedStateContainer(State::class)
|
class Instance: TTTItem.Instance(FakeCorpse) {
|
||||||
|
var chosenRole: Role? = null
|
||||||
|
var choosePlayerInventory: Inventory? = null
|
||||||
|
|
||||||
|
override fun onRightClick(event: ClickEvent) {
|
||||||
|
carrier!!.player.openInventory(chooseRoleInventory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val chooseRoleInventory = plugin.server.createInventory(
|
private val chooseRoleInventory = plugin.server.createInventory(
|
||||||
null,
|
null,
|
||||||
|
@ -72,17 +85,17 @@ object FakeCorpse: TTTItem, Buyable {
|
||||||
.toTypedArray())
|
.toTypedArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
override val listener = object : TTTItemListener(this, true) {
|
override val listener = object : TTTItemListener<Instance>(this) {
|
||||||
override fun onRightClick(data: ClickEventData) {
|
|
||||||
isc.getOrCreate(data.tttPlayer).chosenRole = null
|
|
||||||
data.tttPlayer.player.openInventory(chooseRoleInventory)
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onInventoryClick(event: InventoryClickEvent) = handle(event) { tttPlayer ->
|
fun onInventoryClick(event: InventoryClickEvent) = handle(event) { tttPlayer ->
|
||||||
val state = isc.getOrCreate(tttPlayer)
|
val instance = getInstance(tttPlayer) ?: return@handle
|
||||||
|
|
||||||
if (!setOf(state.choosePlayerInventory, chooseRoleInventory).contains(event.clickedInventory)) return@handle
|
if (
|
||||||
|
!setOf(
|
||||||
|
instance.choosePlayerInventory,
|
||||||
|
chooseRoleInventory
|
||||||
|
).contains(event.clickedInventory)
|
||||||
|
) return@handle
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
|
|
||||||
val item = event.currentItem
|
val item = event.currentItem
|
||||||
|
@ -90,11 +103,12 @@ object FakeCorpse: TTTItem, Buyable {
|
||||||
if (item != null && event.click == ClickType.LEFT) {
|
if (item != null && event.click == ClickType.LEFT) {
|
||||||
when (event.clickedInventory) {
|
when (event.clickedInventory) {
|
||||||
chooseRoleInventory -> {
|
chooseRoleInventory -> {
|
||||||
state.chosenRole = Role.values()[event.slot]
|
instance.chosenRole = Role.values()[event.slot]
|
||||||
state.choosePlayerInventory = createChoosePlayerInventory()
|
val choosePlayerInventory = createChoosePlayerInventory()
|
||||||
tttPlayer.player.openInventory(state.choosePlayerInventory!!)
|
instance.choosePlayerInventory = choosePlayerInventory
|
||||||
|
tttPlayer.player.openInventory(choosePlayerInventory)
|
||||||
}
|
}
|
||||||
state.choosePlayerInventory -> {
|
instance.choosePlayerInventory -> {
|
||||||
tttPlayer.player.closeInventory()
|
tttPlayer.player.closeInventory()
|
||||||
|
|
||||||
val corpsePlayer = plugin.server.getPlayer((item.itemMeta as SkullMeta).owningPlayer!!.uniqueId)!!
|
val corpsePlayer = plugin.server.getPlayer((item.itemMeta as SkullMeta).owningPlayer!!.uniqueId)!!
|
||||||
|
@ -103,8 +117,7 @@ object FakeCorpse: TTTItem, Buyable {
|
||||||
if (corpseTTTPlayer == null) {
|
if (corpseTTTPlayer == null) {
|
||||||
tttPlayer.player.sendActionBarMessage("${ChatColor.RED}Das hat nicht funktioniert")
|
tttPlayer.player.sendActionBarMessage("${ChatColor.RED}Das hat nicht funktioniert")
|
||||||
} else {
|
} else {
|
||||||
TTTCorpse.spawnFake(state.chosenRole!!, corpseTTTPlayer, tttPlayer.player.location)
|
TTTCorpse.spawnFake(instance.chosenRole!!, corpseTTTPlayer, tttPlayer.player.location)
|
||||||
|
|
||||||
tttPlayer.player.inventory.removeTTTItem(FakeCorpse)
|
tttPlayer.player.inventory.removeTTTItem(FakeCorpse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,9 +125,4 @@ object FakeCorpse: TTTItem, Buyable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class State: IState {
|
|
||||||
var chosenRole: Role? = null
|
|
||||||
var choosePlayerInventory: Inventory? = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.impl
|
package de.moritzruth.spigot_ttt.game.items.impl
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
|
||||||
import de.moritzruth.spigot_ttt.game.GameManager
|
import de.moritzruth.spigot_ttt.game.GameManager
|
||||||
|
import de.moritzruth.spigot_ttt.game.items.ClickEvent
|
||||||
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
|
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
||||||
import de.moritzruth.spigot_ttt.game.players.Role
|
import de.moritzruth.spigot_ttt.game.players.Role
|
||||||
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
||||||
import de.moritzruth.spigot_ttt.game.players.roles
|
import de.moritzruth.spigot_ttt.game.players.roles
|
||||||
import de.moritzruth.spigot_ttt.game.items.Buyable
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
|
||||||
import de.moritzruth.spigot_ttt.utils.applyMeta
|
import de.moritzruth.spigot_ttt.utils.applyMeta
|
||||||
import de.moritzruth.spigot_ttt.utils.clearHeldItemSlot
|
import de.moritzruth.spigot_ttt.utils.clearHeldItemSlot
|
||||||
import de.moritzruth.spigot_ttt.utils.createKillExplosion
|
import de.moritzruth.spigot_ttt.utils.createKillExplosion
|
||||||
|
@ -18,44 +18,49 @@ import org.bukkit.entity.EntityType
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
import org.bukkit.event.entity.ExplosionPrimeEvent
|
import org.bukkit.event.entity.ExplosionPrimeEvent
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
typealias FireballEntity = org.bukkit.entity.Fireball
|
typealias FireballEntity = org.bukkit.entity.Fireball
|
||||||
|
|
||||||
object Fireball: TTTItem, Buyable {
|
object Fireball: TTTItem<Fireball.Instance>(
|
||||||
override val type = TTTItem.Type.SPECIAL
|
type = Type.SPECIAL,
|
||||||
override val itemStack = ItemStack(Material.FIRE_CHARGE).applyMeta {
|
instanceType = Instance::class,
|
||||||
|
templateItemStack = ItemStack(Material.FIRE_CHARGE).applyMeta {
|
||||||
setDisplayName("${ChatColor.DARK_RED}${ChatColor.BOLD}Feuerball")
|
setDisplayName("${ChatColor.DARK_RED}${ChatColor.BOLD}Feuerball")
|
||||||
|
|
||||||
lore = listOf(
|
lore = listOf(
|
||||||
"",
|
"",
|
||||||
"${ChatColor.GOLD}Wirf einen Feuerball"
|
"${ChatColor.GOLD}Wirf einen Feuerball"
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
override val buyableBy = roles(Role.TRAITOR, Role.JACKAL)
|
shopInfo = ShopInfo(
|
||||||
override val price = 1
|
buyableBy = roles(Role.TRAITOR, Role.JACKAL),
|
||||||
override val buyLimit: Int? = null
|
buyLimit = 0,
|
||||||
|
price = 1
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
class Instance: TTTItem.Instance(Fireball) {
|
||||||
|
override fun onRightClick(event: ClickEvent) {
|
||||||
|
val carrier = carrier!!
|
||||||
|
carrier.player.inventory.clearHeldItemSlot()
|
||||||
|
|
||||||
val sendersByEntity = mutableMapOf<FireballEntity, TTTPlayer>()
|
val vector = carrier.player.eyeLocation.toVector()
|
||||||
|
val location = vector.add(carrier.player.eyeLocation.direction.multiply(1.2))
|
||||||
override val listener = object : TTTItemListener(this, true) {
|
.toLocation(carrier.player.location.world!!)
|
||||||
override fun onRightClick(data: ClickEventData) {
|
|
||||||
data.tttPlayer.player.inventory.clearHeldItemSlot()
|
|
||||||
|
|
||||||
val vector = data.tttPlayer.player.eyeLocation.toVector()
|
|
||||||
val location = vector.add(data.tttPlayer.player.eyeLocation.direction.multiply(1.2))
|
|
||||||
.toLocation(data.tttPlayer.player.location.world!!)
|
|
||||||
|
|
||||||
val fireball = GameManager.world.spawnEntity(location, EntityType.FIREBALL) as FireballEntity
|
val fireball = GameManager.world.spawnEntity(location, EntityType.FIREBALL) as FireballEntity
|
||||||
fireball.direction = data.tttPlayer.player.eyeLocation.direction
|
fireball.direction = carrier.player.eyeLocation.direction
|
||||||
sendersByEntity[fireball] = data.tttPlayer
|
sendersByEntity[fireball] = carrier
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val sendersByEntity = WeakHashMap<FireballEntity, TTTPlayer>()
|
||||||
|
|
||||||
|
override val listener = object : TTTItemListener<Instance>(this) {
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onExplosionPrime(event: ExplosionPrimeEvent) {
|
fun onExplosionPrime(event: ExplosionPrimeEvent) {
|
||||||
val sender = sendersByEntity[event.entity]
|
val sender = sendersByEntity[event.entity]
|
||||||
|
|
||||||
if (sender != null) {
|
if (sender != null) {
|
||||||
sendersByEntity.remove(event.entity)
|
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
|
|
||||||
GameManager.world.playSound(
|
GameManager.world.playSound(
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.impl
|
package de.moritzruth.spigot_ttt.game.items.impl
|
||||||
|
|
||||||
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
||||||
import de.moritzruth.spigot_ttt.game.players.Role
|
import de.moritzruth.spigot_ttt.game.players.Role
|
||||||
import de.moritzruth.spigot_ttt.game.players.roles
|
import de.moritzruth.spigot_ttt.game.players.roles
|
||||||
import de.moritzruth.spigot_ttt.game.items.Buyable
|
import de.moritzruth.spigot_ttt.utils.Probability
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
|
||||||
import de.moritzruth.spigot_ttt.utils.applyMeta
|
import de.moritzruth.spigot_ttt.utils.applyMeta
|
||||||
|
import de.moritzruth.spigot_ttt.utils.applyTypedMeta
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.bukkit.attribute.Attribute
|
import org.bukkit.attribute.Attribute
|
||||||
|
@ -17,35 +18,35 @@ import org.bukkit.inventory.meta.PotionMeta
|
||||||
import org.bukkit.potion.PotionData
|
import org.bukkit.potion.PotionData
|
||||||
import org.bukkit.potion.PotionType
|
import org.bukkit.potion.PotionType
|
||||||
|
|
||||||
object HealingPotion: TTTItem, Buyable {
|
object HealingPotion: TTTItem<HealingPotion.Instance>(
|
||||||
override val itemStack = ItemStack(Material.POTION).apply {
|
instanceType = Instance::class,
|
||||||
val potionMeta = itemMeta as PotionMeta
|
type = Type.SPECIAL,
|
||||||
potionMeta.basePotionData = PotionData(PotionType.INSTANT_HEAL, false, true)
|
spawnProbability = Probability.VERY_LOW,
|
||||||
itemMeta = potionMeta
|
templateItemStack = ItemStack(Material.POTION)
|
||||||
}.applyMeta {
|
.applyTypedMeta<PotionMeta> { basePotionData = PotionData(PotionType.INSTANT_HEAL, false, true) }
|
||||||
setDisplayName("${ChatColor.LIGHT_PURPLE}Heiltrank")
|
.applyMeta {
|
||||||
lore = listOf(
|
setDisplayName("${ChatColor.LIGHT_PURPLE}Heiltrank")
|
||||||
|
lore = listOf(
|
||||||
"",
|
"",
|
||||||
"${ChatColor.GOLD}Heilt dich voll"
|
"${ChatColor.GOLD}Heilt dich voll"
|
||||||
)
|
)
|
||||||
|
|
||||||
addItemFlags(ItemFlag.HIDE_POTION_EFFECTS)
|
addItemFlags(ItemFlag.HIDE_POTION_EFFECTS)
|
||||||
}
|
},
|
||||||
override val type = TTTItem.Type.SPECIAL
|
shopInfo = ShopInfo(
|
||||||
override val buyableBy = roles(Role.TRAITOR, Role.JACKAL, Role.DETECTIVE)
|
buyableBy = roles(Role.TRAITOR, Role.JACKAL, Role.DETECTIVE),
|
||||||
override val price = 1
|
price = 1,
|
||||||
override val buyLimit = 2
|
buyLimit = 2
|
||||||
|
)
|
||||||
override val listener = object : TTTItemListener(this, true) {
|
) {
|
||||||
|
override val listener = object : TTTItemListener<Instance>(this) {
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onPlayerItemConsume(event: PlayerItemConsumeEvent) = handle(event) {
|
fun onPlayerItemConsume(event: PlayerItemConsumeEvent) = handle(event) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
event.player.inventory.clear(event.player.inventory.indexOf(event.item))
|
event.player.inventory.clear(event.player.inventory.indexOf(event.item))
|
||||||
event.player.health = event.player.getAttribute(Attribute.GENERIC_MAX_HEALTH)?.value ?: 100.0
|
event.player.health = event.player.getAttribute(Attribute.GENERIC_MAX_HEALTH)?.value ?: 100.0
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRightClick(data: ClickEventData) {
|
|
||||||
data.event.isCancelled = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Instance: TTTItem.Instance(HealingPotion)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.impl
|
package de.moritzruth.spigot_ttt.game.items.impl
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.GameEndEvent
|
|
||||||
import de.moritzruth.spigot_ttt.game.GameManager
|
import de.moritzruth.spigot_ttt.game.GameManager
|
||||||
import de.moritzruth.spigot_ttt.game.items.Buyable
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.PASSIVE
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
||||||
import de.moritzruth.spigot_ttt.game.players.*
|
import de.moritzruth.spigot_ttt.game.players.Role
|
||||||
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayerTrueDeathEvent
|
||||||
|
import de.moritzruth.spigot_ttt.game.players.roles
|
||||||
import de.moritzruth.spigot_ttt.plugin
|
import de.moritzruth.spigot_ttt.plugin
|
||||||
import de.moritzruth.spigot_ttt.utils.applyMeta
|
import de.moritzruth.spigot_ttt.utils.applyMeta
|
||||||
import de.moritzruth.spigot_ttt.utils.createKillExplosion
|
import de.moritzruth.spigot_ttt.utils.createKillExplosion
|
||||||
|
@ -19,33 +18,39 @@ import org.bukkit.event.EventHandler
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.scheduler.BukkitTask
|
import org.bukkit.scheduler.BukkitTask
|
||||||
|
|
||||||
object MartyrdomGrenade: TTTItem, Buyable {
|
object MartyrdomGrenade: TTTItem<MartyrdomGrenade.Instance>(
|
||||||
override val type = TTTItem.Type.SPECIAL
|
type = Type.SPECIAL,
|
||||||
override val itemStack = ItemStack(Resourcepack.Items.martyrdomGrenade).applyMeta {
|
instanceType = Instance::class,
|
||||||
|
templateItemStack = ItemStack(Resourcepack.Items.martyrdomGrenade).applyMeta {
|
||||||
hideInfo()
|
hideInfo()
|
||||||
setDisplayName("${ChatColor.DARK_PURPLE}${ChatColor.BOLD}Märtyriumsgranate $PASSIVE")
|
setDisplayName("${ChatColor.DARK_PURPLE}${ChatColor.BOLD}Märtyriumsgranate$PASSIVE_SUFFIX")
|
||||||
|
|
||||||
lore = listOf(
|
lore = listOf(
|
||||||
"",
|
"",
|
||||||
"${ChatColor.GOLD}Lasse bei deinem Tod",
|
"${ChatColor.GOLD}Lasse bei deinem Tod",
|
||||||
"${ChatColor.GOLD}eine Granate fallen"
|
"${ChatColor.GOLD}eine Granate fallen"
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
override val buyableBy = roles(Role.TRAITOR)
|
shopInfo = ShopInfo(
|
||||||
override val buyLimit: Int? = null
|
buyableBy = roles(Role.TRAITOR, Role.JACKAL),
|
||||||
override val price = 1
|
price = 1
|
||||||
val isc = InversedStateContainer(State::class)
|
)
|
||||||
|
) {
|
||||||
|
class Instance: TTTItem.Instance(MartyrdomGrenade, true) {
|
||||||
|
var explodeTask: BukkitTask? = null
|
||||||
|
|
||||||
override fun onOwn(tttPlayer: TTTPlayer) {
|
override fun reset() {
|
||||||
isc.getOrCreate(tttPlayer)
|
explodeTask?.cancel()
|
||||||
|
explodeTask = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val listener = object : TTTItemListener(this, true) {
|
override val listener = object : TTTItemListener<Instance>(this) {
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onTTTPlayerTrueDeath(event: TTTPlayerTrueDeathEvent) {
|
fun onTTTPlayerTrueDeath(event: TTTPlayerTrueDeathEvent) {
|
||||||
val state = isc.get(event.tttPlayer) ?: return
|
val instance = getInstance(event.tttPlayer) ?: return
|
||||||
|
event.tttPlayer.removeItem(MartyrdomGrenade, false)
|
||||||
|
|
||||||
state.explodeTask = plugin.server.scheduler.runTaskLater(plugin, fun() {
|
instance.explodeTask = plugin.server.scheduler.runTaskLater(plugin, fun() {
|
||||||
GameManager.world.playSound(
|
GameManager.world.playSound(
|
||||||
event.location,
|
event.location,
|
||||||
Resourcepack.Sounds.grenadeExplode,
|
Resourcepack.Sounds.grenadeExplode,
|
||||||
|
@ -57,15 +62,5 @@ object MartyrdomGrenade: TTTItem, Buyable {
|
||||||
createKillExplosion(event.tttPlayer, event.location, 2.5)
|
createKillExplosion(event.tttPlayer, event.location, 2.5)
|
||||||
}, secondsToTicks(3).toLong())
|
}, secondsToTicks(3).toLong())
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onGameEnd(event: GameEndEvent) = isc.forEveryState { state, _ ->
|
|
||||||
state.explodeTask?.cancel()
|
|
||||||
state.explodeTask = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class State: IState {
|
|
||||||
var explodeTask: BukkitTask? = null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,35 +5,29 @@ import com.comphenix.protocol.PacketType
|
||||||
import com.comphenix.protocol.events.PacketAdapter
|
import com.comphenix.protocol.events.PacketAdapter
|
||||||
import com.comphenix.protocol.events.PacketEvent
|
import com.comphenix.protocol.events.PacketEvent
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.GameEndEvent
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.Buyable
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.PASSIVE
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
import de.moritzruth.spigot_ttt.game.players.PlayerManager
|
||||||
import de.moritzruth.spigot_ttt.game.players.*
|
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.plugin
|
import de.moritzruth.spigot_ttt.plugin
|
||||||
import de.moritzruth.spigot_ttt.utils.applyMeta
|
import de.moritzruth.spigot_ttt.utils.applyMeta
|
||||||
import de.moritzruth.spigot_ttt.utils.hideInfo
|
import de.moritzruth.spigot_ttt.utils.hideInfo
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.boss.BarColor
|
import org.bukkit.boss.BarColor
|
||||||
import org.bukkit.boss.BarStyle
|
import org.bukkit.boss.BarStyle
|
||||||
import org.bukkit.boss.BossBar
|
|
||||||
import org.bukkit.event.EventHandler
|
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.scheduler.BukkitTask
|
import org.bukkit.scheduler.BukkitTask
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
|
||||||
import kotlin.experimental.and
|
import kotlin.experimental.and
|
||||||
import kotlin.experimental.or
|
import kotlin.experimental.or
|
||||||
|
|
||||||
object Radar: TTTItem, Buyable {
|
object Radar: TTTItem<Radar.Instance>(
|
||||||
private val DISPLAY_NAME = "${ChatColor.DARK_AQUA}${ChatColor.BOLD}Radar"
|
type = Type.SPECIAL,
|
||||||
private const val ACTIVE_DURATION = 10
|
instanceType = Instance::class,
|
||||||
private const val COOLDOWN_DURATION = 40
|
templateItemStack = ItemStack(Resourcepack.Items.radar).applyMeta {
|
||||||
|
setDisplayName("${ChatColor.DARK_AQUA}${ChatColor.BOLD}Radar$PASSIVE_SUFFIX")
|
||||||
override val itemStack = ItemStack(Resourcepack.Items.radar).applyMeta {
|
|
||||||
setDisplayName("$DISPLAY_NAME $PASSIVE")
|
|
||||||
lore = listOf(
|
lore = listOf(
|
||||||
"",
|
"",
|
||||||
"${ChatColor.GOLD}Zeigt dir alle 30 Sekunden",
|
"${ChatColor.GOLD}Zeigt dir alle 30 Sekunden",
|
||||||
|
@ -42,75 +36,66 @@ object Radar: TTTItem, Buyable {
|
||||||
)
|
)
|
||||||
|
|
||||||
hideInfo()
|
hideInfo()
|
||||||
}
|
},
|
||||||
override val type = TTTItem.Type.SPECIAL
|
shopInfo = ShopInfo(
|
||||||
override val buyableBy: EnumSet<Role> = EnumSet.of(Role.TRAITOR, Role.DETECTIVE, Role.JACKAL)
|
buyableBy = roles(Role.TRAITOR, Role.DETECTIVE, Role.JACKAL),
|
||||||
override val price = 2
|
price = 2
|
||||||
override val buyLimit: Int? = null
|
)
|
||||||
|
) {
|
||||||
|
private const val ACTIVE_DURATION = 10
|
||||||
|
private const val COOLDOWN_DURATION = 40
|
||||||
|
private val BOSS_BAR_TITLE = "${ChatColor.DARK_AQUA}${ChatColor.BOLD}Radar"
|
||||||
|
|
||||||
val isc = InversedStateContainer(State::class)
|
class Instance: TTTItem.Instance(Radar) {
|
||||||
|
var active: Boolean = true
|
||||||
|
private var timestamp = Instant.now()!!
|
||||||
|
private val bossBar = plugin.server.createBossBar(BOSS_BAR_TITLE, BarColor.BLUE, BarStyle.SOLID)
|
||||||
|
|
||||||
override fun onOwn(tttPlayer: TTTPlayer) {
|
private var task: BukkitTask = plugin.server.scheduler.runTaskTimer(plugin, fun() {
|
||||||
val state = isc.getOrCreate(tttPlayer)
|
val duration = Duration.between(timestamp, Instant.now()).toMillis().toDouble() / 1000
|
||||||
|
|
||||||
state.bossBar = plugin.server.createBossBar(DISPLAY_NAME, BarColor.BLUE, BarStyle.SOLID)
|
if (active) {
|
||||||
state.bossBar.addPlayer(tttPlayer.player)
|
|
||||||
|
|
||||||
setActive(tttPlayer, true)
|
|
||||||
state.task = plugin.server.scheduler.runTaskTimer(plugin, fun() {
|
|
||||||
val duration = Duration.between(state.timestamp, Instant.now()).toMillis().toDouble() / 1000
|
|
||||||
|
|
||||||
if (state.active) {
|
|
||||||
if (duration > ACTIVE_DURATION) {
|
if (duration > ACTIVE_DURATION) {
|
||||||
setActive(tttPlayer, false)
|
active = false
|
||||||
|
bossBar.setTitle(BOSS_BAR_TITLE + "${ChatColor.WHITE} - ${ChatColor.GRAY}Cooldown")
|
||||||
|
carrier?.let { resendEntityMetadata(it) }
|
||||||
|
timestamp = Instant.now()
|
||||||
} else {
|
} else {
|
||||||
state.bossBar.progress = 1.0 - duration / ACTIVE_DURATION
|
bossBar.progress = 1.0 - duration / ACTIVE_DURATION
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (duration > COOLDOWN_DURATION) {
|
if (duration > COOLDOWN_DURATION) {
|
||||||
setActive(tttPlayer, true)
|
active = true
|
||||||
|
bossBar.setTitle(BOSS_BAR_TITLE + "${ChatColor.WHITE} - ${ChatColor.GREEN}Aktiv")
|
||||||
|
carrier?.let { resendEntityMetadata(it) }
|
||||||
|
timestamp = Instant.now()
|
||||||
} else {
|
} else {
|
||||||
state.bossBar.progress = duration / COOLDOWN_DURATION
|
bossBar.progress = duration / COOLDOWN_DURATION
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 0, 2)
|
}, 0, 1)
|
||||||
}
|
|
||||||
|
|
||||||
private fun setActive(tttPlayer: TTTPlayer, value: Boolean) {
|
override fun onCarrierSet(carrier: TTTPlayer, isFirst: Boolean) {
|
||||||
val state = isc.getOrCreate(tttPlayer)
|
bossBar.addPlayer(carrier.player)
|
||||||
|
if (active) resendEntityMetadata(carrier)
|
||||||
|
}
|
||||||
|
|
||||||
if (state.active != value) {
|
override fun onCarrierRemoved(oldCarrier: TTTPlayer) {
|
||||||
state.active = value
|
bossBar.removePlayer(oldCarrier.player)
|
||||||
state.timestamp = Instant.now()
|
if (active) resendEntityMetadata(oldCarrier)
|
||||||
|
}
|
||||||
|
|
||||||
if (value) {
|
override fun reset() {
|
||||||
state.bossBar.setTitle(DISPLAY_NAME + "${ChatColor.WHITE} - ${ChatColor.GREEN}Aktiv")
|
task.cancel()
|
||||||
} else {
|
|
||||||
state.bossBar.setTitle(DISPLAY_NAME + "${ChatColor.WHITE} - ${ChatColor.GRAY}Cooldown")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Toggle sending the entity metadata
|
|
||||||
PlayerManager.tttPlayers.forEach {
|
|
||||||
if (it !== tttPlayer) {
|
|
||||||
tttPlayer.player.hidePlayer(plugin, it.player)
|
|
||||||
tttPlayer.player.showPlayer(plugin, it.player)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val listener = object : TTTItemListener(this, true) {
|
fun resendEntityMetadata(tttPlayer: TTTPlayer) {
|
||||||
@EventHandler
|
PlayerManager.tttPlayers.forEach {
|
||||||
fun onTTTPlayerTrueDeath(event: TTTPlayerTrueDeathEvent) {
|
if (it !== tttPlayer) {
|
||||||
isc.get(event.tttPlayer)?.reset(event.tttPlayer)
|
tttPlayer.player.hidePlayer(plugin, it.player)
|
||||||
isc.remove(event.tttPlayer)
|
tttPlayer.player.showPlayer(plugin, it.player)
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onGameEnd(event: GameEndEvent) = isc.forEveryState { state, tttPlayer -> state.reset(tttPlayer) }
|
|
||||||
|
|
||||||
override fun onRightClick(data: ClickEventData) {
|
|
||||||
data.event.isCancelled = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,15 +104,17 @@ object Radar: TTTItem, Buyable {
|
||||||
val receivingTTTPlayer = TTTPlayer.of(event.player) ?: return
|
val receivingTTTPlayer = TTTPlayer.of(event.player) ?: return
|
||||||
|
|
||||||
val packet = WrapperPlayServerEntityMetadata(event.packet)
|
val packet = WrapperPlayServerEntityMetadata(event.packet)
|
||||||
val playerOfPacket = plugin.server.onlinePlayers.find { it.entityId == packet.entityID } ?: return
|
val tttPlayerOfPacket = plugin.server.onlinePlayers
|
||||||
val tttPlayerOfPacket = TTTPlayer.of(playerOfPacket) ?: return
|
.find { it.entityId == packet.entityID }
|
||||||
|
?.let { TTTPlayer.of(it) } ?: return
|
||||||
|
val instance = getInstance(receivingTTTPlayer) ?: return
|
||||||
|
|
||||||
if (tttPlayerOfPacket.alive) {
|
if (tttPlayerOfPacket.alive) {
|
||||||
// https://wiki.vg/Entity_metadata#Entity_Metadata_Format
|
// https://wiki.vg/Entity_metadata#Entity_Metadata_Format
|
||||||
try {
|
try {
|
||||||
val modifiers = packet.metadata[0].value as Byte
|
val modifiers = packet.metadata[0].value as Byte
|
||||||
packet.metadata[0].value =
|
packet.metadata[0].value =
|
||||||
if (isc.get(receivingTTTPlayer)?.active == true) modifiers or 0x40.toByte()
|
if (instance.active) modifiers or 0x40.toByte()
|
||||||
else modifiers and 0b10111111.toByte()
|
else modifiers and 0b10111111.toByte()
|
||||||
} catch (ignored: Exception) {
|
} catch (ignored: Exception) {
|
||||||
// Idk why this throws exceptions, but it works anyways
|
// Idk why this throws exceptions, but it works anyways
|
||||||
|
@ -135,18 +122,4 @@ object Radar: TTTItem, Buyable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class State: IState {
|
|
||||||
var task: BukkitTask? = null
|
|
||||||
var active: Boolean = false
|
|
||||||
lateinit var timestamp: Instant
|
|
||||||
lateinit var bossBar: BossBar
|
|
||||||
|
|
||||||
fun reset(tttPlayer: TTTPlayer) {
|
|
||||||
setActive(tttPlayer, false)
|
|
||||||
|
|
||||||
task?.cancel()
|
|
||||||
bossBar.removePlayer(tttPlayer.player)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.impl
|
package de.moritzruth.spigot_ttt.game.items.impl
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.GameEndEvent
|
|
||||||
import de.moritzruth.spigot_ttt.game.GameManager
|
import de.moritzruth.spigot_ttt.game.GameManager
|
||||||
import de.moritzruth.spigot_ttt.game.items.Buyable
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.PASSIVE
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
||||||
import de.moritzruth.spigot_ttt.game.players.*
|
import de.moritzruth.spigot_ttt.game.players.*
|
||||||
|
@ -27,26 +24,76 @@ import java.time.Duration
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
object SecondChance: TTTItem, Buyable {
|
object SecondChance: TTTItem<SecondChance.Instance>(
|
||||||
private val DISPLAY_NAME = "${ChatColor.GREEN}${ChatColor.BOLD}Second Chance"
|
type = Type.SPECIAL,
|
||||||
val ON_CORPSE = Resourcepack.Items.arrowDown
|
instanceType = Instance::class,
|
||||||
val ON_SPAWN = Resourcepack.Items.dot
|
templateItemStack = ItemStack(Resourcepack.Items.secondChance).applyMeta {
|
||||||
private const val TIMEOUT = 10.0
|
setDisplayName("${ChatColor.GREEN}${ChatColor.BOLD}Second Chance$PASSIVE_SUFFIX")
|
||||||
|
|
||||||
override val type = TTTItem.Type.SPECIAL
|
|
||||||
override val itemStack = ItemStack(Resourcepack.Items.secondChance).applyMeta {
|
|
||||||
setDisplayName("$DISPLAY_NAME $PASSIVE")
|
|
||||||
hideInfo()
|
hideInfo()
|
||||||
lore = listOf(
|
lore = listOf(
|
||||||
"",
|
"",
|
||||||
"${ChatColor.GOLD}Du wirst mit einer 50%-Chance",
|
"${ChatColor.GOLD}Du wirst mit einer 50%-Chance",
|
||||||
"${ChatColor.GOLD}wiederbelebt, wenn du stirbst"
|
"${ChatColor.GOLD}wiederbelebt, wenn du stirbst"
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
shopInfo = ShopInfo(
|
||||||
|
buyableBy = roles(Role.TRAITOR, Role.JACKAL),
|
||||||
|
buyLimit = 1,
|
||||||
|
price = 2
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
val ON_CORPSE = Resourcepack.Items.arrowDown
|
||||||
|
val ON_SPAWN = Resourcepack.Items.dot
|
||||||
|
private const val TIMEOUT = 10.0
|
||||||
|
|
||||||
|
class Instance: TTTItem.Instance(SecondChance, false) {
|
||||||
|
var preventRoundEnd = false; private set
|
||||||
|
var timeoutAction: TimeoutAction? = null
|
||||||
|
|
||||||
|
fun possiblyTrigger() {
|
||||||
|
if (Random.nextBoolean()) trigger()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun trigger() {
|
||||||
|
preventRoundEnd = true
|
||||||
|
timeoutAction = TimeoutAction(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class TimeoutAction(private val instance: Instance) {
|
||||||
|
val deathLocation: Location = instance.requireCarrier().player.location
|
||||||
|
private val startedAt = Instant.now()!!
|
||||||
|
private var bossBar = plugin.server.createBossBar(
|
||||||
|
"${ChatColor.GREEN}${ChatColor.BOLD}Second Chance",
|
||||||
|
BarColor.GREEN,
|
||||||
|
BarStyle.SOLID
|
||||||
|
).also { it.addPlayer(instance.requireCarrier().player) }
|
||||||
|
|
||||||
|
private var task: BukkitTask = plugin.server.scheduler.runTaskTimer(plugin, fun() {
|
||||||
|
val duration = Duration.between(startedAt, Instant.now()).toMillis().toDouble() / 1000
|
||||||
|
val progress = duration / TIMEOUT
|
||||||
|
|
||||||
|
if (progress > 1) onTimeout() else bossBar.progress = 1.0 - progress
|
||||||
|
}, 0, 1)
|
||||||
|
|
||||||
|
private fun onTimeout() {
|
||||||
|
try {
|
||||||
|
PlayerManager.letRemainingRoleGroupWin()
|
||||||
|
} catch (e: IllegalStateException) {}
|
||||||
|
|
||||||
|
stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop() {
|
||||||
|
val carrier = instance.requireCarrier()
|
||||||
|
task.cancel()
|
||||||
|
carrier.player.apply {
|
||||||
|
closeInventory()
|
||||||
|
bossBar.removePlayer(this)
|
||||||
|
}
|
||||||
|
carrier.removeItem(SecondChance)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
override val buyableBy = roles(Role.TRAITOR, Role.JACKAL)
|
|
||||||
override val buyLimit = 1
|
|
||||||
override val price = 2
|
|
||||||
val isc = InversedStateContainer(State::class)
|
|
||||||
|
|
||||||
private val chooseSpawnInventory = plugin.server.createInventory(
|
private val chooseSpawnInventory = plugin.server.createInventory(
|
||||||
null,
|
null,
|
||||||
|
@ -69,97 +116,42 @@ object SecondChance: TTTItem, Buyable {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOwn(tttPlayer: TTTPlayer) {
|
override val listener = object : TTTItemListener<Instance>(this) {
|
||||||
isc.getOrCreate(tttPlayer)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val listener = object : TTTItemListener(this, true, false) {
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onTTTPlayerTrueDeath(event: TTTPlayerTrueDeathEvent) {
|
fun onTTTPlayerTrueDeath(event: TTTPlayerTrueDeathEvent) {
|
||||||
val state = isc.get(event.tttPlayer)
|
val instance = getInstance(event.tttPlayer) ?: return
|
||||||
if (state != null) {
|
instance.possiblyTrigger()
|
||||||
if (true || Random.nextBoolean()) {
|
if (instancesByUUID.values.find { it.preventRoundEnd } != null) event.winnerRoleGroup = null
|
||||||
event.winnerRoleGroup = null
|
|
||||||
event.tttPlayer.player.openInventory(chooseSpawnInventory)
|
|
||||||
state.timeoutAction = TimeoutAction(event.tttPlayer, event.tttCorpse.location)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isc.forEveryState { s, _ -> if (s.timeoutAction != null) event.winnerRoleGroup = null }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onInventoryClose(event: InventoryCloseEvent) = handle(event) { tttPlayer ->
|
fun onInventoryClose(event: InventoryCloseEvent) {
|
||||||
if (event.inventory == chooseSpawnInventory) {
|
if (event.inventory == chooseSpawnInventory) {
|
||||||
if (isc.get(tttPlayer)?.timeoutAction != null) {
|
handleWithInstance(event) { instance ->
|
||||||
nextTick { if (isc.get(tttPlayer) != null) tttPlayer.player.openInventory(chooseSpawnInventory) }
|
nextTick { instance.carrier?.player?.openInventory(chooseSpawnInventory) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onInventoryClick(event: InventoryClickEvent) = handle(event) { tttPlayer ->
|
fun onInventoryClick(event: InventoryClickEvent) {
|
||||||
if (event.clickedInventory != chooseSpawnInventory) return@handle
|
if (event.clickedInventory != chooseSpawnInventory) return
|
||||||
val state = isc.get(tttPlayer) ?: return@handle
|
|
||||||
val timeoutAction = state.timeoutAction ?: return@handle
|
|
||||||
|
|
||||||
val location = when (event.currentItem?.type) {
|
handleWithInstance(event) { instance ->
|
||||||
ON_SPAWN -> GameManager.world.spawnLocation
|
val timeoutAction = instance.timeoutAction!!
|
||||||
ON_CORPSE -> timeoutAction.deathLocation
|
|
||||||
else -> return@handle
|
val location = when (event.currentItem?.type) {
|
||||||
|
ON_SPAWN -> GameManager.world.spawnLocation
|
||||||
|
ON_CORPSE -> timeoutAction.deathLocation
|
||||||
|
else -> return@handleWithInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutAction.stop()
|
||||||
|
instance.carrier!!.revive(location)
|
||||||
}
|
}
|
||||||
|
|
||||||
timeoutAction.stop()
|
|
||||||
tttPlayer.revive(location)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
fun onTTTPlayerRevive(event: TTTPlayerReviveEvent) {
|
fun onTTTPlayerRevive(event: TTTPlayerReviveEvent) = handle(event) { it.timeoutAction?.stop() }
|
||||||
isc.get(event.tttPlayer)?.timeoutAction?.stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onGameEnd(event: GameEndEvent) {
|
|
||||||
isc.forEveryState { state, _ -> state.timeoutAction?.stop() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TimeoutAction(
|
|
||||||
private val tttPlayer: TTTPlayer,
|
|
||||||
val deathLocation: Location
|
|
||||||
) {
|
|
||||||
private val startedAt = Instant.now()!!
|
|
||||||
private var bossBar = plugin.server.createBossBar(
|
|
||||||
"${ChatColor.GREEN}${ChatColor.BOLD}Second Chance",
|
|
||||||
BarColor.GREEN,
|
|
||||||
BarStyle.SOLID
|
|
||||||
).also { it.addPlayer(tttPlayer.player) }
|
|
||||||
|
|
||||||
private var task: BukkitTask = plugin.server.scheduler.runTaskTimer(plugin, fun() {
|
|
||||||
val duration = Duration.between(startedAt, Instant.now()).toMillis().toDouble() / 1000
|
|
||||||
val progress = duration / TIMEOUT
|
|
||||||
|
|
||||||
if (progress > 1) onTimeout() else bossBar.progress = 1.0 - progress
|
|
||||||
}, 0, 1)
|
|
||||||
|
|
||||||
private fun onTimeout() {
|
|
||||||
try {
|
|
||||||
PlayerManager.letRemainingRoleGroupWin()
|
|
||||||
} catch (e: IllegalStateException) {}
|
|
||||||
|
|
||||||
stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun stop() {
|
|
||||||
isc.remove(tttPlayer)
|
|
||||||
task.cancel()
|
|
||||||
tttPlayer.player.closeInventory()
|
|
||||||
tttPlayer.removeItem(SecondChance)
|
|
||||||
bossBar.removePlayer(tttPlayer.player)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class State: IState {
|
|
||||||
var timeoutAction: TimeoutAction? = null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,24 +2,23 @@ package de.moritzruth.spigot_ttt.game.items.impl
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.GameManager
|
import de.moritzruth.spigot_ttt.game.GameManager
|
||||||
import de.moritzruth.spigot_ttt.game.items.Buyable
|
import de.moritzruth.spigot_ttt.game.items.ClickEvent
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
import de.moritzruth.spigot_ttt.game.players.PlayerManager
|
||||||
import de.moritzruth.spigot_ttt.game.players.*
|
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.utils.applyMeta
|
import de.moritzruth.spigot_ttt.utils.applyMeta
|
||||||
import de.moritzruth.spigot_ttt.utils.clearHeldItemSlot
|
|
||||||
import de.moritzruth.spigot_ttt.utils.sendActionBarMessage
|
import de.moritzruth.spigot_ttt.utils.sendActionBarMessage
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.Sound
|
import org.bukkit.Sound
|
||||||
import org.bukkit.event.EventHandler
|
|
||||||
import org.bukkit.event.player.PlayerSwapHandItemsEvent
|
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
|
|
||||||
object Teleporter: TTTItem, Buyable {
|
object Teleporter: TTTItem<Teleporter.Instance>(
|
||||||
override val type = TTTItem.Type.SPECIAL
|
type = Type.SPECIAL,
|
||||||
override val itemStack = ItemStack(Resourcepack.Items.teleporter).applyMeta {
|
instanceType = Instance::class,
|
||||||
|
templateItemStack = ItemStack(Resourcepack.Items.teleporter).applyMeta {
|
||||||
setDisplayName("${ChatColor.LIGHT_PURPLE}${ChatColor.BOLD}Teleporter")
|
setDisplayName("${ChatColor.LIGHT_PURPLE}${ChatColor.BOLD}Teleporter")
|
||||||
|
|
||||||
lore = listOf(
|
lore = listOf(
|
||||||
"",
|
"",
|
||||||
"${ChatColor.GOLD}Tausche die Positionen zweier Spieler",
|
"${ChatColor.GOLD}Tausche die Positionen zweier Spieler",
|
||||||
|
@ -28,42 +27,28 @@ object Teleporter: TTTItem, Buyable {
|
||||||
"",
|
"",
|
||||||
"${ChatColor.RED}Kann nur einmal verwendet werden"
|
"${ChatColor.RED}Kann nur einmal verwendet werden"
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
override val buyableBy = roles(Role.TRAITOR, Role.JACKAL)
|
shopInfo = ShopInfo(
|
||||||
override val price = 1
|
buyableBy = roles(Role.TRAITOR, Role.JACKAL),
|
||||||
override val buyLimit = 1
|
price = 1,
|
||||||
val isc = InversedStateContainer(State::class)
|
buyLimit = 1
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
class Instance: TTTItem.Instance(Teleporter) {
|
||||||
|
private var teleportSelf = false
|
||||||
|
|
||||||
private fun getRandomPlayerToTeleport(vararg exclude: TTTPlayer): TTTPlayer? {
|
override fun onRightClick(event: ClickEvent) {
|
||||||
return try {
|
val tttPlayer = carrier!!
|
||||||
PlayerManager.tttPlayers.filter { !exclude.contains(it) && it.alive && !it.player.isSneaking }.random()
|
val firstPlayer = if (teleportSelf) {
|
||||||
} catch (e: NoSuchElementException) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val listener = object : TTTItemListener(this, true) {
|
|
||||||
@EventHandler
|
|
||||||
fun onPlayerSwapHandItems(event: PlayerSwapHandItemsEvent) = handle(event) { tttPlayer ->
|
|
||||||
val state = isc.getOrCreate(tttPlayer)
|
|
||||||
state.teleportSelf = !state.teleportSelf
|
|
||||||
|
|
||||||
tttPlayer.player.sendActionBarMessage(
|
|
||||||
if (state.teleportSelf) "${ChatColor.AQUA}Mode: Teleportiere dich selbst"
|
|
||||||
else "${ChatColor.AQUA}Mode: Teleportiere jemand anderen"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRightClick(data: ClickEventData) {
|
|
||||||
val tttPlayer = data.tttPlayer
|
|
||||||
val state = isc.getOrCreate(tttPlayer)
|
|
||||||
|
|
||||||
val firstPlayer = if (state.teleportSelf) {
|
|
||||||
if (!tttPlayer.player.isOnGround) {
|
if (!tttPlayer.player.isOnGround) {
|
||||||
tttPlayer.player.sendActionBarMessage("${ChatColor.RED}${ChatColor.BOLD}Du musst auf dem Boden stehen")
|
tttPlayer.player.sendActionBarMessage(
|
||||||
|
"${ChatColor.RED}${ChatColor.BOLD}Du musst auf dem Boden stehen"
|
||||||
|
)
|
||||||
null
|
null
|
||||||
} else if (tttPlayer.player.isSneaking) {
|
} else if (tttPlayer.player.isSneaking) {
|
||||||
tttPlayer.player.sendActionBarMessage("${ChatColor.RED}${ChatColor.BOLD}Du darfst nicht sneaken")
|
tttPlayer.player.sendActionBarMessage(
|
||||||
|
"${ChatColor.RED}${ChatColor.BOLD}Du darfst nicht sneaken"
|
||||||
|
)
|
||||||
null
|
null
|
||||||
} else tttPlayer
|
} else tttPlayer
|
||||||
} else getRandomPlayerToTeleport(tttPlayer)
|
} else getRandomPlayerToTeleport(tttPlayer)
|
||||||
|
@ -76,7 +61,7 @@ object Teleporter: TTTItem, Buyable {
|
||||||
firstPlayer.player.teleport(secondPlayer.player.location)
|
firstPlayer.player.teleport(secondPlayer.player.location)
|
||||||
secondPlayer.player.teleport(firstLocation)
|
secondPlayer.player.teleport(firstLocation)
|
||||||
|
|
||||||
tttPlayer.player.inventory.clearHeldItemSlot()
|
tttPlayer.removeItem(Teleporter)
|
||||||
|
|
||||||
GameManager.world.playSound(firstPlayer.player.location, Sound.ENTITY_ENDERMAN_TELEPORT, 1F, 1F)
|
GameManager.world.playSound(firstPlayer.player.location, Sound.ENTITY_ENDERMAN_TELEPORT, 1F, 1F)
|
||||||
GameManager.world.playSound(secondPlayer.player.location, Sound.ENTITY_ENDERMAN_TELEPORT, 1F, 1F)
|
GameManager.world.playSound(secondPlayer.player.location, Sound.ENTITY_ENDERMAN_TELEPORT, 1F, 1F)
|
||||||
|
@ -87,9 +72,22 @@ object Teleporter: TTTItem, Buyable {
|
||||||
// Teleport failed
|
// Teleport failed
|
||||||
tttPlayer.player.playSound(tttPlayer.player.location, Resourcepack.Sounds.error, 1F, 1F)
|
tttPlayer.player.playSound(tttPlayer.player.location, Resourcepack.Sounds.error, 1F, 1F)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onHandSwap() {
|
||||||
|
teleportSelf = !teleportSelf
|
||||||
|
|
||||||
|
carrier!!.player.sendActionBarMessage(
|
||||||
|
if (teleportSelf) "${ChatColor.AQUA}Mode: Teleportiere dich selbst"
|
||||||
|
else "${ChatColor.AQUA}Mode: Teleportiere jemand anderen"
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class State: IState {
|
private fun getRandomPlayerToTeleport(vararg exclude: TTTPlayer): TTTPlayer? {
|
||||||
var teleportSelf = false
|
return try {
|
||||||
|
PlayerManager.tttPlayers.filter { !exclude.contains(it) && it.alive && !it.player.isSneaking }.random()
|
||||||
|
} catch (e: NoSuchElementException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.impl.weapons
|
package de.moritzruth.spigot_ttt.game.items.impl.weapons
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
|
||||||
import de.moritzruth.spigot_ttt.game.GameManager
|
import de.moritzruth.spigot_ttt.game.GameManager
|
||||||
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.game.items.Buyable
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.Selectable
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
|
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
||||||
|
import de.moritzruth.spigot_ttt.game.players.Role
|
||||||
|
import de.moritzruth.spigot_ttt.game.players.roles
|
||||||
import de.moritzruth.spigot_ttt.utils.applyMeta
|
import de.moritzruth.spigot_ttt.utils.applyMeta
|
||||||
import de.moritzruth.spigot_ttt.utils.hideInfo
|
import de.moritzruth.spigot_ttt.utils.hideInfo
|
||||||
import de.moritzruth.spigot_ttt.utils.removeTTTItemNextTick
|
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.SoundCategory
|
import org.bukkit.SoundCategory
|
||||||
import org.bukkit.attribute.Attribute
|
import org.bukkit.attribute.Attribute
|
||||||
|
@ -22,9 +18,10 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.util.Vector
|
import org.bukkit.util.Vector
|
||||||
|
|
||||||
object BaseballBat: TTTItem, Buyable, Selectable {
|
object BaseballBat: TTTItem<BaseballBat.Instance>(
|
||||||
override val type = TTTItem.Type.MELEE
|
type = Type.SPECIAL,
|
||||||
override val itemStack = ItemStack(Resourcepack.Items.baseballBat).applyMeta {
|
instanceType = Instance::class,
|
||||||
|
templateItemStack = ItemStack(Resourcepack.Items.baseballBat).applyMeta {
|
||||||
setDisplayName("${ChatColor.RESET}${ChatColor.BOLD}Baseball-Schläger")
|
setDisplayName("${ChatColor.RESET}${ChatColor.BOLD}Baseball-Schläger")
|
||||||
lore = listOf(
|
lore = listOf(
|
||||||
"",
|
"",
|
||||||
|
@ -41,22 +38,28 @@ object BaseballBat: TTTItem, Buyable, Selectable {
|
||||||
-0.8,
|
-0.8,
|
||||||
AttributeModifier.Operation.ADD_SCALAR
|
AttributeModifier.Operation.ADD_SCALAR
|
||||||
))
|
))
|
||||||
}
|
},
|
||||||
override val buyableBy = roles(Role.TRAITOR, Role.JACKAL)
|
shopInfo = ShopInfo(
|
||||||
override val price = 1
|
buyableBy = roles(Role.TRAITOR, Role.JACKAL),
|
||||||
override val buyLimit: Int? = null
|
price = 1
|
||||||
|
),
|
||||||
|
disableDamage = false
|
||||||
|
) {
|
||||||
|
const val WALK_SPEED_INCREASE = 0.1F
|
||||||
|
|
||||||
override fun onSelect(tttPlayer: TTTPlayer) {
|
class Instance: TTTItem.Instance(BaseballBat) {
|
||||||
tttPlayer.player.walkSpeed = 0.3F
|
override fun onSelect() {
|
||||||
|
carrier!!.walkSpeed += WALK_SPEED_INCREASE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDeselect() {
|
||||||
|
carrier!!.walkSpeed -= WALK_SPEED_INCREASE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDeselect(tttPlayer: TTTPlayer) {
|
override val listener = object : TTTItemListener<Instance>(this) {
|
||||||
tttPlayer.player.walkSpeed = 0.2F
|
|
||||||
}
|
|
||||||
|
|
||||||
override val listener = object : TTTItemListener(this, false) {
|
|
||||||
@EventHandler(ignoreCancelled = true)
|
@EventHandler(ignoreCancelled = true)
|
||||||
override fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) = handle(event) { tttPlayer, _ ->
|
fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) = handle(event) { tttPlayer, _ ->
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
if (event.damage != 1.0) return@handle // Cooldown on weapon
|
if (event.damage != 1.0) return@handle // Cooldown on weapon
|
||||||
|
|
||||||
|
@ -64,7 +67,7 @@ object BaseballBat: TTTItem, Buyable, Selectable {
|
||||||
val distance = tttPlayer.player.location.distance(damagedPlayer.location)
|
val distance = tttPlayer.player.location.distance(damagedPlayer.location)
|
||||||
|
|
||||||
if (distance < 2.5) {
|
if (distance < 2.5) {
|
||||||
tttPlayer.player.inventory.removeTTTItemNextTick(BaseballBat)
|
tttPlayer.removeItem(BaseballBat)
|
||||||
|
|
||||||
GameManager.world.playSound(
|
GameManager.world.playSound(
|
||||||
damagedPlayer.location,
|
damagedPlayer.location,
|
||||||
|
@ -74,6 +77,8 @@ object BaseballBat: TTTItem, Buyable, Selectable {
|
||||||
1F
|
1F
|
||||||
)
|
)
|
||||||
|
|
||||||
|
event.damage = 0.0
|
||||||
|
|
||||||
val direction = tttPlayer.player.location.direction
|
val direction = tttPlayer.player.location.direction
|
||||||
damagedPlayer.velocity = Vector(direction.x * 5, 8.0, direction.z * 5)
|
damagedPlayer.velocity = Vector(direction.x * 5, 8.0, direction.z * 5)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package de.moritzruth.spigot_ttt.game.items.impl.weapons
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.GameManager
|
import de.moritzruth.spigot_ttt.game.GameManager
|
||||||
import de.moritzruth.spigot_ttt.game.items.Buyable
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.LoreHelper
|
import de.moritzruth.spigot_ttt.game.items.LoreHelper
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
import de.moritzruth.spigot_ttt.game.items.TTTItemListener
|
||||||
|
@ -11,7 +10,6 @@ import de.moritzruth.spigot_ttt.game.players.Role
|
||||||
import de.moritzruth.spigot_ttt.game.players.roles
|
import de.moritzruth.spigot_ttt.game.players.roles
|
||||||
import de.moritzruth.spigot_ttt.utils.applyMeta
|
import de.moritzruth.spigot_ttt.utils.applyMeta
|
||||||
import de.moritzruth.spigot_ttt.utils.hideInfo
|
import de.moritzruth.spigot_ttt.utils.hideInfo
|
||||||
import de.moritzruth.spigot_ttt.utils.removeTTTItemNextTick
|
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.Sound
|
import org.bukkit.Sound
|
||||||
import org.bukkit.SoundCategory
|
import org.bukkit.SoundCategory
|
||||||
|
@ -21,8 +19,10 @@ import org.bukkit.event.EventHandler
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
|
|
||||||
object Knife: TTTItem, Buyable {
|
object Knife: TTTItem<Knife.Instance>(
|
||||||
override val itemStack = ItemStack(Resourcepack.Items.knife).applyMeta {
|
type = Type.MELEE,
|
||||||
|
instanceType = Instance::class,
|
||||||
|
templateItemStack = ItemStack(Resourcepack.Items.knife).applyMeta {
|
||||||
setDisplayName("${ChatColor.RED}${ChatColor.BOLD}Knife")
|
setDisplayName("${ChatColor.RED}${ChatColor.BOLD}Knife")
|
||||||
lore = listOf(
|
lore = listOf(
|
||||||
"",
|
"",
|
||||||
|
@ -31,23 +31,26 @@ object Knife: TTTItem, Buyable {
|
||||||
"${ChatColor.RED}Nur einmal verwendbar",
|
"${ChatColor.RED}Nur einmal verwendbar",
|
||||||
"${ChatColor.RED}Nur aus nächster Nähe"
|
"${ChatColor.RED}Nur aus nächster Nähe"
|
||||||
)
|
)
|
||||||
|
|
||||||
hideInfo()
|
hideInfo()
|
||||||
addAttributeModifier(
|
addAttributeModifier(
|
||||||
Attribute.GENERIC_ATTACK_SPEED, AttributeModifier(
|
Attribute.GENERIC_ATTACK_SPEED, AttributeModifier(
|
||||||
"_",
|
"_",
|
||||||
-0.9,
|
-0.9,
|
||||||
AttributeModifier.Operation.ADD_SCALAR
|
AttributeModifier.Operation.ADD_SCALAR
|
||||||
))
|
))
|
||||||
}
|
},
|
||||||
override val buyableBy = roles(Role.TRAITOR, Role.JACKAL)
|
shopInfo = ShopInfo(
|
||||||
override val price = 1
|
buyableBy = roles(Role.TRAITOR, Role.JACKAL),
|
||||||
override val type = TTTItem.Type.MELEE
|
price = 1,
|
||||||
override val buyLimit = 1
|
buyLimit = 1
|
||||||
|
),
|
||||||
|
disableDamage = false
|
||||||
|
) {
|
||||||
|
class Instance: TTTItem.Instance(Knife)
|
||||||
|
|
||||||
override val listener = object : TTTItemListener(this, false) {
|
override val listener = object : TTTItemListener<Instance>(this) {
|
||||||
@EventHandler(ignoreCancelled = true)
|
@EventHandler(ignoreCancelled = true)
|
||||||
override fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) = handle(event) { damagerTTTPlayer, damagedTTTPlayer ->
|
fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) = handle(event) { damagerTTTPlayer, damagedTTTPlayer ->
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
|
|
||||||
if (event.damage == 1.0) {
|
if (event.damage == 1.0) {
|
||||||
|
@ -77,7 +80,7 @@ object Knife: TTTItem, Buyable {
|
||||||
1F
|
1F
|
||||||
)
|
)
|
||||||
|
|
||||||
damagerTTTPlayer.player.inventory.removeTTTItemNextTick(Knife)
|
damagerTTTPlayer.removeItem(Knife)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,24 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.impl.weapons.guns
|
package de.moritzruth.spigot_ttt.game.items.impl.weapons.guns
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.items.Spawning
|
import de.moritzruth.spigot_ttt.utils.Probability
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
|
||||||
import de.moritzruth.spigot_ttt.utils.heartsToHealth
|
import de.moritzruth.spigot_ttt.utils.heartsToHealth
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
|
|
||||||
object Deagle: Gun(
|
object Deagle: Gun(
|
||||||
stateClass = State::class,
|
type = Type.PISTOL_LIKE,
|
||||||
|
instanceType = Instance::class,
|
||||||
|
spawnProbability = Probability.NORMAL,
|
||||||
displayName = "${ChatColor.BLUE}${ChatColor.BOLD}Deagle",
|
displayName = "${ChatColor.BLUE}${ChatColor.BOLD}Deagle",
|
||||||
damage = heartsToHealth(3.0),
|
damage = heartsToHealth(3.0),
|
||||||
cooldown = 1.4,
|
cooldown = 1.4,
|
||||||
magazineSize = 8,
|
magazineSize = 8,
|
||||||
reloadTime = 3.0,
|
reloadTime = 3.0,
|
||||||
itemMaterial = Resourcepack.Items.deagle,
|
material = Resourcepack.Items.deagle,
|
||||||
shootSound = Resourcepack.Sounds.Item.Weapon.Deagle.fire,
|
shootSound = Resourcepack.Sounds.Item.Weapon.Deagle.fire,
|
||||||
reloadSound = Resourcepack.Sounds.Item.Weapon.Deagle.reload
|
reloadSound = Resourcepack.Sounds.Item.Weapon.Deagle.reload
|
||||||
), Spawning {
|
) {
|
||||||
override val type = TTTItem.Type.PISTOL_LIKE
|
class Instance: Gun.Instance(Deagle)
|
||||||
|
|
||||||
class State: Gun.State(magazineSize)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,24 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.impl.weapons.guns
|
package de.moritzruth.spigot_ttt.game.items.impl.weapons.guns
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.items.Spawning
|
import de.moritzruth.spigot_ttt.utils.Probability
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
|
||||||
import de.moritzruth.spigot_ttt.utils.heartsToHealth
|
import de.moritzruth.spigot_ttt.utils.heartsToHealth
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
|
|
||||||
object Glock: Gun(
|
object Glock: Gun(
|
||||||
stateClass = State::class,
|
type = Type.PISTOL_LIKE,
|
||||||
|
instanceType = Instance::class,
|
||||||
displayName = "${ChatColor.YELLOW}${ChatColor.BOLD}Glock",
|
displayName = "${ChatColor.YELLOW}${ChatColor.BOLD}Glock",
|
||||||
damage = heartsToHealth(1.5),
|
damage = heartsToHealth(1.5),
|
||||||
|
spawnProbability = Probability.NORMAL,
|
||||||
cooldown = 0.3,
|
cooldown = 0.3,
|
||||||
magazineSize = 20,
|
magazineSize = 20,
|
||||||
reloadTime = 2.0,
|
reloadTime = 2.0,
|
||||||
itemMaterial = Resourcepack.Items.glock,
|
material = Resourcepack.Items.glock,
|
||||||
shootSound = Resourcepack.Sounds.Item.Weapon.Glock.fire,
|
shootSound = Resourcepack.Sounds.Item.Weapon.Glock.fire,
|
||||||
reloadSound = Resourcepack.Sounds.Item.Weapon.Glock.reload
|
reloadSound = Resourcepack.Sounds.Item.Weapon.Glock.reload
|
||||||
), Spawning {
|
) {
|
||||||
override val type = TTTItem.Type.PISTOL_LIKE
|
class Instance: Gun.Instance(Glock)
|
||||||
|
|
||||||
class State: Gun.State(magazineSize)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,89 +1,99 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.impl.weapons.guns
|
package de.moritzruth.spigot_ttt.game.items.impl.weapons.guns
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.GameEndEvent
|
|
||||||
import de.moritzruth.spigot_ttt.game.GameManager
|
import de.moritzruth.spigot_ttt.game.GameManager
|
||||||
import de.moritzruth.spigot_ttt.game.GamePhase
|
import de.moritzruth.spigot_ttt.game.items.ClickEvent
|
||||||
import de.moritzruth.spigot_ttt.game.items.*
|
import de.moritzruth.spigot_ttt.game.items.LoreHelper
|
||||||
import de.moritzruth.spigot_ttt.game.players.*
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
|
import de.moritzruth.spigot_ttt.game.players.DeathReason
|
||||||
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
||||||
|
import de.moritzruth.spigot_ttt.utils.Probability
|
||||||
import de.moritzruth.spigot_ttt.utils.applyMeta
|
import de.moritzruth.spigot_ttt.utils.applyMeta
|
||||||
import de.moritzruth.spigot_ttt.utils.nextTick
|
import de.moritzruth.spigot_ttt.utils.hideInfo
|
||||||
import de.moritzruth.spigot_ttt.utils.startItemDamageProgress
|
import de.moritzruth.spigot_ttt.utils.startProgressTask
|
||||||
import org.bukkit.*
|
import org.bukkit.*
|
||||||
import org.bukkit.entity.Item
|
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.event.EventHandler
|
|
||||||
import org.bukkit.inventory.ItemFlag
|
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.inventory.meta.Damageable
|
|
||||||
import org.bukkit.inventory.meta.ItemMeta
|
|
||||||
import org.bukkit.scheduler.BukkitTask
|
import org.bukkit.scheduler.BukkitTask
|
||||||
import java.time.Duration
|
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
typealias ClickAction = org.bukkit.event.block.Action
|
|
||||||
|
|
||||||
abstract class Gun(
|
abstract class Gun(
|
||||||
private val stateClass: KClass<out State>,
|
type: Type,
|
||||||
|
instanceType: KClass<out Instance>,
|
||||||
|
spawnProbability: Probability? = null,
|
||||||
|
shopInfo: ShopInfo? = null,
|
||||||
|
material: Material,
|
||||||
displayName: String,
|
displayName: String,
|
||||||
additionalLore: List<String>? = null,
|
itemLore: List<String>? = null,
|
||||||
|
appendLore: Boolean = true,
|
||||||
val damage: Double,
|
val damage: Double,
|
||||||
val cooldown: Double,
|
val cooldown: Double,
|
||||||
val magazineSize: Int,
|
val magazineSize: Int,
|
||||||
val reloadTime: Double,
|
val reloadTime: Double,
|
||||||
val itemMaterial: Material,
|
|
||||||
val shootSound: String,
|
val shootSound: String,
|
||||||
val reloadSound: String
|
val reloadSound: String
|
||||||
): TTTItem, Selectable, DropHandler {
|
): TTTItem<Gun.Instance>(
|
||||||
override val itemStack = ItemStack(itemMaterial).applyMeta {
|
type = type,
|
||||||
|
instanceType = instanceType,
|
||||||
|
spawnProbability = spawnProbability,
|
||||||
|
shopInfo = shopInfo,
|
||||||
|
templateItemStack = ItemStack(material).applyMeta {
|
||||||
setDisplayName(displayName)
|
setDisplayName(displayName)
|
||||||
lore = listOf(
|
lore =
|
||||||
"",
|
if (appendLore) listOf(
|
||||||
"${ChatColor.GRAY}Schaden: ${LoreHelper.damage(if (damage < 0) null else (damage / 2))}",
|
"",
|
||||||
"${ChatColor.GRAY}Cooldown: ${LoreHelper.cooldown(cooldown)}",
|
"${ChatColor.GRAY}Schaden: ${LoreHelper.damage(if (damage < 0) null else (damage / 2))}",
|
||||||
"${ChatColor.GRAY}Magazin: ${LoreHelper.uses(magazineSize)} Schuss"
|
"${ChatColor.GRAY}Cooldown: ${LoreHelper.cooldown(cooldown)}",
|
||||||
) + run {
|
"${ChatColor.GRAY}Magazin: ${LoreHelper.uses(magazineSize)} Schuss"
|
||||||
if (additionalLore == null) emptyList()
|
) + run {
|
||||||
else listOf("") + additionalLore
|
if (itemLore == null) emptyList()
|
||||||
|
else listOf("") + itemLore
|
||||||
|
}
|
||||||
|
else itemLore ?: emptyList()
|
||||||
|
|
||||||
|
hideInfo()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
open class Instance(val gun: Gun): TTTItem.Instance(gun) {
|
||||||
|
var currentAction: Action? = null
|
||||||
|
var remainingShots: Int = gun.magazineSize
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
setCarrierLevel()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setCarrierLevel() {
|
||||||
|
if (isSelected) carrier!!.player.level = remainingShots
|
||||||
}
|
}
|
||||||
|
|
||||||
addItemFlags(ItemFlag.HIDE_ATTRIBUTES)
|
private fun shoot() {
|
||||||
}
|
val tttPlayer = requireCarrier()
|
||||||
|
if (!onBeforeShoot()) return
|
||||||
|
|
||||||
val isc = InversedStateContainer(stateClass)
|
if (remainingShots == 0) {
|
||||||
|
GameManager.world.playSound(
|
||||||
|
tttPlayer.player.location,
|
||||||
|
Resourcepack.Sounds.Item.Weapon.Generic.emptyMagazine,
|
||||||
|
SoundCategory.PLAYERS,
|
||||||
|
1F,
|
||||||
|
1F
|
||||||
|
)
|
||||||
|
|
||||||
protected fun updateLevel(tttPlayer: TTTPlayer, state: State = isc.getOrCreate(tttPlayer)) {
|
return
|
||||||
tttPlayer.player.level = state.remainingShots
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fun shoot(tttPlayer: TTTPlayer, itemStack: ItemStack, state: State = isc.getOrCreate(tttPlayer)) {
|
GameManager.world.playSound(tttPlayer.player.location, gun.shootSound, SoundCategory.PLAYERS, 1F, 1F)
|
||||||
if (!onBeforeShoot(tttPlayer, itemStack, state)) return
|
|
||||||
|
|
||||||
if (state.remainingShots == 0) {
|
remainingShots--
|
||||||
GameManager.world.playSound(
|
|
||||||
tttPlayer.player.location,
|
|
||||||
Resourcepack.Sounds.Item.Weapon.Generic.emptyMagazine,
|
|
||||||
SoundCategory.PLAYERS,
|
|
||||||
1F,
|
|
||||||
1F
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
GameManager.world.playSound(tttPlayer.player.location, shootSound, SoundCategory.PLAYERS, 1F, 1F)
|
|
||||||
|
|
||||||
state.remainingShots--
|
|
||||||
updateLevel(tttPlayer)
|
|
||||||
|
|
||||||
if (GameManager.phase == GamePhase.COMBAT) {
|
|
||||||
val rayTraceResult = GameManager.world.rayTrace(
|
val rayTraceResult = GameManager.world.rayTrace(
|
||||||
tttPlayer.player.eyeLocation,
|
tttPlayer.player.eyeLocation,
|
||||||
tttPlayer.player.eyeLocation.direction,
|
tttPlayer.player.eyeLocation.direction,
|
||||||
200.0,
|
200.0,
|
||||||
FluidCollisionMode.ALWAYS,
|
FluidCollisionMode.ALWAYS,
|
||||||
true,
|
true,
|
||||||
0.01
|
0.01
|
||||||
) { it !== tttPlayer.player }
|
) { it !== tttPlayer.player }
|
||||||
|
|
||||||
if (rayTraceResult !== null) {
|
if (rayTraceResult !== null) {
|
||||||
|
@ -100,167 +110,124 @@ abstract class Gun(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentAction = Action.Cooldown(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
state.currentAction = Action.Cooldown(this, itemStack, state)
|
open fun reload() {
|
||||||
}
|
val carrier = requireCarrier()
|
||||||
|
if (currentAction != null) throw ActionInProgressError()
|
||||||
|
if (remainingShots == gun.magazineSize) return
|
||||||
|
|
||||||
open fun reload(tttPlayer: TTTPlayer, itemStack: ItemStack, state: State = isc.getOrCreate(tttPlayer)) {
|
currentAction = Action.Reloading(this)
|
||||||
if (state.currentAction != null) throw ActionInProgressError()
|
|
||||||
if (state.remainingShots == magazineSize) return
|
|
||||||
|
|
||||||
state.currentAction = Action.Reloading(this, itemStack, state, tttPlayer).also { it.start() }
|
GameManager.world.playSound(
|
||||||
|
carrier.player.location,
|
||||||
GameManager.world.playSound(tttPlayer.player.location, reloadSound, SoundCategory.PLAYERS, 1F, 1F)
|
gun.reloadSound,
|
||||||
}
|
SoundCategory.PLAYERS,
|
||||||
|
1F,
|
||||||
open fun computeActualDamage(tttPlayer: TTTPlayer, receiver: Player) = if (damage < 0 ) 1000.0 else damage
|
1F
|
||||||
|
)
|
||||||
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) {
|
|
||||||
val actualDamage = computeActualDamage(tttPlayer, hitTTTPlayer.player)
|
|
||||||
|
|
||||||
hitTTTPlayer.damage(actualDamage, DeathReason.Item(this), tttPlayer, true)
|
|
||||||
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) {
|
|
||||||
updateLevel(tttPlayer)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDeselect(tttPlayer: TTTPlayer) {
|
|
||||||
tttPlayer.player.level = 0
|
|
||||||
|
|
||||||
val state = isc.get(tttPlayer) ?: return
|
|
||||||
val currentAction = state.currentAction
|
|
||||||
|
|
||||||
if (currentAction is Action.Reloading) {
|
|
||||||
state.currentAction = null
|
|
||||||
currentAction.task.cancel()
|
|
||||||
|
|
||||||
val meta = currentAction.itemStack.itemMeta as Damageable
|
|
||||||
meta.damage = 0
|
|
||||||
currentAction.itemStack.itemMeta = meta as ItemMeta
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDrop(tttPlayer: TTTPlayer, itemEntity: Item): Boolean {
|
|
||||||
val state = isc.get(tttPlayer) ?: return true
|
|
||||||
|
|
||||||
when(val currentAction = state.currentAction) {
|
|
||||||
is Action.Reloading -> {
|
|
||||||
state.currentAction = null
|
|
||||||
currentAction.task.cancel()
|
|
||||||
}
|
|
||||||
is Action.Cooldown -> {
|
|
||||||
currentAction.pause()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
itemEntity.setItemStack(itemStack.clone())
|
open fun computeActualDamage(receiver: TTTPlayer): Double {
|
||||||
|
requireCarrier() // Only to keep parity with possible override
|
||||||
ItemManager.droppedItemStates[itemEntity.entityId] = state
|
return if (gun.damage < 0 ) 1000.0 else gun.damage
|
||||||
isc.remove(tttPlayer)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPickup(tttPlayer: TTTPlayer, itemEntity: Item) {
|
|
||||||
val state = ItemManager.droppedItemStates[itemEntity.entityId] as State?
|
|
||||||
|
|
||||||
if (state != null) {
|
|
||||||
tttPlayer.stateContainer.put(stateClass, state)
|
|
||||||
val currentAction = state.currentAction ?: return
|
|
||||||
|
|
||||||
nextTick { currentAction.itemStack = tttPlayer.player.inventory.find { it.type == itemEntity.itemStack.type }!!
|
|
||||||
|
|
||||||
if (currentAction is Action.Cooldown) {
|
|
||||||
currentAction.resume()
|
|
||||||
} }
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override val listener = object : TTTItemListener(this, true) {
|
/**
|
||||||
override fun onLeftClick(data: ClickEventData) {
|
* @return Whether the gun will really shoot
|
||||||
|
*/
|
||||||
|
open fun onBeforeShoot(): Boolean {
|
||||||
|
if (currentAction !== null) throw ActionInProgressError()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun onHit(tttPlayer: TTTPlayer, hitTTTPlayer: TTTPlayer) {
|
||||||
|
val actualDamage = computeActualDamage(hitTTTPlayer)
|
||||||
|
hitTTTPlayer.damage(actualDamage, DeathReason.Item(gun), tttPlayer, true)
|
||||||
|
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 onLeftClick(event: ClickEvent) {
|
||||||
try {
|
try {
|
||||||
reload(data.tttPlayer, data.event.item!!)
|
reload()
|
||||||
} catch (e: ActionInProgressError) {}
|
} catch (e: ActionInProgressError) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRightClick(data: ClickEventData) {
|
override fun onRightClick(event: ClickEvent) {
|
||||||
try {
|
try {
|
||||||
shoot(data.tttPlayer, data.event.item!!)
|
shoot()
|
||||||
} catch (e: ActionInProgressError) {}
|
} catch (e: ActionInProgressError) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
protected open fun onMovedOutOfHand(tttPlayer: TTTPlayer) {
|
||||||
fun onTTTPlayerDeath(event: TTTPlayerTrueDeathEvent) = isc.get(event.tttPlayer)?.reset()
|
tttPlayer.player.level = 0
|
||||||
|
tttPlayer.player.exp = 0F
|
||||||
|
|
||||||
@EventHandler
|
val action = currentAction
|
||||||
fun onGameEnd(event: GameEndEvent) = isc.forEveryState { state, _ -> state.reset() }
|
if (action is Action.Reloading) {
|
||||||
|
currentAction = null
|
||||||
|
action.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCarrierSet(carrier: TTTPlayer, isFirst: Boolean) {
|
||||||
|
setCarrierLevel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSelect() {
|
||||||
|
setCarrierLevel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCarrierRemoved(oldCarrier: TTTPlayer) {
|
||||||
|
onMovedOutOfHand(oldCarrier)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDeselect() {
|
||||||
|
onMovedOutOfHand(carrier!!)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ActionInProgressError: RuntimeException("The gun has an ongoing action which may not be canceled")
|
class ActionInProgressError: RuntimeException("The gun has an ongoing action")
|
||||||
|
|
||||||
abstract class State(magazineSize: Int): IState {
|
sealed class Action(val instance: Instance) {
|
||||||
var currentAction: Action? = null
|
|
||||||
var remainingShots = magazineSize
|
|
||||||
|
|
||||||
fun reset() { currentAction?.reset() }
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class Action(var itemStack: ItemStack) {
|
|
||||||
val startedAt = Instant.now()!!
|
val startedAt = Instant.now()!!
|
||||||
abstract var task: BukkitTask; protected set
|
abstract val task: BukkitTask
|
||||||
|
|
||||||
open fun reset() {
|
open fun cancel() {
|
||||||
task.cancel()
|
task.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
open class Reloading(
|
open class Reloading(instance: Instance): Action(instance) {
|
||||||
private val gun: Gun,
|
override val task = createProgressTask()
|
||||||
itemStack: ItemStack,
|
|
||||||
protected val state: State,
|
|
||||||
protected val tttPlayer: TTTPlayer
|
|
||||||
): Action(itemStack) {
|
|
||||||
override lateinit var task: BukkitTask
|
|
||||||
|
|
||||||
open fun start() {
|
protected open fun createProgressTask() = startProgressTask(instance.gun.reloadTime) { data ->
|
||||||
task = startItemDamageProgress(itemStack, gun.reloadTime) {
|
val exp = if (data.isComplete) {
|
||||||
state.currentAction = null
|
instance.remainingShots = instance.gun.magazineSize
|
||||||
state.remainingShots = gun.magazineSize
|
instance.currentAction = null
|
||||||
gun.updateLevel(tttPlayer, state)
|
0F
|
||||||
}
|
} else data.progress.toFloat()
|
||||||
|
if (instance.isSelected) instance.carrier!!.player.exp = exp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Cooldown(private val gun: Gun, itemStack: ItemStack, private val state: State): Action(itemStack) {
|
class Cooldown(instance: Instance): Action(instance) {
|
||||||
override var task = startTask()
|
override val task = startProgressTask(instance.gun.cooldown) { data ->
|
||||||
private var pausedProgress: Double? = null
|
val exp = if (data.isComplete) {
|
||||||
|
instance.currentAction = null
|
||||||
private fun startTask() = startItemDamageProgress(
|
0F
|
||||||
itemStack = itemStack,
|
} else data.progress.toFloat()
|
||||||
duration = gun.cooldown,
|
if (instance.isSelected) instance.carrier!!.player.exp = exp
|
||||||
startProgress = pausedProgress ?: 0.0
|
|
||||||
) {
|
|
||||||
state.currentAction = null
|
|
||||||
}
|
|
||||||
|
|
||||||
fun resume() {
|
|
||||||
if (task.isCancelled) task = startTask()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun pause() {
|
|
||||||
if (!task.isCancelled) {
|
|
||||||
task.cancel()
|
|
||||||
pausedProgress = (Duration.between(startedAt, Instant.now()).toMillis().toDouble() / 1000) / gun.cooldown
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,24 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.impl.weapons.guns
|
package de.moritzruth.spigot_ttt.game.items.impl.weapons.guns
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.items.Spawning
|
import de.moritzruth.spigot_ttt.utils.Probability
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
|
||||||
import de.moritzruth.spigot_ttt.utils.heartsToHealth
|
import de.moritzruth.spigot_ttt.utils.heartsToHealth
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
|
|
||||||
object Pistol: Gun(
|
object Pistol: Gun(
|
||||||
stateClass = State::class,
|
type = Type.PISTOL_LIKE,
|
||||||
|
instanceType = Instance::class,
|
||||||
|
spawnProbability = Probability.NORMAL,
|
||||||
displayName = "${ChatColor.YELLOW}${ChatColor.BOLD}Pistol",
|
displayName = "${ChatColor.YELLOW}${ChatColor.BOLD}Pistol",
|
||||||
damage = heartsToHealth(2.5),
|
damage = heartsToHealth(2.5),
|
||||||
cooldown = 0.8,
|
cooldown = 0.8,
|
||||||
magazineSize = 10,
|
magazineSize = 10,
|
||||||
reloadTime = 2.0,
|
reloadTime = 2.0,
|
||||||
itemMaterial = Resourcepack.Items.pistol,
|
material = Resourcepack.Items.pistol,
|
||||||
shootSound = Resourcepack.Sounds.Item.Weapon.Pistol.fire,
|
shootSound = Resourcepack.Sounds.Item.Weapon.Pistol.fire,
|
||||||
reloadSound = Resourcepack.Sounds.Item.Weapon.Pistol.reload
|
reloadSound = Resourcepack.Sounds.Item.Weapon.Pistol.reload
|
||||||
), Spawning {
|
) {
|
||||||
override val type = TTTItem.Type.PISTOL_LIKE
|
class Instance: Gun.Instance(Pistol)
|
||||||
|
|
||||||
class State: Gun.State(magazineSize)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,24 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.impl.weapons.guns
|
package de.moritzruth.spigot_ttt.game.items.impl.weapons.guns
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.items.Spawning
|
import de.moritzruth.spigot_ttt.utils.Probability
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
|
||||||
import de.moritzruth.spigot_ttt.utils.heartsToHealth
|
import de.moritzruth.spigot_ttt.utils.heartsToHealth
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
|
|
||||||
object Rifle: Gun(
|
object Rifle: Gun(
|
||||||
stateClass = State::class,
|
type = Type.HEAVY_WEAPON,
|
||||||
|
instanceType = Instance::class,
|
||||||
|
spawnProbability = Probability.NORMAL,
|
||||||
displayName = "${ChatColor.YELLOW}${ChatColor.BOLD}Rifle",
|
displayName = "${ChatColor.YELLOW}${ChatColor.BOLD}Rifle",
|
||||||
damage = heartsToHealth(0.8),
|
damage = heartsToHealth(0.8),
|
||||||
cooldown = 0.15,
|
cooldown = 0.15,
|
||||||
magazineSize = 40,
|
magazineSize = 40,
|
||||||
reloadTime = 2.0,
|
reloadTime = 2.0,
|
||||||
itemMaterial = Resourcepack.Items.rifle,
|
material = Resourcepack.Items.rifle,
|
||||||
shootSound = Resourcepack.Sounds.Item.Weapon.Rifle.fire,
|
shootSound = Resourcepack.Sounds.Item.Weapon.Rifle.fire,
|
||||||
reloadSound = Resourcepack.Sounds.Item.Weapon.Rifle.reload
|
reloadSound = Resourcepack.Sounds.Item.Weapon.Rifle.reload
|
||||||
), Spawning {
|
) {
|
||||||
override val type = TTTItem.Type.HEAVY_WEAPON
|
class Instance: Gun.Instance(Rifle)
|
||||||
|
|
||||||
class State: Gun.State(magazineSize)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,122 +2,99 @@ package de.moritzruth.spigot_ttt.game.items.impl.weapons.guns
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.GameManager
|
import de.moritzruth.spigot_ttt.game.GameManager
|
||||||
import de.moritzruth.spigot_ttt.game.items.Spawning
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
|
||||||
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
||||||
import de.moritzruth.spigot_ttt.plugin
|
import de.moritzruth.spigot_ttt.plugin
|
||||||
|
import de.moritzruth.spigot_ttt.utils.Probability
|
||||||
import de.moritzruth.spigot_ttt.utils.heartsToHealth
|
import de.moritzruth.spigot_ttt.utils.heartsToHealth
|
||||||
import de.moritzruth.spigot_ttt.utils.secondsToTicks
|
import de.moritzruth.spigot_ttt.utils.secondsToTicks
|
||||||
import de.moritzruth.spigot_ttt.utils.startItemDamageProgress
|
import de.moritzruth.spigot_ttt.utils.startProgressTask
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.SoundCategory
|
import org.bukkit.SoundCategory
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
import org.bukkit.inventory.meta.Damageable
|
|
||||||
import org.bukkit.inventory.meta.ItemMeta
|
|
||||||
import org.bukkit.scheduler.BukkitTask
|
import org.bukkit.scheduler.BukkitTask
|
||||||
|
|
||||||
private const val RELOAD_TIME_PER_BULLET = 0.5
|
private const val RELOAD_TIME_PER_BULLET = 0.5
|
||||||
private const val MAGAZINE_SIZE = 8
|
private const val MAGAZINE_SIZE = 8
|
||||||
|
|
||||||
object Shotgun: Gun(
|
object Shotgun: Gun(
|
||||||
stateClass = State::class,
|
type = Type.HEAVY_WEAPON,
|
||||||
|
instanceType = Instance::class,
|
||||||
|
spawnProbability = Probability.LOW,
|
||||||
displayName = "${ChatColor.YELLOW}${ChatColor.BOLD}Shotgun",
|
displayName = "${ChatColor.YELLOW}${ChatColor.BOLD}Shotgun",
|
||||||
damage = heartsToHealth(3.0),
|
damage = heartsToHealth(3.0),
|
||||||
cooldown = 0.9,
|
cooldown = 0.9,
|
||||||
magazineSize = MAGAZINE_SIZE,
|
magazineSize = MAGAZINE_SIZE,
|
||||||
reloadTime = RELOAD_TIME_PER_BULLET * MAGAZINE_SIZE,
|
reloadTime = RELOAD_TIME_PER_BULLET * MAGAZINE_SIZE,
|
||||||
itemMaterial = Resourcepack.Items.shotgun,
|
material = Resourcepack.Items.shotgun,
|
||||||
additionalLore = listOf("${ChatColor.RED}Weniger Schaden auf Distanz"),
|
itemLore = listOf("${ChatColor.RED}Weniger Schaden auf Distanz"),
|
||||||
shootSound = Resourcepack.Sounds.Item.Weapon.Shotgun.fire,
|
shootSound = Resourcepack.Sounds.Item.Weapon.Shotgun.fire,
|
||||||
reloadSound = Resourcepack.Sounds.Item.Weapon.Shotgun.reload
|
reloadSound = Resourcepack.Sounds.Item.Weapon.Shotgun.reload
|
||||||
), Spawning {
|
) {
|
||||||
override val type = TTTItem.Type.HEAVY_WEAPON
|
class Instance: Gun.Instance(Shotgun) {
|
||||||
|
override fun computeActualDamage(receiver: TTTPlayer): Double {
|
||||||
|
val distance = requireCarrier().player.location.distance(receiver.player.location)
|
||||||
|
|
||||||
override fun computeActualDamage(tttPlayer: TTTPlayer, receiver: Player): Double {
|
return when {
|
||||||
val distance = tttPlayer.player.location.distance(receiver.location)
|
distance <= 1 -> heartsToHealth(10.0)
|
||||||
|
distance >= 14 -> 0.5
|
||||||
return when {
|
distance > 8 -> heartsToHealth(1.5)
|
||||||
distance <= 1 -> heartsToHealth(10.0)
|
else -> heartsToHealth(damage)
|
||||||
distance >= 14 -> 0.5
|
|
||||||
distance > 8 -> heartsToHealth(1.5)
|
|
||||||
else -> heartsToHealth(damage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDeselect(tttPlayer: TTTPlayer) {
|
|
||||||
tttPlayer.player.level = 0
|
|
||||||
val state = (isc.get(tttPlayer) ?: return) as State
|
|
||||||
|
|
||||||
val currentAction = state.currentAction
|
|
||||||
|
|
||||||
if (currentAction is ReloadingAction) {
|
|
||||||
state.currentAction = null
|
|
||||||
currentAction.task.cancel()
|
|
||||||
currentAction.updateTask.cancel()
|
|
||||||
|
|
||||||
val meta = currentAction.itemStack.itemMeta as Damageable
|
|
||||||
meta.damage = 0
|
|
||||||
currentAction.itemStack.itemMeta = meta as ItemMeta
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun reload(tttPlayer: TTTPlayer, itemStack: ItemStack, state: Gun.State) {
|
|
||||||
val ownState = state as State
|
|
||||||
if (ownState.currentAction != null) throw ActionInProgressError()
|
|
||||||
if (ownState.remainingShots == magazineSize) return
|
|
||||||
|
|
||||||
ownState.currentAction = ReloadingAction(itemStack, ownState, tttPlayer).also { it.start() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBeforeShoot(tttPlayer: TTTPlayer, item: ItemStack, state: Gun.State): Boolean {
|
|
||||||
val ownState = state as State
|
|
||||||
if (ownState.remainingShots == 0) return true
|
|
||||||
|
|
||||||
when(val currentAction = ownState.currentAction) {
|
|
||||||
is Action.Cooldown -> throw ActionInProgressError()
|
|
||||||
is ReloadingAction -> {
|
|
||||||
currentAction.reset()
|
|
||||||
ownState.currentAction = null
|
|
||||||
|
|
||||||
val damageMeta = item.itemMeta!! as Damageable
|
|
||||||
damageMeta.damage = 0
|
|
||||||
item.itemMeta = damageMeta as ItemMeta
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
override fun onMovedOutOfHand(tttPlayer: TTTPlayer) {
|
||||||
}
|
tttPlayer.player.level = 0
|
||||||
|
tttPlayer.player.exp = 0F
|
||||||
|
|
||||||
class State: Gun.State(magazineSize)
|
val action = currentAction
|
||||||
|
if (action is ReloadingAction) {
|
||||||
private class ReloadingAction(itemStack: ItemStack, state: State, tttPlayer: TTTPlayer): Action.Reloading(Shotgun, itemStack, state, tttPlayer) {
|
currentAction = null
|
||||||
lateinit var updateTask: BukkitTask
|
action.cancel()
|
||||||
|
}
|
||||||
override fun reset() {
|
|
||||||
task.cancel()
|
|
||||||
updateTask.cancel()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun start() {
|
override fun reload() {
|
||||||
task = startItemDamageProgress(
|
if (currentAction != null) throw ActionInProgressError()
|
||||||
itemStack,
|
if (remainingShots == magazineSize) return
|
||||||
reloadTime,
|
currentAction = ReloadingAction(this)
|
||||||
state.remainingShots.toDouble() / magazineSize
|
}
|
||||||
) { state.currentAction = null }
|
|
||||||
|
|
||||||
|
override fun onBeforeShoot(): Boolean {
|
||||||
|
if (remainingShots == 0) return true
|
||||||
|
|
||||||
|
when(val action = currentAction) {
|
||||||
|
is Action.Cooldown -> throw ActionInProgressError()
|
||||||
|
is ReloadingAction -> action.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ReloadingAction(instance: Instance): Action.Reloading(instance) {
|
||||||
|
override fun createProgressTask(): BukkitTask = startProgressTask(
|
||||||
|
instance.gun.reloadTime,
|
||||||
|
startAt = instance.remainingShots.toDouble() / instance.gun.magazineSize
|
||||||
|
) { data ->
|
||||||
|
val exp = if (data.isComplete) {
|
||||||
|
instance.currentAction = null
|
||||||
|
0F
|
||||||
|
} else data.progress.toFloat()
|
||||||
|
if (instance.isSelected) instance.carrier!!.player.exp = exp
|
||||||
|
}
|
||||||
|
|
||||||
|
private var updateTask: BukkitTask? = null
|
||||||
|
|
||||||
|
init {
|
||||||
updateTask = plugin.server.scheduler.runTaskTimer(plugin, fun() {
|
updateTask = plugin.server.scheduler.runTaskTimer(plugin, fun() {
|
||||||
state.remainingShots++
|
instance.remainingShots++
|
||||||
updateLevel(tttPlayer)
|
GameManager.world.playSound(instance.carrier!!.player.location, reloadSound, SoundCategory.PLAYERS, 1F, 1F)
|
||||||
|
if (instance.remainingShots == magazineSize) updateTask?.cancel()
|
||||||
|
}, secondsToTicks(RELOAD_TIME_PER_BULLET).toLong(), secondsToTicks(RELOAD_TIME_PER_BULLET).toLong())
|
||||||
|
}
|
||||||
|
|
||||||
GameManager.world.playSound(tttPlayer.player.location, reloadSound, SoundCategory.PLAYERS, 1F, 1F)
|
override fun cancel() {
|
||||||
|
task.cancel()
|
||||||
if (state.remainingShots == magazineSize) {
|
updateTask?.cancel()
|
||||||
this.updateTask.cancel()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
secondsToTicks(RELOAD_TIME_PER_BULLET).toLong(),
|
|
||||||
secondsToTicks(RELOAD_TIME_PER_BULLET).toLong())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,74 +1,55 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.impl.weapons.guns
|
package de.moritzruth.spigot_ttt.game.items.impl.weapons.guns
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Resourcepack
|
import de.moritzruth.spigot_ttt.Resourcepack
|
||||||
import de.moritzruth.spigot_ttt.game.items.Buyable
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
|
||||||
import de.moritzruth.spigot_ttt.game.players.Role
|
import de.moritzruth.spigot_ttt.game.players.Role
|
||||||
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
||||||
import de.moritzruth.spigot_ttt.game.players.roles
|
import de.moritzruth.spigot_ttt.game.players.roles
|
||||||
import de.moritzruth.spigot_ttt.utils.applyMeta
|
|
||||||
import de.moritzruth.spigot_ttt.utils.hideInfo
|
|
||||||
import de.moritzruth.spigot_ttt.utils.sendActionBarMessage
|
import de.moritzruth.spigot_ttt.utils.sendActionBarMessage
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.entity.Item
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
|
|
||||||
object SidekickDeagle: Gun(
|
object SidekickDeagle: Gun(
|
||||||
stateClass = State::class,
|
type = Type.SPECIAL,
|
||||||
|
instanceType = Instance::class,
|
||||||
|
shopInfo = ShopInfo(
|
||||||
|
buyableBy = roles(Role.JACKAL),
|
||||||
|
buyLimit = 1,
|
||||||
|
price = 1
|
||||||
|
),
|
||||||
displayName = "${ChatColor.AQUA}${ChatColor.BOLD}Sidekick Deagle",
|
displayName = "${ChatColor.AQUA}${ChatColor.BOLD}Sidekick Deagle",
|
||||||
|
itemLore = listOf(
|
||||||
|
"",
|
||||||
|
"${ChatColor.GOLD}Mache einen Spieler zu deinem Sidekick",
|
||||||
|
"",
|
||||||
|
"${ChatColor.RED}Nur ein Schuss"
|
||||||
|
),
|
||||||
|
appendLore = false,
|
||||||
damage = 0.1, // Not really
|
damage = 0.1, // Not really
|
||||||
cooldown = 1.0,
|
cooldown = 1.0,
|
||||||
magazineSize = 1,
|
magazineSize = 1,
|
||||||
reloadTime = 0.0,
|
reloadTime = 0.0,
|
||||||
itemMaterial = Resourcepack.Items.sidekickDeagle,
|
material = Resourcepack.Items.sidekickDeagle,
|
||||||
shootSound = Resourcepack.Sounds.Item.Weapon.Deagle.fire,
|
shootSound = Resourcepack.Sounds.Item.Weapon.Deagle.fire,
|
||||||
reloadSound = Resourcepack.Sounds.Item.Weapon.Deagle.reload
|
reloadSound = Resourcepack.Sounds.Item.Weapon.Deagle.reload
|
||||||
), Buyable {
|
) {
|
||||||
override val buyableBy = roles(Role.JACKAL)
|
class Instance: Gun.Instance(SidekickDeagle) {
|
||||||
override val price = 1
|
override fun reload() {
|
||||||
override val type = TTTItem.Type.PISTOL_LIKE
|
requireCarrier().player.sendActionBarMessage("${ChatColor.RED}Du kannst diese Waffe nicht nachladen")
|
||||||
override val buyLimit = 1
|
|
||||||
|
|
||||||
override val itemStack = ItemStack(Resourcepack.Items.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) {
|
|
||||||
tttPlayer.player.sendActionBarMessage("${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) {
|
|
||||||
tttPlayer.player.sendActionBarMessage("${ChatColor.RED}Diese Waffe kann nur der Jackal benutzen")
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.onBeforeShoot(tttPlayer, item, state)
|
override fun onHit(tttPlayer: TTTPlayer, hitTTTPlayer: TTTPlayer) {
|
||||||
}
|
hitTTTPlayer.changeRole(Role.SIDEKICK)
|
||||||
|
}
|
||||||
|
|
||||||
class State: Gun.State(magazineSize)
|
override fun onBeforeShoot(): Boolean {
|
||||||
|
val tttPlayer = requireCarrier()
|
||||||
|
if (tttPlayer.role != Role.JACKAL) {
|
||||||
|
tttPlayer.player.sendActionBarMessage("${ChatColor.RED}Diese Waffe kann nur der Jackal benutzen")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onBeforeShoot()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.shop
|
package de.moritzruth.spigot_ttt.game.items.shop
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.Buyable
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.ItemManager
|
import de.moritzruth.spigot_ttt.game.items.ItemManager
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
||||||
|
@ -16,7 +15,9 @@ object Shop {
|
||||||
}.toList()
|
}.toList()
|
||||||
private val ITEMS_PER_PAGE = SHOP_SLOTS.count()
|
private val ITEMS_PER_PAGE = SHOP_SLOTS.count()
|
||||||
|
|
||||||
private 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.shopInfo?.run { buyableBy.contains(tttPlayer.role) } ?: false }
|
||||||
|
.toSet()
|
||||||
|
|
||||||
fun setItems(tttPlayer: TTTPlayer) {
|
fun setItems(tttPlayer: TTTPlayer) {
|
||||||
clear(tttPlayer)
|
clear(tttPlayer)
|
||||||
|
@ -26,12 +27,12 @@ object Shop {
|
||||||
if (!itemsIterator.hasNext()) break
|
if (!itemsIterator.hasNext()) break
|
||||||
|
|
||||||
val tttItem = itemsIterator.next()
|
val tttItem = itemsIterator.next()
|
||||||
if (tttItem !is Buyable) throw Error("Item is not buyable")
|
val shopInfo = tttItem.shopInfo!!
|
||||||
|
|
||||||
tttPlayer.player.inventory.setItem(index, tttItem.itemStack.clone().applyMeta {
|
tttPlayer.player.inventory.setItem(index, tttItem.templateItemStack.clone().applyMeta {
|
||||||
val displayNameSuffix =
|
val displayNameSuffix =
|
||||||
if (isOutOfStock(tttPlayer, tttItem)) "${ChatColor.RED}Ausverkauft"
|
if (isOutOfStock(tttPlayer, tttItem)) "${ChatColor.RED}Ausverkauft"
|
||||||
else "$${tttItem.price}"
|
else "$${shopInfo.price}"
|
||||||
|
|
||||||
setDisplayName("$displayName${ChatColor.RESET} - ${ChatColor.BOLD}$displayNameSuffix")
|
setDisplayName("$displayName${ChatColor.RESET} - ${ChatColor.BOLD}$displayNameSuffix")
|
||||||
})
|
})
|
||||||
|
@ -42,8 +43,8 @@ object Shop {
|
||||||
for(index in 9..35) tttPlayer.player.inventory.clear(index) // All slots except the hotbar and armor
|
for(index in 9..35) tttPlayer.player.inventory.clear(index) // All slots except the hotbar and armor
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isOutOfStock(tttPlayer: TTTPlayer, tttItem: TTTItem): Boolean {
|
fun isOutOfStock(tttPlayer: TTTPlayer, tttItem: TTTItem<*>): Boolean {
|
||||||
if (tttItem !is Buyable) throw Error("Item is not buyable")
|
val shopInfo = tttItem.shopInfo ?: throw Error("Item is not buyable")
|
||||||
return tttItem.buyLimit != null && tttPlayer.boughtItems.filter { it == tttItem }.count() >= tttItem.buyLimit!!
|
return shopInfo.buyLimit != 0 && tttPlayer.boughtItems.filter { it == tttItem }.count() >= shopInfo.buyLimit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,21 @@
|
||||||
package de.moritzruth.spigot_ttt.game.items.shop
|
package de.moritzruth.spigot_ttt.game.items.shop
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.Settings
|
import de.moritzruth.spigot_ttt.Settings
|
||||||
import de.moritzruth.spigot_ttt.game.items.Buyable
|
import de.moritzruth.spigot_ttt.game.GameListener
|
||||||
import de.moritzruth.spigot_ttt.game.items.ItemManager
|
import de.moritzruth.spigot_ttt.game.items.ItemManager
|
||||||
import de.moritzruth.spigot_ttt.game.players.PlayerManager
|
import de.moritzruth.spigot_ttt.game.players.PlayerManager
|
||||||
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayer
|
||||||
import de.moritzruth.spigot_ttt.game.players.TTTPlayerTrueDeathEvent
|
import de.moritzruth.spigot_ttt.game.players.TTTPlayerTrueDeathEvent
|
||||||
import de.moritzruth.spigot_ttt.utils.sendActionBarMessage
|
import de.moritzruth.spigot_ttt.utils.sendActionBarMessage
|
||||||
import org.bukkit.ChatColor
|
import org.bukkit.ChatColor
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
import org.bukkit.event.Listener
|
|
||||||
import org.bukkit.event.inventory.ClickType
|
import org.bukkit.event.inventory.ClickType
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent
|
import org.bukkit.event.inventory.InventoryClickEvent
|
||||||
|
|
||||||
object ShopListener: Listener {
|
object ShopListener: GameListener() {
|
||||||
@EventHandler(ignoreCancelled = true)
|
@EventHandler(ignoreCancelled = true)
|
||||||
fun onInventoryClick(event: InventoryClickEvent) {
|
fun onInventoryClick(event: InventoryClickEvent) = handle(event) { tttPlayer ->
|
||||||
if (event.whoClicked !is Player) return
|
if (event.click === ClickType.CREATIVE || event.clickedInventory?.holder != event.whoClicked) return@handle
|
||||||
val tttPlayer = TTTPlayer.of(event.whoClicked as Player) ?: return
|
|
||||||
|
|
||||||
if (event.click === ClickType.CREATIVE || event.clickedInventory?.holder != event.whoClicked) return
|
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
|
|
||||||
val itemStack = event.currentItem
|
val itemStack = event.currentItem
|
||||||
|
@ -30,21 +25,21 @@ object ShopListener: Listener {
|
||||||
event.clickedInventory?.holder == tttPlayer.player &&
|
event.clickedInventory?.holder == tttPlayer.player &&
|
||||||
Shop.SHOP_SLOTS.contains(event.slot)
|
Shop.SHOP_SLOTS.contains(event.slot)
|
||||||
) {
|
) {
|
||||||
val tttItem = ItemManager.getItemByItemStack(itemStack)
|
val tttItem = ItemManager.getTTTItemByItemStack(itemStack) ?: return@handle
|
||||||
if (tttItem === null || tttItem !is Buyable || !tttItem.buyableBy.contains(tttPlayer.role)) return
|
val shopMeta = tttItem.shopInfo
|
||||||
|
if (shopMeta == null || !shopMeta.buyableBy.contains(tttPlayer.role)) return@handle
|
||||||
|
|
||||||
when {
|
when {
|
||||||
Shop.isOutOfStock(tttPlayer, tttItem) ->
|
Shop.isOutOfStock(tttPlayer, tttItem) ->
|
||||||
tttPlayer.player.sendActionBarMessage("${ChatColor.RED}Dieses Item ist ausverkauft")
|
tttPlayer.player.sendActionBarMessage("${ChatColor.RED}Dieses Item ist ausverkauft")
|
||||||
|
|
||||||
tttPlayer.credits < tttItem.price ->
|
tttPlayer.credits < tttItem.shopInfo.price ->
|
||||||
tttPlayer.player.sendActionBarMessage("${ChatColor.RED}Du hast nicht genug Credits")
|
tttPlayer.player.sendActionBarMessage("${ChatColor.RED}Du hast nicht genug Credits")
|
||||||
|
|
||||||
else -> try {
|
else -> try {
|
||||||
tttPlayer.addItem(tttItem)
|
tttPlayer.addItem(tttItem)
|
||||||
tttPlayer.boughtItems.add(tttItem)
|
tttPlayer.boughtItems.add(tttItem)
|
||||||
tttPlayer.credits -= tttItem.price
|
tttPlayer.credits -= shopMeta.price
|
||||||
|
|
||||||
Shop.setItems(tttPlayer)
|
Shop.setItems(tttPlayer)
|
||||||
} catch (e: TTTPlayer.AlreadyHasItemException) {
|
} catch (e: TTTPlayer.AlreadyHasItemException) {
|
||||||
tttPlayer.player.sendActionBarMessage("${ChatColor.RED}Du hast dieses Item bereits")
|
tttPlayer.player.sendActionBarMessage("${ChatColor.RED}Du hast dieses Item bereits")
|
||||||
|
@ -63,8 +58,9 @@ object ShopListener: Listener {
|
||||||
PlayerManager.tttPlayers
|
PlayerManager.tttPlayers
|
||||||
.filter { it.role.canOwnCredits && it.role.group == killer.role.group }
|
.filter { it.role.canOwnCredits && it.role.group == killer.role.group }
|
||||||
.forEach {
|
.forEach {
|
||||||
it.credits += Settings.creditsPerKill
|
val creditsPerKill = Settings.creditsPerKill
|
||||||
it.player.sendActionBarMessage("${ChatColor.GREEN}Du hast ${Settings.creditsPerKill} Credit(s) erhalten")
|
it.credits += creditsPerKill
|
||||||
|
it.player.sendActionBarMessage("${ChatColor.GREEN}Du hast $creditsPerKill Credit(s) erhalten")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,5 +10,5 @@ sealed class DeathReason(val displayText: String) {
|
||||||
object DROWNED: DeathReason("Ertrunken")
|
object DROWNED: DeathReason("Ertrunken")
|
||||||
object FIRE: DeathReason("Verbrannt")
|
object FIRE: DeathReason("Verbrannt")
|
||||||
object POISON: DeathReason("Vergiftet")
|
object POISON: DeathReason("Vergiftet")
|
||||||
class Item(val item: TTTItem): DeathReason("Getötet mit: ${item.itemStack.itemMeta!!.displayName}")
|
class Item(val item: TTTItem<*>): DeathReason("Getötet mit: ${item.templateItemStack.itemMeta!!.displayName}")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
package de.moritzruth.spigot_ttt.game.players
|
|
||||||
|
|
||||||
import com.google.common.collect.MutableClassToInstanceMap
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
import kotlin.reflect.KVisibility
|
|
||||||
|
|
||||||
interface IState
|
|
||||||
|
|
||||||
class StateContainer(private val tttPlayer: TTTPlayer) {
|
|
||||||
private val instances = MutableClassToInstanceMap.create<IState>()
|
|
||||||
|
|
||||||
fun <T: IState> getOrCreate(stateClass: KClass<T>): T =
|
|
||||||
get(stateClass) ?: run {
|
|
||||||
val parameterlessConstructor = stateClass.constructors
|
|
||||||
.find { it.parameters.isEmpty() && it.visibility == KVisibility.PUBLIC }
|
|
||||||
?: throw NoSuchMethodException("The stateClass has no public parameterless constructor")
|
|
||||||
|
|
||||||
parameterlessConstructor.call().also { instances[stateClass.java] = it }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T: IState> get(stateClass: KClass<T>): T? = instances.getInstance(stateClass.java)
|
|
||||||
|
|
||||||
fun <T: IState> has(stateClass: KClass<T>): Boolean = instances.containsKey(stateClass.java)
|
|
||||||
|
|
||||||
fun <T: IState> put(stateClass: KClass<out T>, value: T) {
|
|
||||||
if (instances.containsKey(stateClass.java))
|
|
||||||
throw IllegalStateException("There is already a state instance in this container")
|
|
||||||
|
|
||||||
instances[stateClass.java] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T: IState> remove(stateClass: KClass<T>) = instances.remove(stateClass.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
class InversedStateContainer<T: IState>(private val stateClass: KClass<T>) {
|
|
||||||
fun getOrCreate(tttPlayer: TTTPlayer) = tttPlayer.stateContainer.getOrCreate(stateClass)
|
|
||||||
fun get(tttPlayer: TTTPlayer) = tttPlayer.stateContainer.get(stateClass)
|
|
||||||
fun remove(tttPlayer: TTTPlayer) = tttPlayer.stateContainer.remove(stateClass)
|
|
||||||
|
|
||||||
val tttPlayers get() = PlayerManager.tttPlayers.filter { it.stateContainer.has(stateClass) }
|
|
||||||
|
|
||||||
fun forEveryState(fn: (T, TTTPlayer) -> Unit) {
|
|
||||||
tttPlayers.forEach { it.stateContainer.get(stateClass)?.run { fn(this, it) } }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,20 +7,25 @@ import de.moritzruth.spigot_ttt.game.GameManager
|
||||||
import de.moritzruth.spigot_ttt.game.GamePhase
|
import de.moritzruth.spigot_ttt.game.GamePhase
|
||||||
import de.moritzruth.spigot_ttt.game.ScoreboardHelper
|
import de.moritzruth.spigot_ttt.game.ScoreboardHelper
|
||||||
import de.moritzruth.spigot_ttt.game.classes.TTTClass
|
import de.moritzruth.spigot_ttt.game.classes.TTTClass
|
||||||
|
import de.moritzruth.spigot_ttt.game.classes.TTTClassCompanion
|
||||||
import de.moritzruth.spigot_ttt.game.corpses.TTTCorpse
|
import de.moritzruth.spigot_ttt.game.corpses.TTTCorpse
|
||||||
import de.moritzruth.spigot_ttt.game.items.ItemManager
|
import de.moritzruth.spigot_ttt.game.items.ItemManager
|
||||||
import de.moritzruth.spigot_ttt.game.items.Selectable
|
|
||||||
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
import de.moritzruth.spigot_ttt.game.items.TTTItem
|
||||||
import de.moritzruth.spigot_ttt.game.items.shop.Shop
|
import de.moritzruth.spigot_ttt.game.items.shop.Shop
|
||||||
import de.moritzruth.spigot_ttt.utils.*
|
import de.moritzruth.spigot_ttt.utils.*
|
||||||
import org.bukkit.*
|
import org.bukkit.ChatColor
|
||||||
|
import org.bukkit.GameMode
|
||||||
|
import org.bukkit.Location
|
||||||
|
import org.bukkit.SoundCategory
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
class TTTPlayer(player: Player, role: Role, val tttClass: TTTClass = TTTClass.None) {
|
class TTTPlayer(player: Player, role: Role, val tttClass: TTTClassCompanion = TTTClass.None) {
|
||||||
var alive = true
|
var alive = true
|
||||||
var player by Delegates.observable(player) { _, _, _ -> adjustPlayer() }
|
var player by Delegates.observable(player) { _, _, _ -> adjustPlayer() }
|
||||||
|
|
||||||
|
val tttClassInstance = tttClass.createInstance(this)
|
||||||
|
|
||||||
var role = role
|
var role = role
|
||||||
private set(value) {
|
private set(value) {
|
||||||
if (value !== field) {
|
if (value !== field) {
|
||||||
|
@ -33,34 +38,20 @@ class TTTPlayer(player: Player, role: Role, val tttClass: TTTClass = TTTClass.No
|
||||||
}
|
}
|
||||||
val roleHistory = mutableListOf<Role>()
|
val roleHistory = mutableListOf<Role>()
|
||||||
|
|
||||||
var itemInHand by Delegates.observable<TTTItem?>(null) { _, oldItem, newItem ->
|
|
||||||
if (oldItem !== newItem) onItemInHandChanged(oldItem, newItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
var walkSpeed
|
var walkSpeed
|
||||||
get() = player.walkSpeed
|
get() = player.walkSpeed
|
||||||
set(value) { player.walkSpeed = value }
|
set(value) { player.walkSpeed = value }
|
||||||
|
|
||||||
var credits by Delegates.observable(Settings.initialCredits) { _, _, _ -> scoreboard.updateCredits() }
|
var credits by Delegates.observable(Settings.initialCredits) { _, _, _ -> scoreboard.updateCredits() }
|
||||||
val boughtItems = mutableListOf<TTTItem>()
|
val boughtItems = mutableListOf<TTTItem<*>>()
|
||||||
|
|
||||||
val scoreboard = TTTScoreboard(this)
|
val scoreboard = TTTScoreboard(this)
|
||||||
val stateContainer = StateContainer(this)
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
adjustPlayer()
|
adjustPlayer()
|
||||||
scoreboard.initialize()
|
scoreboard.initialize()
|
||||||
tttClass.onInit(this)
|
tttClassInstance.tttPlayer = this
|
||||||
}
|
tttClassInstance.init()
|
||||||
|
|
||||||
private fun onItemInHandChanged(oldItem: TTTItem?, newItem: TTTItem?) {
|
|
||||||
if (oldItem !== null && oldItem is Selectable) {
|
|
||||||
oldItem.onDeselect(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newItem !== null && newItem is Selectable) {
|
|
||||||
newItem.onSelect(this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun damage(damage: Double, reason: DeathReason, damager: TTTPlayer, scream: Boolean = true) {
|
fun damage(damage: Double, reason: DeathReason, damager: TTTPlayer, scream: Boolean = true) {
|
||||||
|
@ -159,7 +150,9 @@ class TTTPlayer(player: Player, role: Role, val tttClass: TTTClass = TTTClass.No
|
||||||
player.scoreboard = scoreboard.scoreboard
|
player.scoreboard = scoreboard.scoreboard
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getOwningTTTItems() = player.inventory.hotbarContents.mapNotNull { it?.run { ItemManager.getItemByItemStack(this) } }
|
fun getOwningTTTItemInstances() = player.inventory.hotbarContents
|
||||||
|
.filterNotNull()
|
||||||
|
.mapNotNull { ItemManager.getInstanceByItemStack(it) }
|
||||||
|
|
||||||
fun changeRole(newRole: Role, notify: Boolean = true) {
|
fun changeRole(newRole: Role, notify: Boolean = true) {
|
||||||
roleHistory.add(role)
|
roleHistory.add(role)
|
||||||
|
@ -194,12 +187,6 @@ class TTTPlayer(player: Player, role: Role, val tttClass: TTTClass = TTTClass.No
|
||||||
player.spigot().respawn()
|
player.spigot().respawn()
|
||||||
}
|
}
|
||||||
|
|
||||||
itemInHand?.let {
|
|
||||||
if (it is Selectable) {
|
|
||||||
it.onDeselect(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
player.gameMode = GameMode.SURVIVAL
|
player.gameMode = GameMode.SURVIVAL
|
||||||
player.activePotionEffects.forEach { player.removePotionEffect(it.type) }
|
player.activePotionEffects.forEach { player.removePotionEffect(it.type) }
|
||||||
player.health = 20.0
|
player.health = 20.0
|
||||||
|
@ -208,44 +195,39 @@ class TTTPlayer(player: Player, role: Role, val tttClass: TTTClass = TTTClass.No
|
||||||
player.exp = 0F
|
player.exp = 0F
|
||||||
player.allowFlight = player.gameMode == GameMode.CREATIVE
|
player.allowFlight = player.gameMode == GameMode.CREATIVE
|
||||||
player.foodLevel = 20
|
player.foodLevel = 20
|
||||||
|
|
||||||
player.inventory.clear()
|
player.inventory.clear()
|
||||||
|
|
||||||
|
tttClassInstance.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateItemInHand() {
|
fun checkAddItemPreconditions(tttItem: TTTItem<*>) {
|
||||||
val itemStack = player.inventory.itemInMainHand
|
val owningTTTItemInstances = getOwningTTTItemInstances()
|
||||||
this.itemInHand =
|
if (owningTTTItemInstances.find { it.tttItem === tttItem } != null) throw AlreadyHasItemException()
|
||||||
if (itemStack.type === Material.AIR) null
|
|
||||||
else ItemManager.getItemByItemStack(itemStack)
|
val maxItemsOfTypeInInventory = tttItem.type.maxItemsOfTypeInInventory
|
||||||
|
if (
|
||||||
|
maxItemsOfTypeInInventory != null &&
|
||||||
|
owningTTTItemInstances.filter { it.tttItem.type == tttItem.type }.count() >= maxItemsOfTypeInInventory
|
||||||
|
) throw TooManyItemsOfTypeException()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkAddItemPreconditions(item: TTTItem) {
|
|
||||||
val owningTTTItems = getOwningTTTItems()
|
|
||||||
|
|
||||||
if (owningTTTItems.contains(item)) {
|
|
||||||
throw AlreadyHasItemException()
|
|
||||||
}
|
|
||||||
|
|
||||||
val maxItemsOfTypeInInventory = item.type.maxItemsOfTypeInInventory
|
|
||||||
if (maxItemsOfTypeInInventory !== null && owningTTTItems.filter { it.type === item.type }.count() >= maxItemsOfTypeInInventory) {
|
|
||||||
throw TooManyItemsOfTypeException()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class AlreadyHasItemException: Exception("The player already owns this item")
|
class AlreadyHasItemException: Exception("The player already owns this item")
|
||||||
|
|
||||||
class TooManyItemsOfTypeException: Exception("The player already owns too much items of this type")
|
class TooManyItemsOfTypeException: Exception("The player already owns too much items of this type")
|
||||||
|
|
||||||
fun addItem(item: TTTItem) {
|
fun addItem(item: TTTItem<*>) {
|
||||||
checkAddItemPreconditions(item)
|
checkAddItemPreconditions(item)
|
||||||
player.inventory.addItem(item.itemStack.clone())
|
val instance = item.createInstance()
|
||||||
item.onOwn(this)
|
player.inventory.addItem(instance.createItemStack())
|
||||||
updateItemInHand()
|
instance.carrier = this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeItem(item: TTTItem) {
|
fun removeItem(item: TTTItem<*>, removeInstance: Boolean = true) {
|
||||||
|
item.getInstance(this)?.let {
|
||||||
|
it.carrier = null
|
||||||
|
if (removeInstance) item.instancesByUUID.remove(it.uuid)
|
||||||
|
}
|
||||||
|
|
||||||
player.inventory.removeTTTItem(item)
|
player.inventory.removeTTTItem(item)
|
||||||
item.onRemove(this)
|
|
||||||
updateItemInHand()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addDefaultClassItems() = tttClass.defaultItems.forEach { addItem(it) }
|
fun addDefaultClassItems() = tttClass.defaultItems.forEach { addItem(it) }
|
||||||
|
|
|
@ -9,11 +9,12 @@ fun Inventory.setAllToItem(indexes: Iterable<Int>, itemStack: ItemStack) {
|
||||||
indexes.forEach { setItem(it, itemStack) }
|
indexes.forEach { setItem(it, itemStack) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Inventory.removeTTTItem(tttItem: TTTItem) {
|
fun Inventory.removeTTTItem(tttItem: TTTItem<*>) {
|
||||||
val index = indexOfFirst { it?.type == tttItem.itemStack.type }
|
val index = indexOfFirst { it?.type == tttItem.material }
|
||||||
if (index != -1) clear(index)
|
if (index != -1) clear(index)
|
||||||
}
|
}
|
||||||
fun Inventory.removeTTTItemNextTick(tttItem: TTTItem) = nextTick { removeTTTItem(tttItem) }
|
|
||||||
|
fun Inventory.removeTTTItemNextTick(tttItem: TTTItem<*>) = nextTick { removeTTTItem(tttItem) }
|
||||||
|
|
||||||
fun PlayerInventory.clearHeldItemSlot() = clear(heldItemSlot)
|
fun PlayerInventory.clearHeldItemSlot() = clear(heldItemSlot)
|
||||||
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
package de.moritzruth.spigot_ttt.utils
|
|
||||||
|
|
||||||
import de.moritzruth.spigot_ttt.plugin
|
|
||||||
import org.bukkit.inventory.ItemStack
|
|
||||||
import org.bukkit.inventory.meta.Damageable
|
|
||||||
import org.bukkit.inventory.meta.ItemMeta
|
|
||||||
import org.bukkit.scheduler.BukkitTask
|
|
||||||
import java.time.Instant
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
fun startItemDamageProgress(itemStack: ItemStack, duration: Double, startProgress: Double = 0.0, fromRight: Boolean = false, onFinish: () -> Unit): BukkitTask {
|
|
||||||
val startedAt = Instant.now().toEpochMilli()
|
|
||||||
|
|
||||||
lateinit var task: BukkitTask
|
|
||||||
|
|
||||||
task = plugin.server.scheduler.runTaskTimer(plugin, fun() {
|
|
||||||
val secondsElapsed = (Instant.now().toEpochMilli() - startedAt) / 1000.0
|
|
||||||
val progress = secondsElapsed / duration + startProgress
|
|
||||||
|
|
||||||
val maxDurability = itemStack.type.maxDurability
|
|
||||||
val damageMeta = itemStack.itemMeta!! as Damageable
|
|
||||||
|
|
||||||
if (fromRight) {
|
|
||||||
damageMeta.damage = (maxDurability * progress).roundToInt()
|
|
||||||
} else {
|
|
||||||
damageMeta.damage = maxDurability - (maxDurability * progress).roundToInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
itemStack.itemMeta = damageMeta as ItemMeta
|
|
||||||
|
|
||||||
if (progress >= 1) {
|
|
||||||
task.cancel()
|
|
||||||
onFinish()
|
|
||||||
}
|
|
||||||
}, 0, 1)
|
|
||||||
|
|
||||||
return task
|
|
||||||
}
|
|
|
@ -7,3 +7,11 @@ fun ItemStack.applyMeta(fn: ItemMeta.() -> Unit): ItemStack {
|
||||||
itemMeta = itemMeta!!.apply(fn)
|
itemMeta = itemMeta!!.apply(fn)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun <T: Any> ItemStack.applyTypedMeta(fn: T.() -> Unit): ItemStack {
|
||||||
|
val typedMeta = itemMeta as T
|
||||||
|
typedMeta.fn()
|
||||||
|
itemMeta = itemMeta as ItemMeta
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package de.moritzruth.spigot_ttt.utils
|
||||||
|
|
||||||
|
enum class Probability {
|
||||||
|
VERY_LOW,
|
||||||
|
LOW,
|
||||||
|
NORMAL
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package de.moritzruth.spigot_ttt.utils
|
||||||
|
|
||||||
|
import de.moritzruth.spigot_ttt.plugin
|
||||||
|
import org.bukkit.scheduler.BukkitTask
|
||||||
|
import java.time.Duration
|
||||||
|
import java.time.Instant
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
data class TickData(
|
||||||
|
val elapsedSeconds: Double,
|
||||||
|
val progress: Double,
|
||||||
|
val isComplete: Boolean,
|
||||||
|
val trueProgress: Double
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param duration Duration in seconds
|
||||||
|
*/
|
||||||
|
fun startProgressTask(duration: Double, startAt: Double = 0.0, onTick: (data: TickData) -> Unit): BukkitTask {
|
||||||
|
val startedAt = Instant.now()
|
||||||
|
|
||||||
|
var task: BukkitTask? = null
|
||||||
|
task = plugin.server.scheduler.runTaskTimer(plugin, fun() {
|
||||||
|
val elapsedSeconds: Double = Duration.between(startedAt, Instant.now()).toMillis().toDouble() / 1000
|
||||||
|
val progress: Double = (elapsedSeconds / duration) + startAt
|
||||||
|
val data = TickData(
|
||||||
|
elapsedSeconds = elapsedSeconds,
|
||||||
|
progress = min(a = progress, b = 1.0),
|
||||||
|
trueProgress = progress,
|
||||||
|
isComplete = progress >= 1.0
|
||||||
|
)
|
||||||
|
|
||||||
|
if (data.isComplete) {
|
||||||
|
task?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
onTick(data)
|
||||||
|
|
||||||
|
}, 0, 1)
|
||||||
|
return task
|
||||||
|
}
|
Reference in a new issue