diff --git a/Server/src/main/content/minigame/barbassault/arena/CollectionBag.kt b/Server/src/main/content/minigame/barbassault/arena/CollectionBag.kt index 161beba4f..900455fa0 100644 --- a/Server/src/main/content/minigame/barbassault/arena/CollectionBag.kt +++ b/Server/src/main/content/minigame/barbassault/arena/CollectionBag.kt @@ -35,7 +35,7 @@ class CollectorBagManager(val player: Player) { fun totalEggs(): Int = container.toArray().filterNotNull().sumOf { it.amount } fun freeEggSpace(): Int = capacity - totalEggs() - fun getEggCount(itemId: Int): Int = container.toArray().filterNotNull().count { it.id == itemId } + fun getEggCount(itemId: Int): Int = container.toArray().filterNotNull().filter { it.id == itemId }.sumOf { it.amount } } @@ -48,4 +48,4 @@ class CollectorBagManager(val player: Player) { sendMessage(player, "You put the egg in the bag.") return true } -} \ No newline at end of file +} diff --git a/Server/src/main/content/minigame/barbassault/bots/AttackerBehavior.kt b/Server/src/main/content/minigame/barbassault/bots/AttackerBehavior.kt index 28be0d97a..7d0845f33 100644 --- a/Server/src/main/content/minigame/barbassault/bots/AttackerBehavior.kt +++ b/Server/src/main/content/minigame/barbassault/bots/AttackerBehavior.kt @@ -1,10 +1,12 @@ package content.minigame.barbassault.bots.roles import content.minigame.barbassault.BarbRole +import content.minigame.barbassault.arena.PenanceType 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.combat.DeathTask 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 @@ -16,13 +18,11 @@ class AttackerBehavior : RoleBehavior { override fun tick(ctx: BABotContext) { val bot = ctx.bot - val api = ctx.api + ctx.insultDefender() useCalledAttackStyle(bot) if (attackPenance(ctx)) return - if (ctx.poolIdle()) return - if (ctx.insultDefender(bot)) return - + if (ctx.poolIdle("BA-Attacker: Idling at pool")) return } @@ -36,6 +36,9 @@ class AttackerBehavior : RoleBehavior { } private fun checkValidTargets(target: NPC): Boolean { if (!target.isActive()) return false + if (target.skills.lifepoints <= 0 || DeathTask.isDead(target)) return false + val penanceType = target.getAttribute("barbass-type", null) + if (penanceType != PenanceType.FIGHTER && penanceType != PenanceType.RANGER) return false if (!target.getProperties().isMultiZone() && target.inCombat()) return false if (!target.getDefinition().hasAction("attack")) return false return true @@ -59,4 +62,4 @@ class AttackerBehavior : RoleBehavior { 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 index d06583d75..25e67e80c 100644 --- a/Server/src/main/content/minigame/barbassault/bots/BABotContext.kt +++ b/Server/src/main/content/minigame/barbassault/bots/BABotContext.kt @@ -1,12 +1,18 @@ package content.minigame.barbassault.bots.core import content.minigame.barbassault.BarbRole +import content.minigame.barbassault.arena.BAGroundSpawn 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.global.action.PickupHandler +import core.game.interaction.IntType +import core.game.interaction.InteractionListeners import core.game.node.Node import core.game.node.entity.player.Player +import core.game.node.item.GroundItemManager +import core.game.world.map.Location import core.game.world.map.zone.ZoneBorders @@ -18,7 +24,7 @@ class BABotContext( val bot: Player,val api: ScriptAPI ) { var role: BarbRole? = null private var delayTicks = 0 - internal var insultNextTick = 0 + private var defenderInsultNextTick = 0 var tick: Int = 0 @@ -51,32 +57,103 @@ class BABotContext( val bot: Player,val api: ScriptAPI ) { return false } - fun poolIdle(): Boolean { - val base = session?.base ?: return false + fun poolIdle(state: String = "BA-Bot: Idling at pool"): Boolean { + val s = session ?: return false + val base = s.base 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) + bot.customState = state + api.walkTo(base.transform(25, 17, 0)) 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 + fun sameTile(a: Location, b: Location): Boolean { + return a.x == b.x && a.y == b.y && a.z == b.z + } + + fun walkToTile(loc: Location, state: String, delay: Int = 2): Boolean { + if (sameTile(bot.location, loc)) return false + + bot.customState = state + api.walkTo(loc) + tickDelay(delay) + return true + } + + fun findBAGroundItem(itemId: Int, spawnLoc: Location? = null): BAGroundSpawn? { + val s = session ?: return null + return s.BAgroundItems + .filter { + it.id == itemId && + it.isActive && + GroundItemManager.getItems().contains(it) && + (spawnLoc == null || sameTile(it.location, spawnLoc)) + } + .minByOrNull { it.location.getDistance(bot.location) } + } + + fun findNearestBAGroundItem(itemId: Int, spawnLocs: List): BAGroundSpawn? { + val s = session ?: return null + return s.BAgroundItems + .filter { item -> + item.id == itemId && + item.isActive && + GroundItemManager.getItems().contains(item) && + spawnLocs.any { sameTile(item.location, it) } + } + .minByOrNull { it.location.getDistance(bot.location) } + } + + fun takeBAGroundItem(item: BAGroundSpawn, state: String, delay: Int = 3): Boolean { + if (walkToTile(item.location, state)) return true + + bot.customState = state + val takeListener = InteractionListeners.get(item.id, IntType.GROUNDITEM.ordinal, "Take") + ?: InteractionListeners.get("Take", IntType.GROUNDITEM.ordinal) + + if (takeListener != null) { + takeListener.invoke(bot, item) + } else { + PickupHandler.take(bot, item) + } + tickDelay(delay) + return true + } + + fun pickUpBAGroundItem(itemId: Int, spawnLoc: Location, state: String): Boolean { + val item = findBAGroundItem(itemId, spawnLoc) ?: return walkToTile(spawnLoc, state) + return takeBAGroundItem(item, state) + } + + fun pickUpNearestBAGroundItem(itemId: Int, spawnLocs: List, state: String): Boolean { + val item = findNearestBAGroundItem(itemId, spawnLocs) + if (item != null) return takeBAGroundItem(item, state) + + val nearestSpawn = spawnLocs.minByOrNull { it.getDistance(bot.location) } ?: return false + return walkToTile(nearestSpawn, state) + } + + fun insultDefender() { + val s = session ?: return + if (!s.isPenanceDead(PenanceType.HEALER) || !s.isPenanceDead(PenanceType.RANGER) || + !s.isPenanceDead(PenanceType.FIGHTER) || s.isPenanceDead(PenanceType.RUNNER) + ) { + return + } + if (tick < defenderInsultNextTick) return - if (tick < insultNextTick) return false val defenderInsults = listOf( - "you defend like Ryan codes Barbass", + "You defend like Ryan codes Barbass", "R u asleep?", - "get szued", + "Get szued", "I've seen better defense from a broken gate", - "do you even see the runners?", - "my grandma can do better then that!" + "Do you even see the runners?", + "My grandma can do better then that!" ) api.sendChat(defenderInsults.random()) - insultNextTick = tick + (8..20).random() - return true + defenderInsultNextTick = tick + (8..20).random() } } diff --git a/Server/src/main/content/minigame/barbassault/bots/CollectorBehavior.kt b/Server/src/main/content/minigame/barbassault/bots/CollectorBehavior.kt index 1b99e4b89..39e8487c5 100644 --- a/Server/src/main/content/minigame/barbassault/bots/CollectorBehavior.kt +++ b/Server/src/main/content/minigame/barbassault/bots/CollectorBehavior.kt @@ -1,25 +1,149 @@ package content.minigame.barbassault.bots.roles +import content.minigame.barbassault.BarbRole +import content.minigame.barbassault.arena.BarbassaultSession import content.minigame.barbassault.bots.RoleBehavior import content.minigame.barbassault.bots.core.BABotContext -import core.game.interaction.IntType -import core.game.interaction.InteractionListeners +import content.minigame.barbassault.arena.scenery.EggCannon +import core.api.amountInInventory +import core.api.freeSlots +import getCollectorBag +import org.rs09.consts.Items +import org.rs09.consts.NPCs +import org.rs09.consts.Scenery class CollectorBehavior : RoleBehavior { override fun tick(ctx: BABotContext) { - val bot = ctx.bot - val api = ctx.api + val session = ctx.session ?: return + ctx.script?.preventRandomIdle = true - if (ctx.insultDefender(bot)) return + ctx.insultDefender() + if (isHopperFull(session)) { + bot.customState = "BA-Collector: Hopper full, idling at cannon" + idleAtCannon(ctx) + return + } - bot.customState = "Collector" + if (hasLoadableCarriedEggs(ctx, session)) { + if (loadHopper(ctx)) return + } + val calledEgg = getCalledEgg(session) ?: run { + bot.customState = "BA-Collector: Waiting for attacker call" + idleAtCannon(ctx) + return + } - val cannon = api.getNearestNode(2213, true) - if (cannon != null) { - api.walkTo(cannon.location) + if (bot.skills.lifepoints <= MIN_SAFE_EGG_HP) { + bot.customState = "BA-Collector: Low HP (${bot.skills.lifepoints}), not picking eggs" + idleAtCannon(ctx) + return + } + + if (!canHopperTake(session, calledEgg.itemId)) { + bot.customState = "BA-Collector: Hopper already full for ${calledEgg.name.lowercase()} eggs" + idleAtCannon(ctx) + return + } + + if (pickUpCalledEgg(ctx, calledEgg)) return + + bot.customState = "BA-Collector: No ${calledEgg.name.lowercase()} eggs nearby" + idleAtCannon(ctx) + } + + private fun getCalledEgg(session: BarbassaultSession): BarbassaultSession.EggColor? { + val call = session.roleCalls[BarbRole.COLLECTOR] as? BarbassaultSession.CollectorCall + return call?.called + } + + private fun loadHopper(ctx: BABotContext): Boolean { + val hopper = ctx.api.getNearestNode(Scenery.EGG_HOPPER_20264, true) ?: run { + ctx.bot.customState = "BA-Collector: Looking for egg hopper" + return false + } + + if (hopper.location.getDistance(ctx.bot.location) > 2) { + ctx.bot.customState = "BA-Collector: Walking to egg hopper" + ctx.api.walkTo(hopper.location) + ctx.tickDelay(2) + return true + } + + val session = ctx.session ?: return false + val redBefore = session.eggHopper.red + val carriedBefore = carriedEggCount(ctx, Items.RED_EGG_10532) + ctx.bot.customState = "BA-Collector: Loading red eggs into hopper carried=$carriedBefore hopper=$redBefore" + + PRIORITY_HOPPER_EGGS.filter { carriedEggCount(ctx, it) > 0 && canHopperTake(session, it) } + .forEach { EggCannon.loadHopperEggs(ctx.bot, it) } + + ctx.bot.customState = "BA-Collector: Loaded red eggs carried=$carriedBefore hopper=$redBefore->${session.eggHopper.red}" + ctx.tickDelay(5) + return true + } + + private fun pickUpCalledEgg(ctx: BABotContext, calledEgg: BarbassaultSession.EggColor): Boolean { + if (!canCarryMoreEggs(ctx)) return false + + val egg = ctx.findBAGroundItem(calledEgg.itemId) ?: return false + return ctx.takeBAGroundItem( + egg, + "BA-Collector: Picking up ${calledEgg.name.lowercase()} egg id=${egg.id} loc=${egg.location}" + ) + } + + private fun canCarryMoreEggs(ctx: BABotContext): Boolean { + return getCollectorBag(ctx.bot).bag.freeEggSpace() > 0 || freeSlots(ctx.bot) > 0 + } + + private fun hasLoadableCarriedEggs(ctx: BABotContext, session: BarbassaultSession): Boolean { + return PRIORITY_HOPPER_EGGS.any { carriedEggCount(ctx, it) > 0 && canHopperTake(session, it) } + } + + private fun carriedEggCount(ctx: BABotContext, itemId: Int): Int { + val bot = ctx.bot + return getCollectorBag(bot).bag.getEggCount(itemId) + amountInInventory(bot, itemId) + } + + private fun canHopperTake(session: BarbassaultSession, itemId: Int): Boolean { + val hopper = session.eggHopper + return when (itemId) { + Items.GREEN_EGG_10531 -> hopper.green < MAX_HOPPER_EGGS_PER_COLOR + Items.RED_EGG_10532 -> hopper.red < MAX_HOPPER_EGGS_PER_COLOR + Items.BLUE_EGG_10533 -> hopper.blue < MAX_HOPPER_EGGS_PER_COLOR + Items.OMEGA_EGG_10537 -> hopper.yellow < MAX_HOPPER_EGGS_PER_COLOR + else -> false } } -} \ No newline at end of file + + private fun isHopperFull(session: BarbassaultSession): Boolean { + val hopper = session.eggHopper + return hopper.green >= MAX_HOPPER_EGGS_PER_COLOR && + hopper.red >= MAX_HOPPER_EGGS_PER_COLOR && + hopper.blue >= MAX_HOPPER_EGGS_PER_COLOR + } + + private fun idleAtCannon(ctx: BABotContext) { + val cannon = ctx.api.getNearestNode(NPCs.EGG_LAUNCHER_5026, false) + if (cannon != null && cannon.location.getDistance(ctx.bot.location) > 2) { + ctx.api.walkTo(cannon.location) + ctx.tickDelay(2) + return + } + + val hopper = ctx.api.getNearestNode(Scenery.EGG_HOPPER_20264, true) + if (hopper != null && hopper.location.getDistance(ctx.bot.location) > 2) { + ctx.api.walkTo(hopper.location) + ctx.tickDelay(2) + } + } + + private companion object { + private const val MIN_SAFE_EGG_HP = 6 + private const val MAX_HOPPER_EGGS_PER_COLOR = 5 + private val PRIORITY_HOPPER_EGGS = intArrayOf(Items.RED_EGG_10532) + } +} diff --git a/Server/src/main/content/minigame/barbassault/bots/DefenderBehavior.kt b/Server/src/main/content/minigame/barbassault/bots/DefenderBehavior.kt index b5a371a5f..ec3f0d0fd 100644 --- a/Server/src/main/content/minigame/barbassault/bots/DefenderBehavior.kt +++ b/Server/src/main/content/minigame/barbassault/bots/DefenderBehavior.kt @@ -1,44 +1,230 @@ package content.minigame.barbassault.bots.roles +import content.minigame.barbassault.BarbRole +import content.minigame.barbassault.LureItems +import content.minigame.barbassault.arena.BAGroundSpawn +import content.minigame.barbassault.arena.BarbassaultSession 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.api.getWorldTicks +import core.api.setAttribute +import core.game.node.item.Item import core.game.world.map.Location +import core.game.world.map.RegionManager +import org.rs09.consts.Items +import org.rs09.consts.Scenery class DefenderBehavior : RoleBehavior { override fun tick(ctx: BABotContext) { val bot = ctx.bot - val api = ctx.api + val session = ctx.session ?: return + ctx.script?.preventRandomIdle = true - if (!bot.walkingQueue.isMoving) { - //ctx.api.walkTo(null) - ctx.tickDelay(3) + if (session.isPenanceDead(PenanceType.RUNNER)) { + if (ctx.poolIdle("BA-Defender: Idling at pool")) return + bot.customState = "BA-Defender: Idle at pool" + return } - if (defendInsults(ctx)) return - bot.customState = "Defender: " + val calledFood = getCalledFood(session) ?: run { + bot.customState = "BA-Defender: Waiting for healer call" + return + } + + if (stockUp(ctx, session, calledFood)) return + if (repairTrap(ctx, session)) return + if (dropTrapFood(ctx, session, calledFood)) return + if (dropTrailFood(ctx, session, calledFood)) return + if (pickUpTools(ctx)) return + + bot.customState = "BA-Defender: Guarding trap" + walkNearTrap(ctx, session) } - 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 + private fun getCalledFood(session: BarbassaultSession): Int? { + val call = session.roleCalls[BarbRole.DEFENDER] as? BarbassaultSession.DefenderCall + return call?.called?.itemId + } + + private fun stockUp(ctx: BABotContext, session: BarbassaultSession, calledFood: Int): Boolean { + val bot = ctx.bot + + if (!needsMoreFood(session) || bot.inventory.containsAtLeastOneItem(calledFood)) { + return false + } + + val machine = ctx.api.getNearestNode(Scenery.DEFENDER_ITEM_MACHINE_20242, true) ?: return false + val option = defenderMachineOption(calledFood) ?: "Stock-up" + bot.customState = "BA-Defender: Taking food id=$calledFood ($option)" + ctx.api.interact(bot, machine, option) + ctx.tickDelay(5) return true } -} \ No newline at end of file + + private fun repairTrap(ctx: BABotContext, session: BarbassaultSession): Boolean { + val bot = ctx.bot + if (!bot.inventory.containsAtLeastOneItem(Items.HAMMER_2347) || !bot.inventory.containsAtLeastOneItem(Items.LOGS_11760)) { + return false + } + + val trap = RegionManager.getObject(trapLocation(session)) ?: return false + if (trap.id != Scenery.RUNNER_TRAP1_20230 && trap.id != Scenery.BROKEN_TRAP0_20231) { + return false + } + + bot.customState = "BA-Defender: Repairing trap" + ctx.api.interact(bot, trap, "Fix") + ctx.tickDelay(6) + return true + } + + private fun dropTrapFood(ctx: BABotContext, session: BarbassaultSession, calledFood: Int): Boolean { + val existingTrapFood = countTrapFood(session) + if (existingTrapFood >= TRAP_DROP_COUNT) return false + + val botLoc = ctx.bot.location + val inTrapArea = trapTiles(session).any { sameTile(botLoc, it) } + if (!inTrapArea || hasLureFoodAt(session, botLoc)) { + val trapDropLoc = trapDropLocation(session, botLoc) + if (ctx.walkToTile(trapDropLoc, "BA-Defender: Moving to trap bait")) return true + } + + if (!dropFood(ctx, session, calledFood, "BA-Defender: Dropping trap bait ${existingTrapFood + 1}/$TRAP_DROP_COUNT")) { + return false + } + + return true + } + + private fun dropTrailFood(ctx: BABotContext, session: BarbassaultSession, calledFood: Int): Boolean { + val nextTrail = TRAIL_SPOTS + .mapIndexed { index, offset -> index to session.base.transform(offset) } + .firstOrNull { (_, loc) -> !hasLureFoodAt(session, loc) } + ?: return false + + val (trailIndex, loc) = nextTrail + if (ctx.walkToTile(loc, "BA-Defender: Walking trail ${trailIndex + 1}/${TRAIL_SPOTS.size}")) return true + + if (!dropFood(ctx, session, calledFood, "BA-Defender: Dropping trail food ${trailIndex + 1}/${TRAIL_SPOTS.size}")) { + return false + } + + return true + } + + private fun pickUpTools(ctx: BABotContext): Boolean { + val bot = ctx.bot + val base = ctx.session?.base ?: return false + + if (!bot.inventory.containsAtLeastOneItem(Items.HAMMER_2347)) { + return ctx.pickUpBAGroundItem( + Items.HAMMER_2347, + base.transform(32, 42, 0), + "BA-Defender: Getting hammer" + ) + } + + if (!bot.inventory.containsAtLeastOneItem(Items.LOGS_11760)) { + return ctx.pickUpNearestBAGroundItem( + Items.LOGS_11760, + listOf(base.transform(30, 46, 0), base.transform(29, 47, 0)), + "BA-Defender: Getting logs" + ) + } + + return false + } + + private fun dropFood(ctx: BABotContext, session: BarbassaultSession, foodId: Int, state: String): Boolean { + val bot = ctx.bot + val inventoryItem = bot.inventory.getItem(Item(foodId)) ?: run { + bot.customState = "$state - missing food id=$foodId" + return false + } + val item = Item(foodId, 1) + val droppedItem = item.dropItem + val requiredFood = (session.roleCalls[BarbRole.DEFENDER] as? BarbassaultSession.DefenderCall)?.required?.itemId + val isGoodFood = foodId == requiredFood + + if (!bot.inventory.remove(item)) { + bot.customState = "$state - failed remove ${inventoryItem.name} id=${inventoryItem.id}" + return false + } + + bot.customState = "$state - ${inventoryItem.name} id=${inventoryItem.id}" + BAGroundSpawn(session, 60, droppedItem, bot.location, isGoodFood).init() + setAttribute(bot, "droppedItem:${droppedItem.id}", getWorldTicks() + 2) + ctx.tickDelay(2) + return true + } + + private fun walkNearTrap(ctx: BABotContext, session: BarbassaultSession) { + ctx.walkToTile(trapDropLocation(session, ctx.bot.location), "BA-Defender: Returning to trap") + } + + private fun trapLocation(session: BarbassaultSession): Location { + return session.base.transform(45, 34, 0) + } + + private fun trapDropLocation(session: BarbassaultSession, from: Location): Location { + val center = trapLocation(session) + if (!hasLureFoodAt(session, center)) return center + + return trapTiles(session) + .filter { !hasLureFoodAt(session, it) } + .minByOrNull { it.getDistance(from) } + ?: center + } + + private fun countTrapFood(session: BarbassaultSession): Int { + val trapTiles = trapTiles(session) + return session.BAgroundItems.count { + it.id in LureItems && + it.isActive && + trapTiles.any { tile -> sameTile(it.location, tile) } + } + } + + private fun needsMoreFood(session: BarbassaultSession): Boolean { + return countTrapFood(session) < TRAP_DROP_COUNT || + TRAIL_SPOTS.any { !hasLureFoodAt(session, session.base.transform(it)) } + } + + private fun hasLureFoodAt(session: BarbassaultSession, loc: Location): Boolean { + return session.BAgroundItems.any { + it.id in LureItems && + it.isActive && + sameTile(it.location, loc) + } + } + + private fun sameTile(a: Location, b: Location): Boolean { + return a.x == b.x && a.y == b.y && a.z == b.z + } + + private fun trapTiles(session: BarbassaultSession): List { + return trapLocation(session).get3x3Tiles() + } + + private fun defenderMachineOption(foodId: Int): String? { + return when (foodId) { + Items.WORMS_10515 -> "Take-worms" + Items.CRACKERS_10513 -> "Take-crackers" + Items.TOFU_10514 -> "Take-tofu" + else -> null + } + } + + private companion object { + private const val TRAP_DROP_COUNT = 2 + + private val TRAIL_SPOTS = listOf( + Location.create(44, 36, 0), + Location.create(41, 37, 0), + Location.create(36, 37, 0), + Location.create(34, 40, 0) + ) + } +} diff --git a/Server/src/main/content/minigame/barbassault/bots/HealerBehavior.kt b/Server/src/main/content/minigame/barbassault/bots/HealerBehavior.kt index eb549b29b..352715d8b 100644 --- a/Server/src/main/content/minigame/barbassault/bots/HealerBehavior.kt +++ b/Server/src/main/content/minigame/barbassault/bots/HealerBehavior.kt @@ -20,15 +20,17 @@ class HealerBehavior : RoleBehavior { val bot = ctx.bot val session = ctx.session ?: return + ctx.insultDefender() 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" + if (ctx.poolIdle("BA-Healer: Idling at pool")) return + + bot.customState = "BA-Healer: Idle at pool" } private fun healTeamMate(ctx: BABotContext, session: BarbassaultSession): Boolean { @@ -69,8 +71,16 @@ class HealerBehavior : RoleBehavior { } 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") + val healerCall = ctx.session?.roleCalls?.get(BarbRole.HEALER) as? BarbassaultSession.HealerCall + val calledPoison = healerCall?.called?.itemId + val option = when { + !hasAnyVial(bot) -> "Take-vial" + calledPoison != null && !bot.inventory.containsAtLeastOneItem(calledPoison) -> healerMachineOption(calledPoison) + else -> "Stock-up" + } ?: "Stock-up" + + bot.customState = "BA-Healer: Taking supplies ($option)" + ctx.api.interact(bot, machine, option) ctx.tickDelay(5) return true } @@ -108,8 +118,9 @@ class HealerBehavior : RoleBehavior { 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") + val option = healerMachineOption(poison.itemId) ?: "Stock-up" + bot.customState = "BA-Healer: Restocking ${poison.ui} ($option)" + ctx.api.interact(bot, machine, option) ctx.tickDelay(5) return true } @@ -148,6 +159,15 @@ class HealerBehavior : RoleBehavior { !DeathTask.isDead(npc) } + private fun healerMachineOption(foodId: Int): String? { + return when (foodId) { + Items.POISONED_TOFU_10539 -> "Take-tofu" + Items.POISONED_WORMS_10540 -> "Take-worms" + Items.POISONED_MEAT_10541 -> "Take-meat" + else -> null + } + } + private companion object { private const val TEAM_HEAL_PERCENT = 0.65 private const val SELF_HEAL_PERCENT = 0.40 diff --git a/Server/src/main/content/minigame/barbassault/bots/LobbyBehavior.kt b/Server/src/main/content/minigame/barbassault/bots/LobbyBehavior.kt index f0f1c3e4d..79fb02851 100644 --- a/Server/src/main/content/minigame/barbassault/bots/LobbyBehavior.kt +++ b/Server/src/main/content/minigame/barbassault/bots/LobbyBehavior.kt @@ -31,9 +31,8 @@ class LobbyBehavior : RoleBehavior { 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}" - ) + 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 @@ -53,8 +52,8 @@ class LobbyBehavior : RoleBehavior { return } - if (ctx.tick % 50 == 0) { - ctx.bot.sendChat("Cmon, we need more people!!") + if (ctx.tick % 150 == 0) { + ctx.api.sendChat("Cmon, we need more people!!") } } private fun getToBA(ctx: BABotContext) { diff --git a/Server/src/main/content/minigame/barbassault/bots/SmartBABot.kt b/Server/src/main/content/minigame/barbassault/bots/SmartBABot.kt index a7d28c025..ee960aeb2 100644 --- a/Server/src/main/content/minigame/barbassault/bots/SmartBABot.kt +++ b/Server/src/main/content/minigame/barbassault/bots/SmartBABot.kt @@ -70,8 +70,8 @@ class SmartBABot(l: Location) : PvMBots(l) { } override fun tick() { - super.tick() brain.tick() + super.tick() } }