package cc.maxmc.blastingcrisis.game import cc.maxmc.blastingcrisis.game.GamePlaceBreakRule.ActionType.BREAK import cc.maxmc.blastingcrisis.game.GamePlaceBreakRule.ActionType.PLACE import cc.maxmc.blastingcrisis.misc.EnhancedLinkedList import cc.maxmc.blastingcrisis.misc.debug import org.bukkit.Location import org.bukkit.entity.Player import taboolib.library.xseries.XMaterial typealias PlaceBreakRule = (GamePlaceBreakRule.GamePlaceBreakEvent) -> GamePlaceBreakRule.MatchResult @Suppress("unused") // API class GamePlaceBreakRule(val game: Game) { enum class ActionType { PLACE, BREAK } enum class MatchResult { DEFAULT, ALLOW, DENY } data class GamePlaceBreakEvent(val player: Player, val actionType: ActionType, val loc: Location, val type: XMaterial) private val rules = HashMap() private val rulesPriority = EnhancedLinkedList() fun matchRule(player: Player, actionType: ActionType, location: Location, type: XMaterial): Boolean { // match rules rules.forEach { (name, func) -> val result = func(GamePlaceBreakEvent(player, actionType, location, type)) if (result != MatchResult.DEFAULT) { debug("Hit rule $name") return result == MatchResult.ALLOW } } // fallback strategy return false } private fun recordRule(name: String, rule: PlaceBreakRule) { if (rules.containsKey(name)) { throw IllegalArgumentException("Rule $name already exists.") } debug("rule $name added") rules[name] = rule } fun addRuleLast( name: String, rule: PlaceBreakRule ) { recordRule(name, rule) rulesPriority.addLast(name) } fun addRuleFirst( name: String, rule: PlaceBreakRule ) { recordRule(name, rule) rulesPriority.addFirst(name) } fun addRuleBefore( base: String, name: String, rule: PlaceBreakRule ) { recordRule(name, rule) rulesPriority.addBefore(base, name) } fun addRuleAfter( base: String, name: String, rule: PlaceBreakRule ) { recordRule(name, rule) rulesPriority.addAfter(base, name) } fun loadDefaultRule() { // allow mine addRuleLast("allow_mine") { (_, _, loc, _) -> val result = game.map.teams.flatMap { it.sides + it.mine }.map { it.containsBlock(loc) }.reduce { a, b -> a || b } if (result) MatchResult.ALLOW else MatchResult.DEFAULT } // allow enemy wall addRuleLast("allow_wall_conditional") { (player, actionType, loc, _) -> val team = player.team ?: return@addRuleLast MatchResult.DENY 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@addRuleLast MatchResult.DEFAULT val isHome = team.teamInfo.wall.containsBlock(loc) if ((actionType == BREAK) xor isHome) MatchResult.ALLOW else MatchResult.DENY } // allow tnt in enemy's home addRuleFirst("allow_tnt_conditional") { (player, actionType, loc, type) -> if (type != XMaterial.TNT) return@addRuleFirst MatchResult.DEFAULT val team = player.team ?: return@addRuleFirst MatchResult.DENY val isHome = game.teams .map { it.teamInfo.home.containsBlock(loc) .also { result -> debug("area ${it.teamInfo.home} contains $loc is $result") } } .reduce { a, b -> a || b } if (!isHome) return@addRuleFirst MatchResult.DENY val isSelf = team.teamInfo.home.containsBlock(loc) if ((actionType == PLACE) xor isSelf) MatchResult.ALLOW else MatchResult.DENY } } }