Compare commits

..

9 Commits

Author SHA1 Message Date
TONY_All ef8e2391d6
fix rule logic 2023-06-10 22:02:00 +08:00
TONY_All 20b1004e62
fix test data 2023-06-10 21:06:13 +08:00
TONY_All 3d35de3fe3
add toString for Area 2023-06-10 19:40:14 +08:00
tony_all 764ead46c2 fix rule match
add debug
2023-06-07 16:05:45 +08:00
tony_all 84baa309e3 optimize rule structure 2023-06-07 15:54:37 +08:00
tony_all ed6f40b462 fix rule initialize
add dynamic rule when the wall falls
2023-06-07 15:47:36 +08:00
tony_all 45882c8cb6 add break & place check
optimize code logic of Teleport Listener
2023-06-07 15:34:44 +08:00
TONY_All 97c5c1c9fb sync with remote 2023-06-07 14:47:30 +08:00
tony_all 362941fe58 fix location
format code
2023-06-06 22:50:16 +08:00
8 changed files with 127 additions and 30 deletions

View File

@ -22,7 +22,6 @@ object BlastingCrisis : Plugin() {
override fun onEnable() {
info("§a| §7Loading BlastingCrisis")
DebugCommand.debug("debugcmd")
info("§a| §7Loading BlastingCrisis")
createDefaultGame()
}
@ -40,12 +39,13 @@ object BlastingCrisis : Plugin() {
location(0, 72, -44),
location(0, 72, -44),
location(-8, 73, -47),
Area(location(14, 72, -48), location(-13, 78, -34)),
Area(location(14, 72, -48), location(-14, 78, -34)),
Area(location(-13, 78, -33), location(13, 72, -33)),
Area(location(-13, 78, -32), location(13, 71, -1)),
Area(location(-13, 78, -32), location(13, 72, -1)),
Area(location(7, 72, -45), location(9, 74, -48)),
listOf(
Area(location(15, 72, -1), location(19, 78, -48)), Area(location(19, 78, -48), location(-15, 72, -1))
Area(location(15, 72, -1), location(19, 78, -48)),
Area(location(-19, 78, -48), location(-15, 72, -1))
),
)
val teamGreen = MapTeam(
@ -54,12 +54,13 @@ object BlastingCrisis : Plugin() {
location(0, 72, 44),
location(0, 72, 44),
location(8, 73, 47),
Area(location(-14, 72, 48), location(13, 78, 34)),
Area(location(-14, 72, 48), location(14, 78, 34)),
Area(location(13, 78, 33), location(-13, 72, 33)),
Area(location(13, 78, 32), location(-13, 71, 1)),
Area(location(13, 78, 32), location(-13, 72, 1)),
Area(location(-7, 72, 45), location(-9, 74, 48)),
listOf(
Area(location(-15, 72, 1), location(-19, 78, 48)), Area(location(-19, 78, 48), location(15, 72, 1))
Area(location(-15, 72, 1), location(-19, 78, 48)),
Area(location(19, 78, 48), location(15, 72, 1))
),
)
val map = GameMap(

View File

@ -15,6 +15,7 @@ class Game(
val scoreboard: GameScoreboard = GameScoreboard(this)
val timer: GameTimer = GameTimer(this)
val players = ArrayList<Player>()
val placeBreakRule = GamePlaceBreakRule(this)
var state: GameState = GameState.WAITING
private fun autoJoinTeam() {
@ -47,6 +48,8 @@ class Game(
fun start() {
debug("game ${map.name} started.")
placeBreakRule.defaultRule()
state = GameState.START
timer.startTimer()
timer.submitEvent("wall_fall", Duration.ofMinutes(1)) {
@ -55,6 +58,9 @@ class Game(
map.wall.forBlocksInArea().forEach {
it.block.type = Material.AIR
}
placeBreakRule.addRule("allow_center_wall") { _, _, loc ->
map.wall.contains(loc)
}
}
}
autoJoinTeam()

View File

@ -0,0 +1,59 @@
package cc.maxmc.blastingcrisis.game
import cc.maxmc.blastingcrisis.game.GamePlaceBreakRule.ActionType.BREAK
import cc.maxmc.blastingcrisis.misc.debug
import org.bukkit.Location
import org.bukkit.entity.Player
class GamePlaceBreakRule(val game: Game) {
enum class ActionType {
PLACE,
BREAK
}
private val rules = HashMap<String, (Player, ActionType, Location) -> Boolean>()
fun matchRule(player: Player, actionType: ActionType, location: Location): Boolean {
// match rules
rules.forEach { (name, func) ->
if (func(player, actionType, location)) {
debug("Hit rule $name")
return true
}
}
// fallback strategy
return false
}
fun addRule(name: String, rule: (player: Player, type: ActionType, loc: Location) -> Boolean) {
if (rules.containsKey(name)) {
throw IllegalArgumentException("Rule $name already exists.")
}
debug("rule $name added")
rules[name] = rule
}
fun defaultRule() {
// allow mine
addRule("allow_mine") { _, _, loc ->
game.map.teams.flatMap {
it.sides + it.mine
}.map {
it.containsBlock(loc)
}.reduce { a, b -> a || b }
}
// allow enemy wall
addRule("allow_wall_conditional") { player, type, loc ->
val team = player.team ?: return@addRule false
val isWall = game.teams
.map {
it.teamInfo.wall.containsBlock(loc).also { result -> debug("area ${it.teamInfo.wall} contains $loc is $result") }
}
.reduce { a, b -> a || b }
if (!isWall) return@addRule false
val isHome = team.teamInfo.wall.containsBlock(loc)
(type == BREAK) xor isHome
}
}
}

View File

@ -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) {

View File

@ -1,26 +1,28 @@
package cc.maxmc.blastingcrisis.listener
import cc.maxmc.blastingcrisis.game.team
import cc.maxmc.blastingcrisis.game.GamePlaceBreakRule
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<Location, (PlayerInteractEvent) -> Unit>()
val moveSubscribed = ArrayList<Pair<Area, (PlayerMoveEvent) -> Unit>>()
@SubscribeEvent
fun onMoveInTeleport(event: PlayerMoveEvent) {
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
@ -35,10 +37,28 @@ 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")
} ?: throw IllegalStateException("TNT Exploded at no team, which shouldn't happen")
}
@SubscribeEvent
fun onBreak(breakEvent: BlockBreakEvent) {
val loc = breakEvent.block.location ?: return
val player = breakEvent.player ?: return
if (GameManager.currentGame.placeBreakRule.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.placeBreakRule.matchRule(player, GamePlaceBreakRule.ActionType.PLACE, loc)) return
placeEvent.isCancelled = true
player.sendLang("game_cant_place_block")
}
}

View File

@ -2,7 +2,13 @@ package cc.maxmc.blastingcrisis.map
import cc.maxmc.blastingcrisis.misc.Area
class GameMap(val name: String, val area: Area, val wall: Area, val teams: List<MapTeam>, val maxPlayersPerTeam: Int) {
class GameMap(
val name: String,
val area: Area,
val wall: Area,
val teams: List<MapTeam>,
val maxPlayersPerTeam: Int
) {
val maxPlayer: Int
get() = maxPlayersPerTeam * teams.size
}

View File

@ -9,5 +9,4 @@ class MapInfo(
var waitArea: Area,
val teams: List<MapTeam>,
val maxPlayersPerTeam: Int,
)

View File

@ -2,7 +2,6 @@ package cc.maxmc.blastingcrisis.misc
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.block.Block
import org.bukkit.configuration.serialization.ConfigurationSerializable
import org.bukkit.configuration.serialization.SerializableAs
import org.bukkit.util.Vector
@ -15,6 +14,7 @@ class Area(loc1: Location, loc2: Location) : ConfigurationSerializable {
val locTop: Location
val locMin: Location
@Suppress("unused") // Bukkit Specification
constructor(map: Map<String, Any>) : this(map["locTop"] as Location, map["locMin"] as Location)
init {
@ -30,21 +30,18 @@ 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
if (location.z !in (locMin.z - 1)..(locTop.z + 1)) return false
return true
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
if (location.z !in locMin.z..locTop.z) return false
return true
return location.z in locMin.z..locTop.z
}
/**
@ -101,11 +98,10 @@ class Area(loc1: Location, loc2: Location) : ConfigurationSerializable {
other as Area
if (locTop != other.locTop) return false
if (locMin != other.locMin) return false
return true
return locMin == other.locMin
}
override fun hashCode(): Int {
var result = locTop.hashCode()
result = 31 * result + locMin.hashCode()
@ -114,4 +110,8 @@ class Area(loc1: Location, loc2: Location) : ConfigurationSerializable {
override fun serialize() = mutableMapOf<String, Any>("locTop" to locTop, "locMin" to locMin)
override fun toString(): String {
return "Area(locTop=$locTop, locMin=$locMin)"
}
}