Add Second Chance item
This commit is contained in:
parent
33a6a2dafd
commit
021ed57486
14 changed files with 214 additions and 21 deletions
|
@ -8,13 +8,15 @@ object ResourcePack {
|
|||
val deathReason = Material.GRAY_STAINED_GLASS_PANE
|
||||
val questionMark = Material.GRASS_BLOCK
|
||||
val time = Material.CLOCK
|
||||
val dot = Material.GRAY_STAINED_GLASS
|
||||
val arrowDown = Material.WHITE_STAINED_GLASS
|
||||
|
||||
// Roles
|
||||
val innocent = Material.GREEN_STAINED_GLASS_PANE
|
||||
val detective = Material.YELLOW_STAINED_GLASS_PANE
|
||||
val traitor = Material.RED_STAINED_GLASS_PANE
|
||||
val jackal = Material.LIGHT_BLUE_STAINED_GLASS_PANE
|
||||
val sidekick = Material.LIGHT_BLUE_STAINED_GLASS_PANE
|
||||
val sidekick = Material.BLUE_STAINED_GLASS_PANE
|
||||
|
||||
// Special Items
|
||||
val cloakingDevice = Material.COBWEB
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.bukkit.event.EventHandler
|
|||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.event.inventory.InventoryClickEvent
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent
|
||||
import org.bukkit.event.player.PlayerEvent
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.event.player.PlayerItemConsumeEvent
|
||||
|
@ -73,6 +74,13 @@ open class TTTItemListener(private val tttItem: TTTItem, private val cancelDamag
|
|||
}
|
||||
}
|
||||
|
||||
protected fun handle(event: InventoryCloseEvent, handler: (tttPlayer: TTTPlayer) -> Unit) {
|
||||
val player = event.player
|
||||
if (player is Player) {
|
||||
handler(PlayerManager.getTTTPlayer(player) ?: return)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun <T: PlayerEvent> handle(event: T, handler: (tttPlayer: TTTPlayer) -> Unit) {
|
||||
handler(PlayerManager.getTTTPlayer(event.player) ?: return)
|
||||
}
|
||||
|
|
|
@ -124,6 +124,7 @@ class TTTCorpse private constructor(
|
|||
}
|
||||
|
||||
fun destroy() {
|
||||
ensureNotDestroyed()
|
||||
status = Status.DESTROYED
|
||||
CorpseAPI.removeCorpse(corpse)
|
||||
updateTimeListener.cancel()
|
||||
|
@ -146,15 +147,13 @@ class TTTCorpse private constructor(
|
|||
private const val REASON_SLOT = 1
|
||||
private const val TIME_SLOT = 2
|
||||
|
||||
fun spawn(tttPlayer: TTTPlayer, reason: DeathReason) {
|
||||
CorpseManager.add(TTTCorpse(
|
||||
fun spawn(tttPlayer: TTTPlayer, reason: DeathReason): TTTCorpse = TTTCorpse(
|
||||
tttPlayer,
|
||||
tttPlayer.player.location,
|
||||
tttPlayer.role,
|
||||
reason,
|
||||
tttPlayer.credits
|
||||
))
|
||||
}
|
||||
).also { CorpseManager.add(it) }
|
||||
|
||||
fun spawnFake(role: Role, tttPlayer: TTTPlayer, location: Location) {
|
||||
CorpseManager.add(TTTCorpse(
|
||||
|
|
|
@ -39,7 +39,7 @@ class InversedStateContainer<T: IState>(private val stateClass: KClass<T>) {
|
|||
|
||||
val tttPlayers get() = PlayerManager.tttPlayers.filter { it.stateContainer.has(stateClass) }
|
||||
|
||||
fun forEachState(fn: (T, TTTPlayer) -> Unit) {
|
||||
fun forEveryState(fn: (T, TTTPlayer) -> Unit) {
|
||||
tttPlayers.forEach { it.stateContainer.get(stateClass)?.run { fn(this, it) } }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,15 +84,21 @@ class TTTPlayer(player: Player, role: Role) {
|
|||
fun onDeath(reason: DeathReason = DeathReason.SUICIDE) {
|
||||
GameManager.ensurePhase(GamePhase.COMBAT)
|
||||
|
||||
player.sendMessage(TTTPlugin.prefix + "${ChatColor.RED}${ChatColor.BOLD}Du bist gestorben")
|
||||
|
||||
player.gameMode = GameMode.SPECTATOR
|
||||
alive = false
|
||||
TTTCorpse.spawn(this, reason)
|
||||
val tttCorpse = TTTCorpse.spawn(this, reason)
|
||||
|
||||
player.inventory.clear()
|
||||
credits = 0
|
||||
|
||||
val event = TTTPlayerDeathEvent(this, player.location, tttCorpse)
|
||||
plugin.server.pluginManager.callEvent(event)
|
||||
|
||||
if (event.letRoundEnd) {
|
||||
// PlayerManager.letRemainingRoleGroupWin()
|
||||
plugin.server.pluginManager.callEvent(TTTPlayerDeathEvent(this, player.location))
|
||||
}
|
||||
}
|
||||
|
||||
fun revive(location: Location, credits: Int = 0) {
|
||||
|
@ -106,6 +112,7 @@ class TTTPlayer(player: Player, role: Role) {
|
|||
|
||||
Shop.setItems(this)
|
||||
|
||||
plugin.server.pluginManager.callEvent(TTTPlayerReviveEvent(this))
|
||||
player.sendMessage(TTTPlugin.prefix + "${ChatColor.GREEN}${ChatColor.BOLD}Du wurdest wiederbelebt")
|
||||
|
||||
plugin.server.scheduler.runTask(plugin, fun() {
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
package de.moritzruth.spigot_ttt.game.players
|
||||
|
||||
import de.moritzruth.spigot_ttt.game.corpses.TTTCorpse
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.event.Event
|
||||
import org.bukkit.event.HandlerList
|
||||
|
||||
class TTTPlayerDeathEvent(
|
||||
val tttPlayer: TTTPlayer,
|
||||
val location: Location
|
||||
val location: Location,
|
||||
val tttCorpse: TTTCorpse
|
||||
): Event() {
|
||||
override fun getHandlers(): HandlerList {
|
||||
@Suppress("RedundantCompanionReference") // false positive
|
||||
return Companion.handlers
|
||||
}
|
||||
|
||||
var letRoundEnd = true
|
||||
|
||||
companion object {
|
||||
private val handlers = HandlerList()
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package de.moritzruth.spigot_ttt.game.players
|
||||
|
||||
import org.bukkit.event.Event
|
||||
import org.bukkit.event.HandlerList
|
||||
|
||||
class TTTPlayerReviveEvent(val tttPlayer: TTTPlayer): Event() {
|
||||
override fun getHandlers(): HandlerList {
|
||||
@Suppress("RedundantCompanionReference") // false positive
|
||||
return Companion.handlers
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val handlers = HandlerList()
|
||||
|
||||
@JvmStatic
|
||||
fun getHandlerList() = handlers
|
||||
}
|
||||
}
|
|
@ -29,7 +29,7 @@ object ItemManager {
|
|||
BaseballBat,
|
||||
CloakingDevice, Rifle,
|
||||
EnderPearl, Radar, HealingPotion, Fireball,
|
||||
Teleporter, MartyrdomGrenade, FakeCorpse, Defibrillator
|
||||
Teleporter, MartyrdomGrenade, FakeCorpse, Defibrillator, SecondChance
|
||||
)
|
||||
|
||||
val droppedItemStates = mutableMapOf<Int, IState>()
|
||||
|
|
|
@ -82,7 +82,7 @@ object Defibrillator: TTTItem, Buyable {
|
|||
}
|
||||
|
||||
@EventHandler
|
||||
fun onGameEnd(event: GameEndEvent) = isc.forEachState { state, tttPlayer -> state.reset(tttPlayer) }
|
||||
fun onGameEnd(event: GameEndEvent) = isc.forEveryState { state, tttPlayer -> state.reset(tttPlayer) }
|
||||
}
|
||||
|
||||
sealed class Action(val tttPlayer: TTTPlayer) {
|
||||
|
|
|
@ -59,7 +59,7 @@ object MartyrdomGrenade: TTTItem, Buyable {
|
|||
}
|
||||
|
||||
@EventHandler
|
||||
fun onGameEnd(event: GameEndEvent) = isc.forEachState { state, _ ->
|
||||
fun onGameEnd(event: GameEndEvent) = isc.forEveryState { state, _ ->
|
||||
state.explodeTask?.cancel()
|
||||
state.explodeTask = null
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ object Radar: TTTItem, Buyable {
|
|||
}
|
||||
|
||||
@EventHandler
|
||||
fun onGameEnd(event: GameEndEvent) = isc.forEachState { state, tttPlayer -> state.reset(tttPlayer) }
|
||||
fun onGameEnd(event: GameEndEvent) = isc.forEveryState { state, tttPlayer -> state.reset(tttPlayer) }
|
||||
}
|
||||
|
||||
override val packetListener = object : PacketAdapter(plugin, PacketType.Play.Server.ENTITY_METADATA) {
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
package de.moritzruth.spigot_ttt.items.impl
|
||||
|
||||
import de.moritzruth.spigot_ttt.ResourcePack
|
||||
import de.moritzruth.spigot_ttt.TTTItemListener
|
||||
import de.moritzruth.spigot_ttt.game.GameEndEvent
|
||||
import de.moritzruth.spigot_ttt.game.GameManager
|
||||
import de.moritzruth.spigot_ttt.game.players.*
|
||||
import de.moritzruth.spigot_ttt.items.Buyable
|
||||
import de.moritzruth.spigot_ttt.items.PASSIVE
|
||||
import de.moritzruth.spigot_ttt.items.TTTItem
|
||||
import de.moritzruth.spigot_ttt.plugin
|
||||
import de.moritzruth.spigot_ttt.utils.applyMeta
|
||||
import de.moritzruth.spigot_ttt.utils.hideInfo
|
||||
import de.moritzruth.spigot_ttt.utils.setAllToItem
|
||||
import org.bukkit.ChatColor
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.boss.BarColor
|
||||
import org.bukkit.boss.BarStyle
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.inventory.InventoryClickEvent
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent
|
||||
import org.bukkit.event.inventory.InventoryType
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import kotlin.random.Random
|
||||
|
||||
object SecondChance: TTTItem, Buyable {
|
||||
private val DISPLAY_NAME = "${ChatColor.GREEN}${ChatColor.BOLD}Second Chance"
|
||||
val ON_CORPSE = ResourcePack.Items.arrowDown
|
||||
val ON_SPAWN = ResourcePack.Items.dot
|
||||
private const val TIMEOUT = 20.0
|
||||
|
||||
override val type = TTTItem.Type.SPECIAL
|
||||
override val itemStack = ItemStack(ResourcePack.Items.secondChance).applyMeta {
|
||||
setDisplayName("$DISPLAY_NAME $PASSIVE")
|
||||
hideInfo()
|
||||
lore = listOf(
|
||||
"",
|
||||
"${ChatColor.GOLD}Du wirst mit einer 50%-Chance",
|
||||
"${ChatColor.GOLD}wiederbelebt, wenn du stirbst"
|
||||
)
|
||||
}
|
||||
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(
|
||||
null,
|
||||
InventoryType.CHEST,
|
||||
"${ChatColor.DARK_RED}${ChatColor.BOLD}Second Chance"
|
||||
).apply {
|
||||
setAllToItem(setOf(0, 1, 2, 9, 10, 11, 18, 19, 20), ItemStack(ON_CORPSE).applyMeta {
|
||||
hideInfo()
|
||||
setDisplayName("${ChatColor.GREEN}${ChatColor.BOLD}Bei der Leiche")
|
||||
})
|
||||
|
||||
setAllToItem(setOf(3, 4, 5, 12, 13, 14, 21, 22, 23), ItemStack(ResourcePack.Items.textureless).applyMeta {
|
||||
hideInfo()
|
||||
setDisplayName("${ChatColor.RESET}${ChatColor.BOLD}Wo möchtest du spawnen?")
|
||||
})
|
||||
|
||||
setAllToItem(setOf(6, 7, 8, 15, 16, 17, 24, 25, 26), ItemStack(ON_SPAWN).applyMeta {
|
||||
hideInfo()
|
||||
setDisplayName("${ChatColor.AQUA}${ChatColor.BOLD}Am Spawn")
|
||||
})
|
||||
}
|
||||
|
||||
override fun onBuy(tttPlayer: TTTPlayer) {
|
||||
isc.getOrCreate(tttPlayer)
|
||||
}
|
||||
|
||||
override val listener = object : TTTItemListener(this, true) {
|
||||
@EventHandler
|
||||
fun onTTTPlayerDeath(event: TTTPlayerDeathEvent) {
|
||||
val state = isc.get(event.tttPlayer)
|
||||
if (state != null) {
|
||||
if (Random.nextBoolean()) {
|
||||
event.letRoundEnd = false
|
||||
event.tttPlayer.player.openInventory(chooseSpawnInventory)
|
||||
state.timeoutAction = TimeoutAction(event.tttPlayer, event.tttCorpse.corpse.trueLocation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onInventoryClose(event: InventoryCloseEvent) = handle(event) { tttPlayer ->
|
||||
if (event.inventory == chooseSpawnInventory) {
|
||||
if (isc.get(tttPlayer)?.timeoutAction != null) {
|
||||
plugin.server.scheduler.runTask(plugin, fun() {
|
||||
if (isc.get(tttPlayer) != null) tttPlayer.player.openInventory(chooseSpawnInventory)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onInventoryClick(event: InventoryClickEvent) = handle(event) { tttPlayer ->
|
||||
if (event.clickedInventory != chooseSpawnInventory) return@handle
|
||||
val state = isc.get(tttPlayer) ?: return@handle
|
||||
val timeoutAction = state.timeoutAction ?: return@handle
|
||||
|
||||
val location = when (event.currentItem?.type) {
|
||||
ON_SPAWN -> GameManager.world.spawnLocation
|
||||
ON_CORPSE -> timeoutAction.deathLocation
|
||||
else -> return@handle
|
||||
}
|
||||
|
||||
timeoutAction.stop()
|
||||
tttPlayer.revive(location)
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onTTTPlayerRevive(event: TTTPlayerReviveEvent) {
|
||||
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) stop() else bossBar.progress = 1.0 - progress
|
||||
}, 0, 1)
|
||||
|
||||
fun stop() {
|
||||
isc.remove(tttPlayer)
|
||||
task.cancel()
|
||||
tttPlayer.player.closeInventory()
|
||||
bossBar.removePlayer(tttPlayer.player)
|
||||
}
|
||||
}
|
||||
|
||||
class State: IState {
|
||||
var timeoutAction: TimeoutAction? = null
|
||||
}
|
||||
}
|
|
@ -201,7 +201,7 @@ abstract class Gun(
|
|||
fun onTTTPlayerDeath(event: TTTPlayerDeathEvent) = isc.get(event.tttPlayer)?.reset()
|
||||
|
||||
@EventHandler
|
||||
fun onGameEnd(event: GameEndEvent) = isc.forEachState { state, _ -> state.reset() }
|
||||
fun onGameEnd(event: GameEndEvent) = isc.forEveryState { state, _ -> state.reset() }
|
||||
}
|
||||
|
||||
class ActionInProgressError: RuntimeException("The gun has an ongoing action which may not be canceled")
|
||||
|
|
|
@ -10,7 +10,7 @@ fun Inventory.setAllToItem(indexes: Iterable<Int>, itemStack: ItemStack) {
|
|||
indexes.forEach { setItem(it, itemStack) }
|
||||
}
|
||||
|
||||
fun Inventory.removeTTTItem(tttItem: TTTItem) = clear(indexOfFirst { it.type == tttItem.itemStack.type })
|
||||
fun Inventory.removeTTTItem(tttItem: TTTItem) = clear(indexOfFirst { it?.type == tttItem.itemStack.type })
|
||||
fun Inventory.removeTTTItemNextTick(tttItem: TTTItem) = plugin.server.scheduler.runTask(plugin, fun() {
|
||||
removeTTTItem(tttItem)
|
||||
})
|
||||
|
|
Reference in a new issue