Files
SteamWar/TNTLeague/src/de/steamwar/tntleague/game/TNTLeagueGame.kt
YoyoNow 61d84492dc
All checks were successful
SteamWarCI Build successful
Merge branch 'main' into TNTLeague/BiggerCoins
2025-04-17 21:18:40 +02:00

284 lines
10 KiB
Kotlin

/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2024 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.tntleague.game
import de.steamwar.kotlin.util.Area
import de.steamwar.message.SubMessage
import de.steamwar.network.NetworkSender
import de.steamwar.network.packets.common.FightInfoPacket
import de.steamwar.scoreboard.SWScoreboard
import de.steamwar.sql.SteamwarUser
import de.steamwar.tntleague.colorByTeam
import de.steamwar.tntleague.config.TNTLeagueConfig
import de.steamwar.tntleague.config.TNTLeagueWorldConfig
import de.steamwar.tntleague.config.world
import de.steamwar.tntleague.events.DummyListener
import de.steamwar.tntleague.events.IngameListener
import de.steamwar.tntleague.events.LobbyListener
import de.steamwar.tntleague.inventory.DealerInventory
import de.steamwar.tntleague.message
import de.steamwar.tntleague.plugin
import de.steamwar.tntleague.util.TNTLeagueScoreboard
import org.bukkit.GameMode
import org.bukkit.Location
import org.bukkit.Sound
import org.bukkit.entity.Item
import org.bukkit.entity.Player
import org.bukkit.entity.TNTPrimed
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.inventory.ItemStack
import org.bukkit.scheduler.BukkitTask
import java.sql.Timestamp
import java.time.Instant
import kotlin.random.Random
object TNTLeagueGame {
var state: GameState = GameState.LOBBY
set(value) {
if (field.listener != value.listener) {
HandlerList.unregisterAll(field.listener)
plugin.server.pluginManager.registerEvents(value.listener, plugin)
}
field = value
}
var gameTimeRemaining: Int = TNTLeagueConfig.config.gameTime
val blueTeam = TNTLeagueTeam(TNTLeagueConfig.config.blueTeam)
val redTeam = TNTLeagueTeam(TNTLeagueConfig.config.redTeam)
private lateinit var start: Timestamp
private var task: Int? = null
private lateinit var spawnerTask: BukkitTask
private lateinit var timerTask: BukkitTask
private fun setup() {
assert(state == GameState.STARTING) { "Game is already running" }
state = GameState.RUNNING
plugin.server.onlinePlayers.forEach { SWScoreboard.impl.createScoreboard(it, TNTLeagueScoreboard(it)) }
blueTeam.start()
redTeam.start()
updateFightinfo()
message.broadcast("GAME_STARTED")
start = Timestamp.from(Instant.now())
var spawnCount = 0
spawnerTask = plugin.server.scheduler.runTaskTimer(plugin, bukkit {
val coinsToSpawn = if (spawnCount % 28 == 0) {
DealerInventory.huge_coins
} else if (spawnCount % 7 == 0) {
DealerInventory.big_coins
} else {
DealerInventory.coins
}
spawnCount++
if (world.getNearbyEntitiesByType(Item::class.java, TNTLeagueWorldConfig.blueTeam.itemSpawn, 3.0).sumOf { it.itemStack.amount } <= 256) {
spawnItems(TNTLeagueWorldConfig.blueTeam.itemSpawn, coinsToSpawn)
}
if (world.getNearbyEntitiesByType(Item::class.java, TNTLeagueWorldConfig.redTeam.itemSpawn, 3.0).sumOf { it.itemStack.amount } <= 256) {
spawnItems(TNTLeagueWorldConfig.redTeam.itemSpawn, coinsToSpawn)
}
}, 5, 10)
timerTask = plugin.server.scheduler.runTaskTimer(plugin, bukkit {
gameTimeRemaining--
if (gameTimeRemaining == 0) {
if (blueTeam.damagedBlocks > redTeam.damagedBlocks)
win(blueTeam, WinReason.TIMEOUT)
else if (redTeam.damagedBlocks > blueTeam.damagedBlocks)
win(redTeam, WinReason.TIMEOUT)
else
draw(WinReason.TIMEOUT)
return@bukkit
}
if (gameTimeRemaining % 300 == 0) {
message.broadcast("TIME_REMAINING", (gameTimeRemaining / 60))
plugin.server.onlinePlayers.forEach { it.playSound(it.location, Sound.BLOCK_NOTE_BLOCK_PLING, 1f, 1f) }
}
}, 20, 20)
}
private fun bukkit(f: () -> Unit): () -> Unit = f
private fun end() {
if(state != GameState.RUNNING) return
state = GameState.END
plugin.server.onlinePlayers.forEach {
it.gameMode = GameMode.SPECTATOR
SWScoreboard.impl.removeScoreboard(it)
it.playSound(it.location, Sound.ENTITY_ENDER_DRAGON_DEATH, 1f, 1f)
}
message.broadcast("GAME_ENDED")
spawnerTask.cancel()
var shutdown = 10
plugin.server.scheduler.runTaskTimer(plugin, bukkit {
if (shutdown == 0) {
plugin.server.shutdown()
}
message.broadcast("SHUTDOWN", shutdown)
shutdown--
}, 20, 20)
updateFightinfo()
}
private fun spawnItems(loc: Location, item: ItemStack) = plugin.server.worlds.first().dropItem(loc, item)
fun getTeam(player: Player) = if (player in blueTeam.members) blueTeam else if (player in redTeam.members) redTeam else null
fun getFreeTeam(player: Player) = if (TNTLeagueConfig.isEvent()) getEventFreeTeam(player) else getNormalFreeTeam(player)
private fun getNormalFreeTeam(player: Player) = if (blueTeam.leader == null && (TNTLeagueConfig.config.blueLeader == null || player.uniqueId == TNTLeagueConfig.config.blueLeader)) blueTeam
else if (redTeam.leader == null && TNTLeagueConfig.config.redLeader == null || player.uniqueId == TNTLeagueConfig.config.redLeader) redTeam
else null
private fun getEventFreeTeam(player: Player) = SteamwarUser.get(player.uniqueId).let { user ->
if (user.team == TNTLeagueConfig.config.eventTeamBlue.teamId && blueTeam.members.size < TNTLeagueConfig.config.event.maximumTeamMembers) blueTeam
else if (user.team == TNTLeagueConfig.config.eventTeamRed.teamId && redTeam.members.size < TNTLeagueConfig.config.event.maximumTeamMembers) redTeam
else null
}
fun checkStart() {
if (blueTeam.isReady && redTeam.isReady) {
blueTeam.leader?.inventory?.clear()
redTeam.leader?.inventory?.clear()
state = GameState.STARTING
var countdown = TNTLeagueConfig.config.startDelay
message.broadcast("GAME_STARTING", countdown.toString())
task = plugin.server.scheduler.scheduleSyncRepeatingTask(plugin, {
plugin.server.onlinePlayers.forEach { it.playSound(it.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1f, 1f) }
if (--countdown == 0) {
plugin.server.onlinePlayers.forEach { it.level = 0 }
task = task?.also { plugin.server.scheduler.cancelTask(it) }.let { null }
setup()
} else {
plugin.server.onlinePlayers.forEach { it.level = countdown }
}
}, 20, 20)
if (task == -1) {
error("Failed to start countdown task")
}
updateFightinfo()
}
}
fun playerLeave(player: Player) {
blueTeam.invites.remove(player)
redTeam.invites.remove(player)
getTeam(player)?.apply {
remove(player)
}
}
fun reset() {
assert(state == GameState.LOBBY || state == GameState.STARTING) { "Game is not in lobby or starting state" }
if (state == GameState.STARTING) {
task = task?.also { plugin.server.scheduler.cancelTask(it) }.let { null }
state = GameState.LOBBY
}
updateFightinfo()
}
fun win(tntLeagueTeam: TNTLeagueTeam, reason: WinReason) {
if (state != GameState.RUNNING) return
end()
plugin.server.onlinePlayers.forEach { message.send("TEAM_WIN", it, tntLeagueTeam.name) }
explode(tntLeagueTeam.opposite)
if (TNTLeagueConfig.isEvent()) {
TNTLeagueConfig.config.eventFight.ergebnis = tntLeagueTeam.ergebnisInt
}
}
fun draw(reason: WinReason) {
if (state != GameState.RUNNING) return
end()
message.broadcast("DRAW")
if (TNTLeagueConfig.isEvent()) {
TNTLeagueConfig.config.eventFight.ergebnis = 3
}
}
fun explode(team: TNTLeagueTeam) {
Area(team.config.worldConfig.spawnLocation.clone().add(20.0, 30.0, 20.0), team.config.worldConfig.spawnLocation.clone().subtract(20.0, 0.0, 20.0).add(0.0, 30.0, 0.0))
.locations
.filterIndexed { index, _ -> index % 7 == 0 }
.forEachIndexed { index, location ->
world.spawn(location, TNTPrimed::class.java).apply {
fuseTicks = index + 40
}
}
}
fun updateFightinfo() {
NetworkSender.send(FightInfoPacket(
plugin.server.worlds.first().name,
"TNTLeague",
"",
blueTeam.name.message.colorByTeam(blueTeam),
redTeam.name.message.colorByTeam(redTeam),
state.lobbyName,
TNTLeagueConfig.config.gameTime - gameTimeRemaining,
blueTeam.leader?.let { SteamwarUser.get(it.uniqueId).id } ?: 0,
redTeam.leader?.let { SteamwarUser.get(it.uniqueId).id } ?: 0,
0,
0,
blueTeam.members.map { SteamwarUser.get(it.uniqueId).id },
redTeam.members.map { SteamwarUser.get(it.uniqueId).id },
plugin.server.onlinePlayers.filter {! blueTeam.members.contains(it) && !redTeam.members.contains(it) }.map { SteamwarUser.get(it.uniqueId).id }
))
}
enum class GameState(val listener: Listener, val lobbyName: String) {
LOBBY(LobbyListener, "PRE_LEADER_SETUP"),
STARTING(LobbyListener, "POST_SCHEM_SETUP"),
RUNNING(IngameListener, "RUNNING"),
END(DummyListener, "SPECTATE");
}
enum class WinReason {
TIMEOUT,
DESTROYED,
LEAVE
}
}