From 00d876485bd0218df11f6a7b81b9efa2bec7093f Mon Sep 17 00:00:00 2001 From: Tooze Date: Mon, 8 Jun 2026 17:28:08 -0400 Subject: [PATCH] bot bots bots bot bot bots bot Yes,. --- .../minigame/barbassault/BADevHelper.kt | 51 ++++- .../barbassault/arena/BAHornSystem.kt | 2 +- .../minigame/barbassault/arena/BASession.kt | 17 +- .../barbassault/bots/AttackerBehavior.kt | 62 ++++++ .../minigame/barbassault/bots/BABotContext.kt | 82 ++++++++ .../barbassault/bots/CollectorBehavior.kt | 25 +++ .../barbassault/bots/DefenderBehavior.kt | 44 +++++ .../barbassault/bots/HealerBehavior.kt | 176 ++++++++++++++++++ .../barbassault/bots/LobbyBehavior.kt | 88 +++++++++ .../minigame/barbassault/bots/SmartBABot.kt | 100 ++++++++++ .../barbassault/bots/{ => oldbot}/BABot.kt | 47 ++--- .../bots/{ => oldbot}/BACombatState.kt | 14 +- .../main/core/game/bots/GeneralBotCreator.kt | 2 +- Server/src/main/core/game/bots/Script.java | 2 + Server/src/main/core/game/bots/ScriptAPI.kt | 3 +- 15 files changed, 664 insertions(+), 51 deletions(-) create mode 100644 Server/src/main/content/minigame/barbassault/bots/AttackerBehavior.kt create mode 100644 Server/src/main/content/minigame/barbassault/bots/BABotContext.kt create mode 100644 Server/src/main/content/minigame/barbassault/bots/CollectorBehavior.kt create mode 100644 Server/src/main/content/minigame/barbassault/bots/DefenderBehavior.kt create mode 100644 Server/src/main/content/minigame/barbassault/bots/HealerBehavior.kt create mode 100644 Server/src/main/content/minigame/barbassault/bots/LobbyBehavior.kt create mode 100644 Server/src/main/content/minigame/barbassault/bots/SmartBABot.kt rename Server/src/main/content/minigame/barbassault/bots/{ => oldbot}/BABot.kt (75%) rename Server/src/main/content/minigame/barbassault/bots/{ => oldbot}/BACombatState.kt (83%) diff --git a/Server/src/main/content/minigame/barbassault/BADevHelper.kt b/Server/src/main/content/minigame/barbassault/BADevHelper.kt index 498647039..16d68e43b 100644 --- a/Server/src/main/content/minigame/barbassault/BADevHelper.kt +++ b/Server/src/main/content/minigame/barbassault/BADevHelper.kt @@ -1,6 +1,6 @@ package content.minigame.barbassault -import content.minigame.barbassault.bots.BABot +import content.minigame.barbassault.bots.oldbot.BABot import content.minigame.barbassault.lobby.BALobby import core.api.* import core.game.container.impl.EquipmentContainer @@ -8,9 +8,14 @@ import core.game.node.item.Item import core.game.system.command.Privilege import core.game.system.command.sets.CommandSet import core.game.world.map.Location +import core.game.world.repository.Repository import core.plugin.Initializable import org.rs09.consts.Items import org.rs09.consts.Scenery +import content.minigame.barbassault.bots.SmartBAPlayerScript +import content.minigame.barbassault.bots.SmartBABot +import core.game.bots.AIPlayer +import core.game.bots.GeneralBotCreator @Initializable class BADevHelper : CommandSet(Privilege.ADMIN) { @@ -74,6 +79,48 @@ class BADevHelper : CommandSet(Privilege.ADMIN) { return@define } + define("smartbabot") { player, _ -> + if (babotcount >= 25) { + sendMessage(player, "25 is max amount of BA bots allowed") + return@define + } + + SmartBABot(BALobby.MAIN_LOBBY.randomWalkableLoc) + + babotcount++ + sendMessage(player, "Spawned Smart BA bot.") + return@define + } + + define("smartbaplayer") { player, _ -> + GeneralBotCreator(SmartBAPlayerScript(), player, true) + sendMessage(player, "Started Smart BA bot script on your player.") + return@define + } + + define("babotstate") { player, args -> + val nameFilter = args.getOrNull(1)?.lowercase() + val bots = Repository.players + .filterIsInstance() + .filter { nameFilter == null || it.username.lowercase().contains(nameFilter) } + + val bot = bots.minByOrNull { it.location.getDistance(player.location) } + if (bot == null) { + sendMessage(player, "No BA bot found.") + return@define + } + + sendMessage(player, "${bot.username}: ${bot.customState} : loc: ${bot.location}") + return@define + } + define("iswait"){player,_ -> + val iswait = BALobby.isWaitingArea(player.location) + sendMessage(player,"isWaiting : ${iswait}") + } + define("ishall"){player,_ -> + val ishall = BALobby.isInHalls(player.location) + sendMessage(player,"isInhall : ${ishall}") + } define("hch"){ player,args-> val chId = args[1].toIntOrNull() @@ -178,4 +225,4 @@ class BADevHelper : CommandSet(Privilege.ADMIN) { return@define } } -} \ No newline at end of file +} diff --git a/Server/src/main/content/minigame/barbassault/arena/BAHornSystem.kt b/Server/src/main/content/minigame/barbassault/arena/BAHornSystem.kt index 308a5a7e2..cc4ae9a47 100644 --- a/Server/src/main/content/minigame/barbassault/arena/BAHornSystem.kt +++ b/Server/src/main/content/minigame/barbassault/arena/BAHornSystem.kt @@ -56,7 +56,7 @@ class BAHornSystem : InteractionListener { when (optionClicked) { "tell-red" -> eggToTell = BarbassaultSession.EggColor.RED "tell-green" -> eggToTell = BarbassaultSession.EggColor.GREEN - "tell-blue" -> eggToTell = BarbassaultSession.EggColor.RED + "tell-blue" -> eggToTell = BarbassaultSession.EggColor.BLUE "drop" -> { sendMessage(player, "I need that!");return@on true } "medic" -> { sendChat(player, "Medic!"); session.alertHealers(player);return@on true } } diff --git a/Server/src/main/content/minigame/barbassault/arena/BASession.kt b/Server/src/main/content/minigame/barbassault/arena/BASession.kt index bb3daf197..5d1b01361 100644 --- a/Server/src/main/content/minigame/barbassault/arena/BASession.kt +++ b/Server/src/main/content/minigame/barbassault/arena/BASession.kt @@ -47,7 +47,6 @@ data class PenanceNpcTunnel( val type: PenanceType, val caveLocation: Location, data class ArenaSpawnItems(val id: Int, val location: Location) class BarbassaultSession( val activity: BAActivity ? = null) :LogoutListener, MapArea { - //constructor(region: DynamicRegion, activity: BarbassaultActivity) : this(activity) {this.region = region; this.base = region.baseLocation} lateinit var region: DynamicRegion lateinit var base: Location lateinit var currentWaveDefinition: WaveDefinition @@ -76,11 +75,10 @@ class BarbassaultSession( val activity: BAActivity ? = null) :LogoutListener, M val scoreManager = BarbScoreManager() val eventBus = BarbAssEventBus() - private val countDoown = if(GameWorld.settings?.isDevMode == true) 10 else 30 + private var countDoown = if(GameWorld.settings?.isDevMode == true) 10 else 30 private var countdownPulse: Pulse? = null - fun beginStartingPhase(quickStart: Boolean = false) { if (state != BarbassaultState.PARTY_CREATION) return state = BarbassaultState.STARTING @@ -133,7 +131,8 @@ class BarbassaultSession( val activity: BAActivity ? = null) :LogoutListener, M } private fun startCountdown(quickStart: Boolean) { - var ticks = secondsToTicks(countDoown)//60 + countDoown = if (quickStart) 1 else countDoown + var ticks = secondsToTicks(countDoown)//30 if(!quickStart){ team.allPlayers().forEach { openOverlay(it, 494);setInterfaceText(it, "30", 494, 0) } } countdownPulse = object : Pulse(1) { override fun pulse(): Boolean { @@ -149,8 +148,9 @@ class BarbassaultSession( val activity: BAActivity ? = null) :LogoutListener, M val secondsLeft = ticksToSeconds(ticks) val display = secondsLeft.toString().padStart(2, '0') - - team.allPlayers().forEach { setInterfaceText(it, display, 494, 0) } + if(!quickStart) { + team.allPlayers().forEach { setInterfaceText(it, display, 494, 0) } + } return false } @@ -190,11 +190,14 @@ class BarbassaultSession( val activity: BAActivity ? = null) :LogoutListener, M tracker.defenderStats.runnersPast++ } } + fun isPenanceDead( type: PenanceType): Boolean = currentNPCDeathCount[type] >= currentNPCCount[type] + fun isAllPenanceDead(): Boolean = PenanceType.values().all { isPenanceDead(it) } + fun pennanceClearedMessage(npc: NPC) { val session = getBASession(npc) ?: return val type = npc.getAttribute("barbass-type") session.currentNPCDeathCount[type]++ - if (session.currentNPCDeathCount[type] == session.currentWaveDefinition.caps[type]) { + if (session.isPenanceDead(type)) { type.toString() session.broadcast("All of the Penance ${type.name.lowercase().replaceFirstChar { it.uppercase() }}s have been killed!") } diff --git a/Server/src/main/content/minigame/barbassault/bots/AttackerBehavior.kt b/Server/src/main/content/minigame/barbassault/bots/AttackerBehavior.kt new file mode 100644 index 000000000..28be0d97a --- /dev/null +++ b/Server/src/main/content/minigame/barbassault/bots/AttackerBehavior.kt @@ -0,0 +1,62 @@ +package content.minigame.barbassault.bots.roles + +import content.minigame.barbassault.BarbRole +import content.minigame.barbassault.arena.BarbassaultSession.AttackerStyle +import content.minigame.barbassault.bots.RoleBehavior +import content.minigame.barbassault.bots.core.BABotContext +import content.minigame.barbassault.getBASession +import core.game.node.entity.Entity +import core.game.node.entity.combat.equipment.WeaponInterface.AttackStyle +import core.game.node.entity.combat.equipment.WeaponInterface.BONUS_SLASH +import core.game.node.entity.npc.NPC +import core.game.node.entity.player.Player + +class AttackerBehavior : RoleBehavior { + + override fun tick(ctx: BABotContext) { + + val bot = ctx.bot + val api = ctx.api + + useCalledAttackStyle(bot) + if (attackPenance(ctx)) return + if (ctx.poolIdle()) return + if (ctx.insultDefender(bot)) return + + + } + + + private fun useCalledAttackStyle(bot: Player) { + val baSession = getBASession(bot) ?: return + val called = (baSession.roleCalls[BarbRole.ATTACKER]?.called ?: AttackerStyle.values().random() ) as AttackerStyle + if (bot.properties.attackStyle.style == called.attackStyle) return + + bot.properties.attackStyle = AttackStyle(called.attackStyle, BONUS_SLASH) + } + private fun checkValidTargets(target: NPC): Boolean { + if (!target.isActive()) return false + if (!target.getProperties().isMultiZone() && target.inCombat()) return false + if (!target.getDefinition().hasAction("attack")) return false + return true + } + private fun findTargets(entity: Entity): List = getBASession(entity)?.sessionNpcs?.filter { checkValidTargets(it) }?.sortedBy { it.location.getDistance(entity.location) }?.take(5)?: emptyList() + + fun attackPenance(ctx: BABotContext): Boolean { + val bot = ctx.bot + if (bot.inCombat()) return true + var target = ctx.currentTarget as? Entity + + if (target != null && !checkValidTargets(target as NPC)) { ctx.currentTarget = null; target = null } + + if (target == null) { + target = findTargets(bot).firstOrNull { !it.inCombat() }?: findTargets(bot).firstOrNull() + if (target == null) return false + ctx.currentTarget = target + } + + bot.attack(target) + return true + } + +} \ No newline at end of file diff --git a/Server/src/main/content/minigame/barbassault/bots/BABotContext.kt b/Server/src/main/content/minigame/barbassault/bots/BABotContext.kt new file mode 100644 index 000000000..d06583d75 --- /dev/null +++ b/Server/src/main/content/minigame/barbassault/bots/BABotContext.kt @@ -0,0 +1,82 @@ +package content.minigame.barbassault.bots.core + +import content.minigame.barbassault.BarbRole +import content.minigame.barbassault.arena.BarbassaultSession +import content.minigame.barbassault.arena.PenanceType +import core.game.bots.Script +import core.game.bots.ScriptAPI +import core.game.node.Node +import core.game.node.entity.player.Player +import core.game.world.map.zone.ZoneBorders + + + +class BABotContext( val bot: Player,val api: ScriptAPI ) { + var currentTarget: Node? = null + var script: Script? = null + var session: BarbassaultSession? = null + var role: BarbRole? = null + + private var delayTicks = 0 + internal var insultNextTick = 0 + + var tick: Int = 0 + + fun tickDelay(ticks: Int) { delayTicks = ticks } + + fun processDelay(): Boolean { + if (delayTicks > 0) { + delayTicks-- + return true + } + return false + } + + fun clickDialogueOption(buttonId: Int): Boolean { + val chatbox = bot.interfaceManager.chatbox ?: return false + + val action = bot.dialogueInterpreter.actions.removeFirstOrNull() + if (action != null) { + action.handle(bot, buttonId) + bot.interfaceManager.closeChatbox() + bot.dialogueInterpreter.close() + return true + } + + if (bot.dialogueInterpreter.dialogue != null) { + bot.dialogueInterpreter.handle(chatbox.id, buttonId) + return true + } + + return false + } + + fun poolIdle(): Boolean { + val base = session?.base ?: return false + val poolArea = ZoneBorders(base.x+27, base.y+18, base.x+24, base.y+16, 0) + if (poolArea.insideBorder(bot.location)) { + return false + } + api.walkTo(poolArea.randomWalkableLoc) + return true + } + + fun insultDefender(bot: Player): Boolean { + val s = session!! + if (!s.isPenanceDead(PenanceType.HEALER) && !s.isPenanceDead(PenanceType.RANGER )&& !s.isPenanceDead(PenanceType.FIGHTER)) return false + + if (tick < insultNextTick) return false + val defenderInsults = listOf( + "you defend like Ryan codes Barbass", + "R u asleep?", + "get szued", + "I've seen better defense from a broken gate", + "do you even see the runners?", + "my grandma can do better then that!" + ) + api.sendChat(defenderInsults.random()) + insultNextTick = tick + (8..20).random() + return true + } + +} diff --git a/Server/src/main/content/minigame/barbassault/bots/CollectorBehavior.kt b/Server/src/main/content/minigame/barbassault/bots/CollectorBehavior.kt new file mode 100644 index 000000000..1b99e4b89 --- /dev/null +++ b/Server/src/main/content/minigame/barbassault/bots/CollectorBehavior.kt @@ -0,0 +1,25 @@ +package content.minigame.barbassault.bots.roles + +import content.minigame.barbassault.bots.RoleBehavior +import content.minigame.barbassault.bots.core.BABotContext +import core.game.interaction.IntType +import core.game.interaction.InteractionListeners + +class CollectorBehavior : RoleBehavior { + + override fun tick(ctx: BABotContext) { + + val bot = ctx.bot + val api = ctx.api + + if (ctx.insultDefender(bot)) return + + bot.customState = "Collector" + + + val cannon = api.getNearestNode(2213, true) + if (cannon != null) { + api.walkTo(cannon.location) + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/minigame/barbassault/bots/DefenderBehavior.kt b/Server/src/main/content/minigame/barbassault/bots/DefenderBehavior.kt new file mode 100644 index 000000000..b5a371a5f --- /dev/null +++ b/Server/src/main/content/minigame/barbassault/bots/DefenderBehavior.kt @@ -0,0 +1,44 @@ +package content.minigame.barbassault.bots.roles + +import content.minigame.barbassault.arena.PenanceType +import content.minigame.barbassault.bots.RoleBehavior +import content.minigame.barbassault.bots.core.BABotContext +import content.minigame.barbassault.getBASession +import core.api.sendChat +import core.game.node.entity.player.Player +import core.game.world.map.Location + +class DefenderBehavior : RoleBehavior { + + override fun tick(ctx: BABotContext) { + val bot = ctx.bot + val api = ctx.api + + if (!bot.walkingQueue.isMoving) { + //ctx.api.walkTo(null) + ctx.tickDelay(3) + } + if (defendInsults(ctx)) return + + bot.customState = "Defender: " + } + + fun defendInsults(ctx: BABotContext): Boolean { + val s = ctx.session!! + if (!s.isPenanceDead(PenanceType.HEALER) && !s.isPenanceDead(PenanceType.RANGER )&& !s.isPenanceDead(PenanceType.FIGHTER)) return false + if (ctx.tick < ctx.insultNextTick) return false + val defenderInsults = listOf( + "Have you seen the size of these things?", + "them leggs", + "get szued", + "like to see you try...", + "Where? what runners? I CANT SEEE!!", + "...", + "call the right food!" + ) + ctx.api.sendChat(defenderInsults.random()) + ctx.insultNextTick = ctx.tick + (8..20).random() + return true + return true + } +} \ No newline at end of file diff --git a/Server/src/main/content/minigame/barbassault/bots/HealerBehavior.kt b/Server/src/main/content/minigame/barbassault/bots/HealerBehavior.kt new file mode 100644 index 000000000..eb549b29b --- /dev/null +++ b/Server/src/main/content/minigame/barbassault/bots/HealerBehavior.kt @@ -0,0 +1,176 @@ +package content.minigame.barbassault.bots.roles + +import content.minigame.barbassault.BarbRole +import content.minigame.barbassault.arena.BarbassaultSession +import content.minigame.barbassault.arena.npcs.PENANCE_HEALER_IDS +import content.minigame.barbassault.bots.RoleBehavior +import content.minigame.barbassault.bots.core.BABotContext +import core.game.interaction.IntType +import core.game.interaction.InteractionListeners +import core.game.node.entity.combat.DeathTask +import core.game.node.entity.npc.NPC +import core.game.node.entity.player.Player +import core.game.node.item.Item +import org.rs09.consts.Items +import org.rs09.consts.Scenery + +class HealerBehavior : RoleBehavior { + + override fun tick(ctx: BABotContext) { + val bot = ctx.bot + val session = ctx.session ?: return + + if (healTeamMate(ctx, session)) return + if (stockUp(ctx)) return + if (fillVial(ctx)) return + if (healSelf(ctx)) return + if (poisonPenanceHealer(ctx, session)) return + if (healAnyTeammate(ctx, session)) return + if (ctx.insultDefender(bot)) return + + bot.customState = "BA-Healer: Idle" + } + + private fun healTeamMate(ctx: BABotContext, session: BarbassaultSession): Boolean { + val bot = ctx.bot + val target = session.team.allPlayers() + .filter { it != bot && healthPercent(it) <= TEAM_HEAL_PERCENT && it.skills.lifepoints > 0 } + .minByOrNull { healthPercent(it) } + ?: return false + + val vial = getBestUsableVial(bot) ?: return false + bot.customState = "BA-Healer: Healing ${target.username} (${target.skills.lifepoints}/${target.skills.maximumLifepoints})" + InteractionListeners.run(vial, target, IntType.PLAYER, bot) + ctx.tickDelay(3) + return true + } + private fun healAnyTeammate(ctx: BABotContext, session: BarbassaultSession): Boolean { + val bot = ctx.bot + + val target = session.team.allPlayers() + .filter { it != bot && it.skills.lifepoints > 0 } + .minByOrNull { healthPercent(it) } + ?: return false + + val vial = getBestUsableVial(bot) ?: return false + if (healthPercent(target) >= 0.95) return false + + bot.customState = "BA-Healer: Idle-heal ${target.username}" + InteractionListeners.run(vial, target, IntType.PLAYER, bot) + ctx.tickDelay(2) + return true + } + + private fun stockUp(ctx: BABotContext): Boolean { + val bot = ctx.bot + + if (hasAnyVial(bot) && POISON_FOODS.any { bot.inventory.containsAtLeastOneItem(it) }) { + return false + } + + val machine = ctx.api.getNearestNode(Scenery.HEALER_ITEM_MACHINE_20243, true) ?: return false + bot.customState = "BA-Healer: Stocking up" + ctx.api.interact(bot, machine, "Stock-up") + ctx.tickDelay(5) + return true + } + + private fun fillVial(ctx: BABotContext): Boolean { + val bot = ctx.bot + + if (!hasAnyVial(bot) || bot.inventory.containsAtLeastOneItem(Items.HEALING_VIAL4_10542)) { + return false + } + + val spring = ctx.api.getNearestNode(Scenery.HEALER_SPRING_20150, true) ?: return false + bot.customState = "BA-Healer: Filling vial" + ctx.api.interact(bot, spring, "Take-from") + ctx.tickDelay(4) + return true + } + + private fun healSelf(ctx: BABotContext): Boolean { + val bot = ctx.bot + + if (healthPercent(bot) > SELF_HEAL_PERCENT) return false + + val spring = ctx.api.getNearestNode(Scenery.HEALER_SPRING_20150, true) ?: return false + bot.customState = "BA-Healer: Drinking from spring" + ctx.api.interact(bot, spring, "Drink-from") + ctx.tickDelay(5) + return true + } + + private fun poisonPenanceHealer(ctx: BABotContext, session: BarbassaultSession): Boolean { + val bot = ctx.bot + val poison = (session.roleCalls[BarbRole.HEALER] as? BarbassaultSession.HealerCall)?.called + ?: return false + + if (!bot.inventory.containsAtLeastOneItem(poison.itemId)) { + val machine = ctx.api.getNearestNode(Scenery.HEALER_ITEM_MACHINE_20243, true) ?: return false + bot.customState = "BA-Healer: Restocking ${poison.ui}" + ctx.api.interact(bot, machine, "Stock-up") + ctx.tickDelay(5) + return true + } + + val target = session.sessionNpcs + .filter { isValidPenanceHealer(it) } + .minByOrNull { it.location.getDistance(bot.location) } + ?: return false + + bot.customState = "BA-Healer: Poisoning ${target.name} with ${poison.ui}" + ctx.api.useWith(bot, poison.itemId, target) + ctx.tickDelay(3) + return true + } + + private fun getBestUsableVial(player: Player): Item? { + return USABLE_HEALING_VIALS + .firstOrNull { player.inventory.containsAtLeastOneItem(it) } + ?.let { player.inventory.getItem(Item(it)) } + } + + private fun hasAnyVial(player: Player): Boolean { + return ALL_HEALING_VIALS.any { player.inventory.containsAtLeastOneItem(it) } + } + + private fun healthPercent(player: Player): Double { + val max = player.skills.maximumLifepoints + if (max <= 0) return 1.0 + return player.skills.lifepoints.toDouble() / max.toDouble() + } + + private fun isValidPenanceHealer(npc: NPC): Boolean { + return npc.id in PENANCE_HEALER_IDS && + npc.isActive && + npc.skills.lifepoints > 0 && + !DeathTask.isDead(npc) + } + + private companion object { + private const val TEAM_HEAL_PERCENT = 0.65 + private const val SELF_HEAL_PERCENT = 0.40 + + private val ALL_HEALING_VIALS = intArrayOf( + Items.HEALING_VIAL_10546, + Items.HEALING_VIAL1_10545, + Items.HEALING_VIAL2_10544, + Items.HEALING_VIAL3_10543, + Items.HEALING_VIAL4_10542 + ) + + private val USABLE_HEALING_VIALS = intArrayOf( + Items.HEALING_VIAL4_10542, + Items.HEALING_VIAL3_10543, + Items.HEALING_VIAL2_10544, + Items.HEALING_VIAL1_10545 + ) + + private val POISON_FOODS = intArrayOf( + Items.POISONED_TOFU_10539, + Items.POISONED_WORMS_10540, + Items.POISONED_MEAT_10541 + ) + } +} diff --git a/Server/src/main/content/minigame/barbassault/bots/LobbyBehavior.kt b/Server/src/main/content/minigame/barbassault/bots/LobbyBehavior.kt new file mode 100644 index 000000000..f0f1c3e4d --- /dev/null +++ b/Server/src/main/content/minigame/barbassault/bots/LobbyBehavior.kt @@ -0,0 +1,88 @@ +package content.minigame.barbassault.bots + +import content.minigame.barbassault.arena.BarbassaultState +import content.minigame.barbassault.bots.core.BABotContext +import content.minigame.barbassault.getBASession + +import content.minigame.barbassault.lobby.BALobby +import content.minigame.barbassault.lobby.BALobby.Companion.QUICK_START +import core.game.world.map.Location +import org.rs09.consts.Scenery + + +class LobbyBehavior : RoleBehavior { + private enum class LobbyState { GET_TO_BA, FINDING_ROOM, WAITING_IN_ROOM,IN_ARENA } + + + override fun tick(ctx: BABotContext) { + + val state = state(ctx) + ctx.bot.customState = "BA-Lobby: $state" + ctx.bot.debug("$state") + + when (state) { + LobbyState.GET_TO_BA -> getToBA(ctx) + LobbyState.FINDING_ROOM -> enterRoom(ctx) + LobbyState.WAITING_IN_ROOM -> waitingInRoom(ctx) + LobbyState.IN_ARENA -> return + } + } + + private fun state(ctx: BABotContext): LobbyState { + val loc = ctx.bot.location + val session = getBASession(ctx.bot) + ctx.bot.debug( + "loc=$loc waiting=${isWaitingArea(loc)} halls=${isInHalls(loc)} session=${session != null}" + ) + return when { + (session?.state == BarbassaultState.IN_ARENA) -> LobbyState.IN_ARENA + (session?.state == BarbassaultState.END) -> LobbyState.IN_ARENA + (session?.state == BarbassaultState.COMPLETE) -> LobbyState.IN_ARENA + isWaitingQuick(loc) -> LobbyState.WAITING_IN_ROOM + isWaitingArea(loc) && (session != null) -> LobbyState.WAITING_IN_ROOM + isInHalls(loc) -> LobbyState.FINDING_ROOM + + else -> LobbyState.GET_TO_BA + } + } + + private fun waitingInRoom(ctx: BABotContext) { + if (ctx.tick % 12 == 0 && !ctx.bot.walkingQueue.isMoving) { + ctx.api.walkTo(QUICK_START.randomWalkableLoc) + ctx.tickDelay(3) + return + } + + if (ctx.tick % 50 == 0) { + ctx.bot.sendChat("Cmon, we need more people!!") + } + } + private fun getToBA(ctx: BABotContext) { + ctx.bot.teleport(BALobby.MAIN_LOBBY.randomWalkableLoc) + ctx.tickDelay(4) + } + + private fun enterRoom(ctx: BABotContext) { + if (ctx.bot.interfaceManager.hasChatbox()) { + ctx.clickDialogueOption(6) + ctx.tickDelay(8) + return + } + val quickDoor = ctx.api.getNearestNode(Scenery.DOOR_20209, true) + ctx.api.interact(ctx.bot, quickDoor, "Pass") + ctx.tickDelay(16) + + } + + private fun isInHalls(location: Location): Boolean { + return BALobby.isInHalls(location) + } + + private fun isWaitingQuick(location: Location): Boolean { + return QUICK_START.insideBorder(location) + } + private fun isWaitingArea(location: Location): Boolean { + return BALobby.isWaitingArea(location) + } + +} diff --git a/Server/src/main/content/minigame/barbassault/bots/SmartBABot.kt b/Server/src/main/content/minigame/barbassault/bots/SmartBABot.kt new file mode 100644 index 000000000..a7d28c025 --- /dev/null +++ b/Server/src/main/content/minigame/barbassault/bots/SmartBABot.kt @@ -0,0 +1,100 @@ +package content.minigame.barbassault.bots + +import content.minigame.barbassault.BarbRole +import content.minigame.barbassault.arena.BarbassaultState +import content.minigame.barbassault.bots.core.BABotContext +import content.minigame.barbassault.bots.roles.AttackerBehavior +import content.minigame.barbassault.bots.roles.CollectorBehavior +import content.minigame.barbassault.bots.roles.DefenderBehavior +import content.minigame.barbassault.bots.roles.HealerBehavior +import content.minigame.barbassault.getBARoleForPlayer +import content.minigame.barbassault.getBASession +import core.game.bots.AIPlayer +import core.game.bots.CombatBotAssembler +import core.game.bots.PvMBots +import core.game.bots.Script +import core.game.bots.ScriptAPI +import core.game.container.impl.EquipmentContainer +import core.game.global.action.EquipHandler +import core.game.world.map.Location + +interface RoleBehavior { + fun tick(ctx: BABotContext) +} + +private class SmartBABotBrain(private val ctx: BABotContext) { + private val lobby = LobbyBehavior() + private val attacker = AttackerBehavior() + private val collector = CollectorBehavior() + private val defender = DefenderBehavior() + private val healer = HealerBehavior() + + private var tickTimer = 0 + + fun tick() { + tickTimer++ + ctx.tick = tickTimer + + if (ctx.processDelay()) return + + ctx.session = getBASession(ctx.bot) + + if (ctx.session?.state == BarbassaultState.IN_ARENA) { + ctx.role = getBARoleForPlayer(ctx.bot) + when (ctx.role) { + BarbRole.ATTACKER -> attacker.tick(ctx) + BarbRole.COLLECTOR -> collector.tick(ctx) + BarbRole.DEFENDER -> defender.tick(ctx) + BarbRole.HEALER -> healer.tick(ctx) + null -> return + } + return + } + + lobby.tick(ctx) + } +} + +class SmartBABot(l: Location) : PvMBots(l) { + private val ctx = BABotContext(this, ScriptAPI(this)) + private val brain = SmartBABotBrain(ctx) + + init { + (this as AIPlayer).fullRestore() + CombatBotAssembler().gearPCiMeleeBot(this) + + val cape = equipment.get(EquipmentContainer.SLOT_CAPE) + if (cape != null) { + EquipHandler.unequip(this, EquipmentContainer.SLOT_CAPE, cape.id) + } + } + + override fun tick() { + super.tick() + brain.tick() + } +} + +class SmartBAPlayerScript : Script() { + private lateinit var brain: SmartBABotBrain + + init { + endDialogue = false + preventRandomIdle = true + } + + override fun init(isPlayer: Boolean) { + super.init(isPlayer) + val ctx = BABotContext(bot, scriptAPI) + ctx.script = this + brain = SmartBABotBrain(ctx) + } + + override fun tick() { + brain.tick() + } + + override fun newInstance(): Script { + return SmartBAPlayerScript().also { it.bot = this.bot } + } +} diff --git a/Server/src/main/content/minigame/barbassault/bots/BABot.kt b/Server/src/main/content/minigame/barbassault/bots/oldbot/BABot.kt similarity index 75% rename from Server/src/main/content/minigame/barbassault/bots/BABot.kt rename to Server/src/main/content/minigame/barbassault/bots/oldbot/BABot.kt index 682046350..eebdcd668 100644 --- a/Server/src/main/content/minigame/barbassault/bots/BABot.kt +++ b/Server/src/main/content/minigame/barbassault/bots/oldbot/BABot.kt @@ -1,23 +1,18 @@ -package content.minigame.barbassault.bots +package content.minigame.barbassault.bots.oldbot import content.minigame.barbassault.BarbRole import content.minigame.barbassault.arena.BarbassaultState -import content.minigame.barbassault.arena.scenery.ItemMachine -import content.minigame.barbassault.arena.scenery.ItemMachine.DispenserType import content.minigame.barbassault.getBARoleForPlayer import content.minigame.barbassault.getBASession -import content.minigame.barbassault.lobby.BALobby.Companion.MAIN_LOBBY -import content.minigame.barbassault.lobby.BALobby.Companion.QUICK_START -import content.minigame.barbassault.lobby.BALobby.Companion.waveLobbies -import content.minigame.barbassault.lobby.BarbassQuickWaveActivity.Companion.addToQueue +import content.minigame.barbassault.lobby.BALobby +import content.minigame.barbassault.lobby.BarbassQuickWaveActivity import core.api.forceMove import core.api.getRegionBorders import core.api.log -import core.api.queueScript -import core.api.stopExecuting import core.game.bots.AIPlayer import core.game.bots.CombatBotAssembler import core.game.bots.PvMBots +import core.game.bots.ScriptAPI import core.game.global.action.EquipHandler import core.game.node.entity.Entity import core.game.node.entity.player.Player @@ -25,8 +20,6 @@ import core.game.node.item.Item import core.game.world.map.Location import core.tools.Log import org.rs09.consts.Scenery -import org.rs09.consts.Scenery.COLLECTOR_CONVERTER_21250 - class BABot(l: Location) : PvMBots(legitimizeLocation(l)) { @@ -36,7 +29,7 @@ class BABot(l: Location) : PvMBots(legitimizeLocation(l)) { val cape: Item? = equipment.get(1) if (cape != null) { - EquipHandler.unequip(this, 1, cape.id) + EquipHandler.Companion.unequip(this, 1, cape.id) } } @@ -44,6 +37,7 @@ class BABot(l: Location) : PvMBots(legitimizeLocation(l)) { private var tickTimer = 0 private var moveTimer = 0 var hasVendingItems = false + var scriptAPI: ScriptAPI? = null enum class State { GET_TO_BA, OUTSIDE_ROOM, ENTER_ROOM, WAITING_IN_ROOM, PLAY_GAME } @@ -89,22 +83,15 @@ class BABot(l: Location) : PvMBots(legitimizeLocation(l)) { } private fun getToBA() { - teleport(MAIN_LOBBY.randomWalkableLoc) + teleport(BALobby.Companion.MAIN_LOBBY.randomWalkableLoc) moveTimer = 3 } fun useRoleVendingMachine() { if (hasVendingItems) return - - val roleMachine = getClosestNodeWithEntry(60, getBARoleForPlayer(this)!!.machineId) ?: return - if (roleMachine.id == COLLECTOR_CONVERTER_21250) return - queueScript(this,3) { - roleMachine.interaction.handle(this, roleMachine.interaction[0]) - // ItemMachine().handleAddItemMachine(this, roleMachine,10558, STOCK_UP_DEF, 1,DispenserType.FOOD) - - hasVendingItems = true - return@queueScript stopExecuting(this) - } + val roleMachine = scriptAPI?.getNearestNode(getBARoleForPlayer(this)!!.machineId, true) + if (roleMachine?.id == Scenery.COLLECTOR_CONVERTER_21250) return + scriptAPI?.interact(this, roleMachine, "Stock-up") } @@ -121,8 +108,8 @@ class BABot(l: Location) : PvMBots(legitimizeLocation(l)) { quickDoor.interaction.handle(this, quickDoor.interaction[0]) forceMove(this, location, location.transform(0, -1, 0), 25, 60, null, 819) { - addToQueue(this, null) - combatHandler.walkTo(QUICK_START.randomWalkableLoc) + BarbassQuickWaveActivity.Companion.addToQueue(this, null) + combatHandler.walkTo(BALobby.Companion.QUICK_START.randomWalkableLoc) } moveTimer = 4 @@ -146,20 +133,20 @@ class BABot(l: Location) : PvMBots(legitimizeLocation(l)) { fun isInLobbyOnly(location: Location): Boolean { return getRegionBorders(10322).insideBorder(location) - && waveLobbies.none { - it != MAIN_LOBBY - && it != QUICK_START + && BALobby.Companion.waveLobbies.none { + it != BALobby.Companion.MAIN_LOBBY + && it != BALobby.Companion.QUICK_START && it.insideBorder(location) } } private fun isWaitingArea(location: Location): Boolean { hasVendingItems = false - return QUICK_START.insideBorder(location) || waveLobbies.any { it.insideBorder(location) && it != MAIN_LOBBY } + return BALobby.Companion.QUICK_START.insideBorder(location) || BALobby.Companion.waveLobbies.any { it.insideBorder(location) && it != BALobby.Companion.MAIN_LOBBY } } fun debugthis(info : Any) { - log(this.javaClass, Log.FINE,state.toString()) + log(this.javaClass, Log.FINE, state.toString()) } override fun AttackNpcsInRadius(bot: Player, radius: Int): Boolean { diff --git a/Server/src/main/content/minigame/barbassault/bots/BACombatState.kt b/Server/src/main/content/minigame/barbassault/bots/oldbot/BACombatState.kt similarity index 83% rename from Server/src/main/content/minigame/barbassault/bots/BACombatState.kt rename to Server/src/main/content/minigame/barbassault/bots/oldbot/BACombatState.kt index deacd9669..8bae977ff 100644 --- a/Server/src/main/content/minigame/barbassault/bots/BACombatState.kt +++ b/Server/src/main/content/minigame/barbassault/bots/oldbot/BACombatState.kt @@ -1,19 +1,15 @@ -package content.minigame.barbassault.bots +package content.minigame.barbassault.bots.oldbot import content.minigame.barbassault.BarbRole -import content.minigame.barbassault.arena.BarbassaultSession.AttackerStyle -import content.minigame.barbassault.arena.scenery.ItemMachine -import content.minigame.barbassault.arena.scenery.ItemMachine.DispenserType +import content.minigame.barbassault.arena.BarbassaultSession import content.minigame.barbassault.getBARoleForPlayer import content.minigame.barbassault.getBASession import core.game.interaction.MovementPulse -import core.game.node.entity.combat.equipment.WeaponInterface.AttackStyle -import core.game.node.entity.combat.equipment.WeaponInterface.BONUS_SLASH +import core.game.node.entity.combat.equipment.WeaponInterface import core.game.world.GameWorld import core.game.world.map.Location import core.game.world.map.path.Pathfinder import core.tools.RandomFunction -import org.rs09.consts.Scenery class BACombatState(private val bot: BABot) { @@ -23,8 +19,8 @@ class BACombatState(private val bot: BABot) { bot.AttackNpcsInRadius(bot,25) //use Called AttackStyle val baSession = getBASession(bot) ?: return - val called = (baSession.roleCalls[BarbRole.ATTACKER]?.called ?: AttackerStyle.values().random() ) as AttackerStyle - bot.properties.attackStyle = AttackStyle(called.attackStyle, BONUS_SLASH) + val called = (baSession.roleCalls[BarbRole.ATTACKER]?.called ?: BarbassaultSession.AttackerStyle.values().random() ) as BarbassaultSession.AttackerStyle + bot.properties.attackStyle = WeaponInterface.AttackStyle(called.attackStyle, WeaponInterface.BONUS_SLASH) } diff --git a/Server/src/main/core/game/bots/GeneralBotCreator.kt b/Server/src/main/core/game/bots/GeneralBotCreator.kt index 7e3cb5478..9dc712852 100644 --- a/Server/src/main/core/game/bots/GeneralBotCreator.kt +++ b/Server/src/main/core/game/bots/GeneralBotCreator.kt @@ -102,7 +102,7 @@ class GeneralBotCreator { return false val idleRoll = RandomFunction.random(10) - if(idleRoll == 2 && botScript !is Idler){ + if(idleRoll == 2 && botScript !is Idler && !botScript.preventRandomIdle){ randomDelay += RandomFunction.random(20,50) return false } diff --git a/Server/src/main/core/game/bots/Script.java b/Server/src/main/core/game/bots/Script.java index 9c5da330a..47e487c64 100644 --- a/Server/src/main/core/game/bots/Script.java +++ b/Server/src/main/core/game/bots/Script.java @@ -22,6 +22,8 @@ public abstract class Script { public boolean running = true; public boolean endDialogue = true; + public boolean preventRandomIdle = false; + public void init(boolean isPlayer) { //bot.init(); diff --git a/Server/src/main/core/game/bots/ScriptAPI.kt b/Server/src/main/core/game/bots/ScriptAPI.kt index c2ac69649..a6d81669b 100644 --- a/Server/src/main/core/game/bots/ScriptAPI.kt +++ b/Server/src/main/core/game/bots/ScriptAPI.kt @@ -104,7 +104,8 @@ class ScriptAPI(private val bot: Player) { val item = bot.inventory.getItem(Item(itemId)) - val childNode = node.asScenery()?.getChild(bot) + //val childNode = node.asScenery()?.getChild(bot) + val childNode = if (node is Scenery) node.getChild(bot) else null if (InteractionListeners.run(item, node, type, bot)) return