diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/game/Game.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/game/Game.kt index 3976e76..fc8595c 100644 --- a/src/main/kotlin/cc/maxmc/blastingcrisis/game/Game.kt +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/game/Game.kt @@ -15,6 +15,7 @@ class Game( val scoreboard: GameScoreboard = GameScoreboard(this) val timer: GameTimer = GameTimer(this) val players = ArrayList() + val rule = GamePlaceBreakRule(this) var state: GameState = GameState.WAITING private fun autoJoinTeam() { @@ -47,6 +48,7 @@ class Game( fun start() { debug("game ${map.name} started.") + state = GameState.START timer.startTimer() timer.submitEvent("wall_fall", Duration.ofMinutes(1)) { diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameBreakRule.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameBreakRule.kt deleted file mode 100644 index 71eb3ea..0000000 --- a/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameBreakRule.kt +++ /dev/null @@ -1,19 +0,0 @@ -package cc.maxmc.blastingcrisis.game - -import org.bukkit.Location - -class GameBreakRule(val rule: MutableList<(Location) -> Boolean>) { - fun matchRule(location: Location) { - - } - - fun addRule(rule: (Location) -> Boolean) { - - } - - fun defaultRule() { - rule.add { - true - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/game/GamePlaceBreakRule.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GamePlaceBreakRule.kt new file mode 100644 index 0000000..275086c --- /dev/null +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GamePlaceBreakRule.kt @@ -0,0 +1,47 @@ +package cc.maxmc.blastingcrisis.game + +import cc.maxmc.blastingcrisis.game.GamePlaceBreakRule.ActionType.BREAK +import org.bukkit.Location +import org.bukkit.entity.Player + +class GamePlaceBreakRule(val game: Game) { + enum class ActionType { + PLACE, + BREAK + } + + private val rule = ArrayList<(Player, ActionType, Location) -> Boolean>() + fun matchRule(player: Player, actionType: ActionType, location: Location): Boolean { + // match rules + rule.forEach { + if (it(player, actionType, location)) return true + } + + // fallback strategy + return false + } + + fun addRule(rule: (Player, Location) -> Boolean) { + + } + + fun defaultRule(game: Game) { + // allow mine + rule.add { _, _, loc -> + game.map.teams.flatMap { + it.sides + it.mine + }.map { + it.containsBlock(loc) + }.reduce { a, b -> a || b } + } + + // allow enemy wall + rule.add { player, type, loc -> + val team = player.team ?: return@add false + val result = game.teams.filterNot { it == team } + .map { team.teamInfo.wall.containsBlock(loc) } + .reduce { a, b -> a || b } + if (type == BREAK) result else !result + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameTeam.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameTeam.kt index 0821223..e46727c 100644 --- a/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameTeam.kt +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameTeam.kt @@ -20,6 +20,12 @@ class GameTeam(val game: Game, val teamInfo: MapTeam) { GameListener.interactSubscribed[teamInfo.upgrade] = { debug("interact team ${teamInfo.name} upgrade.") } + GameListener.moveSubscribed.add(teamInfo.teleport to { + val player = it.player ?: throw IllegalStateException("Bukkit API LOL") + debug("teleporting $player to battle field") + val team = player.team ?: throw IllegalStateException("Player ${player.name} should have a team") + player.teleport(team.teamInfo.mine.randomLocation().toPlayerLocation()) + }) } fun join(player: Player) { diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/listener/GameListener.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/listener/GameListener.kt index d8d2956..6fb95b0 100644 --- a/src/main/kotlin/cc/maxmc/blastingcrisis/listener/GameListener.kt +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/listener/GameListener.kt @@ -1,27 +1,29 @@ package cc.maxmc.blastingcrisis.listener +import cc.maxmc.blastingcrisis.game.GamePlaceBreakRule import cc.maxmc.blastingcrisis.game.team +import cc.maxmc.blastingcrisis.misc.Area import cc.maxmc.blastingcrisis.misc.GameManager import cc.maxmc.blastingcrisis.misc.debug -import cc.maxmc.blastingcrisis.misc.toPlayerLocation import org.bukkit.Location import org.bukkit.event.block.BlockBreakEvent +import org.bukkit.event.block.BlockPlaceEvent import org.bukkit.event.entity.EntityExplodeEvent import org.bukkit.event.player.PlayerInteractEvent import org.bukkit.event.player.PlayerMoveEvent import taboolib.common.platform.event.SubscribeEvent +import taboolib.platform.util.sendLang object GameListener { val interactSubscribed = HashMap Unit>() + val moveSubscribed = ArrayList Unit>>() @SubscribeEvent fun portalTeleport(event: PlayerMoveEvent) { if (!GameManager.currentGame.players.contains(event.player)) return - val player = event.player - val team = player.team ?: return - if (!team.teamInfo.teleport.isInArea(event.to)) return - debug("teleporting ${event.player} to battle field") - player.teleport(team.teamInfo.mine.randomLocation().toPlayerLocation()) + moveSubscribed.forEach { (area, func) -> + if (area.contains(event.to)) func(event) + } } @SubscribeEvent @@ -36,7 +38,7 @@ object GameListener { tntExplode.blockList().clear() if (!GameManager.currentGame.state.isStarted()) return GameManager.currentGame.teams.findLast { - it.teamSurvive && it.teamInfo.home.isInArea(tntExplode.location) + it.teamSurvive && it.teamInfo.home.contains(tntExplode.location) }?.apply { villager.damage() debug("team ${teamInfo.name}'s villager damaged") @@ -45,7 +47,19 @@ object GameListener { @SubscribeEvent fun onBreak(breakEvent: BlockBreakEvent) { - val loc = breakEvent.block.location - + val loc = breakEvent.block.location ?: return + val player = breakEvent.player ?: return + if (GameManager.currentGame.rule.matchRule(player, GamePlaceBreakRule.ActionType.BREAK, loc)) return + breakEvent.isCancelled = true + player.sendLang("game_cant_break_block") + } + + @SubscribeEvent + fun onPlace(placeEvent: BlockPlaceEvent) { + val loc = placeEvent.block.location ?: return + val player = placeEvent.player ?: return + if (GameManager.currentGame.rule.matchRule(player, GamePlaceBreakRule.ActionType.PLACE, loc)) return + placeEvent.isCancelled = true + player.sendLang("game_cant_place_block") } } \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/map/MapInitializer.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/map/MapInitializer.kt index 417accb..a49462f 100644 --- a/src/main/kotlin/cc/maxmc/blastingcrisis/map/MapInitializer.kt +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/map/MapInitializer.kt @@ -9,5 +9,4 @@ class MapInfo( var waitArea: Area, val teams: List, val maxPlayersPerTeam: Int, - - ) \ No newline at end of file +) \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/misc/Area.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/misc/Area.kt index 2cb0ad5..a7add4a 100644 --- a/src/main/kotlin/cc/maxmc/blastingcrisis/misc/Area.kt +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/misc/Area.kt @@ -31,15 +31,14 @@ class Area(loc1: Location, loc2: Location) : ConfigurationSerializable { * * @return true if the location is in this area */ - fun isInArea(location: Location): Boolean { + fun contains(location: Location): Boolean { if (location.world != locTop.world) return false if (location.x !in (locMin.x - 1)..(locTop.x + 1)) return false if (location.y !in locMin.y..locTop.y + 1) return false return location.z in (locMin.z - 1)..(locTop.z + 1) } - fun isBlockInArea(block: Block): Boolean { - val location = block.location + fun containsBlock(location: Location): Boolean { if (location.world != locTop.world) return false if (location.x !in locMin.x..locTop.x) return false if (location.y !in locMin.y..locTop.y) return false